[asterisk-commits] jrose: branch group/bridge_construction r388233 - in /team/group/bridge_const...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu May 9 17:21:12 CDT 2013
Author: jrose
Date: Thu May 9 17:21:09 2013
New Revision: 388233
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=388233
Log:
res_parking: Rebuilding parking from the ground up for the new bridging model
Parking has been rebuilt from scratch in order to support the new bridging
architecture.
Parking configuration works somewhat differently now and extensions aren't
necessarily automatically generated (it's optional and hasn't been implemented),
but the intention with the final result is that if you were using parking before
without too much additional dialplan manipulation, that should all just work
once your parking lots are migrated to the new configuration file.
Currently supported:
parking from the PBX with the Park application (all arguments are supported)
parking within a call using the one touch parking feature
parking within a call using DTMF blind transfers (attended transfers work,
but it's basically just like they called the application itself).
Picking up parked calls using the PBX
Multiple parking lots
All options available to parking lots are currently configurable. Some aren't
currently doing anything, namely parkext and hints.
Added:
team/group/bridge_construction/configs/res_parking.conf.sample
- copied unchanged from r388227, team/jrose/bridge_projects/configs/res_parking.conf.sample
team/group/bridge_construction/include/asterisk/parking.h
- copied unchanged from r388227, team/jrose/bridge_projects/include/asterisk/parking.h
team/group/bridge_construction/main/parking.c
- copied unchanged from r388227, team/jrose/bridge_projects/main/parking.c
team/group/bridge_construction/res/parking/
- copied from r388227, team/jrose/bridge_projects/res/parking/
team/group/bridge_construction/res/parking/parking_applications.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_applications.c
team/group/bridge_construction/res/parking/parking_bridge.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_bridge.c
team/group/bridge_construction/res/parking/parking_bridge_features.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_bridge_features.c
team/group/bridge_construction/res/parking/parking_controller.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_controller.c
team/group/bridge_construction/res/parking/parking_manager.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_manager.c
team/group/bridge_construction/res/parking/parking_ui.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/parking_ui.c
team/group/bridge_construction/res/parking/res_parking.h
- copied unchanged from r388227, team/jrose/bridge_projects/res/parking/res_parking.h
team/group/bridge_construction/res/res_parking.c
- copied unchanged from r388227, team/jrose/bridge_projects/res/res_parking.c
Modified:
team/group/bridge_construction/CHANGES
team/group/bridge_construction/bridges/bridge_builtin_features.c
team/group/bridge_construction/include/asterisk/bridging.h
team/group/bridge_construction/include/asterisk/config_options.h
team/group/bridge_construction/main/bridging.c
team/group/bridge_construction/main/bridging_roles.c
team/group/bridge_construction/main/config_options.c
team/group/bridge_construction/main/features.c
team/group/bridge_construction/res/Makefile
Modified: team/group/bridge_construction/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/CHANGES?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/CHANGES (original)
+++ team/group/bridge_construction/CHANGES Thu May 9 17:21:09 2013
@@ -50,6 +50,19 @@
* The AMI event 'UserEvent' from app_userevent now contains the channel state
fields. The channel state fields will come before the body fields.
+ * The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and
+ 'UnParkedCall' have changed significantly in the new res_parking module.
+ First, channel snapshot data is included for both the parker and the parkee
+ in lieu of the "From" and "Channel" fields. They follow standard channel
+ snapshot format but each field is suffixed with 'Parker' or 'Parkee'
+ depending on which side it applies to. The 'Exten' field is replaced with
+ 'ParkingSpace' since the registration of extensions as for parking spaces
+ is no longer mandatory.
+
+ * The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar
+ fashion has changed the field names 'StartExten' and 'StopExten' to
+ 'StartSpace' and 'StopSpace' respectively.
+
* The deprecated use of | (pipe) as a separator in the channelvars setting in
manager.conf has been removed.
@@ -95,8 +108,8 @@
* Add support for automixmonitor to the BRIDGE_FEATURES channel variable.
- * PARKINGSLOT and PARKEDLOT channel variables will now be set for a parked
- channel even when comebactoorigin=yes
+ * Parking has been pulled from core and placed into a separate module called
+ res_parking. See Parking changes below for more details.
* You can now have the settings for a channel updated using the FEATURE()
and FEATUREMAP() functions inherited to child channels by setting
@@ -124,6 +137,43 @@
of audio samples in a voice frame will experience significant quality problems
if a denoiser is attached to the channel; this option gives them the ability
to remove the denoiser without having to unload func_speex.
+
+Parking
+-------------------
+ * Parking is now implemented as a module instead of as core functionality.
+ The preferred way to configure parking is now through res_parking.conf while
+ configuration through features.conf is not currently supported.
+
+ * Parked calls are now placed in bridges. This is a largely architectural change,
+ but it could have some implications in allowing for new parked call retrieval
+ methods and the contents of parking lots will be visible though certain bridge
+ commands.
+
+ * The order of arguments for the new parking application are different from the
+ old one to be more intuitive. Timeout and return context/exten/priority are now
+ implemented as options. parking_lot_name is now the first parameter. See the
+ application documentation for Park for more in-depth information.
+
+ * Extensions are no longer automatically created in the dialplan to park calls,
+ pickup parked calls, etc by default.
+
+ * adsipark is no longer supported under the new parking model
+
+ * The PARKINGSLOT channel variable has been deprecated in favor of PARKING_SPACE
+ to match the naming scheme of the new system.
+
+ * PARKING_SPACE and PARKEDLOT channel variables will now be set for a parked
+ channel even when comebactoorigin=yes
+
+ * New CLI command 'parking show' allows you to inspect the currently in use
+ parking lots. 'parking show <parkinglot>' will also show the parked calls
+ in that specific parking lot.
+
+ * The CLI command 'parkedcalls' is now deprecated in favor of
+ 'parking show <parkinglot>'.
+
+ * The AMI command 'ParkedCalls' will now accept a 'ParkingLot' argument which
+ can be used to get a list of parked calls only for a specific parking lot.
Queue
-------------------
Modified: team/group/bridge_construction/bridges/bridge_builtin_features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/bridges/bridge_builtin_features.c?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/bridges/bridge_builtin_features.c (original)
+++ team/group/bridge_construction/bridges/bridge_builtin_features.c Thu May 9 17:21:09 2013
@@ -48,6 +48,7 @@
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
#include "asterisk/pbx.h"
+#include "asterisk/parking.h"
/*!
* \brief Helper function that presents dialtone and grabs extension
@@ -165,6 +166,7 @@
struct ast_channel *chan = NULL;
struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
const char *context;
+ struct ast_exten *park_exten;
/* BUGBUG the peer needs to be put on hold for the transfer. */
ast_channel_lock(bridge_channel->chan);
@@ -174,6 +176,16 @@
/* Grab the extension to transfer to */
if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
+ return 0;
+ }
+
+ /* Parking blind transfer override - phase this out for something more general purpose in the future. */
+ park_exten = ast_get_parking_exten(exten, bridge_channel->chan, context);
+ if (park_exten) {
+ /* We are transfering the transferee to a parking lot. */
+ if (ast_park_blind_xfer(bridge, bridge_channel, park_exten)) {
+ ast_log(LOG_ERROR, "%s attempted to transfer to park application and failed.\n", ast_channel_name(bridge_channel->chan));
+ };
return 0;
}
Modified: team/group/bridge_construction/include/asterisk/bridging.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/bridging.h?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/include/asterisk/bridging.h (original)
+++ team/group/bridge_construction/include/asterisk/bridging.h Thu May 9 17:21:09 2013
@@ -219,6 +219,8 @@
AST_BRIDGE_ACTION_TALKING_STOP,
/*! Bridge channel is to play the indicated sound file. */
AST_BRIDGE_ACTION_PLAY_FILE,
+ /*! Bridge channel is to get parked. */
+ AST_BRIDGE_ACTION_PARK,
/*! Bridge channel is to run the indicated application. */
AST_BRIDGE_ACTION_RUN_APP,
@@ -1129,6 +1131,22 @@
void ast_bridge_channel_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class);
/*!
+ * \brief Have a bridge channel park a channel in the bridge
+ * \since 12.0.0
+ *
+ * \param bridge_channel Bridge channel performing the parking
+ * \param parkee_uuid Unique id of the channel we want to park
+ * \param parker_uuid Unique id of the channel parking the call
+ * \param app_data string indicating data used for park application (NULL allowed)
+ *
+ * \note This is intended to be called by bridge hooks.
+ *
+ * \return Nothing
+ */
+void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid,
+ const char *parker_uuid, const char *app_data);
+
+/*!
* \brief Write a bridge action play file frame into the bridge.
* \since 12.0.0
*
Modified: team/group/bridge_construction/include/asterisk/config_options.h
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/include/asterisk/config_options.h?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/include/asterisk/config_options.h (original)
+++ team/group/bridge_construction/include/asterisk/config_options.h Thu May 9 17:21:09 2013
@@ -574,6 +574,16 @@
* \retval -1 Failure
*/
int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to);
+
+/*!
+ * \brief Read the flags of a config option - useful when using a custom callback for a config option
+ * \since 12
+ *
+ * \param option Pointer to the aco_option struct
+ *
+ * \retval value of the flags on the config option
+ */
+unsigned int aco_option_get_flags(const struct aco_option *option);
/*! \note Everything below this point is to handle converting varargs
* containing field names, to varargs containing a count of args, followed
Modified: team/group/bridge_construction/main/bridging.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging.c?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/main/bridging.c (original)
+++ team/group/bridge_construction/main/bridging.c Thu May 9 17:21:09 2013
@@ -58,6 +58,7 @@
#include "asterisk/musiconhold.h"
#include "asterisk/features.h"
#include "asterisk/cli.h"
+#include "asterisk/parking.h"
/*! All bridges container. */
static struct ao2_container *bridges;
@@ -523,6 +524,8 @@
AST_LIST_REMOVE(&bridge->channels, bridge_channel, entry);
bridge->v_table->pull(bridge, bridge_channel);
+ ast_bridge_channel_clear_roles(bridge_channel);
+
bridge_dissolve_check(bridge_channel);
bridge->reconfigured = 1;
@@ -564,7 +567,8 @@
if (bridge->dissolved
|| bridge_channel->state != AST_BRIDGE_CHANNEL_STATE_WAIT
|| (swap && swap->state != AST_BRIDGE_CHANNEL_STATE_WAIT)
- || bridge->v_table->push(bridge, bridge_channel, swap)) {
+ || bridge->v_table->push(bridge, bridge_channel, swap)
+ || ast_bridge_channel_establish_roles(bridge_channel)) {
ast_debug(1, "Bridge %s: pushing %p(%s) into bridge failed\n",
bridge->uniqueid, bridge_channel, ast_channel_name(bridge_channel->chan));
return -1;
@@ -901,6 +905,50 @@
{
payload_helper_playfile(ast_bridge_channel_queue_action_data,
bridge_channel, custom_play, playfile, moh_class);
+}
+
+struct bridge_park {
+ int parker_uuid_offset;
+ int app_data_offset;
+ /* buffer used for holding those strings */
+ char parkee_uuid[0];
+};
+
+static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struct bridge_park *payload)
+{
+ ast_bridge_channel_park(bridge_channel, payload->parkee_uuid,
+ &payload->parkee_uuid[payload->parker_uuid_offset],
+ payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL);
+}
+
+static void payload_helper_park(ast_bridge_channel_post_action_data post_it,
+ struct ast_bridge_channel *bridge_channel,
+ const char *parkee_uuid,
+ const char *parker_uuid,
+ const char *app_data)
+{
+ struct bridge_park *payload;
+ size_t len_parkee_uuid = strlen(parkee_uuid) + 1;
+ size_t len_parker_uuid = strlen(parker_uuid) + 1;
+ size_t len_app_data = !app_data ? 0 : strlen(app_data) + 1;
+ size_t len_payload = sizeof(*payload) + len_parker_uuid + len_parkee_uuid + len_app_data;
+
+ payload = alloca(len_payload);
+ payload->app_data_offset = len_app_data ? len_parkee_uuid + len_parker_uuid : 0;
+ payload->parker_uuid_offset = len_parkee_uuid;
+ strcpy(payload->parkee_uuid, parkee_uuid);
+ strcpy(&payload->parkee_uuid[payload->parker_uuid_offset], parker_uuid);
+ if (app_data) {
+ strcpy(&payload->parkee_uuid[payload->app_data_offset], app_data);
+ }
+
+ post_it(bridge_channel, AST_BRIDGE_ACTION_PARK, payload, len_payload);
+}
+
+void ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
+{
+ payload_helper_park(ast_bridge_channel_write_action_data,
+ bridge_channel, parkee_uuid, parker_uuid, app_data);
}
/*!
@@ -1989,6 +2037,13 @@
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
bridge_channel_unsuspend(bridge_channel);
break;
+ case AST_BRIDGE_ACTION_PARK:
+ bridge_channel_suspend(bridge_channel);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_park(bridge_channel, action->data.ptr);
+ ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
+ bridge_channel_unsuspend(bridge_channel);
+ break;
case AST_BRIDGE_ACTION_RUN_APP:
bridge_channel_suspend(bridge_channel);
ast_indicate(bridge_channel->chan, AST_CONTROL_SRCUPDATE);
@@ -2436,8 +2491,6 @@
struct ast_bridge_channel *bridge_channel = obj;
struct ast_frame *fr;
- ast_bridge_channel_clear_roles(bridge_channel);
-
if (bridge_channel->callid) {
bridge_channel->callid = ast_callid_unref(bridge_channel->callid);
}
@@ -2834,16 +2887,6 @@
bridge_channel->swap = swap;
bridge_channel->features = features;
- if (ast_bridge_channel_establish_roles(bridge_channel)) {
- /* A bridge channel should not be allowed to join if its roles couldn't be copied properly. */
- state = AST_BRIDGE_CHANNEL_STATE_HANGUP;
- ast_channel_lock(chan);
- ast_channel_internal_bridge_channel_set(chan, NULL);
- ast_channel_unlock(chan);
- ao2_ref(bridge_channel, -1);
- goto join_exit;
- }
-
bridge_channel_join(bridge_channel);
state = bridge_channel->state;
@@ -2948,11 +2991,6 @@
bridge_channel->depart_wait = independent ? 0 : 1;
bridge_channel->callid = ast_read_threadstorage_callid();
- if (ast_bridge_channel_establish_roles(bridge_channel)) {
- res = -1;
- goto bridge_impart_cleanup;
- }
-
/* Actually create the thread that will handle the channel */
if (independent) {
/* Independently imparted channels cannot have a PBX. */
@@ -2968,7 +3006,6 @@
bridge_channel_depart_thread, bridge_channel);
}
-bridge_impart_cleanup:
if (res) {
/* cleanup */
ast_channel_lock(chan);
Modified: team/group/bridge_construction/main/bridging_roles.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/bridging_roles.c?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/main/bridging_roles.c (original)
+++ team/group/bridge_construction/main/bridging_roles.c Thu May 9 17:21:09 2013
@@ -41,11 +41,14 @@
#include "asterisk/linkedlists.h"
#include "asterisk/bridging.h"
#include "asterisk/bridging_roles.h"
+#include "asterisk/stringfields.h"
struct bridge_role_option {
AST_LIST_ENTRY(bridge_role_option) list;
- char option[AST_ROLE_LEN];
- char value[1];
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(option);
+ AST_STRING_FIELD(value);
+ );
};
struct bridge_role {
@@ -71,6 +74,7 @@
{
struct bridge_role_option *role_option;
while ((role_option = AST_LIST_REMOVE_HEAD(&role->options, list))) {
+ ast_string_field_free_memory(role_option);
ast_free(role_option);
}
ast_free(role);
@@ -290,13 +294,18 @@
value = "";
}
- role_option = ast_calloc(1, sizeof(*role_option) + strlen(value));
+ role_option = ast_calloc(1, sizeof(*role_option));
if (!role_option) {
return -1;
}
- ast_copy_string(role_option->option, option, sizeof(role_option->option));
- strcpy(role_option->value, value);
+ if (ast_string_field_init(role_option, 32)) {
+ ast_free(role_option);
+ return -1;
+ }
+
+ ast_string_field_set(role_option, option, option);
+ ast_string_field_set(role_option, value, value);
AST_LIST_INSERT_TAIL(&role->options, role_option, list);
@@ -358,8 +367,8 @@
role_option = get_role_option(role, option);
if (role_option) {
- /* We need to clear the option out and recreate it. There is no way to do this yet. Implement it later. XXX */
- return -1;
+ ast_string_field_set(role_option, value, value);
+ return 0;
}
setup_bridge_role_option(role, option, value);
Modified: team/group/bridge_construction/main/config_options.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/config_options.c?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/main/config_options.c (original)
+++ team/group/bridge_construction/main/config_options.c Thu May 9 17:21:09 2013
@@ -220,6 +220,11 @@
}
return 0;
+}
+
+unsigned int aco_option_get_flags(const struct aco_option *option)
+{
+ return option->flags;
}
#ifdef AST_XML_DOCS
Modified: team/group/bridge_construction/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/group/bridge_construction/main/features.c?view=diff&rev=388233&r1=388232&r2=388233
==============================================================================
--- team/group/bridge_construction/main/features.c (original)
+++ team/group/bridge_construction/main/features.c Thu May 9 17:21:09 2013
@@ -250,129 +250,6 @@
</variablelist>
</description>
</application>
- <application name="ParkedCall" language="en_US">
- <synopsis>
- Retrieve a parked call.
- </synopsis>
- <syntax>
- <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 retrieve 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 retrieve a parked call from a parking lot.</para>
- <note>
- <para>Parking lots automatically create and manage dialplan extensions in
- the parking lot context. You do not need to explicitly use this
- application in your dialplan. Instead, all you should do is include the
- parking lot context in your dialplan.</para>
- </note>
- </description>
- <see-also>
- <ref type="application">Park</ref>
- <ref type="application">ParkAndAnnounce</ref>
- </see-also>
- </application>
- <application name="Park" language="en_US">
- <synopsis>
- Park yourself.
- </synopsis>
- <syntax>
- <parameter name="timeout">
- <para>A custom parking timeout for this parked call. Value in milliseconds.</para>
- </parameter>
- <parameter name="return_context">
- <para>The context to return the call to after it times out.</para>
- </parameter>
- <parameter name="return_exten">
- <para>The extension to return the call to after it times out.</para>
- </parameter>
- <parameter name="return_priority">
- <para>The priority to return the call to after it times out.</para>
- </parameter>
- <parameter name="options">
- <para>A list of options for this parked call.</para>
- <optionlist>
- <option name="r">
- <para>Send ringing instead of MOH to the parked call.</para>
- </option>
- <option name="R">
- <para>Randomize the selection of a parking space.</para>
- </option>
- <option name="s">
- <para>Silence announcement of the parking space number.</para>
- </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).</para>
- <para>If you set the <variable>PARKINGEXTEN</variable> variable to a
- parking space extension in the parking lot, Park() will attempt to park the call
- on that extension. If the extension is already is in use then execution
- will continue at the next priority.</para>
- <para>If the <literal>parkeddynamic</literal> option is enabled in <filename>features.conf</filename>
- the following variables can be used to dynamically create new parking lots.</para>
- <para>If you set the <variable>PARKINGDYNAMIC</variable> variable and this parking lot
- exists then it will be used as a template for the newly created dynamic lot. Otherwise,
- the default parking lot will be used.</para>
- <para>If you set the <variable>PARKINGDYNCONTEXT</variable> variable then the newly created dynamic
- parking lot will use this context.</para>
- <para>If you set the <variable>PARKINGDYNEXTEN</variable> variable then the newly created dynamic
- parking lot will use this extension to access the parking lot.</para>
- <para>If you set the <variable>PARKINGDYNPOS</variable> variable then the newly created dynamic parking lot
- will use those parking postitions.</para>
- <note>
- <para>This application must be used as the first extension priority
- to be recognized as a parking access extension. DTMF transfers
- and some channel drivers need this distinction to operate properly.
- The parking access extension in this case is treated like a dialplan
- hint.</para>
- </note>
- <note>
- <para>Parking lots automatically create and manage dialplan extensions in
- the parking lot context. You do not need to explicitly use this
- application in your dialplan. Instead, all you should do is include the
- parking lot context in your dialplan.</para>
- </note>
- </description>
- <see-also>
- <ref type="application">ParkAndAnnounce</ref>
- <ref type="application">ParkedCall</ref>
- </see-also>
- </application>
- <manager name="ParkedCalls" language="en_US">
- <synopsis>
- List parked calls.
- </synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
- </syntax>
- <description>
- <para>List parked calls.</para>
- </description>
- </manager>
<manager name="Park" language="en_US">
<synopsis>
Park a channel.
@@ -418,17 +295,6 @@
</syntax>
<description>
<para>Bridge together two channels already in the PBX.</para>
- </description>
- </manager>
- <manager name="Parkinglots" language="en_US">
- <synopsis>
- Get a list of parking lots
- </synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
- </syntax>
- <description>
- <para>List all parking lots as a series of AMI events</para>
</description>
</manager>
<function name="FEATURE" language="en_US">
@@ -540,6 +406,8 @@
#define AST_MAX_WATCHERS 256
#define MAX_DIAL_FEATURE_OPTIONS 30
+/* TODO Scrape all of the parking stuff out of features.c */
+
struct feature_group_exten {
AST_LIST_ENTRY(feature_group_exten) entry;
AST_DECLARE_STRING_FIELDS(
@@ -5228,389 +5096,6 @@
AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
END_OPTIONS );
-
-/*! \brief Park a call */
-static int park_call_exec(struct ast_channel *chan, const char *data)
-{
- struct ast_park_call_args args = { 0, };
- struct ast_flags flags = { 0 };
- char orig_exten[AST_MAX_EXTENSION];
- int orig_priority;
- int res;
- const char *pl_name;
- char *parse;
- struct park_app_args app_args;
-
- /*
- * Cache the original channel name because we are going to
- * masquerade the channel. Prefer the BLINDTRANSFER channel
- * name over this channel name. BLINDTRANSFER could be set if
- * the parking access extension did not get detected and we are
- * executing the Park application from the dialplan.
- *
- * The orig_chan_name is used to return the call to the
- * originator on parking timeout.
- */
- args.orig_chan_name = ast_strdupa(S_OR(
- pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ast_channel_name(chan)));
-
- /* Answer if call is not up */
- if (ast_channel_state(chan) != AST_STATE_UP) {
- if (ast_answer(chan)) {
- return -1;
- }
-
- /* Sleep to allow VoIP streams to settle down */
- if (ast_safe_sleep(chan, 1000)) {
- return -1;
- }
- }
-
- /* Process the dialplan application options. */
- parse = ast_strdupa(data);
- AST_STANDARD_APP_ARGS(app_args, parse);
-
- if (!ast_strlen_zero(app_args.timeout)) {
- if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
- ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
- args.timeout = 0;
- }
- }
- if (!ast_strlen_zero(app_args.return_con)) {
- args.return_con = app_args.return_con;
- }
- if (!ast_strlen_zero(app_args.return_ext)) {
- args.return_ext = app_args.return_ext;
- }
- if (!ast_strlen_zero(app_args.return_pri)) {
- if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
- ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
- args.return_pri = 0;
- }
- }
-
- ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
- args.flags = flags.flags;
-
- /*
- * Setup the exten/priority to be s/1 since we don't know where
- * this call should return.
- */
- ast_copy_string(orig_exten, ast_channel_exten(chan), sizeof(orig_exten));
- orig_priority = ast_channel_priority(chan);
- ast_channel_exten_set(chan, "s");
- ast_channel_priority_set(chan, 1);
-
- /* Park the call */
- 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 && parkeddynamic) {
- args.parkinglot = create_dynamic_parkinglot(pl_name, chan);
- }
- }
- if (args.parkinglot) {
- res = masq_park_call(chan, chan, &args);
- parkinglot_unref(args.parkinglot);
- } else {
- /* Parking failed because the parking lot does not exist. */
- if (!ast_test_flag(&args, AST_PARK_OPT_SILENCE)) {
- ast_stream_and_wait(chan, "pbx-parkingfailed", "");
- }
- res = -1;
- }
- if (res) {
- /* Park failed, try to continue in the dialplan. */
- ast_channel_exten_set(chan, orig_exten);
- ast_channel_priority_set(chan, orig_priority);
- res = 0;
- } else {
- /* Park succeeded. */
- res = -1;
- }
-
- return res;
-}
-
-/*! \brief Pickup parked call */
-static int parked_call_exec(struct ast_channel *chan, const char *data)
-{
- int res;
- 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;
- 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;
- }
- }
-
- 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 (ast_channel_state(chan) != 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", ast_channel_name(chan));
- }
- ast_log(LOG_WARNING,
- "Channel %s tried to retrieve parked call from unknown parking lot '%s'\n",
- ast_channel_name(chan), pl_name);
- return -1;
- }
- }
-
- AST_LIST_LOCK(&parkinglot->parkings);
- AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
- if ((ast_strlen_zero(app_args.pl_space) || pu->parkingnum == park)
- && !pu->notquiteyet && !ast_channel_pbx(pu->chan)) {
- /* The parking space has a call and can be picked up now. */
- AST_LIST_REMOVE_CURRENT(list);
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- if (pu) {
- struct ast_callid *callid = ast_read_threadstorage_callid();
-
- /* Found a parked call to pickup. */
- peer = pu->chan;
-
- /* We need to map the call id we have from this thread to the channel we found. */
- if (callid) {
- ast_channel_callid_set(peer, callid);
- callid = ast_callid_unref(callid);
- }
-
- con = ast_context_find(parkinglot->cfg.parking_con);
- if (con) {
- if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0)) {
- ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
- } else {
- notify_metermaids(pu->parkingexten, parkinglot->cfg.parking_con, AST_DEVICE_NOT_INUSE);
- }
- } else {
- ast_log(LOG_WARNING, "Whoa, no parking context?\n");
- }
-
- ast_cel_report_event(pu->chan, AST_CEL_PARK_END, NULL, "UnParkedCall", chan);
- /*** DOCUMENTATION
- <managerEventInstance>
- <synopsis>Raised when a call has been unparked.</synopsis>
- <syntax>
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Exten'])" />
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" />
- <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCall']/managerEventInstance/syntax/parameter[@name='From'])" />
- </syntax>
- <see-also>
- <ref type="application">ParkedCall</ref>
- <ref type="managerEvent">ParkedCall</ref>
- </see-also>
- </managerEventInstance>
- ***/
- ast_manager_event(pu->chan, EVENT_FLAG_CALL, "UnParkedCall",
- "Exten: %s\r\n"
- "Channel: %s\r\n"
- "Parkinglot: %s\r\n"
- "From: %s\r\n"
- "CallerIDNum: %s\r\n"
- "CallerIDName: %s\r\n"
- "ConnectedLineNum: %s\r\n"
- "ConnectedLineName: %s\r\n"
- "Uniqueid: %s\r\n",
- pu->parkingexten, ast_channel_name(pu->chan), pu->parkinglot->name,
- ast_channel_name(chan),
- S_COR(ast_channel_caller(pu->chan)->id.number.valid, ast_channel_caller(pu->chan)->id.number.str, "<unknown>"),
- S_COR(ast_channel_caller(pu->chan)->id.name.valid, ast_channel_caller(pu->chan)->id.name.str, "<unknown>"),
- S_COR(ast_channel_connected(pu->chan)->id.number.valid, ast_channel_connected(pu->chan)->id.number.str, "<unknown>"),
- S_COR(ast_channel_connected(pu->chan)->id.name.valid, ast_channel_connected(pu->chan)->id.name.str, "<unknown>"),
- ast_channel_uniqueid(pu->chan)
- );
-
- /* Stop entertaining the caller. */
- switch (pu->hold_method) {
- case AST_CONTROL_HOLD:
- ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
- break;
- case AST_CONTROL_RINGING:
- ast_indicate(pu->chan, -1);
- break;
- default:
- break;
- }
- pu->hold_method = 0;
-
- parkinglot_unref(pu->parkinglot);
- ast_free(pu);
- }
- AST_LIST_UNLOCK(&parkinglot->parkings);
-
- if (peer) {
- /* Update connected line between retrieving call and parked call. */
- struct ast_party_connected_line connected;
-
- ast_party_connected_line_init(&connected);
-
- /* Send our caller-id to peer. */
- ast_channel_lock(chan);
- ast_connected_line_copy_from_caller(&connected, ast_channel_caller(chan));
- ast_channel_unlock(chan);
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(chan, peer, &connected, 0) &&
- ast_channel_connected_line_macro(chan, peer, &connected, 0, 0)) {
- ast_channel_update_connected_line(peer, &connected, NULL);
- }
-
- /*
- * Get caller-id from peer.
- *
- * Update the retrieving call before it is answered if possible
- * for best results. Some phones do not support updating the
- * connected line information after connection.
- */
- ast_channel_lock(peer);
- ast_connected_line_copy_from_caller(&connected, ast_channel_caller(peer));
- ast_channel_unlock(peer);
- connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(peer, chan, &connected, 0) &&
- ast_channel_connected_line_macro(peer, chan, &connected, 1, 0)) {
- ast_channel_update_connected_line(chan, &connected, NULL);
- }
-
- ast_party_connected_line_free(&connected);
- }
-
- /* JK02: it helps to answer the channel if not already up */
- if (ast_channel_state(chan) != AST_STATE_UP) {
- ast_answer(chan);
- }
-
- if (peer) {
- struct ast_datastore *features_datastore;
- struct ast_dial_features *dialfeatures;
-
- /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
- if (!ast_strlen_zero(courtesytone)) {
- static const char msg[] = "courtesy tone";
-
- switch (parkedplay) {
- case 0:/* Courtesy tone to pickup chan */
- res = play_message_to_chans(chan, peer, -1, msg, courtesytone);
- break;
- case 1:/* Courtesy tone to parked chan */
- res = play_message_to_chans(chan, peer, 1, msg, courtesytone);
- break;
- case 2:/* Courtesy tone to both chans */
- res = play_message_to_chans(chan, peer, 0, msg, courtesytone);
- break;
- default:
- res = 0;
- break;
- }
- if (res) {
- bridge_failed_peer_goto(chan, peer);
- parkinglot_unref(parkinglot);
- return -1;
- }
- }
-
- res = ast_channel_make_compatible(chan, peer);
- if (res < 0) {
- ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer));
- bridge_failed_peer_goto(chan, peer);
- parkinglot_unref(parkinglot);
- return -1;
- }
- /* This runs sorta backwards, since we give the incoming channel control, as if it
- were the person called. */
- ast_verb(3, "Channel %s connected to parked call %d\n", ast_channel_name(chan), park);
-
- pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", ast_channel_name(peer));
- ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
- memset(&config, 0, sizeof(struct ast_bridge_config));
-
- /* Get datastore for peer and apply it's features to the callee side of the bridge config */
- ast_channel_lock(peer);
- features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL);
- if (features_datastore && (dialfeatures = features_datastore->data)) {
- ast_copy_flags(&config.features_callee, &dialfeatures->my_features,
- AST_FLAGS_ALL);
- }
- ast_channel_unlock(peer);
-
- if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
- }
- if ((parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
- }
- if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
- }
- if ((parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
- }
- if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
- }
- if ((parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
- }
- if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
- }
- if ((parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->cfg.parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
- ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
- }
-
- res = ast_bridge_call(chan, peer, &config);
- } else {
[... 282 lines stripped ...]
More information about the asterisk-commits
mailing list