Fix blind transfer parking issues if the dialed extension is not recognized as a...
authorRichard Mudgett <rmudgett@digium.com>
Thu, 23 Feb 2012 20:14:54 +0000 (20:14 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Thu, 23 Feb 2012 20:14:54 +0000 (20:14 +0000)
Custom parking extensions may not be coded such that the first and only
extension priority is the Park application.  These custom parking
extensions will not be recognized as parking extensions.  When a call is
blind transferred to an extension that is not recognized as a parking
extension, the normal blind transfer code causes the transferred channel
to start executing dialplan.  Calls that get parked in this manner do not
know the original channel name that parked the call so the original parker
could never be called back if the parked call is not retrieved before the
timeout time.  The parking space is also announced to the call being
parked as a side effect of not knowing the original parking channel.

* Fix handling of BLINDTRANSFER channel variable for call parking.

* Fixed SIP blind transfer using the wrong dialplan context variable to
check for the parking extension.

(closes issue ASTERISK-19322)
Reported by: aragon
Tested by: rmudgett, jparker

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

JIRA AST-766
........

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

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

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

channels/chan_sip.c
main/features.c

index 2a4f8b3..513de42 100644 (file)
@@ -24389,7 +24389,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
        sip_pvt_unlock(p);
 
        /* Parking a call.  DO NOT hold any locks while calling ast_parking_ext_valid() */
-       if (localtransfer && ast_parking_ext_valid(refer_to, current.chan1, ast_channel_context(current.chan1))) {
+       if (localtransfer && ast_parking_ext_valid(refer_to, current.chan1, refer_to_context)) {
                sip_pvt_lock(p);
                ast_clear_flag(&p->flags[0], SIP_GOTREFER);
                p->refer->status = REFER_200OK;
@@ -24418,7 +24418,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int
                }
 
                /* DO NOT hold any locks while calling sip_park */
-               if (sip_park(current.chan2, current.chan1, req, seqno, refer_to, ast_channel_context(current.chan1))) {
+               if (sip_park(current.chan2, current.chan1, req, seqno, refer_to, refer_to_context)) {
                        sip_pvt_lock(p);
                        transmit_notify_with_sipfrag(p, seqno, "500 Internal Server Error", TRUE);
                } else {
index d3c98a4..96f76d9 100644 (file)
@@ -784,6 +784,7 @@ static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_cha
        struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
        const char *app_at_exten;
 
+       ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
        exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
                E_MATCH);
        if (!exten) {
@@ -1388,7 +1389,7 @@ static struct parkeduser *park_space_reserve(struct ast_channel *park_me, struct
 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
        struct parkeduser *pu = args->pu;
-       const char *event_from;
+       const char *event_from;         /*!< Channel name that is parking the call. */
        char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
 
        if (pu == NULL) {
@@ -1407,10 +1408,10 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
        if (chan != peer) {
                if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
                        pu->hold_method = AST_CONTROL_RINGING;
-                       ast_indicate(pu->chan, AST_CONTROL_RINGING);
+                       ast_indicate(chan, AST_CONTROL_RINGING);
                } else {
                        pu->hold_method = AST_CONTROL_HOLD;
-                       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
+                       ast_indicate_data(chan, AST_CONTROL_HOLD,
                                S_OR(pu->parkinglot->cfg.mohclass, NULL),
                                !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
                }
@@ -1421,7 +1422,9 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
        if (args->extout)
                *(args->extout) = pu->parkingnum;
 
-       if (peer) { 
+       if (peer) {
+               event_from = S_OR(args->orig_chan_name, ast_channel_name(peer));
+
                /*
                 * This is so ugly that it hurts, but implementing
                 * get_base_channel() on local channels could have ugly side
@@ -1436,7 +1439,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
                        char other_side[AST_CHANNEL_NAME];
                        char *c;
 
-                       ast_copy_string(other_side, S_OR(args->orig_chan_name, ast_channel_name(peer)), sizeof(other_side));
+                       ast_copy_string(other_side, event_from, sizeof(other_side));
                        if ((c = strrchr(other_side, ';'))) {
                                *++c = '1';
                        }
@@ -1449,8 +1452,11 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
                                tmpchan = ast_channel_unref(tmpchan);
                        }
                } else {
-                       ast_copy_string(pu->peername, S_OR(args->orig_chan_name, ast_channel_name(peer)), sizeof(pu->peername));
+                       ast_copy_string(pu->peername, event_from, sizeof(pu->peername));
                }
+       } else {
+               event_from = S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"),
+                       ast_channel_name(chan));
        }
 
        /*
@@ -1486,18 +1492,12 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
        /* Wake up the (presumably select()ing) thread */
        pthread_kill(parking_thread, SIGURG);
        ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n",
-               ast_channel_name(pu->chan), pu->parkingnum, pu->parkinglot->name,
+               ast_channel_name(chan), pu->parkingnum, pu->parkinglot->name,
                pu->context, pu->exten, pu->priority, (pu->parkingtime / 1000));
 
-       ast_cel_report_event(pu->chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
+       ast_cel_report_event(chan, AST_CEL_PARK_START, NULL, pu->parkinglot->name, peer);
 
-       if (peer) {
-               event_from = ast_channel_name(peer);
-       } else {
-               event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
-       }
-
-       ast_manager_event(pu->chan, EVENT_FLAG_CALL, "ParkedCall",
+       ast_manager_event(chan, EVENT_FLAG_CALL, "ParkedCall",
                "Exten: %s\r\n"
                "Channel: %s\r\n"
                "Parkinglot: %s\r\n"
@@ -1508,14 +1508,19 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
                "ConnectedLineNum: %s\r\n"
                "ConnectedLineName: %s\r\n"
                "Uniqueid: %s\r\n",
-               pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name, event_from ? event_from : "",
+               pu->parkingexten, ast_channel_name(chan), pu->parkinglot->name, event_from,
                (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
-               S_COR(pu->chan->caller.id.number.valid, pu->chan->caller.id.number.str, "<unknown>"),
-               S_COR(pu->chan->caller.id.name.valid, pu->chan->caller.id.name.str, "<unknown>"),
-               S_COR(pu->chan->connected.id.number.valid, pu->chan->connected.id.number.str, "<unknown>"),
-               S_COR(pu->chan->connected.id.name.valid, pu->chan->connected.id.name.str, "<unknown>"),
-               ast_channel_uniqueid(pu->chan)
+               S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "<unknown>"),
+               S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "<unknown>"),
+               S_COR(chan->connected.id.number.valid, chan->connected.id.number.str, "<unknown>"),
+               S_COR(chan->connected.id.name.valid, chan->connected.id.name.str, "<unknown>"),
+               ast_channel_uniqueid(chan)
                );
+       ast_debug(4, "peer: %s\n", peer ? ast_channel_name(peer) : "-No peer-");
+       ast_debug(4, "args->orig_chan_name: %s\n", args->orig_chan_name ? args->orig_chan_name : "-none-");
+       ast_debug(4, "pu->peername: %s\n", pu->peername);
+       ast_debug(4, "AMI ParkedCall Channel: %s\n", ast_channel_name(chan));
+       ast_debug(4, "AMI ParkedCall From: %s\n", event_from);
 
        if (peer && adsipark && ast_adsi_available(peer)) {
                adsi_announce_park(peer, pu->parkingexten);     /* Only supports parking numbers */
@@ -1550,7 +1555,7 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, st
        if (peer == chan) { /* pu->notquiteyet = 1 */
                /* Wake up parking thread if we're really done */
                pu->hold_method = AST_CONTROL_HOLD;
-               ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
+               ast_indicate_data(chan, AST_CONTROL_HOLD,
                        S_OR(pu->parkinglot->cfg.mohclass, NULL),
                        !ast_strlen_zero(pu->parkinglot->cfg.mohclass) ? strlen(pu->parkinglot->cfg.mohclass) + 1 : 0);
                pu->notquiteyet = 0;
@@ -3877,6 +3882,10 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a
        pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
        pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
 
+       /* Clear any BLINDTRANSFER since the transfer has completed. */
+       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
+       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", NULL);
+
        set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
        add_features_datastores(chan, peer, config);
 
@@ -4920,13 +4929,7 @@ END_OPTIONS );
 /*! \brief Park a call */
 static int park_call_exec(struct ast_channel *chan, const char *data)
 {
-       /* Cache the original channel name in case we get masqueraded in the middle
-        * of a park--it is still theoretically possible for a transfer to happen before
-        * we get here, but it is _really_ unlikely */
-       char *orig_chan_name = ast_strdupa(ast_channel_name(chan));
-       struct ast_park_call_args args = {
-               .orig_chan_name = orig_chan_name,
-       };
+       struct ast_park_call_args args = { 0, };
        struct ast_flags flags = { 0 };
        char orig_exten[AST_MAX_EXTENSION];
        int orig_priority;
@@ -4935,6 +4938,19 @@ static int park_call_exec(struct ast_channel *chan, const char *data)
        char *parse;
        struct park_app_args app_args;
 
+       /*
+        * Cache the original channel name because we are going to
+        * masquerade the channel.  Prefer the BLINDTRANSFER channel
+        * name over this channel name.  BLINDTRANSFER could be set if
+        * the parking access extension did not get detected and we are
+        * executing the Park application from the dialplan.
+        *
+        * The orig_chan_name is used to return the call to the
+        * originator on parking timeout.
+        */
+       args.orig_chan_name = ast_strdupa(S_OR(
+               pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ast_channel_name(chan)));
+
        /* Answer if call is not up */
        if (ast_channel_state(chan) != AST_STATE_UP) {
                if (ast_answer(chan)) {