diff options
author | Jonathan Rose <jrose@digium.com> | 2013-06-25 22:28:22 +0000 |
---|---|---|
committer | Jonathan Rose <jrose@digium.com> | 2013-06-25 22:28:22 +0000 |
commit | 854c4c64fe2851312b1e13857dcd18e743e07594 (patch) | |
tree | 80d042e06f38f95d4f1fd2adc07658b2cbd46038 /res | |
parent | 5b40420813318e08b9186d41aaf1d1aaff8d61e1 (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.c | 56 | ||||
-rw-r--r-- | res/parking/parking_bridge.c | 4 | ||||
-rw-r--r-- | res/parking/parking_bridge_features.c | 4 | ||||
-rw-r--r-- | res/parking/parking_controller.c | 9 | ||||
-rw-r--r-- | res/parking/parking_manager.c | 89 | ||||
-rw-r--r-- | res/parking/res_parking.h | 14 |
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 { |