[asterisk-commits] rmudgett: branch rmudgett/parking r330986 - /team/rmudgett/parking/main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Aug 5 12:02:19 CDT 2011


Author: rmudgett
Date: Fri Aug  5 12:02:15 2011
New Revision: 330986

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=330986
Log:
* Add parking_lot_name option to Park and ParkedCall applications.

* Made auto-added parking extensions specify the parking lot name to
restore a user's ability to directly access multiple parking lots.

* Made the builtin DTMF transfers use the parking_lot_name option of the
parking ramp to determine which parking lot to use when transfering a call
to parking.

Modified:
    team/rmudgett/parking/main/features.c

Modified: team/rmudgett/parking/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/parking/main/features.c?view=diff&rev=330986&r1=330985&r2=330986
==============================================================================
--- team/rmudgett/parking/main/features.c (original)
+++ team/rmudgett/parking/main/features.c Fri Aug  5 12:02:15 2011
@@ -210,17 +210,29 @@
 	</application>
 	<application name="ParkedCall" language="en_US">
 		<synopsis>
-			Answer a parked call.
+			Retrieve a parked call.
 		</synopsis>
 		<syntax>
-			<parameter name="exten" required="true" />
+			<parameter name="exten">
+				<para>Parking space extension to retrieve a parked call.
+				If not provided then the first available parked call in the
+				parking lot will be retrieved.</para>
+			</parameter>
+			<parameter name="parking_lot_name">
+				<para>Specify from which parking lot to pickup a parked call.</para>
+				<para>The parking lot used is selected in the following order:</para>
+				<para>1) parking_lot_name option</para>
+				<para>2) <variable>PARKINGLOT</variable> variable</para>
+				<para>3) <literal>CHANNEL(parkinglot)</literal> function
+				(Possibly preset by the channel driver.)</para>
+				<para>4) Default parking lot.</para>
+			</parameter>
 		</syntax>
 		<description>
-			<para>Used to connect to a parked call. This application is always
+			<para>Used to connect to a parked call.  This application is always
 			registered internally and does not need to be explicitly added
-			into the dialplan, although you should include the <literal>parkedcalls</literal>
-			context. If no extension is provided, then the first available
-			parked call will be acquired.</para>
+			into the dialplan, although you should include the parking lot
+			context.</para>
 		</description>
 		<see-also>
 			<ref type="application">Park</ref>
@@ -258,23 +270,27 @@
 					</option>
 				</optionlist>
 			</parameter>
+			<parameter name="parking_lot_name">
+				<para>Specify in which parking lot to park a call.</para>
+				<para>The parking lot used is selected in the following order:</para>
+				<para>1) parking_lot_name option</para>
+				<para>2) <variable>PARKINGLOT</variable> variable</para>
+				<para>3) <literal>CHANNEL(parkinglot)</literal> function
+				(Possibly preset by the channel driver.)</para>
+				<para>4) Default parking lot.</para>
+			</parameter>
 		</syntax>
 		<description>
 			<para>Used to park yourself (typically in combination with a supervised
 			transfer to know the parking space). This application is always
 			registered internally and does not need to be explicitly added
-			into the dialplan, although you should include the <literal>parkedcalls</literal>
-			context (or the context specified in <filename>features.conf</filename>).</para>
-			<para>If you set the <variable>PARKINGLOT</variable> variable, the call will be parked
-			in the specifed parking context. Note setting this variable overrides the <variable>
-			PARKINGLOT</variable> set by the <literal>CHANNEL</literal> function.</para>
+			into the dialplan, although you should include the parking lot
+			context.</para>
 			<para>If you set the <variable>PARKINGEXTEN</variable> variable to an extension in your
 			parking context, Park() will park the call on that extension, unless
-			it already exists. In that case, execution will continue at next priority.</para>
-			<para>If you set the <variable>PARKINGLOT</variable> variable, Park() will park the call
-			in that parkinglot.</para>
-			<para>If you set the <variable>PARKINGDYNAMIC</variable> variable, this parkinglot from features.conf
-			will be used as template for the newly created dynamic lot.</para>
+			it already exists. In that case, execution will continue at the next priority.</para>
+			<para>If you set the <variable>PARKINGDYNAMIC</variable> variable, this parkinglot from
+			<literal>features.conf</literal> will be used as a template for the newly created dynamic lot.</para>
 			<para>If you set the <variable>PARKINGDYNCONTEXT</variable> variable the newly created dynamic
 			parking lot will use this context.</para>
 			<para>If you set the <variable>PARKINGDYNPOS</variable> variable the newly created dynamic parkinglot
@@ -312,7 +328,7 @@
 				<para>Number of milliseconds to wait before callback.</para>
 			</parameter>
 			<parameter name="Parkinglot">
-				<para>Parking lot to park channel in.</para>
+				<para>Specify in which parking lot to park the channel.</para>
 			</parameter>
 		</syntax>
 		<description>
@@ -574,6 +590,17 @@
 
 static char *registrar = "features";		   /*!< Registrar for operations */
 
+/*! PARK_APP_NAME application arguments */
+AST_DEFINE_APP_ARGS_TYPE(park_app_args,
+	AST_APP_ARG(timeout);		/*!< Time in ms to remain in the parking lot. */
+	AST_APP_ARG(return_con);	/*!< Context to return parked call if timeout. */
+	AST_APP_ARG(return_ext);	/*!< Exten to return parked call if timeout. */
+	AST_APP_ARG(return_pri);	/*!< Priority to return parked call if timeout. */
+	AST_APP_ARG(options);		/*!< Parking option flags. */
+	AST_APP_ARG(pl_name);		/*!< Parking lot name to use if present. */
+	AST_APP_ARG(dummy);			/*!< Place to put any remaining args string. */
+	);
+
 /* module and CLI command definitions */
 static char *parkcall = PARK_APP_NAME;
 
@@ -703,23 +730,40 @@
 static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
 static int parkinglot_activate(struct ast_parkinglot *parkinglot);
 
-int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
+/*!
+ * \internal
+ * \brief Get the parking extension if it exists.
+ *
+ * \param exten_str Parking extension to see if exists.
+ * \param chan Channel to autoservice while looking for exten.  (Could be NULL)
+ * \param context Parking context to look in for exten.
+ *
+ * \retval exten on success.
+ * \retval NULL on error or exten does not exist.
+ */
+static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
 {
 	struct ast_exten *exten;
 	struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
 	const char *app_at_exten;
 
-	exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL, E_MATCH);
+	exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
+		E_MATCH);
 	if (!exten) {
-		return 0;
+		return NULL;
 	}
 
 	app_at_exten = ast_get_extension_app(exten);
 	if (!app_at_exten || strcasecmp(PARK_APP_NAME, app_at_exten)) {
-		return 0;
-	}
-
-	return 1;
+		return NULL;
+	}
+
+	return exten;
+}
+
+int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
+{
+	return get_parking_exten(exten_str, chan, context) ? 1 : 0;
 }
 
 const char *ast_pickup_ext(void)
@@ -1008,7 +1052,7 @@
 		if (!ast_strlen_zero(parkinglotname)) {
 			parkinglot = find_parkinglot(parkinglotname);
 		} else {
-			/* Parking lot is not specified.  Fallback to default lot. */
+			/* Parking lot is not specified, so use the default parking lot. */
 			ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
 			parkinglot = parkinglot_addref(default_parkinglot);
 		}
@@ -1048,6 +1092,8 @@
 		}
 		parkinglot = copy_parkinglot(parkinglotname, parkinglot_copy);
 
+/* BUGBUG we should check that the dynamic parking lot does not use the same context and parkext as the template lot. */
+/* If this is the case it will make the template lot difficult to park new calls in using the standard access ramp. */
 		/* unref our temporary copy */
 		parkinglot_unref(parkinglot_copy);
 		parkinglot_copy = NULL;
@@ -1348,8 +1394,14 @@
 	if (!con) { /* Still no context? Bad */
 		ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->cfg.parking_con);
 	} else {
-		if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
+		char app_data[AST_MAX_EXTENSION + AST_MAX_CONTEXT];
+
+		snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
+			pu->parkinglot->name);
+		if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall,
+			ast_strdup(app_data), ast_free_ptr, registrar)) {
 			notify_metermaids(pu->parkingexten, pu->parkinglot->cfg.parking_con, AST_DEVICE_INUSE);
+		}
 	}
 
 	AST_LIST_UNLOCK(&pu->parkinglot->parkings);
@@ -1465,6 +1517,72 @@
 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
 {
 	return masq_park_call(rchan, peer, 0, NULL, 1, args);
+}
+
+static int finishup(struct ast_channel *chan)
+{
+	ast_indicate(chan, AST_CONTROL_UNHOLD);
+
+	return ast_autoservice_stop(chan);
+}
+
+/*!
+ * \internal
+ * \brief Builtin transfer park call helper.
+ *
+ * \param park_me Channel to be parked.
+ * \param parker Channel parking the call.
+ * \param park_exten Parking lot dialplan access ramp extension.
+ *
+ * \note Assumes park_me is on hold and in autoservice.
+ *
+ * \retval 0 on success.
+ * \retval -1 on park_me hangup.
+ * \retval AST_FEATURE_RETURN_PARKFAILED on error.
+ */
+static int xfer_park_call_helper(struct ast_channel *park_me, struct ast_channel *parker, struct ast_exten *park_exten)
+{
+	char *parse;
+	const char *app_data;
+	const char *pl_name;
+	struct ast_park_call_args args = { 0, };
+	struct park_app_args app_args;
+	int res;
+
+	app_data = ast_get_extension_app_data(park_exten);
+	if (!app_data) {
+		app_data = "";
+	}
+	parse = ast_strdupa(app_data);
+	AST_STANDARD_APP_ARGS(app_args, parse);
+
+	res = finishup(park_me);
+	if (res) {
+		/* Parkee hungup on us. */
+		return res;
+	}
+
+	/* Park the call */
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(parker);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
+		args.parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		args.parkinglot = find_parkinglot(pl_name);
+	}
+	if (args.parkinglot) {
+		res = masq_park_call_announce(park_me, parker, &args);
+		parkinglot_unref(args.parkinglot);
+	} else {
+		/* Parking failed because parking lot does not exist. */
+		res = AST_FEATURE_RETURN_PARKFAILED;
+	}
+
+	return res;
 }
 
 /*!
@@ -1832,13 +1950,6 @@
 	return AST_FEATURE_RETURN_HANGUP;
 }
 
-static int finishup(struct ast_channel *chan)
-{
-	ast_indicate(chan, AST_CONTROL_UNHOLD);
-
-	return ast_autoservice_stop(chan);
-}
-
 /*!
  * \brief Find the context for the transfer
  * \param transferer
@@ -1880,6 +1991,7 @@
 {
 	struct ast_channel *transferer;
 	struct ast_channel *transferee;
+	struct ast_exten *park_exten;
 	const char *transferer_real_context;
 	char xferto[256] = "";
 	int res;
@@ -1919,10 +2031,10 @@
 		return AST_FEATURE_RETURN_SUCCESS;
 	}
 
-	if (ast_parking_ext_valid(xferto, transferer, transferer_real_context)) {
+	park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
+	if (park_exten) {
 		/* We are transfering the transferee to a parking lot. */
-		finishup(transferee);
-		return masq_park_call_announce(transferee, transferer, NULL);
+		return xfer_park_call_helper(transferee, transferer, park_exten);
 	}
 
 	/* Do blind transfer. */
@@ -2042,6 +2154,7 @@
 {
 	struct ast_channel *transferer;/* Party B */
 	struct ast_channel *transferee;/* Party A */
+	struct ast_exten *park_exten;
 	const char *transferer_real_context;
 	char xferto[256] = "";
 	int res;
@@ -2097,10 +2210,10 @@
 		return AST_FEATURE_RETURN_SUCCESS;
 	}
 
-	if (ast_parking_ext_valid(xferto, transferer, transferer_real_context)) {
+	park_exten = get_parking_exten(xferto, transferer, transferer_real_context);
+	if (park_exten) {
 		/* We are transfering the transferee to a parking lot. */
-		finishup(transferee);
-		return masq_park_call_announce(transferee, transferer, NULL);
+		return xfer_park_call_helper(transferee, transferer, park_exten);
 	}
 
 	/* Append context to dialed transfer number. */
@@ -4485,14 +4598,9 @@
 	char orig_exten[AST_MAX_EXTENSION];
 	int orig_priority;
 	int res;
+	const char *pl_name;
 	char *parse;
-	AST_DECLARE_APP_ARGS(app_args,
-		AST_APP_ARG(timeout);
-		AST_APP_ARG(return_con);
-		AST_APP_ARG(return_ext);
-		AST_APP_ARG(return_pri);
-		AST_APP_ARG(options);
-	);
+	struct park_app_args app_args;
 
 	/* Answer if call is not up */
 	if (chan->_state != AST_STATE_UP) {
@@ -4542,7 +4650,24 @@
 	chan->priority = 1;
 
 	/* Park the call */
-	res = masq_park_call_announce(chan, chan, &args);
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(chan);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
+		args.parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		args.parkinglot = find_parkinglot(pl_name);
+	}
+	if (args.parkinglot) {
+		res = masq_park_call_announce(chan, chan, &args);
+		parkinglot_unref(args.parkinglot);
+	} else {
+		/* Parking failed because the parking lot does not exist. */
+		res = -1;
+	}
 	if (res) {
 		/* Park failed, try to continue in the dialplan. */
 		ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
@@ -4563,25 +4688,57 @@
 	struct ast_channel *peer = NULL;
 	struct parkeduser *pu;
 	struct ast_context *con;
+	char *parse;
+	const char *pl_name;
 	int park = 0;
 	struct ast_bridge_config config;
 	struct ast_parkinglot *parkinglot;
-
-	if (!ast_strlen_zero(data)) {
-		if (sscanf(data, "%30u", &park) != 1) {
-			ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n", data);
+	AST_DECLARE_APP_ARGS(app_args,
+		AST_APP_ARG(pl_space);	/*!< Parking lot space to retrieve if present. */
+		AST_APP_ARG(pl_name);	/*!< Parking lot name to use if present. */
+		AST_APP_ARG(dummy);		/*!< Place to put any remaining args string. */
+	);
+
+	parse = ast_strdupa(data);
+	AST_STANDARD_APP_ARGS(app_args, parse);
+
+	if (!ast_strlen_zero(app_args.pl_space)) {
+		if (sscanf(app_args.pl_space, "%30u", &park) != 1) {
+			ast_log(LOG_WARNING, "Specified parking extension not a number: %s\n",
+				app_args.pl_space);
 			park = -1;
 		}
 	}
 
-	parkinglot = find_parkinglot(findparkinglotname(chan));
-	if (!parkinglot) {
+	if (!ast_strlen_zero(app_args.pl_name)) {
+		pl_name = app_args.pl_name;
+	} else {
+		pl_name = findparkinglotname(chan);
+	}
+	if (ast_strlen_zero(pl_name)) {
+		/* Parking lot is not specified, so use the default parking lot. */
 		parkinglot = parkinglot_addref(default_parkinglot);
+	} else {
+		parkinglot = find_parkinglot(pl_name);
+		if (!parkinglot) {
+			/* It helps to answer the channel if not already up. :) */
+			if (chan->_state != AST_STATE_UP) {
+				ast_answer(chan);
+			}
+			if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
+				ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n",
+					"pbx-invalidpark", chan->name);
+			}
+			ast_log(LOG_WARNING,
+				"Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
+				chan->name, pl_name);
+			return -1;
+		}
 	}
 
 	AST_LIST_LOCK(&parkinglot->parkings);
 	AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
-		if ((ast_strlen_zero(data) || pu->parkingnum == park)
+		if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
 			&& !pu->notquiteyet && !pu->chan->pbx) {
 			/* The parking space has a call and can be picked up now. */
 			AST_LIST_REMOVE_CURRENT(list);
@@ -4765,12 +4922,11 @@
 		/* Simulate the PBX hanging up */
 		ast_hangup(peer);
 	} else {
-		/*! \todo XXX Play a message XXX */
 		if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
 			ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
 				chan->name);
 		}
-		ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n",
+		ast_verb(3, "Channel %s tried to retrieve nonexistent parked call %d\n",
 			chan->name, park);
 	}
 
@@ -4987,6 +5143,10 @@
 {
 	int disabled = 0;
 	struct ast_context *con;
+	char app_data[5 + AST_MAX_CONTEXT];
+
+	/* Create Park option list.  Must match with struct park_app_args options. */
+	snprintf(app_data, sizeof(app_data), ",,,,,%s", parkinglot->name);
 
 	/* Create context */
 	con = ast_context_find_or_create(NULL, NULL, parkinglot->cfg.parking_con, registrar);
@@ -4997,7 +5157,7 @@
 
 	/* Add a parking extension into the context */
 	} else if (ast_add_extension2(con, 1, parkinglot->cfg.parkext, 1, NULL, NULL,
-		parkcall, ast_strdup(""), ast_free_ptr, registrar)) {
+		parkcall, ast_strdup(app_data), ast_free_ptr, registrar)) {
 		ast_log(LOG_ERROR, "Could not create parking lot %s access exten %s@%s\n",
 			parkinglot->name, parkinglot->cfg.parkext, parkinglot->cfg.parking_con);
 		disabled = 1;




More information about the asterisk-commits mailing list