[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