]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Fix Dial I option ignored if dial forked and one fork redirects.
authorRichard Mudgett <rmudgett@digium.com>
Thu, 24 May 2012 22:29:23 +0000 (22:29 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Thu, 24 May 2012 22:29:23 +0000 (22:29 +0000)
The Dial and Queue I option is intended to block connected line updates
and redirecting updates.  However, it is a feature that when a call is
locally redirected, the I option is disabled if the redirected call runs
as a local channel so the administrator can have an opportunity to setup
new connected line information.  Unfortunately, the Dial and Queue I
option is disabled for *all* forked calls if one of those calls is
redirected.

* Make the Dial and Queue I option apply to each outgoing call leg
independently.  Now if one outgoing call leg is locally redirected, the
other outgoing calls are not affected.

* Made Dial not pass any redirecting updates when forking calls.
Redirecting updates do not make sense for this scenario.

* Made Queue not pass any redirecting updates when using the ringall
strategy.  Redirecting updates do not make sense for this scenario.

* Fixed deadlock potential with chan_local when Dial and Queue send
redirecting updates for a local redirect.

* Converted the Queue stillgoing flag to a boolean bitfield.

(closes issue ASTERISK-19511)
Reported by: rmudgett
Tested by: rmudgett

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

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

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

apps/app_dial.c
apps/app_queue.c

index 63bcbab544d4ffc54bac122e058f88fa7985a059..e09a3c2ff37f8fc9bb13011bd3c44d54689cd005 100644 (file)
@@ -823,7 +823,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus)
  * \param o Outgoing call channel list.
  * \param num Incoming call channel cause accumulation
  * \param peerflags Dial option flags
- * \param single_caller_bored From wait_for_answer: single && !caller_entertained
+ * \param single TRUE if there is only one outgoing call.
+ * \param caller_entertained TRUE if the caller is being entertained by MOH or ringback.
  * \param to Remaining call timeout time.
  * \param forced_clid OPT_FORCECLID caller id to send
  * \param stored_clid Caller id representing the called party if needed
@@ -833,8 +834,8 @@ static void senddialendevent(struct ast_channel *src, const char *dialstatus)
  *
  * \todo eventually this function should be intergrated into and replaced by ast_call_forward()
  */
-static void do_forward(struct chanlist *o,
-       struct cause_args *num, struct ast_flags64 *peerflags, int single_caller_bored, int *to,
+static void do_forward(struct chanlist *o, struct cause_args *num,
+       struct ast_flags64 *peerflags, int single, int caller_entertained, int *to,
        struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
 {
        char tmpchan[256];
@@ -862,6 +863,14 @@ static void do_forward(struct chanlist *o,
                stuff = tmpchan;
                tech = "Local";
        }
+       if (!strcasecmp(tech, "Local")) {
+               /*
+                * Drop the connected line update block for local channels since
+                * this is going to run dialplan and the user can change his
+                * mind about what connected line information he wants to send.
+                */
+               ast_clear_flag64(o, OPT_IGNORE_CONNECTEDLINE);
+       }
 
        ast_cel_report_event(in, AST_CEL_FORWARD, NULL, c->call_forward, NULL);
 
@@ -876,11 +885,14 @@ static void do_forward(struct chanlist *o,
                /* Setup parameters */
                c = o->chan = ast_request(tech, in->nativeformats, in, stuff, &cause);
                if (c) {
-                       if (single_caller_bored) {
+                       if (single && !caller_entertained) {
                                ast_channel_make_compatible(o->chan, in);
                        }
+                       ast_channel_lock_both(in, o->chan);
                        ast_channel_inherit_variables(in, o->chan);
                        ast_channel_datastore_inherit(in, o->chan);
+                       ast_channel_unlock(in);
+                       ast_channel_unlock(o->chan);
                        /* When a call is forwarded, we don't want to track new interfaces
                         * dialed for CC purposes. Setting the done flag will ensure that
                         * any Dial operations that happen later won't record CC interfaces.
@@ -897,17 +909,17 @@ static void do_forward(struct chanlist *o,
                handle_cause(cause, num);
                ast_hangup(original);
        } else {
-               struct ast_party_redirecting redirecting;
+               ast_channel_lock_both(c, original);
+               ast_party_redirecting_copy(&c->redirecting, &original->redirecting);
+               ast_channel_unlock(c);
+               ast_channel_unlock(original);
+
+               ast_channel_lock_both(c, in);
 
-               if (single_caller_bored && CAN_EARLY_BRIDGE(peerflags, c, in)) {
+               if (single && !caller_entertained && CAN_EARLY_BRIDGE(peerflags, c, in)) {
                        ast_rtp_instance_early_bridge_make_compatible(c, in);
                }
 
-               ast_channel_set_redirecting(c, &original->redirecting, NULL);
-               ast_channel_lock(c);
-               while (ast_channel_trylock(in)) {
-                       CHANNEL_DEADLOCK_AVOIDANCE(c);
-               }
                if (!c->redirecting.from.number.valid
                        || ast_strlen_zero(c->redirecting.from.number.str)) {
                        /*
@@ -928,6 +940,7 @@ static void do_forward(struct chanlist *o,
                if (ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
                        caller.id = *stored_clid;
                        ast_channel_set_caller_event(c, &caller, NULL);
+                       ast_set_flag64(o, DIAL_CALLERID_ABSENT);
                } else if (ast_strlen_zero(S_COR(c->caller.id.number.valid,
                        c->caller.id.number.str, NULL))) {
                        /*
@@ -936,6 +949,9 @@ static void do_forward(struct chanlist *o,
                         */
                        caller.id = *stored_clid;
                        ast_channel_set_caller_event(c, &caller, NULL);
+                       ast_set_flag64(o, DIAL_CALLERID_ABSENT);
+               } else {
+                       ast_clear_flag64(o, DIAL_CALLERID_ABSENT);
                }
 
                /* Determine CallerID for outgoing channel to send. */
@@ -953,22 +969,32 @@ static void do_forward(struct chanlist *o,
 
                c->appl = "AppDial";
                c->data = "(Outgoing Line)";
-               /*
-                * We must unlock c before calling ast_channel_redirecting_macro, because
-                * we put c into autoservice there. That is pretty much a guaranteed
-                * deadlock. This is why the handling of c's lock may seem a bit unusual
-                * here.
-                */
-               ast_party_redirecting_init(&redirecting);
-               ast_party_redirecting_copy(&redirecting, &c->redirecting);
-               ast_channel_unlock(c);
-               if (ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
-                       ast_channel_update_redirecting(in, &redirecting, NULL);
-               }
-               ast_party_redirecting_free(&redirecting);
+
                ast_channel_unlock(in);
+               if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
+                       struct ast_party_redirecting redirecting;
+
+                       /*
+                        * Redirecting updates to the caller make sense only on single
+                        * calls.
+                        *
+                        * We must unlock c before calling
+                        * ast_channel_redirecting_macro, because we put c into
+                        * autoservice there.  That is pretty much a guaranteed
+                        * deadlock.  This is why the handling of c's lock may seem a
+                        * bit unusual here.
+                        */
+                       ast_party_redirecting_init(&redirecting);
+                       ast_party_redirecting_copy(&redirecting, &c->redirecting);
+                       ast_channel_unlock(c);
+                       if (ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
+                               ast_channel_update_redirecting(in, &redirecting, NULL);
+                       }
+                       ast_party_redirecting_free(&redirecting);
+               } else {
+                       ast_channel_unlock(c);
+               }
 
-               ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
                if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
                        *to = -1;
                }
@@ -982,17 +1008,14 @@ static void do_forward(struct chanlist *o,
                        c = o->chan = NULL;
                        num->nochan++;
                } else {
-                       ast_channel_lock(c);
-                       while (ast_channel_trylock(in)) {
-                               CHANNEL_DEADLOCK_AVOIDANCE(c);
-                       }
+                       ast_channel_lock_both(c, in);
                        senddialevent(in, c, stuff);
                        ast_channel_unlock(in);
                        ast_channel_unlock(c);
                        /* Hangup the original channel now, in case we needed it */
                        ast_hangup(original);
                }
-               if (single_caller_bored) {
+               if (single && !caller_entertained) {
                        ast_indicate(in, -1);
                }
        }
@@ -1052,7 +1075,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                        }
                }
 
-               if (!ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE) && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) {
+               if (!ast_test_flag64(outgoing, OPT_IGNORE_CONNECTEDLINE)
+                       && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) {
                        ast_channel_lock(outgoing->chan);
                        ast_connected_line_copy_from_caller(&connected_caller, &outgoing->chan->caller);
                        ast_channel_unlock(outgoing->chan);
@@ -1113,7 +1137,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                        if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
                                if (!peer) {
                                        ast_verb(3, "%s answered %s\n", c->name, in->name);
-                                       if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+                                       if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
                                                if (o->pending_connected_update) {
                                                        if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
                                                                ast_channel_update_connected_line(in, &o->connected, NULL);
@@ -1164,8 +1188,35 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                        }
                                        ast_frfree(f);
                                }
-                               do_forward(o, &num, peerflags, single && !caller_entertained, to,
+
+                               if (o->pending_connected_update) {
+                                       /*
+                                        * Re-seed the chanlist's connected line information with
+                                        * previously acquired connected line info from the incoming
+                                        * channel.  The previously acquired connected line info could
+                                        * have been set through the CONNECTED_LINE dialplan function.
+                                        */
+                                       o->pending_connected_update = 0;
+                                       ast_channel_lock(in);
+                                       ast_party_connected_line_copy(&o->connected, &in->connected);
+                                       ast_channel_unlock(in);
+                               }
+
+                               do_forward(o, &num, peerflags, single, caller_entertained, to,
                                        forced_clid, stored_clid);
+
+                               if (single && o->chan
+                                       && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)
+                                       && !ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
+                                       ast_channel_lock(o->chan);
+                                       ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
+                                       ast_channel_unlock(o->chan);
+                                       connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+                                       if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
+                                               ast_channel_update_connected_line(in, &connected_caller, NULL);
+                                       }
+                                       ast_party_connected_line_free(&connected_caller);
+                               }
                                continue;
                        }
                        f = ast_read(winner);
@@ -1187,7 +1238,7 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                        /* This is our guy if someone answered. */
                                        if (!peer) {
                                                ast_verb(3, "%s answered %s\n", c->name, in->name);
-                                               if (!single && !ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+                                               if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
                                                        if (o->pending_connected_update) {
                                                                if (ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
                                                                        ast_channel_update_connected_line(in, &o->connected, NULL);
@@ -1319,20 +1370,24 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                        ast_indicate(in, f->subclass.integer);
                                        break;
                                case AST_CONTROL_CONNECTED_LINE:
-                                       if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+                                       if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
                                                ast_verb(3, "Connected line update to %s prevented.\n", in->name);
-                                       } else if (!single) {
+                                               break;
+                                       }
+                                       if (!single) {
                                                struct ast_party_connected_line connected;
-                                               ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", c->name, in->name);
+
+                                               ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n",
+                                                       c->name, in->name);
                                                ast_party_connected_line_set_init(&connected, &o->connected);
                                                ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
                                                ast_party_connected_line_set(&o->connected, &connected, NULL);
                                                ast_party_connected_line_free(&connected);
                                                o->pending_connected_update = 1;
-                                       } else {
-                                               if (ast_channel_connected_line_macro(c, in, f, 1, 1)) {
-                                                       ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
-                                               }
+                                               break;
+                                       }
+                                       if (ast_channel_connected_line_macro(c, in, f, 1, 1)) {
+                                               ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
                                        }
                                        break;
                                case AST_CONTROL_AOC:
@@ -1347,15 +1402,23 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in,
                                        }
                                        break;
                                case AST_CONTROL_REDIRECTING:
-                                       if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
+                                       if (!single) {
+                                               /*
+                                                * Redirecting updates to the caller make sense only on single
+                                                * calls.
+                                                */
+                                               break;
+                                       }
+                                       if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
                                                ast_verb(3, "Redirecting update to %s prevented.\n", in->name);
-                                       } else if (single) {
-                                               ast_verb(3, "%s redirecting info has changed, passing it to %s\n", c->name, in->name);
-                                               if (ast_channel_redirecting_macro(c, in, f, 1, 1)) {
-                                                       ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
-                                               }
-                                               pa->sentringing = 0;
+                                               break;
                                        }
+                                       ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
+                                               c->name, in->name);
+                                       if (ast_channel_redirecting_macro(c, in, f, 1, 1)) {
+                                               ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
+                                       }
+                                       pa->sentringing = 0;
                                        break;
                                case AST_CONTROL_PROCEEDING:
                                        ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
@@ -2162,9 +2225,12 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
        } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
                outbound_group = ast_strdupa(outbound_group);
        }
-       ast_channel_unlock(chan);       
-       ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_IGNORE_CONNECTEDLINE |
-                        OPT_CANCEL_TIMEOUT | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
+       ast_channel_unlock(chan);
+
+       /* Set per dial instance flags.  These flags are also passed back to RetryDial. */
+       ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID
+               | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CANCEL_TIMEOUT
+               | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
 
        /* loop through the list of dial destinations */
        rest = args.peers;
@@ -2186,6 +2252,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                if (!(tmp = ast_calloc(1, sizeof(*tmp))))
                        goto out;
                if (opts.flags) {
+                       /* Set per outgoing call leg options. */
                        ast_copy_flags64(tmp, &opts,
                                OPT_CANCEL_ELSEWHERE |
                                OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -2193,7 +2260,7 @@ static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast
                                OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
                                OPT_CALLEE_PARK | OPT_CALLER_PARK |
                                OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
-                               OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID);
+                               OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE);
                        ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
                }
                ast_copy_string(numsubst, number, sizeof(numsubst));
index cba347f12a4f108926e59269749fcf5d70351ed5..21dd4a7f42d7ba2f464b2887ac5ae74bc2b1644e 100644 (file)
@@ -1004,7 +1004,6 @@ struct callattempt {
        struct callattempt *call_next;
        struct ast_channel *chan;
        char interface[256];
-       int stillgoing;
        int metric;
        time_t lastcall;
        struct call_queue *lastqueue;
@@ -1013,8 +1012,12 @@ struct callattempt {
        struct ast_party_connected_line connected;
        /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
        unsigned int pending_connected_update:1;
+       /*! TRUE if the connected line update is blocked. */
+       unsigned int block_connected_update:1;
        /*! TRUE if caller id is not available for connected line */
        unsigned int dial_callerid_absent:1;
+       /*! TRUE if the call is still active */
+       unsigned int stillgoing:1;
        struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
@@ -3511,15 +3514,13 @@ static void rna(int rnatime, struct queue_ent *qe, char *interface, char *member
  * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
  * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
  * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
- * \param[in] update_connectedline Allow connected line and redirecting updates to pass through.
  *
  * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
  */
-static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
+static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
 {
        const char *queue = qe->parent->name;
        struct callattempt *o, *start = NULL, *prev = NULL;
-       int res;
        int status;
        int numbusies = prebusies;
        int numnochan = 0;
@@ -3600,10 +3601,11 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 
                /* Service all of the outgoing channels */
                for (o = start; o; o = o->call_next) {
-                       /* We go with a static buffer here instead of using ast_strdupa. Using
+                       /* We go with a fixed buffer here instead of using ast_strdupa. Using
                         * ast_strdupa in a loop like this one can cause a stack overflow
                         */
                        char ochan_name[AST_CHANNEL_NAME];
+
                        if (o->chan) {
                                ast_channel_lock(o->chan);
                                ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
@@ -3612,7 +3614,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                        if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
                                if (!peer) {
                                        ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
-                                       if (update_connectedline) {
+                                       if (!o->block_connected_update) {
                                                if (o->pending_connected_update) {
                                                        if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
                                                                ast_channel_update_connected_line(in, &o->connected, NULL);
@@ -3643,6 +3645,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                ast_copy_string(on, o->member->interface, sizeof(on));
                                ast_copy_string(membername, o->member->membername, sizeof(membername));
 
+                               /* Before processing channel, go ahead and check for forwarding */
                                if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
                                        ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
                                        numnochan++;
@@ -3664,10 +3667,17 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                stuff = tmpchan;
                                                tech = "Local";
                                        }
+                                       if (!strcasecmp(tech, "Local")) {
+                                               /*
+                                                * Drop the connected line update block for local channels since
+                                                * this is going to run dialplan and the user can change his
+                                                * mind about what connected line information he wants to send.
+                                                */
+                                               o->block_connected_update = 0;
+                                       }
 
                                        ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
 
-                                       /* Before processing channel, go ahead and check for forwarding */
                                        ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
                                        /* Setup parameters */
                                        o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
@@ -3678,15 +3688,28 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                o->stillgoing = 0;
                                                numnochan++;
                                        } else {
-                                               struct ast_party_redirecting redirecting;
+                                               ast_channel_lock_both(o->chan, original);
+                                               ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting);
+                                               ast_channel_unlock(o->chan);
+                                               ast_channel_unlock(original);
 
                                                ast_channel_lock_both(o->chan, in);
                                                ast_channel_inherit_variables(in, o->chan);
                                                ast_channel_datastore_inherit(in, o->chan);
 
+                                               if (o->pending_connected_update) {
+                                                       /*
+                                                        * Re-seed the callattempt's connected line information with
+                                                        * previously acquired connected line info from the queued
+                                                        * channel.  The previously acquired connected line info could
+                                                        * have been set through the CONNECTED_LINE dialplan function.
+                                                        */
+                                                       o->pending_connected_update = 0;
+                                                       ast_party_connected_line_copy(&o->connected, &in->connected);
+                                               }
+
                                                ast_string_field_set(o->chan, accountcode, in->accountcode);
 
-                                               ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
                                                if (!o->chan->redirecting.from.number.valid
                                                        || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
                                                        /*
@@ -3702,27 +3725,35 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
 
                                                o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
 
-                                               ast_party_caller_copy(&o->chan->caller, &in->caller);
-                                               ast_party_connected_line_copy(&o->chan->connected, &original->connected);
+                                               o->dial_callerid_absent = !o->chan->caller.id.number.valid
+                                                       || ast_strlen_zero(o->chan->caller.id.number.str);
+                                               ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller);
 
-                                               /*
-                                                * We must unlock o->chan before calling
-                                                * ast_channel_redirecting_macro, because we put o->chan into
-                                                * autoservice there.  That is pretty much a guaranteed
-                                                * deadlock.  This is why the handling of o->chan's lock may
-                                                * seem a bit unusual here.
-                                                */
-                                               ast_party_redirecting_init(&redirecting);
-                                               ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
-                                               ast_channel_unlock(o->chan);
-                                               res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
-                                               if (res) {
-                                                       ast_channel_update_redirecting(in, &redirecting, NULL);
-                                               }
-                                               ast_party_redirecting_free(&redirecting);
                                                ast_channel_unlock(in);
+                                               if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
+                                                       && !o->block_connected_update) {
+                                                       struct ast_party_redirecting redirecting;
 
-                                               update_connectedline = 1;
+                                                       /*
+                                                        * Redirecting updates to the caller make sense only on single
+                                                        * call at a time strategies.
+                                                        *
+                                                        * We must unlock o->chan before calling
+                                                        * ast_channel_redirecting_macro, because we put o->chan into
+                                                        * autoservice there.  That is pretty much a guaranteed
+                                                        * deadlock.  This is why the handling of o->chan's lock may
+                                                        * seem a bit unusual here.
+                                                        */
+                                                       ast_party_redirecting_init(&redirecting);
+                                                       ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
+                                                       ast_channel_unlock(o->chan);
+                                                       if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
+                                                               ast_channel_update_redirecting(in, &redirecting, NULL);
+                                                       }
+                                                       ast_party_redirecting_free(&redirecting);
+                                               } else {
+                                                       ast_channel_unlock(o->chan);
+                                               }
 
                                                if (ast_call(o->chan, stuff, 0)) {
                                                        ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
@@ -3743,7 +3774,7 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        /* This is our guy if someone answered. */
                                                        if (!peer) {
                                                                ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
-                                                               if (update_connectedline) {
+                                                               if (!o->block_connected_update) {
                                                                        if (o->pending_connected_update) {
                                                                                if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
                                                                                        ast_channel_update_connected_line(in, &o->connected, NULL);
@@ -3820,20 +3851,30 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        /* Ignore going off hook */
                                                        break;
                                                case AST_CONTROL_CONNECTED_LINE:
-                                                       if (!update_connectedline) {
+                                                       if (o->block_connected_update) {
                                                                ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
-                                                       } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
+                                                               break;
+                                                       }
+                                                       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
                                                                struct ast_party_connected_line connected;
+
                                                                ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
                                                                ast_party_connected_line_set_init(&connected, &o->connected);
                                                                ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
                                                                ast_party_connected_line_set(&o->connected, &connected, NULL);
                                                                ast_party_connected_line_free(&connected);
                                                                o->pending_connected_update = 1;
-                                                       } else {
-                                                               if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
-                                                                       ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
-                                                               }
+                                                               break;
+                                                       }
+
+                                                       /*
+                                                        * Prevent using the CallerID from the outgoing channel since we
+                                                        * got a connected line update from it.
+                                                        */
+                                                       o->dial_callerid_absent = 1;
+
+                                                       if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
+                                                               ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
                                                        }
                                                        break;
                                                case AST_CONTROL_AOC:
@@ -3848,13 +3889,22 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                                        }
                                                        break;
                                                case AST_CONTROL_REDIRECTING:
-                                                       if (!update_connectedline) {
-                                                               ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
-                                                       } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
-                                                               ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
-                                                               if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
-                                                                       ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
-                                                               }
+                                                       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
+                                                               /*
+                                                                * Redirecting updates to the caller make sense only on single
+                                                                * call at a time strategies.
+                                                                */
+                                                               break;
+                                                       }
+                                                       if (o->block_connected_update) {
+                                                               ast_verb(3, "Redirecting update to %s prevented\n",
+                                                                       inchan_name);
+                                                               break;
+                                                       }
+                                                       ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
+                                                               ochan_name, inchan_name);
+                                                       if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
+                                                               ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
                                                        }
                                                        break;
                                                default:
@@ -3893,6 +3943,14 @@ static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callatte
                                }
                                return NULL;
                        }
+
+                       /*!
+                        * \todo
+                        * XXX Queue like Dial really should send any connected line
+                        * updates (AST_CONTROL_CONNECTED_LINE) from the caller to each
+                        * ringing queue member.
+                        */
+
                        if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
                                ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
                                *to = 0;
@@ -4431,7 +4489,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        char *p;
        char vars[2048];
        int forwardsallowed = 1;
-       int update_connectedline = 1;
+       int block_connected_line = 0;
        int callcompletedinsl;
        struct ao2_iterator memi;
        struct ast_datastore *datastore, *transfer_ds;
@@ -4498,7 +4556,7 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        forwardsallowed = 0;
                        break;
                case 'I':
-                       update_connectedline = 0;
+                       block_connected_line = 1;
                        break;
                case 'x':
                        ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
@@ -4598,17 +4656,18 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
                        AST_LIST_UNLOCK(dialed_interfaces);
                }
 
-               ast_channel_lock(qe->chan);
                /*
                 * Seed the callattempt's connected line information with previously
                 * acquired connected line info from the queued channel.  The
                 * previously acquired connected line info could have been set
                 * through the CONNECTED_LINE dialplan function.
                 */
+               ast_channel_lock(qe->chan);
                ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
                ast_channel_unlock(qe->chan);
 
-               tmp->stillgoing = -1;
+               tmp->block_connected_update = block_connected_line;
+               tmp->stillgoing = 1;
                tmp->member = cur;/* Place the reference for cur into callattempt. */
                tmp->lastcall = cur->lastcall;
                tmp->lastqueue = cur->lastqueue;
@@ -4650,7 +4709,9 @@ static int try_calling(struct queue_ent *qe, const char *options, char *announce
        ++qe->pending;
        ao2_unlock(qe->parent);
        ring_one(qe, outgoing, &numbusies);
-       lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
+       lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
+               ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
+               forwardsallowed);
        /* The ast_channel_datastore_remove() function could fail here if the
         * datastore was moved to another channel during a masquerade. If this is
         * the case, don't free the datastore here because later, when the channel