@ -5358,135 +5358,171 @@ static int hex2int(char a)
return 0 ;
}
/*--- get_sip_pvt_byid_locked: Lock interface lock and find matching pvt lock ---*/
static struct sip_pvt * get_sip_pvt_byid_locked ( char * callid )
{
struct sip_pvt * sip_pvt_ptr = NULL ;
/* Search interfaces and find the match */
ast_mutex_lock ( & iflock ) ;
sip_pvt_ptr = iflist ;
while ( sip_pvt_ptr ) {
if ( ! strcmp ( sip_pvt_ptr - > callid , callid ) ) {
/* Go ahead and lock it (and its owner) before returning */
ast_mutex_lock ( & sip_pvt_ptr - > lock ) ;
if ( sip_pvt_ptr - > owner ) {
while ( ast_mutex_trylock ( & sip_pvt_ptr - > owner - > lock ) ) {
ast_mutex_unlock ( & sip_pvt_ptr - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & sip_pvt_ptr - > lock ) ;
if ( ! sip_pvt_ptr - > owner )
break ;
}
}
break ;
}
sip_pvt_ptr = sip_pvt_ptr - > next ;
}
ast_mutex_unlock ( & iflock ) ;
return sip_pvt_ptr ;
}
/*--- sip_unescape_uri: Turn %XX into and ascii char ---*/
static int sip_unescape_uri ( char * uri )
{
char * ptr = uri ;
int replaced = 0 ;
while ( ( ptr = strchr ( ptr , ' % ' ) ) ) {
/* un-escape urlencoded text */
if ( strlen ( ptr ) < 3 )
break ;
* ptr = hex2int ( ptr [ 1 ] ) * 16 + hex2int ( ptr [ 2 ] ) ;
memmove ( ptr + 1 , ptr + 3 , strlen ( ptr + 3 ) + 1 ) ;
ptr + + ;
replaced + + ;
}
return replaced ;
}
/*--- get_refer_info: Call transfer support (new standard) ---*/
static int get_refer_info ( struct sip_pvt * p , struct sip_request * oreq )
static int get_refer_info ( struct sip_pvt * si p_pvt , struct sip_request * o utgoing_ req)
{
char tmp [ 256 ] = " " , * c , * a ;
char tmp2 [ 256 ] = " " , * c2 , * a2 ;
char tmp3 [ 256 ] ;
char tmp4 [ 256 ] ;
char tmp5 [ 256 ] = " " ; /* CallID to replace */
struct sip_request * req ;
struct sip_pvt * p2 ;
char * p_refer_to = NULL , * p_referred_by = NULL , * h_refer_to = NULL , * h_referred_by = NULL , * h_contact = NULL ;
char * replace_callid = " " , * refer_to = NULL , * referred_by = NULL , * ptr = NULL ;
struct sip_request * req = NULL ;
struct sip_pvt * sip_pvt_ptr = NULL ;
struct ast_channel * chan = NULL , * peer = NULL ;
req = oreq ;
if ( ! req )
req = & p - > initreq ;
strncpy ( tmp , get_header ( req , " Refer-To " ) , sizeof ( tmp ) - 1 ) ;
strncpy ( tmp2 , get_header ( req , " Referred-By " ) , sizeof ( tmp2 ) - 1 ) ;
strncpy ( tmp3 , get_header ( req , " Contact " ) , sizeof ( tmp3 ) - 1 ) ;
strncpy ( tmp4 , get_header ( req , " Remote-Party-ID " ) , sizeof ( tmp4 ) - 1 ) ;
req = outgoing_req ;
if ( ! req ) {
req = & sip_pvt - > initreq ;
}
c = ditch_braces ( tmp ) ;
c2 = ditch_braces ( tmp2 ) ;
if ( ! ( ( p_refer_to = get_header ( req , " Refer-To " ) ) & & ( h_refer_to = ast_strdupa ( p_refer_to ) ) ) ) {
ast_log ( LOG_WARNING , " No Refer-To Header That's illegal \n " ) ;
return - 1 ;
}
refer_to = ditch_braces ( h_refer_to ) ;
if ( ! ( ( p_referred_by = get_header ( req , " Referred-By " ) ) & & ( h_referred_by = ast_strdupa ( p_referred_by ) ) ) ) {
ast_log ( LOG_WARNING , " No Refer-To Header That's illegal \n " ) ;
return - 1 ;
}
referred_by = ditch_braces ( h_referred_by ) ;
h_contact = get_header ( req , " Contact " ) ;
if ( strncmp ( c , " sip: " , 4 ) & & strncmp ( c2 , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c ) ;
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , c2 ) ;
if ( strncmp ( refer_to , " sip: " , 4 ) & & strncmp ( referred_by , " sip: " , 4 ) ) {
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , refer_to ) ;
ast_log ( LOG_WARNING , " Huh? Not a SIP header (%s)? \n " , referred_by ) ;
return - 1 ;
}
c + = 4 ;
c2 + = 4 ;
if ( ( a = strchr ( c , ' ? ' ) ) ) {
refer_to + = 4 ;
referred_by + = 4 ;
if ( ( ptr = strchr ( refer_to , ' ? ' ) ) ) {
/* Search for arguemnts */
* a = ' \0 ' ;
a + + ;
if ( ! strncasecmp ( a , " REPLACES= " , strlen ( " REPLACES= " ) ) ) {
strncpy ( tmp5 , a + strlen ( " REPLACES= " ) , sizeof ( tmp5 ) - 1 ) ;
a = tmp5 ;
while ( ( a = strchr ( a , ' % ' ) ) ) {
/* Yuck! Pingtel converts the '@' to a %40, icky icky! Convert
back to an ' @ ' */
if ( strlen ( a ) < 3 )
break ;
* a = hex2int ( a [ 1 ] ) * 16 + hex2int ( a [ 2 ] ) ;
memmove ( a + 1 , a + 3 , strlen ( a + 3 ) + 1 ) ;
a + + ;
}
if ( ( a = strchr ( tmp5 , ' % ' ) ) )
* a = ' \0 ' ;
if ( ( a = strchr ( tmp5 , ' ; ' ) ) )
* a = ' \0 ' ;
* ptr = ' \0 ' ;
ptr + + ;
if ( ! strncasecmp ( ptr , " REPLACES= " , 9 ) ) {
replace_callid = ast_strdupa ( ptr + 9 ) ;
/* someday soon to support invite/replaces properly!
replaces_header = ast_strdupa ( replace_callid ) ;
- anthm
*/
sip_unescape_uri ( replace_callid ) ;
if ( ( ptr = strchr ( replace_callid , ' % ' ) ) )
* ptr = ' \0 ' ;
if ( ( ptr = strchr ( replace_callid , ' ; ' ) ) )
* ptr = ' \0 ' ;
/* Skip leading whitespace */
while ( tmp5 [ 0 ] & & ( tmp5 [ 0 ] < 33 ) )
memmove ( tmp5 , tmp5 + 1 , strlen ( tmp5 ) ) ;
while ( replace_callid [ 0 ] & & ( replace_callid [ 0 ] < 33 ) )
memmove ( replace_callid , replace_callid + 1 , strlen ( replace_callid ) ) ;
}
}
if ( ( a = strchr ( c , ' @ ' ) ) )
* a = ' \0 ' ;
if ( ( a = strchr ( c , ' ; ' ) ) )
* a = ' \0 ' ;
if ( ( ptr = strchr ( refer_to , ' @ ' ) ) )
* ptr = ' \0 ' ;
if ( ( ptr = strchr ( refer_to , ' ; ' ) ) )
* ptr = ' \0 ' ;
if ( ( a2 = strchr ( c2 , ' @ ' ) ) )
* a2 = ' \0 ' ;
if ( ( a2 = strchr ( c2 , ' ; ' ) ) )
* a2 = ' \0 ' ;
if ( ( ptr = strchr ( referred_by , ' @ ' ) ) )
* ptr = ' \0 ' ;
if ( ( ptr = strchr ( referred_by , ' ; ' ) ) )
* ptr = ' \0 ' ;
if ( sip_debug_test_pvt ( p ) ) {
ast_verbose ( " Looking for %s in %s \n " , c , p - > context ) ;
ast_verbose ( " Looking for %s in %s \n " , c2 , p - > context ) ;
if ( sip_debug_test_pvt ( sip_pvt ) ) {
ast_verbose ( " Looking for %s in %s \n " , refer_to , sip_pvt - > context ) ;
ast_verbose ( " Looking for %s in %s \n " , referred_by , sip_pvt - > context ) ;
}
if ( ! ast_strlen_zero ( tmp5 ) ) {
if ( ! ast_strlen_zero ( replace_callid ) ) {
/* This is a supervised transfer */
ast_log ( LOG_DEBUG , " Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID \n " , tmp5 ) ;
ast_log ( LOG_DEBUG , " Assigning Replace-Call-ID Info %s to REPLACE_CALL_ID \n " , replace_callid ) ;
strncpy ( p - > refer_to , " " , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , " " , sizeof ( p - > referred_by ) - 1 ) ;
strncpy ( p - > refer_contact , " " , sizeof ( p - > refer_contact ) - 1 ) ;
p - > refer_call = NULL ;
ast_mutex_lock ( & iflock ) ;
/* Search interfaces and find the match */
p2 = iflist ;
while ( p2 ) {
if ( ! strcmp ( p2 - > callid , tmp5 ) ) {
/* Go ahead and lock it (and its owner) before returning */
ast_mutex_lock ( & p2 - > lock ) ;
if ( p2 - > owner ) {
while ( ast_mutex_trylock ( & p2 - > owner - > lock ) ) {
ast_mutex_unlock ( & p2 - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & p2 - > lock ) ;
if ( ! p2 - > owner )
break ;
}
}
p - > refer_call = p2 ;
break ;
}
p2 = p2 - > next ;
}
ast_mutex_unlock ( & iflock ) ;
if ( p - > refer_call ) {
if ( p - > refer_call = = p ) {
ast_log ( LOG_NOTICE , " Supervised transfer attempted to transfer into same call id (%s == %s)! \n " , tmp5 , p - > callid ) ;
p - > refer_call = NULL ;
strncpy ( sip_pvt - > refer_to , " " , sizeof ( sip_pvt - > refer_to ) - 1 ) ;
strncpy ( sip_pvt - > referred_by , " " , sizeof ( sip_pvt - > referred_by ) - 1 ) ;
strncpy ( sip_pvt - > refer_contact , " " , sizeof ( sip_pvt - > refer_contact ) - 1 ) ;
sip_pvt - > refer_call = NULL ;
if ( ( sip_pvt_ptr = get_sip_pvt_byid_locked ( replace_callid ) ) ) {
sip_pvt - > refer_call = sip_pvt_ptr ;
if ( sip_pvt - > refer_call = = sip_pvt ) {
ast_log ( LOG_NOTICE , " Supervised transfer attempted to transfer into same call id (%s == %s)! \n " , replace_callid , sip_pvt - > callid ) ;
sip_pvt - > refer_call = NULL ;
} else
return 0 ;
} else
ast_log ( LOG_NOTICE , " Supervised transfer requested, but unable to find callid '%s' \n " , tmp5 ) ;
} else if ( ast_exists_extension ( NULL , p - > context , c , 1 , NULL ) | | ! strcmp ( c , ast_parking_ext ( ) ) ) {
} else {
ast_log ( LOG_NOTICE , " Supervised transfer requested, but unable to find callid '%s'. Both legs must reside on Asterisk box to transfer at this time. \n " , replace_callid ) ;
/* XXX The refer_to could contain a call on an entirely different machine, requiring an
INVITE with a replaces header - anthm XXX */
}
} else if ( ast_exists_extension ( NULL , sip_pvt - > context , refer_to , 1 , NULL ) | | ! strcmp ( refer_to , ast_parking_ext ( ) ) ) {
/* This is an unsupervised transfer */
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFER-TO \n " , c ) ;
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFERRED-BY \n " , c2 ) ;
ast_log ( LOG_DEBUG , " Assigning Contact Info %s to REFER_CONTACT \n " , tmp3 ) ;
strncpy ( p - > refer_to , c , sizeof ( p - > refer_to ) - 1 ) ;
strncpy ( p - > referred_by , c2 , sizeof ( p - > referred_by ) - 1 ) ;
strncpy ( p - > refer_contact , tmp3 , sizeof ( p - > refer_contact ) - 1 ) ;
p - > refer_call = NULL ;
if ( ( chan = p - > owner ) & & ( peer = ast_bridged_channel ( p - > owner ) ) ) {
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFER-TO \n " , refer_to ) ;
ast_log ( LOG_DEBUG , " Assigning Extension %s to REFERRED-BY \n " , referred_by ) ;
ast_log ( LOG_DEBUG , " Assigning Contact Info %s to REFER_CONTACT \n " , h_contact ) ;
strncpy ( sip_pvt - > refer_to , refer_to , sizeof ( sip_pvt - > refer_to ) - 1 ) ;
strncpy ( sip_pvt - > referred_by , referred_by , sizeof ( sip_pvt - > referred_by ) - 1 ) ;
if ( h_contact ) {
strncpy ( sip_pvt - > refer_contact , h_contact , sizeof ( sip_pvt - > refer_contact ) - 1 ) ;
}
sip_pvt - > refer_call = NULL ;
if ( ( chan = sip_pvt - > owner ) & & ( peer = ast_bridged_channel ( sip_pvt - > owner ) ) ) {
pbx_builtin_setvar_helper ( chan , " BLINDTRANSFER " , peer - > name ) ;
pbx_builtin_setvar_helper ( peer , " BLINDTRANSFER " , chan - > name ) ;
}
return 0 ;
} else if ( ast_canmatch_extension ( NULL , p- > context , c , 1 , NULL ) ) {
} else if ( ast_canmatch_extension ( NULL , si p_pvt - > context , refer_to , 1 , NULL ) ) {
return 1 ;
}