summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorJonathan Rose <jrose@digium.com>2013-06-25 22:28:22 +0000
committerJonathan Rose <jrose@digium.com>2013-06-25 22:28:22 +0000
commit854c4c64fe2851312b1e13857dcd18e743e07594 (patch)
tree80d042e06f38f95d4f1fd2adc07658b2cbd46038 /res
parent5b40420813318e08b9186d41aaf1d1aaff8d61e1 (diff)
res_parking: Add Parking manager action to the new parking system
(closes issue ASTERISK-21641) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2573/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392915 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r--res/parking/parking_applications.c56
-rw-r--r--res/parking/parking_bridge.c4
-rw-r--r--res/parking/parking_bridge_features.c4
-rw-r--r--res/parking/parking_controller.c9
-rw-r--r--res/parking/parking_manager.c89
-rw-r--r--res/parking/res_parking.h14
6 files changed, 135 insertions, 41 deletions
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
index 097329b93..2b921259f 100644
--- a/res/parking/parking_applications.c
+++ b/res/parking/parking_applications.c
@@ -375,25 +375,13 @@ void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uu
ast_channel_unlock(parkee);
}
-struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data,
- int *silence_announcements)
+struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
+ const char *lot_name, const char *comeback_override,
+ int use_ringing, int randomize, int time_limit, int silence_announcements)
{
- int use_ringing = 0;
- int randomize = 0;
- int time_limit = -1;
- char *lot_name;
-
struct ast_bridge *parking_bridge;
- RAII_VAR(char *, comeback_override, NULL, ast_free);
- RAII_VAR(char *, lot_name_app_arg, NULL, ast_free);
RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
- if (app_data) {
- park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
- }
-
- lot_name = lot_name_app_arg;
-
/* If the name of the parking lot isn't specified in the arguments, find it based on the channel. */
if (ast_strlen_zero(lot_name)) {
ast_channel_lock(parker);
@@ -412,16 +400,34 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan
parking_bridge = parking_lot_get_bridge(lot);
ao2_unlock(lot);
- if (parking_bridge) {
- /* Apply relevant bridge roles and such to the parking channel */
- parking_channel_set_roles(parkee, lot, use_ringing);
- setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
- silence_announcements ? *silence_announcements : 0);
- return parking_bridge;
+ if (!parking_bridge) {
+ return NULL;
+ }
+
+ /* Apply relevant bridge roles and such to the parking channel */
+ parking_channel_set_roles(parkee, lot, use_ringing);
+ setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
+ silence_announcements);
+ return parking_bridge;
+}
+
+struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data,
+ int *silence_announcements)
+{
+ int use_ringing = 0;
+ int randomize = 0;
+ int time_limit = -1;
+
+ RAII_VAR(char *, comeback_override, NULL, ast_free);
+ RAII_VAR(char *, lot_name_app_arg, NULL, ast_free);
+
+ if (app_data) {
+ park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg);
}
- /* Couldn't get the parking bridge. Epic failure. */
- return NULL;
+ return park_common_setup(parkee, parker, lot_name_app_arg, comeback_override, use_ringing,
+ randomize, time_limit, silence_announcements ? *silence_announcements : 0);
+
}
/* XXX BUGBUG - determining the parker when transferred to deep park priority
@@ -452,7 +458,7 @@ int park_app_exec(struct ast_channel *chan, const char *data)
ast_channel_unlock(chan);
/* Handle the common parking setup stuff */
- if (!(parking_bridge = park_common_setup(chan, chan, data, &silence_announcements))) {
+ if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
if (!silence_announcements && !blind_transfer) {
ast_stream_and_wait(chan, "pbx-parkingfailed", "");
}
@@ -753,7 +759,7 @@ int park_and_announce_app_exec(struct ast_channel *chan, const char *data)
}
/* Handle the common parking setup stuff */
- if (!(parking_bridge = park_common_setup(chan, chan, data, &silence_announcements))) {
+ if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) {
return 0;
}
diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c
index ac9b32508..60d05ed59 100644
--- a/res/parking/parking_bridge.c
+++ b/res/parking/parking_bridge.c
@@ -106,6 +106,9 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct
return NULL;
}
+ ast_channel_lock(chan);
+ ast_copy_string(new_parked_user->blindtransfer, S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ""), AST_CHANNEL_NAME);
+ ast_channel_unlock(chan);
if (use_random_space) {
preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1);
@@ -126,7 +129,6 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct
}
}
-
/* We need to keep the lot locked between parking_lot_get_space and actually placing it in the lot. Or until we decide not to. */
ao2_lock(lot);
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
index 3c0120762..f0cf0ae44 100644
--- a/res/parking/parking_bridge_features.c
+++ b/res/parking/parking_bridge_features.c
@@ -328,7 +328,7 @@ static void park_bridge_channel(struct ast_bridge_channel *bridge_channel, const
return;
}
- if (!(parking_bridge = park_common_setup(bridge_channel->chan, parker, app_data, NULL))) {
+ if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
publish_parked_call_failure(bridge_channel->chan);
return;
}
@@ -426,7 +426,7 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg
pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
- peername = ast_strdupa(user->parker->name);
+ peername = ast_strdupa(S_OR(user->blindtransfer, user->parker->name));
channel_name_to_dial_string(peername);
peername_flat = ast_strdupa(user->parker->name);
diff --git a/res/parking/parking_controller.c b/res/parking/parking_controller.c
index 8f2433b29..2764f50d4 100644
--- a/res/parking/parking_controller.c
+++ b/res/parking/parking_controller.c
@@ -244,15 +244,8 @@ int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
{
struct ast_channel *chan = pu->chan;
char *peername;
- const char *blindtransfer;
- ast_channel_lock(chan);
- if ((blindtransfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
- blindtransfer = ast_strdupa(blindtransfer);
- }
- ast_channel_unlock(chan);
-
- peername = blindtransfer ? ast_strdupa(blindtransfer) : ast_strdupa(pu->parker->name);
+ peername = ast_strdupa(S_OR(pu->blindtransfer, pu->parker->name));
/* Flatten the peername so that it can be used for performing the timeout PBX operations */
flatten_peername(peername);
diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c
index 444c5a54f..5a2b3f6fd 100644
--- a/res/parking/parking_manager.c
+++ b/res/parking/parking_manager.c
@@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/astobj2.h"
#include "asterisk/features.h"
#include "asterisk/manager.h"
+#include "asterisk/bridging.h"
/*** DOCUMENTATION
<manager name="Parkinglots" language="en_US">
@@ -64,6 +65,33 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<para>List parked calls.</para>
</description>
</manager>
+ <manager name="Park" language="en_US">
+ <synopsis>
+ Park a channel.
+ </synopsis>
+ <syntax>
+ <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+ <parameter name="Channel" required="true">
+ <para>Channel name to park.</para>
+ </parameter>
+ <parameter name="TimeoutChannel" required="false">
+ <para>Channel name to use when constructing the dial string that will be dialed if the parked channel times out.</para>
+ </parameter>
+ <parameter name="Timeout" required="false">
+ <para>Overrides the timeout of the parking lot for this park action. Specified in milliseconds, but will be converted to
+ seconds. Use a value of 0 to nullify the timeout.
+ </para>
+ </parameter>
+ <parameter name="Parkinglot" required="false">
+ <para>The parking lot to use when parking the channel</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Park an arbitrary channel with optional arguments for specifying the parking lot used, how long
+ the channel should remain parked, and what dial string to use as the parker if the call times out.
+ </para>
+ </description>
+ </manager>
<managerEvent language="en_US" name="ParkedCall">
<managerEventInstance class="EVENT_FLAG_CALL">
<synopsis>Raised when a channel is parked.</synopsis>
@@ -498,6 +526,61 @@ static int manager_parking_lot_list(struct mansession *s, const struct message *
return RESULT_SUCCESS;
}
+static int manager_park(struct mansession *s, const struct message *m)
+{
+ const char *channel = astman_get_header(m, "Channel");
+ const char *timeout_channel = S_OR(astman_get_header(m, "TimeoutChannel"), astman_get_header(m, "Channel2"));
+ const char *timeout = astman_get_header(m, "Timeout");
+ const char *parkinglot = astman_get_header(m, "Parkinglot");
+ char buf[BUFSIZ];
+ int timeout_override = -1;
+
+ RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
+
+ if (ast_strlen_zero(channel)) {
+ astman_send_error(s, m, "Channel not specified");
+ return 0;
+ }
+
+ if (!ast_strlen_zero(timeout)) {
+ if (sscanf(timeout, "%30d", &timeout_override) != 1 || timeout < 0) {
+ astman_send_error(s, m, "Invalid Timeout value.");
+ return 0;
+ }
+
+ if (timeout_override > 0) {
+ /* If greater than zero, convert to seconds for internal use. Must be >= 1 second. */
+ timeout_override = MAX(1, timeout_override / 1000);
+ }
+ }
+
+ if (!(chan = ast_channel_get_by_name(channel))) {
+ snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
+ astman_send_error(s, m, buf);
+ return 0;
+ }
+
+ ast_channel_lock(chan);
+ if (!ast_strlen_zero(timeout_channel)) {
+ pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", timeout_channel);
+ }
+ ast_channel_unlock(chan);
+
+ if (!(parking_bridge = park_common_setup(chan, chan, parkinglot, NULL, 0, 0, timeout_override, 0))) {
+ astman_send_error(s, m, "Park action failed\n");
+ return 0;
+ }
+
+ if (ast_bridge_add_channel(parking_bridge, chan, NULL, 0, NULL)) {
+ astman_send_error(s, m, "Park action failed\n");
+ return 0;
+ }
+
+ astman_send_ack(s, m, "Park successful\n");
+ return 0;
+}
+
void publish_parked_call_failure(struct ast_channel *parkee)
{
RAII_VAR(struct ast_parked_call_payload *, payload, NULL, ao2_cleanup);
@@ -588,9 +671,9 @@ int load_parking_manager(void)
{
int res;
- res = ast_manager_register_xml_core("Parkinglots", 0, manager_parking_lot_list);
- res |= ast_manager_register_xml_core("ParkedCalls", 0, manager_parking_status);
- /* TODO Add a 'Park' manager action */
+ res = ast_manager_register_xml_core("Parkinglots", EVENT_FLAG_CALL, manager_parking_lot_list);
+ res |= ast_manager_register_xml_core("ParkedCalls", EVENT_FLAG_CALL, manager_parking_status);
+ res |= ast_manager_register_xml_core("Park", EVENT_FLAG_CALL, manager_park);
parking_manager_enable_stasis();
return res ? -1 : 0;
}
diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h
index cee93a6ce..a026be41a 100644
--- a/res/parking/res_parking.h
+++ b/res/parking/res_parking.h
@@ -105,8 +105,9 @@ struct parked_user {
struct timeval start; /*!< When the call was parked */
int parking_space; /*!< Which parking space is used */
char comeback[AST_MAX_CONTEXT]; /*!< Where to go on parking timeout */
+ char blindtransfer[AST_CHANNEL_NAME]; /*!< What the BLINDTRANSFER variable was at the time of entry */
unsigned int time_limit; /*!< How long this specific channel may remain in the parking lot before timing out */
- struct parking_lot *lot; /*!< Which parking lot the user is parked to */
+ struct parking_lot *lot; /*!< Which parking lot the user is parked to */
enum park_call_resolution resolution; /*!< How did the parking session end? If the call is in a bridge, lock parked_user before checking/setting */
};
@@ -335,6 +336,15 @@ void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type
/*!
* \since 12.0.0
+ * \brief Setup a parked call on a parking bridge without needing to parse appdata
+ *
+ */
+struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
+ const char *lot_name, const char *comeback_override,
+ int use_ringing, int randomize, int time_limit, int silence_announcements);
+
+/*!
+ * \since 12.0.0
* \brief Function to prepare a channel for parking by determining which parking bridge should
* be used, setting up a park common datastore so that the parking bridge will have access
* to necessary parking information when joining, and applying various bridge roles to the
@@ -351,7 +361,7 @@ void publish_parked_call(struct parked_user *pu, enum ast_parked_call_event_type
*
* \note ao2_cleanup this reference when you are done using it or you'll cause leaks.
*/
-struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker,
+struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast_channel *parker,
const char *app_data, int *silence_announcements);
struct park_common_datastore {