@ -1590,6 +1590,161 @@ static int analog_handles_digit(struct ast_frame *f)
}
}
enum callwaiting_deluxe_option {
CWD_CONFERENCE = ' 3 ' ,
CWD_HOLD = ' 6 ' ,
CWD_DROP = ' 7 ' ,
CWD_ANNOUNCEMENT = ' 8 ' ,
CWD_FORWARD = ' 9 ' ,
} ;
static const char * callwaiting_deluxe_optname ( int option )
{
switch ( option ) {
case CWD_CONFERENCE :
return " CONFERENCE " ;
case CWD_HOLD :
return " HOLD " ;
case CWD_DROP :
return " DROP " ;
case CWD_ANNOUNCEMENT :
return " ANNOUNCEMENT " ;
case CWD_FORWARD :
return " FORWARD " ;
default :
return " DEFAULT " ;
}
}
int analog_callwaiting_deluxe ( struct analog_pvt * p , int option )
{
const char * announce_var ;
char announcement [ PATH_MAX ] ;
ast_debug ( 1 , " Handling Call Waiting on channel %d with option %c: treatment %s \n " , p - > channel , option , callwaiting_deluxe_optname ( option ) ) ;
if ( ! p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) {
/* This can happen if the caller hook flashes and the call waiting hangs up before the CWD timer expires (1 second) */
ast_debug ( 1 , " Call waiting call disappeared before it could be handled? \n " ) ;
return - 1 ;
}
analog_lock_sub_owner ( p , ANALOG_SUB_CALLWAIT ) ;
if ( ! p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) {
ast_log ( LOG_WARNING , " Whoa, the call-waiting call disappeared. \n " ) ;
return - 1 ;
}
/* Note that when p->callwaitingdeluxepending, dahdi_write will drop incoming frames to the channel,
* since the user shouldn ' t hear anything after flashing until either a DTMF has been received
* or it ' s been a second and the decision is made automatically . */
switch ( option ) {
case CWD_CONFERENCE :
/* We should never have a call waiting if we have a 3-way anyways, but check just in case,
* there better be no existing SUB_THREEWAY since we ' re going to make one ( and then swap the call wait to it ) */
if ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner ) {
ast_channel_unlock ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) ;
ast_log ( LOG_ERROR , " Already have a 3-way call on channel %d, can't conference! \n " , p - > channel ) ;
return - 1 ;
}
/* To conference the incoming call, swap it from SUB_CALLWAIT to SUB_THREEWAY,
* and then the existing 3 - way logic will ensure that flashing again will drop the call waiting */
analog_alloc_sub ( p , ANALOG_SUB_THREEWAY ) ;
analog_swap_subs ( p , ANALOG_SUB_THREEWAY , ANALOG_SUB_CALLWAIT ) ;
analog_unalloc_sub ( p , ANALOG_SUB_CALLWAIT ) ;
ast_verb ( 3 , " Building conference call with %s and %s \n " , ast_channel_name ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner ) , ast_channel_name ( p - > subs [ ANALOG_SUB_REAL ] . owner ) ) ;
analog_set_inthreeway ( p , ANALOG_SUB_THREEWAY , 1 ) ;
analog_set_inthreeway ( p , ANALOG_SUB_REAL , 1 ) ;
if ( ast_channel_state ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner ) = = AST_STATE_RINGING ) {
ast_setstate ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner , AST_STATE_UP ) ;
ast_queue_control ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner , AST_CONTROL_ANSWER ) ;
/* Stop the ringing on the call wait channel (yeah, apparently this is how it's done) */
ast_queue_hold ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner , p - > mohsuggest ) ;
ast_queue_unhold ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner ) ;
}
analog_stop_callwait ( p ) ;
ast_channel_unlock ( p - > subs [ ANALOG_SUB_THREEWAY ] . owner ) ; /* Unlock what was originally SUB_CALLWAIT */
break ;
case CWD_HOLD : /* The CI-7112 Visual Director sends "HOLD" for "Play hold message" rather than "ANNOUNCEMENT". For default behavior, nothing is actually sent. */
case CWD_ANNOUNCEMENT :
/* We can't just call ast_streamfile here, this thread isn't responsible for media on the call waiting channel.
* Indicate to the dialing channel in app_dial that it needs to play media .
*
* This is a lot easier than other ways of trying to send early media to the channel
* ( such as every call from the core to dahdi_read , sending the channel one frame of the audio file , etc . )
*/
/* There's not a particularly good stock audio prompt to use here. The Pat Fleet library has some better
* ones but we want one that is also in the default Allison Smith library . " One moment please " works okay .
* Check if a variable containing the prompt to use was specified on the call waiting channel , and
* fall back to a reasonable default if not . */
/* The SUB_CALLWAIT channel is already locked here, no need to lock and unlock to get the variable. */
announce_var = pbx_builtin_getvar_helper ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner , " CALLWAITDELUXEANNOUNCEMENT " ) ;
ast_copy_string ( announcement , S_OR ( announce_var , " one-moment-please " ) , sizeof ( announcement ) ) ;
ast_debug ( 2 , " Call Waiting Deluxe announcement for %s: %s \n " , ast_channel_name ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) , announcement ) ;
ast_channel_unlock ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) ;
/* Tell app_dial what file to play. */
ast_queue_control_data ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner , AST_CONTROL_PLAYBACK_BEGIN , announcement , strlen ( announcement ) + 1 ) ;
/* Unlike all the other options, the call waiting is still active with this option,
* so we don ' t call analog_stop_callwait ( p )
* The call waiting will continue to be here , and at some later point the user can flash again and choose a finalizing option
* ( or even queue the announcement again . . . and again . . . and again . . . )
*/
break ;
case CWD_FORWARD :
/* Go away, call waiting, call again some other day... */
analog_stop_callwait ( p ) ;
/* Can't use p->call_forward exten because that's for *72 forwarding, and sig_analog doesn't
* have a Busy / Don ' t Answer call forwarding exten internally , so let the dialplan deal with it .
* by sending the call to the ' f ' extension .
*/
ast_channel_call_forward_set ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner , " f " ) ;
ast_channel_unlock ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) ;
/* app_dial already has a verbose message for forwarding, so we don't really need one here also since that does the job */
break ;
case CWD_DROP :
/* Fall through: logic is identical to hold, except we drop the original call right after we swap. */
default :
/* Swap to call-wait, same as with the non-deluxe call waiting handling. */
analog_swap_subs ( p , ANALOG_SUB_REAL , ANALOG_SUB_CALLWAIT ) ;
analog_play_tone ( p , ANALOG_SUB_REAL , - 1 ) ;
analog_set_new_owner ( p , p - > subs [ ANALOG_SUB_REAL ] . owner ) ;
ast_debug ( 1 , " Making %s the new owner \n " , ast_channel_name ( p - > owner ) ) ;
if ( ast_channel_state ( p - > subs [ ANALOG_SUB_REAL ] . owner ) = = AST_STATE_RINGING ) {
ast_setstate ( p - > subs [ ANALOG_SUB_REAL ] . owner , AST_STATE_UP ) ;
ast_queue_control ( p - > subs [ ANALOG_SUB_REAL ] . owner , AST_CONTROL_ANSWER ) ;
}
analog_stop_callwait ( p ) ;
if ( option = = CWD_DROP ) {
/* Disconnect the previous call (the original call is now the SUB_CALLWAIT since we swapped above) */
ast_queue_hangup ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) ;
ast_verb ( 3 , " Dropping original call and swapping to call waiting on %s \n " , ast_channel_name ( p - > subs [ ANALOG_SUB_REAL ] . owner ) ) ;
} else {
/* Start music on hold if appropriate */
if ( ! p - > subs [ ANALOG_SUB_CALLWAIT ] . inthreeway ) {
ast_queue_hold ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner , p - > mohsuggest ) ;
}
ast_verb ( 3 , " Holding original call and swapping to call waiting on %s \n " , ast_channel_name ( p - > subs [ ANALOG_SUB_REAL ] . owner ) ) ;
}
/* Stop ringing on the incoming call */
ast_queue_hold ( p - > subs [ ANALOG_SUB_REAL ] . owner , p - > mohsuggest ) ;
ast_queue_unhold ( p - > subs [ ANALOG_SUB_REAL ] . owner ) ;
/* Unlock the call-waiting call that we swapped to real-call. */
ast_channel_unlock ( p - > subs [ ANALOG_SUB_REAL ] . owner ) ;
}
analog_update_conf ( p ) ;
return 0 ;
}
void analog_handle_dtmf ( struct analog_pvt * p , struct ast_channel * ast , enum analog_sub idx , struct ast_frame * * dest )
{
struct ast_frame * f = * dest ;
@ -1627,6 +1782,50 @@ void analog_handle_dtmf(struct analog_pvt *p, struct ast_channel *ast, enum anal
p - > subs [ idx ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ idx ] . f . subclass . integer = 0 ;
* dest = & p - > subs [ idx ] . f ;
} else if ( p - > callwaitingdeluxepending ) {
if ( f - > frametype = = AST_FRAME_DTMF_END ) {
unsigned int mssinceflash = ast_tvdiff_ms ( ast_tvnow ( ) , p - > flashtime ) ;
p - > callwaitingdeluxepending = 0 ;
/* This is the case where a user explicitly took action (made a decision)
* for Call Waiting Deluxe .
* Because we already handled the hook flash , if the user doesn ' t do
* anything within a second , then we still need to eventually take
* the default action ( swap ) for the call waiting .
*
* dahdi_write will also drop audio if callwaitingdeluxepending is set HIGH ,
* and also check if flashtime hits 1000 , in which case it will set the flag LOW and then take the
* default action , e . g . analog_callwaiting_deluxe ( p , 0 ) ;
*/
/* Slightly less than 1000, so there's no chance of a race condition
* between do_monitor when it sees flashtime hitting 1000 and us . */
if ( mssinceflash > 990 ) {
/* This was more than a second ago, clear the flag and process normally. */
/* Because another thread has to monitor channels with pending CWDs,
* in theory , we shouldn ' t need to check this here . */
ast_debug ( 1 , " It's been %u ms since the last flash, this is not a Call Waiting Deluxe DTMF \n " , mssinceflash ) ;
analog_cb_handle_dtmf ( p , ast , idx , dest ) ;
return ;
}
/* Okay, actually do something now. */
switch ( f - > subclass . integer ) {
case CWD_CONFERENCE :
case CWD_HOLD :
case CWD_DROP :
case CWD_ANNOUNCEMENT :
case CWD_FORWARD :
ast_debug ( 1 , " Got some DTMF, but it's for Call Waiting Deluxe: %c \n " , f - > subclass . integer ) ;
analog_callwaiting_deluxe ( p , f - > subclass . integer ) ;
break ;
default :
ast_log ( LOG_WARNING , " Invalid Call Waiting Deluxe option (%c), using default \n " , f - > subclass . integer ) ;
analog_callwaiting_deluxe ( p , 0 ) ;
}
}
p - > subs [ idx ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ idx ] . f . subclass . integer = 0 ;
* dest = & p - > subs [ idx ] . f ;
} else {
analog_cb_handle_dtmf ( p , ast , idx , dest ) ;
}
@ -2991,6 +3190,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
break ;
}
}
p - > callwaitingdeluxepending = 0 ;
ast_queue_control_data ( ast , AST_CONTROL_PVT_CAUSE_CODE , cause_code , data_size ) ;
ast_channel_hangupcause_hash_set ( ast , cause_code , data_size ) ;
switch ( p - > sig ) {
@ -3306,6 +3506,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
}
/* Remember last time we got a flash-hook */
gettimeofday ( & p - > flashtime , NULL ) ;
p - > callwaitingdeluxepending = 0 ;
switch ( mysig ) {
case ANALOG_SIG_FXOLS :
case ANALOG_SIG_FXOGS :
@ -3334,6 +3535,20 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
goto winkflashdone ;
}
/* If line has Call Waiting Deluxe, see what the user wants to do.
* Only do this if this is an as yet unanswered call waiting , not an existing , answered SUB_CALLWAIT . */
if ( ast_channel_state ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) = = AST_STATE_RINGING ) {
if ( p - > callwaitingdeluxe ) {
/* This thread cannot block, so just set the flag that we need
* to wait for a Call Waiting Deluxe option ( or let it time out ) ,
* and then we ' re done for now . */
ast_channel_unlock ( p - > subs [ ANALOG_SUB_CALLWAIT ] . owner ) ;
p - > callwaitingdeluxepending = 1 ;
ast_debug ( 1 , " Deferring call waiting manipulation, waiting for Call Waiting Deluxe option from user \n " ) ;
goto winkflashdone ;
}
}
/* Swap to call-wait */
analog_swap_subs ( p , ANALOG_SUB_REAL , ANALOG_SUB_CALLWAIT ) ;
analog_play_tone ( p , ANALOG_SUB_REAL , - 1 ) ;
@ -3868,6 +4083,7 @@ void *analog_handle_init_event(struct analog_pvt *i, int event)
res = analog_off_hook ( i ) ;
i - > fxsoffhookstate = 1 ;
i - > cshactive = 0 ;
i - > callwaitingdeluxepending = 0 ;
if ( res & & ( errno = = EBUSY ) ) {
break ;
}