2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Jonathan Rose <jrose@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Parking Bridge DTMF and Interval features
23 * \author Jonathan Rose <jrose@digium.com>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include "res_parking.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/astobj2.h"
33 #include "asterisk/logger.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/bridging.h"
36 #include "asterisk/bridging_features.h"
37 #include "asterisk/features.h"
38 #include "asterisk/say.h"
39 #include "asterisk/datastore.h"
40 #include "asterisk/stasis.h"
42 struct parked_subscription_datastore {
43 struct stasis_subscription *parked_subscription;
46 struct parked_subscription_data {
51 static void parked_subscription_datastore_destroy(void *data)
53 struct parked_subscription_datastore *subscription_datastore = data;
55 stasis_unsubscribe(subscription_datastore->parked_subscription);
56 subscription_datastore->parked_subscription = NULL;
58 ast_free(subscription_datastore);
61 static const struct ast_datastore_info parked_subscription_info = {
62 .type = "park subscription",
63 .destroy = parked_subscription_datastore_destroy,
66 static void wipe_subscription_datastore(struct ast_channel *chan)
68 struct ast_datastore *datastore;
70 ast_channel_lock(chan);
72 datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL);
74 ast_channel_datastore_remove(chan, datastore);
75 ast_datastore_free(datastore);
77 ast_channel_unlock(chan);
80 static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
81 struct stasis_subscription *sub)
83 const char *parkee_to_act_on = data->parkee_uuid;
85 struct ast_channel_snapshot *parkee_snapshot = message->parkee;
86 RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
87 RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
89 if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
93 if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
94 /* We only care about these two event types */
98 parker = ast_channel_get_by_name(data->parker_uuid);
103 ast_channel_lock(parker);
104 bridge_channel = ast_channel_get_bridge_channel(parker);
105 ast_channel_unlock(parker);
106 if (!bridge_channel) {
110 if (message->event_type == PARKED_CALL) {
111 /* queue the saynum on the bridge channel and hangup */
112 snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 1, message->parkingspace);
113 ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
114 wipe_subscription_datastore(bridge_channel->chan);
117 if (message->event_type == PARKED_CALL_FAILED) {
118 ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
119 wipe_subscription_datastore(bridge_channel->chan);
123 static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message)
125 if (stasis_subscription_final_message(sub, message)) {
130 if (stasis_message_type(message) == ast_parked_call_type()) {
131 struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
132 parker_parked_call_message_response(parked_call_message, data, sub);
136 static int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid)
138 struct ast_datastore *datastore;
139 struct parked_subscription_datastore *parked_datastore;
140 struct parked_subscription_data *subscription_data;
142 char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan));
143 size_t parker_uuid_size = strlen(parker_uuid) + 1;
145 /* If there is already a subscription, get rid of it. */
146 wipe_subscription_datastore(chan);
148 if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
152 if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
153 ast_datastore_free(datastore);
157 if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
158 strlen(parkee_uuid) + 1))) {
159 ast_datastore_free(datastore);
160 ast_free(parked_datastore);
164 subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
165 strcpy(subscription_data->parkee_uuid, parkee_uuid);
166 strcpy(subscription_data->parker_uuid, parker_uuid);
168 if (!(parked_datastore->parked_subscription = stasis_subscribe(ast_parking_topic(), parker_update_cb, subscription_data))) {
172 datastore->data = parked_datastore;
174 ast_channel_lock(chan);
175 ast_channel_datastore_add(chan, datastore);
176 ast_channel_unlock(chan);
183 * \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly
184 * identical to the dial_transfer function in bridge_builtin_features.c, however it doesn't swap the
185 * local channel and the channel that instigated the park.
187 static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *exten, const char *context)
189 RAII_VAR(struct ast_channel *, parkee_side_2, NULL, ao2_cleanup);
190 char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
191 struct ast_channel *parkee;
194 /* Used for side_2 hack */
198 /* Fill the variable with the extension and context we want to call */
199 snprintf(destination, sizeof(destination), "%s@%s", exten, context);
201 /* Now we request that chan_local prepare to call the destination */
202 parkee = ast_request("Local", ast_channel_nativeformats(parker), parker, destination,
208 /* Before we actually dial out let's inherit appropriate information. */
209 ast_channel_lock_both(parker, parkee);
210 ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker));
211 ast_channel_inherit_variables(parker, parkee);
212 ast_channel_datastore_inherit(parker, parkee);
213 ast_channel_unlock(parkee);
214 ast_channel_unlock(parker);
216 /* BUGBUG Use Richard's unreal channel stuff here instead of this hack */
217 parkee_name = ast_strdupa(ast_channel_name(parkee));
219 semi_pos = strrchr(parkee_name, ';');
221 /* There should always be a semicolon present in the string if is used since it's a local channel. */
226 parkee_name[(semi_pos - parkee_name) + 1] = '2';
227 parkee_side_2 = ast_channel_get_by_name(parkee_name);
229 /* We need to have the parker subscribe to the new local channel before hand. */
230 create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2));
232 pbx_builtin_setvar_helper(parkee_side_2, "BLINDTRANSFER", ast_channel_name(parker));
234 /* Since the above worked fine now we actually call it and return the channel */
235 if (ast_call(parkee, destination, 0)) {
243 static int park_feature_helper(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_exten *park_exten)
245 RAII_VAR(struct ast_channel *, other, NULL, ao2_cleanup);
246 RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
247 RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
248 RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
249 RAII_VAR(struct ao2_container *, bridge_peers, NULL, ao2_cleanup);
250 struct ao2_iterator iter;
252 bridge_peers = ast_bridge_peers(bridge);
254 if (ao2_container_count(bridge_peers) < 2) {
255 /* There is nothing to do if there is no one to park. */
259 if (ao2_container_count(bridge_peers) > 2) {
260 /* With a multiparty bridge, we need to do a regular blind transfer. We link the existing bridge to the parking lot with a
261 * local channel rather than transferring others. */
262 struct ast_channel *transfer_chan = NULL;
265 /* This simply doesn't work. The user attempted to one-touch park the parking lot and we can't originate a local channel
266 * without knowing an extension to transfer it to.
267 * XXX However, when parking lots are changed to be able to register extensions then this will be doable. */
268 ast_log(LOG_ERROR, "Can not one-touch park a multiparty bridge.\n");
272 transfer_chan = park_local_transfer(bridge_channel->chan,
273 ast_get_extension_name(park_exten), ast_get_context_name(ast_get_extension_context(park_exten)));
275 if (!transfer_chan) {
279 if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL, 1)) {
280 ast_hangup(transfer_chan);
286 /* Since neither of the above cases were used, we are doing a simple park with a two party bridge. */
288 for (iter = ao2_iterator_init(bridge_peers, 0); (other = ao2_iterator_next(&iter)); ao2_ref(other, -1)) {
289 /* We need the channel that isn't the bridge_channel's channel. */
290 if (strcmp(ast_channel_uniqueid(other), ast_channel_uniqueid(bridge_channel->chan))) {
294 ao2_iterator_destroy(&iter);
301 /* Subscribe to park messages with the other channel entering */
302 if (create_parked_subscription(bridge_channel->chan, ast_channel_uniqueid(other))) {
306 /* Write the park frame with the intended recipient and other data out to the bridge. */
307 ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(other), ast_channel_uniqueid(bridge_channel->chan), ast_get_extension_app_data(park_exten));
312 static void park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
314 RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
315 RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup);
316 RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
318 if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
319 /* We aren't the parkee, so ignore this action. */
323 parker = ast_channel_get_by_name(uuid_parker);
326 ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
327 publish_parked_call_failure(bridge_channel->chan);
331 if (!(parking_bridge = park_common_setup(bridge_channel->chan, parker, app_data, NULL))) {
332 publish_parked_call_failure(bridge_channel->chan);
336 pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", ast_channel_name(parker));
338 /* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
339 ao2_lock(bridge_channel);
341 original_bridge = bridge_channel->bridge;
342 if (!original_bridge) {
343 ao2_unlock(bridge_channel);
344 publish_parked_call_failure(bridge_channel->chan);
348 ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */
350 ao2_unlock(bridge_channel);
352 if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) {
353 ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
354 ast_channel_name(bridge_channel->chan));
358 static int feature_park(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
360 park_feature_helper(bridge, bridge_channel, NULL);
364 static void parking_duration_cb_destroyer(void *hook_pvt)
366 struct parked_user *user = hook_pvt;
371 * \brief Removes the identification information from a channel name string
374 * \param channel name string that you wish to turn into a dial string. This will be edited in place.
376 static void channel_name_to_dial_string(char *peername)
380 /* Truncate after the dash */
381 dash = strrchr(peername, '-');
388 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
390 * \param bridge Which bridge the channel was parked in
391 * \param bridge_channel bridge channel this interval hook is being executed on
392 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
394 static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
396 struct parked_user *user = hook_pvt;
397 struct ast_channel *chan = user->chan;
398 struct ast_context *park_dial_context;
401 char parking_space[AST_MAX_EXTENSION];
403 char returnexten[AST_MAX_EXTENSION];
404 char *duplicate_returnexten;
405 struct ast_exten *existing_exten;
406 struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */
409 /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
410 to deal with this, lock the parked user, check and set resolution. */
412 if (user->resolution != PARK_UNSET) {
413 /* Abandon timeout since something else has resolved the parked user before we got to it. */
418 user->resolution = PARK_TIMEOUT;
421 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
423 /* Set parking timeout channel variables */
424 snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
425 pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
426 pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
427 pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
429 peername = ast_strdupa(user->parker->name);
430 channel_name_to_dial_string(peername);
432 peername_flat = ast_strdupa(user->parker->name);
433 flatten_peername(peername_flat);
435 pbx_builtin_setvar_helper(chan, "PARKER", peername);
436 pbx_builtin_setvar_helper(chan, "PARKER_FLAT", peername_flat);
438 /* Dialplan generation for park-dial extensions */
440 if (ast_wrlock_contexts()) {
441 ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
445 if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
446 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
447 if (ast_unlock_contexts()) {
450 goto abandon_extension_creation;
453 if (ast_wrlock_context(park_dial_context)) {
454 ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
455 if (ast_unlock_contexts()) {
458 goto abandon_extension_creation;
461 if (ast_unlock_contexts()) {
465 snprintf(returnexten, sizeof(returnexten), "%s,%u", peername,
466 user->lot->cfg->comebackdialtime);
468 duplicate_returnexten = ast_strdup(returnexten);
470 if (!duplicate_returnexten) {
471 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
472 peername_flat, PARK_DIAL_CONTEXT, returnexten);
475 /* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
476 if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, peername_flat, 1, NULL, NULL, E_MATCH)) &&
477 (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
478 ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
479 peername_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
480 } else if (ast_add_extension2_nolock(park_dial_context, 1, peername_flat, 1, NULL, NULL,
481 "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
482 ast_free(duplicate_returnexten);
483 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
484 peername_flat, PARK_DIAL_CONTEXT, returnexten);
487 if (ast_unlock_context(park_dial_context)) {
491 abandon_extension_creation:
493 /* async_goto the proper PBX destination - this should happen when we come out of the bridge */
494 if (!ast_strlen_zero(user->comeback)) {
495 ast_async_parseable_goto(chan, user->comeback);
497 comeback_goto(user, user->lot);
503 void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
508 if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
509 /* If say_parking_space is called with a non-numeric string, we have a problem. */
511 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
515 ast_say_digits(bridge_channel->chan, numeric_value, "", ast_channel_language(bridge_channel->chan));
518 ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
522 void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
524 unsigned int time_limit;
526 time_limit = user->time_limit * 1000;
529 /* There is no duration limit that we need to apply. */
533 /* If the time limit has already been passed, set a really low time limit so we can kick them out immediately. */
534 time_limit = ast_remaining_ms(user->start, time_limit);
535 if (time_limit <= 0) {
539 /* The interval hook is going to need a reference to the parked_user */
542 if (ast_bridge_interval_hook(features, time_limit,
543 parking_duration_callback, user, parking_duration_cb_destroyer, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
544 ast_log(LOG_ERROR, "Failed to apply duration limits to the parking call.\n");
548 void unload_parking_bridge_features(void)
550 ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_PARKCALL);
551 ast_uninstall_park_blind_xfer_func();
552 ast_uninstall_bridge_channel_park_func();
555 int load_parking_bridge_features(void)
557 ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park, NULL);
558 ast_install_park_blind_xfer_func(park_feature_helper);
559 ast_install_bridge_channel_park_func(park_bridge_channel);