@ -1394,6 +1394,18 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
return chan ;
return chan ;
}
}
static struct ast_cdr * pick_unlocked_cdr ( struct ast_cdr * cdr )
{
struct ast_cdr * cdr_orig = cdr ;
while ( cdr ) {
if ( ! ast_test_flag ( cdr , AST_CDR_FLAG_LOCKED ) )
return cdr ;
cdr = cdr - > next ;
}
return cdr_orig ; /* everybody LOCKED or some other weirdness, like a NULL */
}
int ast_bridge_call ( struct ast_channel * chan , struct ast_channel * peer , struct ast_bridge_config * config )
int ast_bridge_call ( struct ast_channel * chan , struct ast_channel * peer , struct ast_bridge_config * config )
{
{
/* Copy voice back and forth between the two channels. Give the peer
/* Copy voice back and forth between the two channels. Give the peer
@ -1413,6 +1425,8 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
struct ast_bridge_config backup_config ;
struct ast_bridge_config backup_config ;
struct ast_cdr * bridge_cdr = NULL ;
struct ast_cdr * bridge_cdr = NULL ;
struct ast_cdr * orig_peer_cdr = NULL ;
struct ast_cdr * orig_peer_cdr = NULL ;
struct ast_cdr * chan_cdr = pick_unlocked_cdr ( chan - > cdr ) ; /* the proper chan cdr, if there are forked cdrs */
struct ast_cdr * peer_cdr = pick_unlocked_cdr ( peer - > cdr ) ; /* the proper chan cdr, if there are forked cdrs */
memset ( & backup_config , 0 , sizeof ( backup_config ) ) ;
memset ( & backup_config , 0 , sizeof ( backup_config ) ) ;
@ -1450,14 +1464,14 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
ast_copy_string ( orig_channame , chan - > name , sizeof ( orig_channame ) ) ;
ast_copy_string ( orig_channame , chan - > name , sizeof ( orig_channame ) ) ;
ast_copy_string ( orig_peername , peer - > name , sizeof ( orig_peername ) ) ;
ast_copy_string ( orig_peername , peer - > name , sizeof ( orig_peername ) ) ;
orig_peer_cdr = peer - > cdr;
orig_peer_cdr = peer _ cdr;
if ( ! chan - > cdr | | ( chan - > cdr & & ! ast_test_flag ( chan - > cdr, AST_CDR_FLAG_POST_DISABLED ) ) ) {
if ( ! chan _cdr | | ( chan_cdr & & ! ast_test_flag ( chan_ cdr, AST_CDR_FLAG_POST_DISABLED ) ) ) {
if ( chan - > cdr) {
if ( chan _ cdr) {
ast_set_flag ( chan - > cdr, AST_CDR_FLAG_MAIN ) ;
ast_set_flag ( chan _ cdr, AST_CDR_FLAG_MAIN ) ;
ast_cdr_update ( chan ) ;
ast_cdr_update ( chan ) ;
bridge_cdr = ast_cdr_dup ( chan - > cdr) ;
bridge_cdr = ast_cdr_dup ( chan _ cdr) ;
ast_copy_string ( bridge_cdr - > lastapp , chan - > appl , sizeof ( bridge_cdr - > lastapp ) ) ;
ast_copy_string ( bridge_cdr - > lastapp , chan - > appl , sizeof ( bridge_cdr - > lastapp ) ) ;
ast_copy_string ( bridge_cdr - > lastdata , chan - > data , sizeof ( bridge_cdr - > lastdata ) ) ;
ast_copy_string ( bridge_cdr - > lastdata , chan - > data , sizeof ( bridge_cdr - > lastdata ) ) ;
} else {
} else {
@ -1475,31 +1489,31 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
/* Destination information */
/* Destination information */
ast_copy_string ( bridge_cdr - > dst , chan - > exten , sizeof ( bridge_cdr - > dst ) ) ;
ast_copy_string ( bridge_cdr - > dst , chan - > exten , sizeof ( bridge_cdr - > dst ) ) ;
ast_copy_string ( bridge_cdr - > dcontext , chan - > context , sizeof ( bridge_cdr - > dcontext ) ) ;
ast_copy_string ( bridge_cdr - > dcontext , chan - > context , sizeof ( bridge_cdr - > dcontext ) ) ;
if ( peer - > cdr) {
if ( peer _ cdr) {
bridge_cdr - > start = peer - > cdr- > start ;
bridge_cdr - > start = peer _ cdr- > start ;
ast_copy_string ( bridge_cdr - > userfield , peer - > cdr- > userfield , sizeof ( bridge_cdr - > userfield ) ) ;
ast_copy_string ( bridge_cdr - > userfield , peer _ cdr- > userfield , sizeof ( bridge_cdr - > userfield ) ) ;
} else {
} else {
ast_cdr_start ( bridge_cdr ) ;
ast_cdr_start ( bridge_cdr ) ;
}
}
}
}
/* peer -> cdr->answer will be set when a macro runs on the peer;
/* peer _ cdr->answer will be set when a macro runs on the peer;
in that case , the bridge answer will be delayed while the
in that case , the bridge answer will be delayed while the
macro plays on the peer channel . The peer answered the call
macro plays on the peer channel . The peer answered the call
before the macro started playing . To the phone system ,
before the macro started playing . To the phone system ,
this is billable time for the call , even tho the caller
this is billable time for the call , even tho the caller
hears nothing but ringing while the macro does its thing . */
hears nothing but ringing while the macro does its thing . */
if ( peer - > cdr & & ! ast_tvzero ( peer - > cdr- > answer ) ) {
if ( peer _cdr & & ! ast_tvzero ( peer_ cdr- > answer ) ) {
bridge_cdr - > answer = peer - > cdr- > answer ;
bridge_cdr - > answer = peer _ cdr- > answer ;
chan - > cdr - > answer = peer - > cdr- > answer ;
chan _cdr- > answer = peer_ cdr- > answer ;
bridge_cdr - > disposition = peer - > cdr- > disposition ;
bridge_cdr - > disposition = peer _ cdr- > disposition ;
chan - > cdr - > disposition = peer - > cdr- > disposition ;
chan _cdr- > disposition = peer_ cdr- > disposition ;
} else {
} else {
ast_cdr_answer ( bridge_cdr ) ;
ast_cdr_answer ( bridge_cdr ) ;
ast_cdr_answer ( chan - > cdr) ; /* for the sake of cli status checks */
ast_cdr_answer ( chan _ cdr) ; /* for the sake of cli status checks */
}
}
ast_set_flag ( chan - > cdr, AST_CDR_FLAG_BRIDGED ) ;
ast_set_flag ( chan _ cdr, AST_CDR_FLAG_BRIDGED ) ;
if ( peer - > cdr) {
if ( peer _ cdr) {
ast_set_flag ( peer - > cdr, AST_CDR_FLAG_BRIDGED ) ;
ast_set_flag ( peer _ cdr, AST_CDR_FLAG_BRIDGED ) ;
}
}
}
}
@ -1669,21 +1683,23 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
}
}
before_you_go :
before_you_go :
/* obey the NoCDR() wishes. */
/* obey the NoCDR() wishes. */
if ( ! chan - > cdr | | ( chan - > cdr & & ! ast_test_flag ( chan - > cdr , AST_CDR_FLAG_POST_DISABLED ) ) ) {
if ( chan_cdr & & ast_test_flag ( chan_cdr , AST_CDR_FLAG_POST_DISABLED ) & & peer_cdr & & ! ast_test_flag ( peer_cdr , AST_CDR_FLAG_POST_DISABLED ) )
ast_set_flag ( peer_cdr , AST_CDR_FLAG_POST_DISABLED ) ; /* DISABLED is viral-- it will propagate across a bridge */
if ( ! chan_cdr | | ( chan_cdr & & ! ast_test_flag ( chan_cdr , AST_CDR_FLAG_POST_DISABLED ) ) ) {
ast_cdr_end ( bridge_cdr ) ;
ast_cdr_end ( bridge_cdr ) ;
ast_cdr_detach ( bridge_cdr ) ;
ast_cdr_detach ( bridge_cdr ) ;
/* just in case, these channels get bridged again before hangup */
/* just in case, these channels get bridged again before hangup */
if ( chan - > cdr) {
if ( chan _ cdr) {
ast_cdr_specialized_reset ( chan - > cdr, 0 ) ;
ast_cdr_specialized_reset ( chan _ cdr, 0 ) ;
}
}
if ( peer - > cdr) {
if ( peer _ cdr) {
struct ast_cdr * cur ;
struct ast_cdr * cur ;
ast_channel_lock ( peer ) ;
ast_channel_lock ( peer ) ;
for ( cur = peer - > cdr; cur ; cur = cur - > next ) {
for ( cur = peer _ cdr; cur ; cur = cur - > next ) {
if ( cur = = orig_peer_cdr ) {
if ( cur = = orig_peer_cdr ) {
break ;
break ;
}
}
@ -1700,7 +1716,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
backend , just in case the cdr . conf file is calling for
backend , just in case the cdr . conf file is calling for
unanswered CDR ' s . */
unanswered CDR ' s . */
/* When peer -> cdr isn't the same addr as orig_peer_cdr,
/* When peer _ cdr isn't the same addr as orig_peer_cdr,
this can only happen if there was a transfer , methinks ;
this can only happen if there was a transfer , methinks ;
at any rate , only pay attention to the original */
at any rate , only pay attention to the original */
if ( ast_cdr_isset_unanswered ( ) ) {
if ( ast_cdr_isset_unanswered ( ) ) {