apps/app_dial: Don't publish DialEnd twice on unexpected GoSub/Macro values

The Dial application has some interesting options with the mid-call Macro (M)
and GoSub (U) options. If the MACRO_RESULT/GOSUB_RESULT returns specific
values, the Dial application will take some action upon the channels involved
in the dial operation (such as hanging up a particular party, etc.) The Dial
application ensures that a Stasis message is published in the event that
MACRO_RESULT/GOSUB_RESULT returns a value that kills the dial operation, so
that there is a corresponding DialEnd event published in AMI/ARI for the
DialBegin event that preceeded it.

A bug exists where that same DialEnd event will be published on Stasis even if
the value returned in MACRO_RESULT/GOSUB_RESULT is not one that the Dial
application cares about. This causes two DialEnd events to be published - one
with the MACRO_RESULT/GOSUB_RESULT and another with "ANSWERED" - which is all
sorts of wrong.

This patch fixes the bug by ensuring that we only publish a DialEnd message to
Stasis if the Dial application's mid-call Macro/GoSub returns something that
Dial cares about.

Review: https://reviewboard.asterisk.org/r/4336

ASTERISK-24682 #close
Reported by: Matt Jordan
........

Merged revisions 430842 from http://svn.asterisk.org/svn/asterisk/branches/13


git-svn-id: https://origsvn.digium.com/svn/asterisk/certified/branches/13.1@430843 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/97/197/1
Matthew Jordan 11 years ago
parent a0cc80d513
commit b9be1f9413

@ -2702,6 +2702,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
} }
} else { } else {
const char *number; const char *number;
int dial_end_raised = 0;
if (ast_test_flag64(&opts, OPT_CALLER_ANSWER)) if (ast_test_flag64(&opts, OPT_CALLER_ANSWER))
ast_answer(chan); ast_answer(chan);
@ -2840,6 +2841,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) { if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
const char *macro_result_peer; const char *macro_result_peer;
int macro_res;
/* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */ /* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */
ast_channel_lock_both(chan, peer); ast_channel_lock_both(chan, peer);
@ -2848,11 +2850,11 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_channel_unlock(peer); ast_channel_unlock(peer);
ast_channel_unlock(chan); ast_channel_unlock(chan);
ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]); ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]); macro_res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]);
ast_channel_lock(peer); ast_channel_lock(peer);
if (!res && (macro_result_peer = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) { if (!macro_res && (macro_result_peer = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
char *macro_result = ast_strdupa(macro_result_peer); char *macro_result = ast_strdupa(macro_result_peer);
char *macro_transfer_dest; char *macro_transfer_dest;
@ -2861,24 +2863,24 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
if (!strcasecmp(macro_result, "BUSY")) { if (!strcasecmp(macro_result, "BUSY")) {
ast_copy_string(pa.status, macro_result, sizeof(pa.status)); ast_copy_string(pa.status, macro_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; macro_res = -1;
} else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) { } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
ast_copy_string(pa.status, macro_result, sizeof(pa.status)); ast_copy_string(pa.status, macro_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; macro_res = -1;
} else if (!strcasecmp(macro_result, "CONTINUE")) { } else if (!strcasecmp(macro_result, "CONTINUE")) {
/* hangup peer and keep chan alive assuming the macro has changed /* hangup peer and keep chan alive assuming the macro has changed
the context / exten / priority or perhaps the context / exten / priority or perhaps
the next priority in the current exten is desired. the next priority in the current exten is desired.
*/ */
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; macro_res = -1;
} else if (!strcasecmp(macro_result, "ABORT")) { } else if (!strcasecmp(macro_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */ /* Hangup both ends unless the caller has the g flag */
res = -1; macro_res = -1;
} else if (!strncasecmp(macro_result, "GOTO:", 5)) { } else if (!strncasecmp(macro_result, "GOTO:", 5)) {
macro_transfer_dest = macro_result + 5; macro_transfer_dest = macro_result + 5;
res = -1; macro_res = -1;
/* perform a transfer to a new extension */ /* perform a transfer to a new extension */
if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/ if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
ast_replace_subargument_delimiter(macro_transfer_dest); ast_replace_subargument_delimiter(macro_transfer_dest);
@ -2887,17 +2889,21 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
} }
} }
ast_channel_publish_dial(chan, peer, NULL, macro_result); if (macro_res && !dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, macro_result);
dial_end_raised = 1;
}
} else { } else {
ast_channel_unlock(peer); ast_channel_unlock(peer);
} }
res = macro_res;
} }
if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) { if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
const char *gosub_result_peer; const char *gosub_result_peer;
char *gosub_argstart; char *gosub_argstart;
char *gosub_args = NULL; char *gosub_args = NULL;
int res9 = -1; int gosub_res = -1;
ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]); ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ','); gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ',');
@ -2923,7 +2929,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
} }
} }
if (gosub_args) { if (gosub_args) {
res9 = ast_app_exec_sub(chan, peer, gosub_args, 0); gosub_res = ast_app_exec_sub(chan, peer, gosub_args, 0);
ast_free(gosub_args); ast_free(gosub_args);
} else { } else {
ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n"); ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
@ -2931,7 +2937,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_channel_lock_both(chan, peer); ast_channel_lock_both(chan, peer);
if (!res9 && (gosub_result_peer = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) { if (!gosub_res && (gosub_result_peer = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) {
char *gosub_transfer_dest; char *gosub_transfer_dest;
char *gosub_result = ast_strdupa(gosub_result_peer); char *gosub_result = ast_strdupa(gosub_result_peer);
const char *gosub_retval = pbx_builtin_getvar_helper(peer, "GOSUB_RETVAL"); const char *gosub_retval = pbx_builtin_getvar_helper(peer, "GOSUB_RETVAL");
@ -2947,21 +2953,21 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
if (!strcasecmp(gosub_result, "BUSY")) { if (!strcasecmp(gosub_result, "BUSY")) {
ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; gosub_res = -1;
} else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) { } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) {
ast_copy_string(pa.status, gosub_result, sizeof(pa.status)); ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; gosub_res = -1;
} else if (!strcasecmp(gosub_result, "CONTINUE")) { } else if (!strcasecmp(gosub_result, "CONTINUE")) {
/* Hangup peer and continue with the next extension priority. */ /* Hangup peer and continue with the next extension priority. */
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
res = -1; gosub_res = -1;
} else if (!strcasecmp(gosub_result, "ABORT")) { } else if (!strcasecmp(gosub_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */ /* Hangup both ends unless the caller has the g flag */
res = -1; gosub_res = -1;
} else if (!strncasecmp(gosub_result, "GOTO:", 5)) { } else if (!strncasecmp(gosub_result, "GOTO:", 5)) {
gosub_transfer_dest = gosub_result + 5; gosub_transfer_dest = gosub_result + 5;
res = -1; gosub_res = -1;
/* perform a transfer to a new extension */ /* perform a transfer to a new extension */
if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/ if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/
ast_replace_subargument_delimiter(gosub_transfer_dest); ast_replace_subargument_delimiter(gosub_transfer_dest);
@ -2970,7 +2976,13 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
ast_set_flag64(peerflags, OPT_GO_ON); ast_set_flag64(peerflags, OPT_GO_ON);
} }
} }
ast_channel_publish_dial(chan, peer, NULL, gosub_result); if (gosub_res) {
res = gosub_res;
if (!dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, gosub_result);
dial_end_raised = 1;
}
}
} else { } else {
ast_channel_unlock(peer); ast_channel_unlock(peer);
ast_channel_unlock(chan); ast_channel_unlock(chan);
@ -2982,7 +2994,10 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
/* None of the Dial options changed our status; inform /* None of the Dial options changed our status; inform
* everyone that this channel answered * everyone that this channel answered
*/ */
ast_channel_publish_dial(chan, peer, NULL, "ANSWER"); if (!dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
dial_end_raised = 1;
}
if (!ast_tvzero(calldurationlimit)) { if (!ast_tvzero(calldurationlimit)) {
struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit); struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit);

Loading…
Cancel
Save