aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_channelredirect.c3
-rw-r--r--include/asterisk/channel.h4
-rw-r--r--main/features.c48
-rw-r--r--main/manager.c15
-rw-r--r--main/pbx.c3
5 files changed, 59 insertions, 14 deletions
diff --git a/apps/app_channelredirect.c b/apps/app_channelredirect.c
index ed7f2e43e..8b11ab08e 100644
--- a/apps/app_channelredirect.c
+++ b/apps/app_channelredirect.c
@@ -75,6 +75,9 @@ static int asyncgoto_exec(struct ast_channel *chan, void *data)
return 0;
}
+ if (chan2->pbx) {
+ ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ }
res = ast_async_parseable_goto(chan2, args.label);
pbx_builtin_setvar_helper(chan, "CHANNELREDIRECT_STATUS", "SUCCESS");
ast_channel_unlock(chan2);
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 7fa376275..5c709d97a 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -592,6 +592,10 @@ enum {
* a message aimed at preventing a subsequent hangup exten being run at the pbx_run
* level */
AST_FLAG_BRIDGE_HANGUP_RUN = (1 << 17),
+ /*! This flag indicates that the hangup exten should NOT be run when the
+ * bridge terminates, this will allow the hangup in the pbx loop to be run instead.
+ * */
+ AST_FLAG_BRIDGE_HANGUP_DONT = (1 << 17),
};
/*! \brief ast_bridge_config flags */
diff --git a/main/features.c b/main/features.c
index 3d94fb82c..056692671 100644
--- a/main/features.c
+++ b/main/features.c
@@ -975,16 +975,24 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
res=finishup(transferee);
- if (!transferer->cdr) {
+ if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
transferer->cdr=ast_cdr_alloc();
- if (transferer) {
+ if (transferer->cdr) {
ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
ast_cdr_start(transferer->cdr);
}
}
if (transferer->cdr) {
- ast_cdr_setdestchan(transferer->cdr, transferee->name);
- ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
+ struct ast_cdr *swap = transferer->cdr;
+ ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
+ transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata,
+ transferer->cdr->channel, transferer->cdr->dstchannel);
+ ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
+ transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
+ ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
+ /* swap cdrs-- it will save us some time & work */
+ transferer->cdr = transferee->cdr;
+ transferee->cdr = swap;
}
if (!transferee->pbx) {
/* Doh! Use our handy async_goto functions */
@@ -994,6 +1002,8 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
ast_log(LOG_WARNING, "Async goto failed :-(\n");
} else {
/* Set the channel's new extension, since it exists, using transferer context */
+ ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
set_c_e_p(transferee, transferer_real_context, xferto, 0);
}
check_goto_on_transfer(transferer);
@@ -2046,9 +2056,11 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
ast_cdr_answer(bridge_cdr);
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);
+ if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
+ ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
+ if (peer_cdr) {
+ ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
+ }
}
}
for (;;) {
@@ -2213,13 +2225,22 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
}
before_you_go:
+
+ if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
+ ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
+ if (bridge_cdr) {
+ ast_cdr_discard(bridge_cdr);
+ /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
+ }
+ return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
+ }
+
if (config->end_bridge_callback) {
config->end_bridge_callback(config->end_bridge_callback_data);
}
- autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
- ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
- if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) && ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
+ 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 = NULL;
char savelastapp[AST_MAX_EXTENSION];
char savelastdata[AST_MAX_EXTENSION];
@@ -2228,6 +2249,8 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
int found = 0; /* set if we find at least one match */
int spawn_error = 0;
+ autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
+ ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
ast_cdr_end(bridge_cdr);
}
@@ -2266,9 +2289,9 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
}
+ ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
}
- ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
-
+
/* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
@@ -2357,6 +2380,7 @@ int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast
ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr */
}
}
+
return res;
}
diff --git a/main/manager.c b/main/manager.c
index ad3fd1977..d1b34629e 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1922,13 +1922,24 @@ static int action_redirect(struct mansession *s, const struct message *m)
ast_channel_unlock(chan2);
return 0;
}
+ if (chan->pbx) {
+ ast_channel_lock(chan);
+ ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_channel_unlock(chan);
+ }
res = ast_async_goto(chan, context, exten, pi);
if (!res) {
if (!ast_strlen_zero(name2)) {
- if (chan2)
+ if (chan2) {
+ if (chan2->pbx) {
+ ast_channel_lock(chan2);
+ ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
+ ast_channel_unlock(chan2);
+ }
res = ast_async_goto(chan2, context, exten, pi);
- else
+ } else {
res = -1;
+ }
if (!res)
astman_send_ack(s, m, "Dual Redirect successful");
else
diff --git a/main/pbx.c b/main/pbx.c
index eb9cf7ee3..b2b3dba17 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -3844,6 +3844,9 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
!ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) &&
ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
set_ext_pri(c, "h", 1);
+ if (c->cdr && ast_opt_end_cdr_before_h_exten) {
+ ast_cdr_end(c->cdr);
+ }
while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
c->priority++;
}