[asterisk-commits] rmudgett: trunk r367693 - in /trunk: ./ apps/app_dial.c apps/app_queue.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu May 24 18:52:47 CDT 2012


Author: rmudgett
Date: Thu May 24 18:52:40 2012
New Revision: 367693

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=367693
Log:
Fix Dial I option ignored if dial forked and one fork redirects.

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
........

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

Modified:
    trunk/   (props changed)
    trunk/apps/app_dial.c
    trunk/apps/app_queue.c

Propchange: trunk/
------------------------------------------------------------------------------
Binary property 'branch-10-merged' - no diff available.

Modified: trunk/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_dial.c?view=diff&rev=367693&r1=367692&r2=367693
==============================================================================
--- trunk/apps/app_dial.c (original)
+++ trunk/apps/app_dial.c Thu May 24 18:52:40 2012
@@ -859,7 +859,8 @@
  * \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
@@ -869,8 +870,8 @@
  *
  * \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];
@@ -897,6 +898,14 @@
 		ast_channel_unlock(c);
 		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, ast_channel_call_forward(c), NULL);
@@ -912,11 +921,14 @@
 		/* Setup parameters */
 		c = o->chan = ast_request(tech, ast_channel_nativeformats(in), 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.
@@ -933,15 +945,18 @@
 		handle_cause(cause, num);
 		ast_hangup(original);
 	} else {
-		struct ast_party_redirecting redirecting;
+		ast_channel_lock_both(c, original);
+		ast_party_redirecting_copy(ast_channel_redirecting(c),
+			ast_channel_redirecting(original));
+		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, ast_channel_redirecting(original), NULL);
 		if (!ast_channel_redirecting(c)->from.number.valid
 			|| ast_strlen_zero(ast_channel_redirecting(c)->from.number.str)) {
 			/*
@@ -962,6 +977,7 @@
 		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(ast_channel_caller(c)->id.number.valid,
 			ast_channel_caller(c)->id.number.str, NULL))) {
 			/*
@@ -970,6 +986,9 @@
 			 */
 			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. */
@@ -987,23 +1006,33 @@
 
 		ast_channel_appl_set(c, "AppDial");
 		ast_channel_data_set(c, "(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, ast_channel_redirecting(c));
-		ast_channel_unlock(c);
-		if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
-			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);
-
-		ast_clear_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE);
+		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, ast_channel_redirecting(c));
+			ast_channel_unlock(c);
+			if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
+				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);
+		}
+
 		if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
 			*to = -1;
 		}
@@ -1024,7 +1053,7 @@
 			/* 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);
 		}
 	}
@@ -1085,7 +1114,8 @@
 			}
 		}
 
-		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, ast_channel_caller(outgoing->chan));
 			ast_channel_unlock(outgoing->chan);
@@ -1148,7 +1178,7 @@
 			if (ast_test_flag64(o, DIAL_STILLGOING) && ast_channel_state(c) == AST_STATE_UP) {
 				if (!peer) {
 					ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
-					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_sub(c, in, &o->connected, 0) &&
 								ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
@@ -1201,8 +1231,37 @@
 					}
 					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, ast_channel_connected(in));
+					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,
+						ast_channel_caller(o->chan));
+					ast_channel_unlock(o->chan);
+					connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
+					if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
+						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);
@@ -1224,7 +1283,7 @@
 					/* This is our guy if someone answered. */
 					if (!peer) {
 						ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
-						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_sub(c, in, &o->connected, 0) &&
 									ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
@@ -1358,21 +1417,25 @@
 					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", ast_channel_name(in));
-					} 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", ast_channel_name(c), ast_channel_name(in));
+
+						ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n",
+							ast_channel_name(c), ast_channel_name(in));
 						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_sub(c, in, f, 1) &&
-							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_sub(c, in, f, 1) &&
+						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:
@@ -1387,16 +1450,24 @@
 					}
 					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", ast_channel_name(in));
-					} else if (single) {
-						ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ast_channel_name(c), ast_channel_name(in));
-						if (ast_channel_redirecting_sub(c, in, f, 1) &&
-							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",
+						ast_channel_name(c), ast_channel_name(in));
+					if (ast_channel_redirecting_sub(c, in, f, 1) &&
+						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", ast_channel_name(c), ast_channel_name(in));
@@ -2202,8 +2273,11 @@
 		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);
+
+	/* 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);
 
 	/* PREDIAL: Run gosub on the caller's channel */
 	if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
@@ -2251,6 +2325,7 @@
 		tmp->number = cur;
 
 		if (opts.flags) {
+			/* Set per outgoing call leg options. */
 			ast_copy_flags64(tmp, &opts,
 				OPT_CANCEL_ELSEWHERE |
 				OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -2258,7 +2333,7 @@
 				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);
 		}
 

Modified: trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/trunk/apps/app_queue.c?view=diff&rev=367693&r1=367692&r2=367693
==============================================================================
--- trunk/apps/app_queue.c (original)
+++ trunk/apps/app_queue.c Thu May 24 18:52:40 2012
@@ -893,7 +893,7 @@
 	OPT_CALLEE_HANGUP =          (1 << 4),
 	OPT_CALLER_HANGUP =          (1 << 5),
 	OPT_IGNORE_CALL_FW =         (1 << 6),
-	OPT_UPDATE_CONNECTED =       (1 << 7),
+	OPT_IGNORE_CONNECTEDLINE =   (1 << 7),
 	OPT_CALLEE_PARK =            (1 << 8),
 	OPT_CALLER_PARK =            (1 << 9),
 	OPT_NO_RETRY =               (1 << 10),
@@ -921,7 +921,7 @@
 	AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
 	AST_APP_OPTION('H', OPT_CALLER_HANGUP),
 	AST_APP_OPTION('i', OPT_IGNORE_CALL_FW),
-	AST_APP_OPTION('I', OPT_UPDATE_CONNECTED),
+	AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
 	AST_APP_OPTION('k', OPT_CALLEE_PARK),
 	AST_APP_OPTION('K', OPT_CALLER_PARK),
 	AST_APP_OPTION('n', OPT_NO_RETRY),
@@ -1097,7 +1097,6 @@
 	struct callattempt *call_next;
 	struct ast_channel *chan;
 	char interface[256];			/*!< An Asterisk dial string (not a channel name) */
-	int stillgoing;
 	int metric;
 	time_t lastcall;
 	struct call_queue *lastqueue;
@@ -1106,8 +1105,12 @@
 	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;
 };
 
@@ -3725,15 +3728,13 @@
  * \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;
@@ -3817,10 +3818,11 @@
 
 		/* 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, ast_channel_name(o->chan), sizeof(ochan_name));
@@ -3829,7 +3831,7 @@
 			if (o->stillgoing && (o->chan) &&  (ast_channel_state(o->chan) == 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_sub(o->chan, in, &o->connected, 0) &&
 								ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
@@ -3862,6 +3864,7 @@
 				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(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
 					ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
 					numnochan++;
@@ -3883,10 +3886,17 @@
 						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, ast_channel_call_forward(o->chan), 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, ast_channel_nativeformats(in), in, stuff, &status);
@@ -3897,15 +3907,29 @@
 						o->stillgoing = 0;
 						numnochan++;
 					} else {
-						struct ast_party_redirecting redirecting;
+						ast_channel_lock_both(o->chan, original);
+						ast_party_redirecting_copy(ast_channel_redirecting(o->chan),
+							ast_channel_redirecting(original));
+						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, ast_channel_connected(in));
+						}
+
 						ast_channel_accountcode_set(o->chan, ast_channel_accountcode(in));
 
-						ast_channel_set_redirecting(o->chan, ast_channel_redirecting(original), NULL);
 						if (!ast_channel_redirecting(o->chan)->from.number.valid
 							|| ast_strlen_zero(ast_channel_redirecting(o->chan)->from.number.str)) {
 							/*
@@ -3921,27 +3945,37 @@
 
 						ast_channel_dialed(o->chan)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
 
-						ast_party_caller_copy(ast_channel_caller(o->chan), ast_channel_caller(in));
-						ast_party_connected_line_copy(ast_channel_connected(o->chan), ast_channel_connected(original));
-
-						/*
-						 * 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, ast_channel_redirecting(o->chan));
-						ast_channel_unlock(o->chan);
-						if ((res = ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) &&
-							(res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0))) {
-							ast_channel_update_redirecting(in, &redirecting, NULL);
+						o->dial_callerid_absent = !ast_channel_caller(o->chan)->id.number.valid
+							|| ast_strlen_zero(ast_channel_caller(o->chan)->id.number.str);
+						ast_connected_line_copy_from_caller(ast_channel_connected(o->chan),
+							ast_channel_caller(in));
+
+						ast_channel_unlock(in);
+						if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
+							&& !o->block_connected_update) {
+							struct ast_party_redirecting redirecting;
+
+							/*
+							 * 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, ast_channel_redirecting(o->chan));
+							ast_channel_unlock(o->chan);
+							if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
+								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);
 						}
-						ast_party_redirecting_free(&redirecting);
-						ast_channel_unlock(in);
-
-						update_connectedline = 1;
 
 						if (ast_call(o->chan, stuff, 0)) {
 							ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
@@ -3962,7 +3996,7 @@
 							/* 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_sub(o->chan, in, &o->connected, 0) &&
 											ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
@@ -4045,21 +4079,31 @@
 							/* 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_sub(o->chan, in, f, 1) &&
-									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_sub(o->chan, in, f, 1) &&
+								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:
@@ -4074,14 +4118,23 @@
 							}
 							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_sub(o->chan, in, f, 1) &&
-									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_sub(o->chan, in, f, 1) &&
+								ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
+								ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
 							}
 							break;
 						case AST_CONTROL_PVT_CAUSE_CODE:
@@ -4124,6 +4177,14 @@
 				}
 				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;
@@ -4679,7 +4740,7 @@
 	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;
@@ -4745,8 +4806,8 @@
 	if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
 		forwardsallowed = 0;
 	}
-	if (ast_test_flag(&opts, OPT_UPDATE_CONNECTED)) {
-		update_connectedline = 0;
+	if (ast_test_flag(&opts, OPT_IGNORE_CONNECTEDLINE)) {
+		block_connected_line = 1;
 	}
 	if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
 		ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
@@ -4847,17 +4908,18 @@
 			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, ast_channel_connected(qe->chan));
 		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;
@@ -4900,7 +4962,9 @@
 	++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




More information about the asterisk-commits mailing list