aboutsummaryrefslogtreecommitdiffstats
path: root/main/features.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/features.c')
-rw-r--r--main/features.c209
1 files changed, 56 insertions, 153 deletions
diff --git a/main/features.c b/main/features.c
index 7f2dba854..f13c5d124 100644
--- a/main/features.c
+++ b/main/features.c
@@ -1871,20 +1871,6 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
}
/*!
- * \brief return the first unlocked cdr in a possible chain
-*/
-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 */
-}
-
-/*!
* \brief bridge the call and set CDR
* \param chan,peer,config
*
@@ -1911,10 +1897,6 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
struct ast_bridge_config backup_config;
struct ast_cdr *bridge_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 */
- struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
- struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
memset(&backup_config, 0, sizeof(backup_config));
@@ -1952,14 +1934,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_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) {
- ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
+ if (chan->cdr) {
+ ast_set_flag(chan->cdr, AST_CDR_FLAG_MAIN);
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->lastdata, chan->data, sizeof(bridge_cdr->lastdata));
} else {
@@ -1977,32 +1959,30 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
/* Destination information */
ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
- if (peer_cdr) {
- bridge_cdr->start = peer_cdr->start;
- ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
+ if (peer->cdr) {
+ bridge_cdr->start = peer->cdr->start;
+ ast_copy_string(bridge_cdr->userfield, peer->cdr->userfield, sizeof(bridge_cdr->userfield));
} else {
ast_cdr_start(bridge_cdr);
}
}
ast_debug(4,"bridge answer set, chan answer set\n");
- /* 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
macro plays on the peer channel. The peer answered the call
before the macro started playing. To the phone system,
this is billable time for the call, even tho the caller
hears nothing but ringing while the macro does its thing. */
- if (peer_cdr && !ast_tvzero(peer_cdr->answer)) {
- bridge_cdr->answer = peer_cdr->answer;
- chan_cdr->answer = peer_cdr->answer;
- bridge_cdr->disposition = peer_cdr->disposition;
- chan_cdr->disposition = peer_cdr->disposition;
+ if (peer->cdr && !ast_tvzero(peer->cdr->answer)) {
+ bridge_cdr->answer = peer->cdr->answer;
+ chan->cdr->answer = peer->cdr->answer;
} else {
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);
- if (peer_cdr) {
- ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
+ ast_set_flag(chan->cdr, AST_CDR_FLAG_BRIDGED);
+ if (peer->cdr) {
+ ast_set_flag(peer->cdr, AST_CDR_FLAG_BRIDGED);
}
}
for (;;) {
@@ -2167,129 +2147,52 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
}
before_you_go:
- new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
- new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
-
- if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
- struct ast_cdr *swapper;
- char savelastapp[AST_MAX_EXTENSION];
- char savelastdata[AST_MAX_EXTENSION];
- char save_exten[AST_MAX_EXTENSION];
- int save_prio;
- int found = 0; /* set if we find at least one match */
-
- if (ast_opt_end_cdr_before_h_exten) {
- ast_cdr_end(bridge_cdr);
- }
- /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
- dialplan code operate on it */
- swapper = chan->cdr;
- ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
- ast_channel_lock(chan);
- chan->cdr = bridge_cdr;
- ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
- save_prio = chan->priority;
- ast_copy_string(chan->exten, "h", sizeof(chan->exten));
- chan->priority = 1;
- ast_channel_unlock(chan);
- while ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
- chan->priority++;
- }
- if (found && res)
- {
- /* Something bad happened, or a hangup has been requested. */
- ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
- ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
- }
- /* swap it back */
- ast_channel_lock(chan);
- ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
- chan->priority = save_prio;
- chan->cdr = swapper;
- ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
- ast_channel_unlock(chan);
- /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
- ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
- }
-
/* obey the NoCDR() wishes. */
- if (new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED) && new_peer_cdr && !ast_test_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED))
- ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
- if (!new_chan_cdr || (new_chan_cdr && !ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
- struct ast_channel *chan_ptr = NULL;
+ if (!chan->cdr || (chan->cdr && !ast_test_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED))) {
ast_cdr_end(bridge_cdr);
ast_cdr_detach(bridge_cdr);
- /* do a specialized reset on the beginning channel
- CDR's, if they still exist, so as not to mess up
- issues in future bridges;
-
- Here are the rules of the game:
- 1. The chan and peer channel pointers will not change
- during the life of the bridge.
- 2. But, in transfers, the channel names will change.
- between the time the bridge is started, and the
- time the channel ends.
- Usually, when a channel changes names, it will
- also change CDR pointers.
- 3. Usually, only one of the two channels (chan or peer)
- will change names.
- 4. Usually, if a channel changes names during a bridge,
- it is because of a transfer. Usually, in these situations,
- it is normal to see 2 bridges running simultaneously, and
- it is not unusual to see the two channels that change
- swapped between bridges.
- 5. After a bridge occurs, we have 2 or 3 channels' CDRs
- to attend to; if the chan or peer changed names,
- we have the before and after attached CDR's.
- */
-
- if (strcasecmp(orig_channame, chan->name) != 0) {
- /* old channel */
- chan_ptr = ast_get_channel_by_name_locked(orig_channame);
- if (chan_ptr) {
- if (!ast_bridged_channel(chan_ptr)) {
- struct ast_cdr *cur;
- for (cur = chan_ptr->cdr; cur; cur = cur->next) {
- if (cur == chan_cdr) {
- break;
- }
- }
- if (cur)
- ast_cdr_specialized_reset(chan_cdr,0);
- }
- ast_channel_unlock(chan_ptr);
- }
- /* new channel */
- ast_cdr_specialized_reset(new_chan_cdr,0);
- } else {
- ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr */
- }
- if (strcasecmp(orig_peername, peer->name) != 0) {
- /* old channel */
- chan_ptr = ast_get_channel_by_name_locked(orig_peername);
- if (chan_ptr) {
- if (!ast_bridged_channel(chan_ptr)) {
- struct ast_cdr *cur;
- for (cur = chan_ptr->cdr; cur; cur = cur->next) {
- if (cur == peer_cdr) {
- break;
- }
- }
- if (cur)
- ast_cdr_specialized_reset(peer_cdr,0);
- }
- ast_channel_unlock(chan_ptr);
- }
- /* new channel */
- ast_cdr_specialized_reset(new_peer_cdr,0);
- } else {
- ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */
- }
+ /* just in case, these channels get bridged again before hangup */
+ if (chan->cdr) {
+ ast_cdr_specialized_reset(chan->cdr,0);
+ }
+ if (peer->cdr) {
+ struct ast_cdr *cur;
+
+ ast_channel_lock(peer);
+ for (cur = peer->cdr; cur; cur = cur->next) {
+ if (cur == orig_peer_cdr) {
+ break;
+ }
+ }
+
+ if (!cur) {
+ /* orig_peer_cdr is gone, probably because of a masquerade
+ * during the bridge. */
+ ast_channel_unlock(peer);
+ return res;
+ }
+
+ /* before resetting the peer cdr, throw a copy of it to the
+ backend, just in case the cdr.conf file is calling for
+ unanswered CDR's. */
+
+ /* When peer->cdr isn't the same addr as orig_peer_cdr,
+ this can only happen if there was a transfer, methinks;
+ at any rate, only pay attention to the original*/
+ if (ast_cdr_isset_unanswered()) {
+ struct ast_cdr *dupd = ast_cdr_dup(orig_peer_cdr);
+ if (dupd) {
+ if (ast_tvzero(dupd->end) && ast_cdr_isset_unanswered())
+ ast_cdr_end(dupd);
+ ast_cdr_detach(dupd);
+ }
+ }
+ ast_cdr_specialized_reset(orig_peer_cdr,0);
+ ast_channel_unlock(peer);
+ }
}
return res;
}