@ -72,6 +72,14 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# define AST_MAX_WATCHERS 256
# define MAX_DIAL_FEATURE_OPTIONS 30
# define FEATURE_RETURN_HANGUP -1
# define FEATURE_RETURN_SUCCESSBREAK 0
# define FEATURE_RETURN_PASSDIGITS 21
# define FEATURE_RETURN_STOREDIGITS 22
# define FEATURE_RETURN_SUCCESS 23
# define FEATURE_RETURN_KEEPTRYING 24
# define FEATURE_RETURN_PARKFAILED 25
enum {
AST_FEATURE_FLAG_NEEDSDTMF = ( 1 < < 0 ) ,
AST_FEATURE_FLAG_ONPEER = ( 1 < < 1 ) ,
@ -338,16 +346,15 @@ static int metermaidstate(const char *data)
return AST_DEVICE_INUSE ;
}
static int park_call_full ( struct ast_channel * chan , struct ast_channel * peer , int timeout , int * extout , const char * orig_chan_name )
static struct parkeduser * park_space_reserve ( struct ast_channel * chan )
{
struct parkeduser * pu , * cur ;
int i , x = - 1 , parking_range , parkingnum_copy ;
struct ast_context * con ;
int i , parking_space = - 1 , parking_range ;
const char * parkingexten ;
/* Allocate memory for parking data */
if ( ! ( pu = ast_calloc ( 1 , sizeof ( * pu ) ) ) )
return - 1 ;
return NULL ;
/* Lock parking lot */
ast_mutex_lock ( & parking_lock ) ;
@ -360,28 +367,28 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
* limitation here . If extout was not numeric , we could permit
* arbitrary non - numeric extensions .
*/
if ( sscanf ( parkingexten , " %d " , & x) ! = 1 | | x < 0 ) {
if ( sscanf ( parkingexten , " %d " , & parking_space) ! = 1 | | parking_space < 0 ) {
ast_log ( LOG_WARNING , " PARKINGEXTEN does not indicate a valid parking slot: '%s'. \n " , parkingexten ) ;
ast_mutex_unlock ( & parking_lock ) ;
free ( pu ) ;
return 1 ; /* Continue execution if possible */
return NULL ;
}
snprintf ( pu - > parkingexten , sizeof ( pu - > parkingexten ) , " %d " , x ) ;
snprintf ( pu - > parkingexten , sizeof ( pu - > parkingexten ) , " %d " , parking_space ) ;
if ( ast_exists_extension ( NULL , parking_con , pu - > parkingexten , 1 , NULL ) ) {
ast_mutex_unlock ( & parking_lock ) ;
free ( pu ) ;
ast_log ( LOG_WARNING , " Requested parking extension already exists: %s@%s \n " , parkingexten , parking_con ) ;
return 1 ; /* Continue execution if possible */
free ( pu ) ;
return NULL ;
}
} else {
/* Select parking space within range */
parking_range = parking_stop - parking_start + 1 ;
for ( i = 0 ; i < parking_range ; i + + ) {
x = ( i + parking_offset ) % parking_range + parking_start ;
parking_space = ( i + parking_offset ) % parking_range + parking_start ;
cur = parkinglot ;
while ( cur ) {
if ( cur - > parkingnum = = x )
if ( cur - > parkingnum = = parking_space )
break ;
cur = cur - > next ;
}
@ -391,16 +398,38 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
if ( ! ( i < parking_range ) ) {
ast_log ( LOG_WARNING , " No more parking spaces \n " ) ;
free ( pu ) ;
ast_mutex_unlock ( & parking_lock ) ;
return - 1 ;
free ( pu ) ;
return NULL ;
}
/* Set pointer for next parking */
if ( parkfindnext )
parking_offset = x - parking_start + 1 ;
snprintf ( pu - > parkingexten , sizeof ( pu - > parkingexten ) , " %d " , x ) ;
parking_offset = parking_space - parking_start + 1 ;
snprintf ( pu - > parkingexten , sizeof ( pu - > parkingexten ) , " %d " , parking_space ) ;
}
pu - > notquiteyet = 1 ;
pu - > parkingnum = parking_space ;
pu - > next = parkinglot ;
parkinglot = pu ;
ast_mutex_unlock ( & parking_lock ) ;
return pu ;
}
static int park_call_full ( struct ast_channel * chan , struct ast_channel * peer , int timeout , int * extout , const char * orig_chan_name , struct parkeduser * pu )
{
struct ast_context * con ;
int parkingnum_copy ;
/* Get a valid space if not already done */
if ( pu = = NULL )
pu = park_space_reserve ( chan ) ;
if ( pu = = NULL )
return 1 ; /* Continue execution if possible */
snprintf ( pu - > parkingexten , sizeof ( pu - > parkingexten ) , " %d " , pu - > parkingnum ) ;
chan - > appl = " Parked Call " ;
chan - > data = NULL ;
@ -414,10 +443,9 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
}
pu - > start = ast_tvnow ( ) ;
pu - > parkingnum = x ;
pu - > parkingtime = ( timeout > 0 ) ? timeout : parkingtime ;
if ( extout )
* extout = x ;
* extout = pu- > parkingnum ;
if ( peer ) {
/* This is so ugly that it hurts, but implementing get_base_channel() on local channels
@ -449,12 +477,12 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
ast_copy_string ( pu - > context , S_OR ( chan - > macrocontext , chan - > context ) , sizeof ( pu - > context ) ) ;
ast_copy_string ( pu - > exten , S_OR ( chan - > macroexten , chan - > exten ) , sizeof ( pu - > exten ) ) ;
pu - > priority = chan - > macropriority ? chan - > macropriority : chan - > priority ;
pu - > next = parkinglot ;
parkinglot = pu ;
parkingnum_copy = pu - > parkingnum ;
/* If parking a channel directly, don't quite yet get parking running on it */
if ( peer = = chan )
pu - > notquiteyet = 1 ;
/* If parking a channel directly (peer == chan), don't quite yet get parking running on it.
* All parking lot entires are put into the parking lot with notquiteyet on . */
if ( peer ! = chan )
pu - > notquiteyet = 0 ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds \n " , pu - > chan - > name , pu - > parkingnum , parking_con , pu - > context , pu - > exten , pu - > priority , ( pu - > parkingtime / 1000 ) ) ;
@ -488,7 +516,6 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
}
}
ast_mutex_unlock ( & parking_lock ) ;
/* Wake up the (presumably select()ing) thread */
pthread_kill ( parking_thread , SIGURG ) ;
@ -517,15 +544,21 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
after these channels too */
int ast_park_call ( struct ast_channel * chan , struct ast_channel * peer , int timeout , int * extout )
{
return park_call_full ( chan , peer , timeout , extout , NULL );
return park_call_full ( chan , peer , timeout , extout , NULL , NULL );
}
static int masq_park_call ( struct ast_channel * rchan , struct ast_channel * peer , int timeout , int * extout , int play_announcement , const char * orig_chan_name )
{
struct ast_channel * chan ;
struct ast_frame * f ;
struct parkeduser * pu ;
int park_status ;
if ( ( pu = park_space_reserve ( rchan ) ) = = NULL ) {
ast_stream_and_wait ( peer , " beeperr " , peer - > language , " " ) ;
return FEATURE_RETURN_PARKFAILED ;
}
/* Make a new, fake channel that we'll use to masquerade in the real one */
if ( ! ( chan = ast_channel_alloc ( 0 , AST_STATE_DOWN , 0 , 0 , rchan - > accountcode , rchan - > exten , rchan - > context , rchan - > amaflags , " Parked/%s " , rchan - > name ) ) ) {
ast_log ( LOG_WARNING , " Unable to create parked channel \n " ) ;
@ -553,7 +586,7 @@ static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, i
orig_chan_name = ast_strdupa ( chan - > name ) ;
}
park_status = park_call_full ( chan , peer , timeout , extout , orig_chan_name );
park_status = park_call_full ( chan , peer , timeout , extout , orig_chan_name , pu );
if ( park_status = = 1 ) {
/* would be nice to play: "invalid parking extension" */
ast_hangup ( chan ) ;
@ -572,12 +605,6 @@ static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel
{
return masq_park_call ( rchan , peer , timeout , extout , 1 , orig_chan_name ) ;
}
# define FEATURE_RETURN_HANGUP -1
# define FEATURE_RETURN_SUCCESSBREAK 0
# define FEATURE_RETURN_PASSDIGITS 21
# define FEATURE_RETURN_STOREDIGITS 22
# define FEATURE_RETURN_SUCCESS 23
# define FEATURE_RETURN_KEEPTRYING 24
# define FEATURE_SENSE_CHAN (1 << 0)
# define FEATURE_SENSE_PEER (1 << 1)
@ -624,8 +651,8 @@ static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer,
res = ast_safe_sleep ( chan , 1000 ) ;
if ( ! res ) { /* one direction used to call park_call.... */
masq_park_call_announce ( parkee , parker , 0 , NULL , orig_chan_name ) ;
res = 0 ; /* PBX should hangup zombie channel */
res = masq_park_call_announce ( parkee , parker , 0 , NULL , orig_chan_name ) ;
/* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
}
ast_module_user_remove ( u ) ;
@ -751,6 +778,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
char xferto [ 256 ] ;
int res ;
const char * orig_chan_name ;
int parkstatus = 0 ;
set_peers ( & transferer , & transferee , peer , chan , sense ) ;
orig_chan_name = ast_strdupa ( transferer - > name ) ;
@ -780,13 +808,13 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
res = finishup ( transferee ) ;
if ( res )
res = - 1 ;
else if ( ! masq_park_call_announce ( transferee , transferer , 0 , NULL , orig_chan_name ) ) { /* success */
else if ( ! ( parkstatus = masq_park_call_announce ( transferee , transferer , 0 , NULL , orig_chan_name ) ) ) { /* success */
/* We return non-zero, but tell the PBX not to hang the channel when
the thread dies - - We have to be careful now though . We are responsible for
hanging up the channel , else it will never be hung up ! */
return 0 ;
} else {
ast_log ( LOG_WARNING , " Unable to park call %s \n " , transferee - > name ) ;
ast_log ( LOG_WARNING , " Unable to park call %s , parkstatus=%d \n " , transferee - > name , parkstatus ) ;
}
/*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
} else if ( ast_exists_extension ( transferee , transferer_real_context , xferto , 1 , transferer - > cid . cid_num ) ) {
@ -825,7 +853,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Unable to find extension '%s' in context '%s' \n " , xferto , transferer_real_context ) ;
}
if ( ast_stream_and_wait ( transferer , xferfailsound , transferer - > language , AST_DIGIT_ANY ) < 0 ) {
if ( parkstatus ! = FEATURE_RETURN_PARKFAILED & & ast_stream_and_wait ( transferer , xferfailsound , transferer - > language , AST_DIGIT_ANY ) < 0 ) {
finishup ( transferee ) ;
return - 1 ;
}
@ -1213,6 +1241,9 @@ static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *p
! ast_strlen_zero ( builtin_features [ x ] . exten ) ) {
/* Feature is up for consideration */
if ( ! strcmp ( builtin_features [ x ] . exten , code ) ) {
if ( option_debug > 2 ) {
ast_log ( LOG_DEBUG , " Feature detected: fname=%s sname=%s exten=%s \n " , builtin_features [ x ] . fname , builtin_features [ x ] . sname , builtin_features [ x ] . exten ) ;
}
res = builtin_features [ x ] . operation ( chan , peer , config , code , sense , NULL ) ;
feature_detected = 1 ;
break ;