[svn-commits] rmudgett: branch 10 r350415 - in /branches/10: ./ apps/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Wed Jan 11 15:47:09 CST 2012


Author: rmudgett
Date: Wed Jan 11 15:47:04 2012
New Revision: 350415

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=350415
Log:
Make FollowMe optionally update connected line information when the accepting endpoint is bridged.

Like Dial and Queue, FollowMe needs to deal with
AST_CONTROL_CONNECTED_LINE information so when the parties are initially
bridged, the connected line information will be correct.

* Added the 'I' option just like the app_dial and app_queue 'I' option.

* Made 'N' option ignored if the call is already answered.

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

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

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

Modified:
    branches/10/   (props changed)
    branches/10/CHANGES
    branches/10/apps/app_dial.c
    branches/10/apps/app_followme.c

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

Modified: branches/10/CHANGES
URL: http://svnview.digium.com/svn/asterisk/branches/10/CHANGES?view=diff&rev=350415&r1=350414&r2=350415
==============================================================================
--- branches/10/CHANGES (original)
+++ branches/10/CHANGES Wed Jan 11 15:47:04 2012
@@ -7,6 +7,18 @@
 === and the other UPGRADE files for older releases.
 ===
 ==============================================================================
+
+------------------------------------------------------------------------------
+--- Functionality changes since Asterisk 10.1.0 ------------------------------
+------------------------------------------------------------------------------
+
+Followme changes
+-------------
+ * A new option, 'I' has been added to app_followme.
+   By setting this option, Asterisk will not update the caller with
+   connected line changes when they occur.  This is similar to app_dial
+   and app_queue.
+ * The 'N' option is now ignored if the call is already answered.
 
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 1.8 to Asterisk 10 -------------------

Modified: branches/10/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_dial.c?view=diff&rev=350415&r1=350414&r2=350415
==============================================================================
--- branches/10/apps/app_dial.c (original)
+++ branches/10/apps/app_dial.c Wed Jan 11 15:47:04 2012
@@ -203,8 +203,8 @@
 					<para>Asterisk will ignore any forwarding requests it may receive on this dial attempt.</para>
 				</option>
 				<option name="I">
-					<para>Asterisk will ignore any connected line update requests or redirecting party update
-					requests it may receiveon this dial attempt.</para>
+					<para>Asterisk will ignore any connected line update requests or any redirecting party
+					update requests it may receive on this dial attempt.</para>
 				</option>
 				<option name="k">
 					<para>Allow the called party to enable parking of the call by sending

Modified: branches/10/apps/app_followme.c
URL: http://svnview.digium.com/svn/asterisk/branches/10/apps/app_followme.c?view=diff&rev=350415&r1=350414&r2=350415
==============================================================================
--- branches/10/apps/app_followme.c (original)
+++ branches/10/apps/app_followme.c Wed Jan 11 15:47:04 2012
@@ -67,30 +67,40 @@
 			<parameter name="followmeid" required="true" />
 			<parameter name="options">
 				<optionlist>
-					<option name="s">
-						<para>Playback the incoming status message prior to starting
-						the follow-me step(s)</para>
-					</option>
 					<option name="a">
 						<para>Record the caller's name so it can be announced to the
 						callee on each step.</para>
 					</option>
-					<option name="n">
-						<para>Playback the unreachable status message if we've run out
-						of steps to reach the or the callee has elected not to be reachable.</para>
-					</option>
-					<option name="N">
-						<para>Don't answer the incoming call until we're ready to
-						connect the caller or give up. This will disable all the other
-						options while implicitly turning on the 'd' option.</para>
-					</option>
 					<option name="d">
 						<para>Disable the 'Please hold while we try to connect your call' announcement.</para>
+					</option>
+					<option name="I">
+						<para>Asterisk will ignore any connected line update requests
+						it may receive on this dial attempt.</para>
 					</option>
 					<option name="l">
 						<para>Disable local call optimization so that applications with
 						audio hooks between the local bridge don't get dropped when the
 						calls get joined directly.</para>
+					</option>
+					<option name="N">
+						<para>Don't answer the incoming call until we're ready to
+						connect the caller or give up.</para>
+						<note>
+	 						<para>This option is ignored if the call is already answered.</para>
+ 						</note>
+						<note>
+							<para>If the call is not already answered, the 'a' and 's'
+							options are ignored while the 'd' option is implicitly enabled.</para>
+ 						</note>
+					</option>
+					<option name="n">
+						<para>Playback the unreachable status message if we've run out
+						of steps or the callee has elected not to be reachable.</para>
+					</option>
+					<option name="s">
+						<para>Playback the incoming status message prior to starting
+						the follow-me step(s)</para>
 					</option>
 				</optionlist>
 			</parameter>
@@ -140,13 +150,23 @@
 };
 
 struct fm_args {
+	/*! Inbound (caller) channel */
 	struct ast_channel *chan;
 	char *mohclass;
 	AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers;
+	/*! Winning outbound (callee) channel */
+	struct ast_channel *outbound;
+	/*! Accumulated connected line information from inbound call. */
+	struct ast_party_connected_line connected_in;
+	/*! Accumulated connected line information from outbound call. */
+	struct ast_party_connected_line connected_out;
+	/*! TRUE if connected line information from inbound call changed. */
+	int pending_in_connected_update:1;
+	/*! TRUE if connected line information from outbound call is available. */
+	int pending_out_connected_update:1;
 	int status;
 	char context[AST_MAX_CONTEXT];
 	char namerecloc[AST_MAX_CONTEXT];
-	struct ast_channel *outbound;
 	char takecall[20];		/*!< Digit mapping to take a call */
 	char nextindp[20];		/*!< Digit mapping to decline a call */
 	char callfromprompt[PATH_MAX];	/*!< Sound prompt name and path */
@@ -160,12 +180,17 @@
 
 struct findme_user {
 	struct ast_channel *ochan;
+	/*! Accumulated connected line information from outgoing call. */
+	struct ast_party_connected_line connected;
+	long digts;
+	int ynidx;
 	int state;
 	char dialarg[256];
 	char yn[10];
-	int ynidx; 
-	long digts;
-	int cleared;
+	/*! TRUE if call cleared. */
+	int cleared:1;
+	/*! TRUE if connected line information is available. */
+	int pending_connected_update:1;
 	AST_LIST_ENTRY(findme_user) entry;
 };
 
@@ -176,15 +201,17 @@
 	FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
 	FOLLOWMEFLAG_NOANSWER = (1 << 4),
 	FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5),
+	FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6),
 };
 
 AST_APP_OPTIONS(followme_opts, {
-	AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG ),
-	AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME ),
-	AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG ),
-	AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT ),
-	AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER ),
-	AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION ),
+	AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME),
+	AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT),
+	AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE),
+	AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION),
+	AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER),
+	AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),
+	AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG),
 });
 
 static int ynlongest = 0;
@@ -538,13 +565,15 @@
 		if (!fmuser->cleared) {
 			clear_caller(fmuser);
 		}
+		ast_party_connected_line_free(&fmuser->connected);
 		ast_free(fmuser);
 	}
 	ast_free(findme_user_list);
 }
 
-static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, int *status, struct fm_args *tpargs) 
-{
+static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, char *namerecloc, struct fm_args *tpargs)
+{
+	struct ast_party_connected_line connected;
 	struct ast_channel *watchers[256];
 	int pos;
 	struct ast_channel *winner;
@@ -670,12 +699,21 @@
 		}
 		if (winner) {
 			/* Need to find out which channel this is */
-			dg = 0;
-			while ((winner != watchers[dg]) && (dg < 256))
-				dg++;
-			AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry)
-				if (tmpuser->ochan == winner)
+			for (dg = 0; dg < ARRAY_LEN(watchers); ++dg) {
+				if (winner == watchers[dg]) {
 					break;
+				}
+			}
+			if (dg) {
+				/* The winner is an outgoing channel. */
+				AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
+					if (tmpuser->ochan == winner) {
+						break;
+					}
+				}
+			} else {
+				tmpuser = NULL;
+			}
 			f = ast_read(winner);
 			if (f) {
 				if (f->frametype == AST_FRAME_CONTROL) {
@@ -729,32 +767,73 @@
 						ast_verb(3, "%s is ringing\n", winner->name);
 						break;
 					case AST_CONTROL_PROGRESS:
-						ast_verb(3, "%s is making progress passing it to %s\n", winner->name, caller->name);
+						ast_verb(3, "%s is making progress\n", winner->name);
 						break;
 					case AST_CONTROL_VIDUPDATE:
-						ast_verb(3, "%s requested a video update, passing it to %s\n", winner->name, caller->name);
+						ast_verb(3, "%s requested a video update\n", winner->name);
 						break;
 					case AST_CONTROL_SRCUPDATE:
-						ast_verb(3, "%s requested a source update, passing it to %s\n", winner->name, caller->name);
+						ast_verb(3, "%s requested a source update\n", winner->name);
 						break;
 					case AST_CONTROL_PROCEEDING:
-						ast_verb(3, "%s is proceeding passing it to %s\n", winner->name,caller->name);
+						ast_verb(3, "%s is proceeding\n", winner->name);
 						break;
 					case AST_CONTROL_HOLD:
-						ast_verb(3, "Call on %s placed on hold\n", winner->name);
+						ast_verb(3, "%s placed call on hold\n", winner->name);
 						break;
 					case AST_CONTROL_UNHOLD:
-						ast_verb(3, "Call on %s left from hold\n", winner->name);
+						ast_verb(3, "%s removed call from hold\n", winner->name);
 						break;
 					case AST_CONTROL_OFFHOOK:
 					case AST_CONTROL_FLASH:
 						/* Ignore going off hook and flash */
 						break;
+					case AST_CONTROL_CONNECTED_LINE:
+						if (!tmpuser) {
+							/*
+							 * Hold connected line update from caller until we have a
+							 * winner.
+							 */
+							ast_verb(3,
+								"%s connected line has changed. Saving it until we have a winner.\n",
+								winner->name);
+							ast_party_connected_line_set_init(&connected, &tpargs->connected_in);
+							if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
+								ast_party_connected_line_set(&tpargs->connected_in,
+									&connected, NULL);
+								tpargs->pending_in_connected_update = 1;
+							}
+							ast_party_connected_line_free(&connected);
+							break;
+						}
+						if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
+							ast_verb(3, "Connected line update from %s prevented.\n",
+								winner->name);
+						} else {
+							ast_verb(3,
+								"%s connected line has changed. Saving it until answer.\n",
+								winner->name);
+							ast_party_connected_line_set_init(&connected, &tmpuser->connected);
+							if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
+								ast_party_connected_line_set(&tmpuser->connected,
+									&connected, NULL);
+								tmpuser->pending_connected_update = 1;
+							}
+							ast_party_connected_line_free(&connected);
+						}
+						break;
+					case AST_CONTROL_REDIRECTING:
+						/*
+						 * Ignore because we are masking the FollowMe search progress to
+						 * the caller.
+						 */
+						break;
 					case -1:
 						ast_verb(3, "%s stopped sounds\n", winner->name);
 						break;
 					default:
-						ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
+						ast_debug(1, "Dunno what to do with control type %d from %s\n",
+							f->subclass.integer, winner->name);
 						break;
 					}
 				} 
@@ -775,36 +854,35 @@
 						}
 						if (!strcmp(tmpuser->yn, tpargs->nextindp)) {
 							ast_debug(1, "Next in dial plan step requested.\n");
-							*status = 1;
 							ast_frfree(f);
-							return NULL;
-						}
-
-					}
-				}
-
-				ast_frfree(f);
-			} else {
-				if (winner) {
-					ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n",dg);					      
-					if (!dg) {
-						clear_calling_tree(findme_user_list);
-						return NULL;
-					} else {
-						tmpuser->state = -1;
-						ast_hangup(winner);  
-						livechannels--;
-						ast_debug(1, "live channels left %d\n", livechannels);
-						if (!livechannels) {
-							ast_verb(3, "no live channels left. exiting.\n");
 							return NULL;
 						}
 					}
 				}
-			}
-
-		} else
+
+				ast_frfree(f);
+			} else {
+				ast_debug(1, "we didn't get a frame. hanging up. dg is %d\n", dg);
+				if (!dg) {
+					/* Caller hung up. */
+					clear_calling_tree(findme_user_list);
+					return NULL;
+				} else {
+					/* Outgoing channel hung up. */
+					tmpuser->state = -1;
+					tmpuser->ochan = NULL;
+					ast_hangup(winner);
+					--livechannels;
+					ast_debug(1, "live channels left %d\n", livechannels);
+					if (!livechannels) {
+						ast_verb(3, "no live channels left. exiting.\n");
+						return NULL;
+					}
+				}
+			}
+		} else {
 			ast_debug(1, "timed out waiting for action\n");
+		}
 	}
 
 	/* --- WAIT FOR WINNER NUMBER END! -----------*/
@@ -824,7 +902,6 @@
 	struct findme_user *tmpuser;
 	struct findme_user *fmuser;
 	struct findme_user_listptr *findme_user_list;
-	int status;
 
 	findme_user_list = ast_calloc(1, sizeof(*findme_user_list));
 	AST_LIST_HEAD_INIT_NOLOCK(findme_user_list);
@@ -839,7 +916,7 @@
 	}
 
 	caller = tpargs->chan;
-	for (idx = 1; !winner && !ast_check_hangup(caller); ++idx) {
+	for (idx = 1; !ast_check_hangup(caller); ++idx) {
 		/* Find next followme numbers to dial. */
 		AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
 			if (nm->order == idx) {
@@ -930,16 +1007,29 @@
 			continue;
 		}
 
-		status = 0;
-		winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, &status, tpargs);
-
-		/* Clean up all calls but winner. */
+		winner = wait_for_winner(findme_user_list, nm, caller, tpargs->namerecloc, tpargs);
+		if (!winner) {
+			continue;
+		}
+
+		/* Destroy losing calls up to the winner.  The rest will be destroyed later. */
 		while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
-			if (!fmuser->cleared && fmuser->ochan != winner) {
-				clear_caller(fmuser);
-			}
-			ast_free(fmuser);
-		}
+			if (fmuser->ochan == winner) {
+				/* Pass any connected line info up. */
+				tpargs->connected_out = fmuser->connected;
+				tpargs->pending_out_connected_update = fmuser->pending_connected_update;
+				ast_free(fmuser);
+				break;
+			} else {
+				/* Destroy losing call. */
+				if (!fmuser->cleared) {
+					clear_caller(fmuser);
+				}
+				ast_party_connected_line_free(&fmuser->connected);
+				ast_free(fmuser);
+			}
+		}
+		break;
 	}
 	destroy_calling_tree(findme_user_list);
 	if (!winner) {
@@ -1066,7 +1156,6 @@
 	int res = 0;
 	char *argstr;
 	char namerecloc[255];
-	int duration = 0;
 	struct ast_channel *caller;
 	struct ast_channel *outbound;
 	AST_DECLARE_APP_ARGS(args,
@@ -1133,27 +1222,36 @@
 	}
 	ast_mutex_unlock(&f->lock);
 
-	snprintf(namerecloc,sizeof(namerecloc),"%s/followme.%s",ast_config_AST_SPOOL_DIR,chan->uniqueid);
-	duration = 5;
-
-	if (!ast_fileexists(namerecloc, NULL, chan->language))
-		ast_copy_string(namerecloc, "", sizeof(namerecloc));
-
+	/* Forget the 'N' option if the call is already up. */
+	if (chan->_state == AST_STATE_UP) {
+		ast_clear_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER);
+	}
+
+	namerecloc[0] = '\0';
 	if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
-		if (chan->_state != AST_STATE_UP) {
-			ast_indicate(chan, AST_CONTROL_RINGING);
-		}
+		ast_indicate(chan, AST_CONTROL_RINGING);
 	} else {
 		/* Answer the call */
-		if (chan->_state != AST_STATE_UP)
+		if (chan->_state != AST_STATE_UP) {
 			ast_answer(chan);
+		}
 
 		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_STATUSMSG)) 
 			ast_stream_and_wait(chan, targs.statusprompt, "");
 
-		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) 
-			if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration, NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0)
+		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
+			int duration = 5;
+
+			snprintf(namerecloc, sizeof(namerecloc), "%s/followme.%s",
+				ast_config_AST_SPOOL_DIR, chan->uniqueid);
+			if (ast_play_and_record(chan, "vm-rec-name", namerecloc, 5, "sln", &duration,
+				NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) {
 				goto outrun;
+			}
+			if (!ast_fileexists(namerecloc, NULL, chan->language)) {
+				namerecloc[0] = '\0';
+			}
+		}
 
 		if (!ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
 			if (ast_streamfile(chan, targs.plsholdprompt, chan->language))
@@ -1167,6 +1265,9 @@
 	targs.status = 0;
 	targs.chan = chan;
 	ast_copy_string(targs.namerecloc, namerecloc, sizeof(targs.namerecloc));
+	ast_channel_lock(chan);
+	ast_connected_line_copy_from_caller(&targs.connected_in, &chan->caller);
+	ast_channel_unlock(chan);
 
 	findmeexec(&targs);
 
@@ -1176,15 +1277,15 @@
 	if (!ast_strlen_zero(namerecloc))
 		unlink(namerecloc);
 
-	if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
-		if (chan->_state != AST_STATE_UP) {
-			ast_answer(chan);
-		}
-	} else {
-		ast_moh_stop(chan);
-	}
-
 	if (targs.status != 100) {
+		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
+			if (chan->_state != AST_STATE_UP) {
+				ast_answer(chan);
+			}
+		} else {
+			ast_moh_stop(chan);
+		}
+
 		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) 
 			ast_stream_and_wait(chan, targs.sorryprompt, "");
 		res = 0;
@@ -1200,6 +1301,21 @@
 		config.end_bridge_callback = end_bridge_callback;
 		config.end_bridge_callback_data = chan;
 		config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
+
+		/* Update connected line to caller if available. */
+		if (targs.pending_out_connected_update) {
+			if (ast_channel_connected_line_macro(outbound, caller, &targs.connected_out, 1, 0)) {
+				ast_channel_update_connected_line(caller, &targs.connected_out, NULL);
+			}
+		}
+
+		if (ast_test_flag(&targs.followmeflags, FOLLOWMEFLAG_NOANSWER)) {
+			if (caller->_state != AST_STATE_UP) {
+				ast_answer(caller);
+			}
+		} else {
+			ast_moh_stop(caller);
+		}
 
 		/* Be sure no generators are left on it */
 		ast_deactivate_generator(caller);
@@ -1210,12 +1326,21 @@
 			ast_hangup(outbound);
 			goto outrun;
 		}
+
+		/* Update connected line to winner if changed. */
+		if (targs.pending_in_connected_update) {
+			if (ast_channel_connected_line_macro(caller, outbound, &targs.connected_in, 0, 0)) {
+				ast_channel_update_connected_line(outbound, &targs.connected_in, NULL);
+			}
+		}
+
 		res = ast_bridge_call(caller, outbound, &config);
 		ast_hangup(outbound);
 	}
 
 outrun:
-
+	ast_party_connected_line_free(&targs.connected_in);
+	ast_party_connected_line_free(&targs.connected_out);
 	if (f->realtime) {
 		/* Not in list */
 		free_numbers(f);




More information about the svn-commits mailing list