@ -28,6 +28,7 @@
# include <asterisk/channel.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/logger.h>
# include <asterisk/say.h>
# include <asterisk/file.h>
# include <asterisk/translate.h>
# include <asterisk/manager.h>
@ -40,7 +41,7 @@
# include <sys/ioctl.h>
# include <linux/zaptel.h>
# ifndef ZT_TIMERPING
# error "You need newer zaptel! Please cvs update zaptel"
# error "You need newer zaptel! Please cvs update zaptel"
# endif
# endif
@ -140,17 +141,19 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
time_t myt ;
time ( & myt ) ;
if ( offset )
if ( offset )
chan - > whentohangup = myt + offset ;
else
chan - > whentohangup = 0 ;
else
chan - > whentohangup = 0 ;
return ;
}
int ast_channel_register ( char * type , char * description , int capabilities ,
struct ast_channel * ( * requester ) ( char * type , int format , void * data ) )
{
return ast_channel_register_ex ( type , description , capabilities , requester , NULL ) ;
return ast_channel_register_ex ( type , description , capabilities , requester , NULL ) ;
}
int ast_channel_register_ex ( char * type , char * description , int capabilities ,
@ -271,8 +274,8 @@ struct ast_channel *ast_channel_alloc(int needqueue)
struct ast_channel_pvt * pvt ;
int x ;
int flags ;
struct varshead * headp ;
struct varshead * headp ;
/* If shutting down, don't allocate any new channels */
if ( shutting_down )
@ -333,7 +336,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
snprintf ( tmp - > uniqueid , sizeof ( tmp - > uniqueid ) , " %li.%d " , ( long ) time ( NULL ) , uniqueint + + ) ;
headp = & tmp - > varshead ;
ast_mutex_init ( & tmp - > lock ) ;
AST_LIST_HEAD_INIT ( headp ) ;
AST_LIST_HEAD_INIT ( headp ) ;
tmp - > vars = ast_var_assign ( " tempvar " , " tempval " ) ;
AST_LIST_INSERT_HEAD ( headp , tmp - > vars , entries ) ;
strncpy ( tmp - > context , " default " , sizeof ( tmp - > context ) - 1 ) ;
@ -461,7 +464,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
}
int ast_safe_sleep_conditional ( struct ast_channel * chan , int ms ,
int ast_safe_sleep_conditional ( struct ast_channel * chan , int ms ,
int ( * cond ) ( void * ) , void * data )
{
struct ast_frame * f ;
@ -569,13 +572,13 @@ void ast_channel_free(struct ast_channel *chan)
/* loop over the variables list, freeing all data and deleting list items */
/* no need to lock the list, as the channel is already locked */
while ( ! AST_LIST_EMPTY ( headp ) ) { /* List Deletion. */
vardata = AST_LIST_FIRST ( headp ) ;
AST_LIST_REMOVE_HEAD ( headp , entries ) ;
// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
ast_var_delete ( vardata ) ;
while ( ! AST_LIST_EMPTY ( headp ) ) { /* List Deletion. */
vardata = AST_LIST_FIRST ( headp ) ;
AST_LIST_REMOVE_HEAD ( headp , entries ) ;
// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
ast_var_delete ( vardata ) ;
}
free ( chan - > pvt ) ;
chan - > pvt = NULL ;
@ -665,7 +668,7 @@ int ast_hangup(struct ast_channel *chan)
}
if ( chan - > blocking ) {
ast_log ( LOG_WARNING , " Hard hangup called by thread %ld on %s, while fd "
" is blocked by thread %ld in procedure %s! Expect a failure\n " ,
" is blocked by thread %ld in procedure %s! Expect a failure\n " ,
( long ) pthread_self ( ) , chan - > name , ( long ) chan - > blocker , chan - > blockproc ) ;
CRASH ;
}
@ -681,9 +684,9 @@ int ast_hangup(struct ast_channel *chan)
ast_mutex_unlock ( & chan - > lock ) ;
manager_event ( EVENT_FLAG_CALL , " Hangup " ,
" Channel: %s \r \n "
" Uniqueid: %s \r \n "
" Cause: %i \r \n " ,
chan - > name , chan - > uniqueid , chan - > hangupcause ) ;
" Uniqueid: %s \r \n "
" Cause: %i \r \n " ,
chan - > name , chan - > uniqueid , chan - > hangupcause ) ;
ast_channel_free ( chan ) ;
return res ;
}
@ -1114,7 +1117,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
ast_log ( LOG_WARNING , " Failed to perform masquerade \n " ) ;
f = NULL ;
} else
f = & null_frame ;
f = & null_frame ;
ast_mutex_unlock ( & chan - > lock ) ;
return f ;
}
@ -1128,7 +1131,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
}
if ( ! chan - > deferdtmf & & strlen ( chan - > dtmfq ) ) {
/* We have DTMF that has been deferred. Return it now */
/* We have DTMF that has been deferred. Return it now */
chan - > dtmff . frametype = AST_FRAME_DTMF ;
chan - > dtmff . subclass = chan - > dtmfq [ 0 ] ;
/* Drop first digit */
@ -1181,7 +1184,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
chan - > timingdata = NULL ;
ast_mutex_unlock ( & chan - > lock ) ;
}
f = & null_frame ;
f = & null_frame ;
return f ;
} else
ast_log ( LOG_NOTICE , " No/unknown event '%d' on timer for '%s'? \n " , blah , chan - > name ) ;
@ -1361,10 +1364,10 @@ int ast_recvchar(struct ast_channel *chan, int timeout)
f = ast_read ( chan ) ;
if ( f = = NULL ) return - 1 ; /* if hangup */
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & &
( f - > subclass = = AST_CONTROL_HANGUP ) ) return - 1 ; /* if hangup */
if ( f - > frametype = = AST_FRAME_TEXT ) /* if a text frame */
( f - > subclass = = AST_CONTROL_HANGUP ) ) return - 1 ; /* if hangup */
if ( f - > frametype = = AST_FRAME_TEXT ) /* if a text frame */
{
c = * ( ( char * ) f - > data ) ; /* get the data */
c = * ( ( char * ) f - > data ) ; /* get the data */
ast_frfree ( f ) ;
return ( c ) ;
}
@ -1397,21 +1400,21 @@ static int do_senddigit(struct ast_channel *chan, char digit)
* it by doing our own generation . ( PM2002 )
*/
static const char * dtmf_tones [ ] = {
" !941+1336/100,!0/100 " , /* 0 */
" !697+1209/100,!0/100 " , /* 1 */
" !697+1336/100,!0/100 " , /* 2 */
" !697+1477/100,!0/100 " , /* 3 */
" !770+1209/100,!0/100 " , /* 4 */
" !770+1336/100,!0/100 " , /* 5 */
" !770+1477/100,!0/100 " , /* 6 */
" !852+1209/100,!0/100 " , /* 7 */
" !852+1336/100,!0/100 " , /* 8 */
" !852+1477/100,!0/100 " , /* 9 */
" !697+1633/100,!0/100 " , /* A */
" !770+1633/100,!0/100 " , /* B */
" !852+1633/100,!0/100 " , /* C */
" !941+1633/100,!0/100 " , /* D */
" !941+1209/100,!0/100 " , /* * */
" !941+1336/100,!0/100 " , /* 0 */
" !697+1209/100,!0/100 " , /* 1 */
" !697+1336/100,!0/100 " , /* 2 */
" !697+1477/100,!0/100 " , /* 3 */
" !770+1209/100,!0/100 " , /* 4 */
" !770+1336/100,!0/100 " , /* 5 */
" !770+1477/100,!0/100 " , /* 6 */
" !852+1209/100,!0/100 " , /* 7 */
" !852+1336/100,!0/100 " , /* 8 */
" !852+1477/100,!0/100 " , /* 9 */
" !697+1633/100,!0/100 " , /* A */
" !770+1633/100,!0/100 " , /* B */
" !852+1633/100,!0/100 " , /* C */
" !941+1633/100,!0/100 " , /* D */
" !941+1209/100,!0/100 " , /* * */
" !941+1477/100,!0/100 " } ; /* # */
if ( digit > = ' 0 ' & & digit < = ' 9 ' )
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' 0 ' ] , 0 ) ;
@ -1462,7 +1465,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
struct ast_frame * f = NULL ;
/* Stop if we're a zombie or need a soft hangup */
ast_mutex_lock ( & chan - > lock ) ;
if ( chan - > zombie | | ast_check_hangup ( chan ) ) {
if ( chan - > zombie | | ast_check_hangup ( chan ) ) {
ast_mutex_unlock ( & chan - > lock ) ;
return - 1 ;
}
@ -1582,7 +1585,7 @@ int ast_set_write_format(struct ast_channel *chan, int fmts)
return - 1 ;
}
/* Now we have a good choice for both. We'll write using our native format. */
/* Now we have a good choice for both. We'll write using our native format. */
chan - > pvt - > rawwriteformat = native ;
/* User perspective is fmt */
chan - > writeformat = fmt ;
@ -1615,7 +1618,7 @@ int ast_set_read_format(struct ast_channel *chan, int fmts)
return - 1 ;
}
/* Now we have a good choice for both. We'll write using our native format. */
/* Now we have a good choice for both. We'll write using our native format. */
chan - > pvt - > rawreadformat = native ;
/* User perspective is fmt */
chan - > readformat = fmt ;
@ -1643,7 +1646,7 @@ struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, i
char * tmp , * var ;
/* JDG chanvar */
tmp = oh - > variable ;
/* FIXME replace this call with strsep NOT*/
/* FIXME replace this call with strsep NOT*/
while ( ( var = strtok_r ( NULL , " | " , & tmp ) ) ) {
pbx_builtin_setvar ( chan , var ) ;
} /* /JDG */
@ -1795,9 +1798,9 @@ int ast_parse_device_state(char *device)
strncpy ( name , chan - > name , sizeof ( name ) - 1 ) ;
cut = strchr ( name , ' - ' ) ;
if ( cut )
* cut = 0 ;
* cut = 0 ;
if ( ! strcmp ( name , device ) )
return AST_DEVICE_INUSE ;
return AST_DEVICE_INUSE ;
chan = ast_channel_walk ( chan ) ;
}
return AST_DEVICE_UNKNOWN ;
@ -1813,7 +1816,7 @@ int ast_device_state(char *device)
strncpy ( tech , device , sizeof ( tech ) - 1 ) ;
number = strchr ( tech , ' / ' ) ;
if ( ! number ) {
return AST_DEVICE_INVALID ;
return AST_DEVICE_INVALID ;
}
* number = 0 ;
number + + ;
@ -2090,8 +2093,8 @@ int ast_do_masquerade(struct ast_channel *original)
clone - > name , clone - > _state , original - > name , original - > _state ) ;
# endif
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
the clone channel into the original channel . Start by killing off the original
channel ' s backend . I ' m not sure we ' re going to keep this function , because
the clone channel into the original channel . Start by killing off the original
channel ' s backend . I ' m not sure we ' re going to keep this function , because
while the features are nice , the cost is very high in terms of pure nastiness . XXX */
/* We need the clone's lock, too */
@ -2126,7 +2129,7 @@ int ast_do_masquerade(struct ast_channel *original)
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , newn , masqn ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , orig , newn ) ;
/* Swap the guts */
/* Swap the guts */
p = original - > pvt ;
original - > pvt = clone - > pvt ;
clone - > pvt = p ;
@ -2175,7 +2178,7 @@ int ast_do_masquerade(struct ast_channel *original)
strncpy ( clone - > name , zombn , sizeof ( clone - > name ) - 1 ) ;
manager_event ( EVENT_FLAG_CALL , " Rename " , " Oldname: %s \r \n Newname: %s \r \n " , masqn , zombn ) ;
/* Keep the same language. */
/* Keep the same language. */
/* Update the type. */
original - > type = clone - > type ;
/* Copy the FD's */
@ -2183,7 +2186,7 @@ int ast_do_masquerade(struct ast_channel *original)
original - > fds [ x ] = clone - > fds [ x ] ;
}
/* Append variables from clone channel into original channel */
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
varptr = original - > varshead . first ;
if ( varptr ) {
while ( varptr - > entries . next ) {
@ -2200,12 +2203,12 @@ int ast_do_masquerade(struct ast_channel *original)
/* CDR fields remain the same */
/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
/* Application and data remain the same */
/* Clone exception becomes real one, as with fdno */
/* Clone exception becomes real one, as with fdno */
original - > exception = clone - > exception ;
original - > fdno = clone - > fdno ;
/* Schedule context remains the same */
/* Stream stuff stays the same */
/* Keep the original state. The fixup code will need to work with it most likely */
/* Keep the original state. The fixup code will need to work with it most likely */
/* dnid and callerid change to become the new, HOWEVER, we also link the original's
fields back into the defunct ' clone ' so that they will be freed when
@ -2229,7 +2232,7 @@ int ast_do_masquerade(struct ast_channel *original)
these separate */
original - > _state = clone - > _state ;
/* Context, extension, priority, app data, jump table, remain the same */
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
/* Set the write format */
@ -2327,16 +2330,73 @@ int ast_setstate(struct ast_channel *chan, int state)
return 0 ;
}
int ast_channel_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , int flags , struct ast_frame * * fo , struct ast_channel * * rc )
{
/* Copy voice back and forth between the two channels. Give the peer
static long tvdiff ( struct timeval * now , struct timeval * then ) {
return ( ( ( now - > tv_sec * 1000 ) + now - > tv_usec / 1000 ) - ( ( then - > tv_sec * 1000 ) + then - > tv_usec / 1000 ) ) ;
}
static void bridge_playfile ( struct ast_channel * chan , char * sound , int remain ) {
int res = 0 , min = 0 , sec = 0 ;
if ( remain > 0 ) {
if ( remain / 60 > 1 ) {
min = remain / 60 ;
sec = remain % 60 ;
}
else {
sec = remain ;
}
}
if ( ! strcmp ( sound , " timeleft " ) ) {
res = ast_streamfile ( chan , " vm-youhave " , chan - > language ) ;
res = ast_waitstream ( chan , " " ) ;
if ( min ) {
res = ast_say_number ( chan , min , AST_DIGIT_ANY , chan - > language ) ;
res = ast_streamfile ( chan , " minutes " , chan - > language ) ;
res = ast_waitstream ( chan , " " ) ;
}
if ( sec ) {
res = ast_say_number ( chan , sec , AST_DIGIT_ANY , chan - > language ) ;
res = ast_streamfile ( chan , " seconds " , chan - > language ) ;
res = ast_waitstream ( chan , " " ) ;
}
}
else {
res = ast_streamfile ( chan , sound , chan - > language ) ;
res = ast_waitstream ( chan , " " ) ;
}
}
int ast_channel_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , struct ast_bridge_config * config , struct ast_frame * * fo , struct ast_channel * * rc ) {
/* Copy voice back and forth between the two channels. Give the peer
the ability to transfer calls with ' # < extension ' syntax . */
int flags ;
struct ast_channel * cs [ 3 ] ;
int to = - 1 ;
struct ast_frame * f ;
struct ast_channel * who = NULL ;
int res ;
int res = 0 ;
int nativefailed = 0 ;
struct timeval start_time , precise_now ;
long elapsed_ms = 0 , time_left_ms = 0 ;
int playit = 0 , playitagain = 1 , first_time = 1 ;
flags = ( config - > allowdisconnect | | config - > allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0 ) + ( config - > allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0 ) ;
/* timestamp */
gettimeofday ( & start_time , NULL ) ;
time_left_ms = config - > timelimit ;
if ( config - > play_to_caller & & config - > start_sound ) {
bridge_playfile ( c0 , config - > start_sound , time_left_ms / 1000 ) ;
}
if ( config - > play_to_callee & & config - > start_sound ) {
bridge_playfile ( c1 , config - > start_sound , time_left_ms / 1000 ) ;
}
/* Stop if we're a zombie or need a soft hangup */
if ( c0 - > zombie | | ast_check_hangup_locked ( c0 ) | | c1 - > zombie | | ast_check_hangup_locked ( c1 ) )
@ -2366,6 +2426,57 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
c0 - > name , c1 - > name , c0 - > uniqueid , c1 - > uniqueid ) ;
for ( /* ever */ ; ; ) {
/* timestamp */
if ( config - > timelimit ) {
gettimeofday ( & precise_now , NULL ) ;
elapsed_ms = tvdiff ( & precise_now , & start_time ) ;
time_left_ms = config - > timelimit - elapsed_ms ;
if ( playitagain & & ( config - > play_to_caller | | config - > play_to_callee ) & & ( config - > play_warning & & time_left_ms < = config - > play_warning ) ) {
/* narrowing down to the end */
if ( config - > warning_freq = = 0 ) {
playit = 1 ;
first_time = 0 ;
playitagain = 0 ;
}
else if ( first_time ) {
playit = 1 ;
first_time = 0 ;
}
else {
if ( ( time_left_ms % config - > warning_freq ) < = 50 ) {
playit = 1 ;
}
}
}
if ( time_left_ms < = 0 ) {
if ( config - > play_to_caller & & config - > end_sound ) {
bridge_playfile ( c0 , config - > end_sound , 0 ) ;
}
if ( config - > play_to_callee & & config - > end_sound ) {
bridge_playfile ( c1 , config - > end_sound , 0 ) ;
}
break ;
}
if ( time_left_ms > = 5000 & & playit ) {
if ( config - > play_to_caller & & config - > warning_sound & & config - > play_warning ) {
bridge_playfile ( c0 , config - > warning_sound , time_left_ms / 1000 ) ;
}
if ( config - > play_to_callee & & config - > warning_sound & & config - > play_warning ) {
bridge_playfile ( c1 , config - > warning_sound , time_left_ms / 1000 ) ;
}
playit = 0 ;
}
}
/* Stop if we're a zombie or need a soft hangup */
if ( c0 - > zombie | | ast_check_hangup_locked ( c0 ) | | c1 - > zombie | | ast_check_hangup_locked ( c1 ) ) {
* fo = NULL ;
@ -2374,7 +2485,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
ast_log ( LOG_DEBUG , " Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s \n " , c0 - > name , c1 - > name , c0 - > zombie ? " Yes " : " No " , ast_check_hangup ( c0 ) ? " Yes " : " No " , c1 - > zombie ? " Yes " : " No " , ast_check_hangup ( c1 ) ? " Yes " : " No " ) ;
break ;
}
if ( c0 - > pvt - > bridge & &
if ( c0 - > pvt - > bridge & & config - > timelimit = = 0 & &
( c0 - > pvt - > bridge = = c1 - > pvt - > bridge ) & & ! nativefailed & & ! c0 - > monitor & & ! c1 - > monitor ) {
/* Looks like they share a bridge code */
if ( option_verbose > 2 )