Fix DTMF blind transfer continuing to execute dialplan after transfer.
authorRichard Mudgett <rmudgett@digium.com>
Thu, 13 Oct 2011 23:08:48 +0000 (23:08 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Thu, 13 Oct 2011 23:08:48 +0000 (23:08 +0000)
Party A calls Party B.
Party A DTMF blind transfers Party B to Party C.
Party A channel continues to execute dialplan.

* Fixed the return value of builtin_blindtransfer() to return the correct
value after a transfer so the dialplan will not keep executing.

* Removed unnecessary connected line update that did not really do
anything.

* Made access to GOTO_ON_BLINDXFR thread safe in check_goto_on_transfer().

* Fixed leak of xferchan for failure cases in check_goto_on_transfer().

* Updated debug messages in builtin_blindtransfer() and
check_goto_on_transfer().

(closes issue ASTERISK-18275)
Reported by: rmudgett
Tested by: rmudgett
........

Merged revisions 340809 from http://svn.asterisk.org/svn/asterisk/branches/1.8
........

Merged revisions 340810 from http://svn.asterisk.org/svn/asterisk/branches/10

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@340813 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/features.c

index f194274..84e427c 100644 (file)
@@ -845,35 +845,49 @@ static void set_c_e_p(struct ast_channel *chan, const char *context, const char
 static void check_goto_on_transfer(struct ast_channel *chan) 
 {
        struct ast_channel *xferchan;
-       const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
-       char *x, *goto_on_transfer;
-       struct ast_frame *f;
+       const char *val;
+       char *goto_on_transfer;
+       char *x;
 
-       if (ast_strlen_zero(val))
+       ast_channel_lock(chan);
+       val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
+       if (ast_strlen_zero(val)) {
+               ast_channel_unlock(chan);
                return;
-
+       }
        goto_on_transfer = ast_strdupa(val);
+       ast_channel_unlock(chan);
 
-       if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0, "%s", chan->name)))
-               return;
+       ast_debug(1, "Attempting GOTO_ON_BLINDXFR=%s for %s.\n", val, chan->name);
 
-       for (x = goto_on_transfer; x && *x; x++) {
-               if (*x == '^')
-                       *x = ',';
+       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", chan->linkedid, 0,
+               "%s", chan->name);
+       if (!xferchan) {
+               return;
        }
+
        /* Make formats okay */
        xferchan->readformat = chan->readformat;
        xferchan->writeformat = chan->writeformat;
-       ast_channel_masquerade(xferchan, chan);
+
+       if (ast_channel_masquerade(xferchan, chan)) {
+               /* Failed to setup masquerade. */
+               ast_hangup(xferchan);
+               return;
+       }
+
+       for (x = goto_on_transfer; *x; ++x) {
+               if (*x == '^') {
+                       *x = ',';
+               }
+       }
        ast_parseable_goto(xferchan, goto_on_transfer);
        xferchan->_state = AST_STATE_UP;
        ast_clear_flag(xferchan, AST_FLAGS_ALL);        
        ast_channel_clear_softhangup(xferchan, AST_SOFTHANGUP_ALL);
-       if ((f = ast_read(xferchan))) {
-               ast_frfree(f);
-               f = NULL;
-               ast_pbx_start(xferchan);
-       } else {
+
+       if (ast_do_masquerade(xferchan) || ast_pbx_start(xferchan)) {
+               /* Failed to do masquerade or could not start PBX. */
                ast_hangup(xferchan);
        }
 }
@@ -2115,6 +2129,7 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        char xferto[256] = "";
        int res;
 
+       ast_debug(1, "Executing Blind Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
        set_peers(&transferer, &transferee, peer, chan, sense);
        transferer_real_context = real_ctx(transferer, transferee);
 
@@ -2157,10 +2172,12 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        }
 
        /* Do blind transfer. */
+       ast_verb(3, "Blind transferring %s to '%s' (context %s) priority 1\n",
+               transferee->name, xferto, transferer_real_context);
        ast_cel_report_event(transferer, AST_CEL_BLINDTRANSFER, NULL, xferto, transferee);
        pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
        pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
-       res = finishup(transferee);
+       finishup(transferee);
        if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
                transferer->cdr = ast_cdr_alloc();
                if (transferer->cdr) {
@@ -2187,21 +2204,24 @@ static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *p
        }
        if (!transferee->pbx) {
                /* Doh!  Use our handy async_goto functions */
-               ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n",
-                       transferee->name, xferto, transferer_real_context);
+               ast_debug(1, "About to ast_async_goto %s.\n", transferee->name);
                if (ast_async_goto(transferee, transferer_real_context, xferto, 1)) {
                        ast_log(LOG_WARNING, "Async goto failed :-(\n");
                }
+
+               /* The transferee is masqueraded and the original bridged channels can be hungup. */
+               res = -1;
        } else {
-               /* Set the channel's new extension, since it exists, using transferer context */
+               /* Set the transferee's new extension, since it exists, using transferer context */
+               ast_debug(1, "About to explicit goto %s, it has a PBX.\n", transferee->name);
                ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
-               ast_debug(1,
-                       "ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n",
-                       transferee->name);
-               if (ast_channel_connected_line_macro(transferee, transferer, &transferer->connected, 1, 0)) {
-                       ast_channel_update_connected_line(transferer, &transferer->connected, NULL);
-               }
                set_c_e_p(transferee, transferer_real_context, xferto, 0);
+
+               /*
+                * Break the bridge.  The transferee needs to resume executing
+                * dialplan at the xferto location.
+                */
+               res = AST_FEATURE_RETURN_SUCCESSBREAK;
        }
        check_goto_on_transfer(transferer);
        return res;