Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
parking_bridge_features.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Jonathan Rose <jrose@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief Parking Bridge DTMF and Interval features
22 *
23 * \author Jonathan Rose <jrose@digium.com>
24 */
25
26#include "asterisk.h"
27
28#include "res_parking.h"
29#include "asterisk/utils.h"
30#include "asterisk/astobj2.h"
31#include "asterisk/logger.h"
32#include "asterisk/pbx.h"
33#include "asterisk/app.h"
34#include "asterisk/bridge.h"
39#include "asterisk/features.h"
40#include "asterisk/say.h"
41#include "asterisk/datastore.h"
42#include "asterisk/stasis.h"
43#include "asterisk/module.h"
44#include "asterisk/core_local.h"
45#include "asterisk/causes.h"
46
47/*** DOCUMENTATION
48 <function name="PARK_GET_CHANNEL" language="en_US">
49 <since>
50 <version>16.0.0</version>
51 </since>
52 <synopsis>
53 Get the channel name of an occupied parking space in a parking lot.
54 </synopsis>
55 <syntax>
56 <parameter name="parking_space" required="true">
57 </parameter>
58 <parameter name="parking_lot" required="true">
59 </parameter>
60 </syntax>
61 <description>
62 <para>This function returns the channel of the specified parking space
63 if the parking lot space is occupied.</para>
64 </description>
65 </function>
66***/
67
70};
71
75 unsigned int hangup_after:1;
76 char parker_uuid[0];
77};
78
80{
81 struct parked_subscription_datastore *subscription_datastore = data;
82
83 stasis_unsubscribe(subscription_datastore->parked_subscription);
84 subscription_datastore->parked_subscription = NULL;
85
86 ast_free(subscription_datastore);
87}
88
90 .type = "park subscription",
92};
93
95{
96 struct ast_datastore *datastore;
97
98 ast_channel_lock(chan);
99
101 if (datastore) {
102 ast_channel_datastore_remove(chan, datastore);
103 ast_datastore_free(datastore);
104 }
105 ast_channel_unlock(chan);
106}
107
109 struct stasis_subscription *sub)
110{
111 const char *parkee_to_act_on = data->parkee_uuid;
112 char saynum_buf[16];
113 struct ast_channel_snapshot *parkee_snapshot = message->parkee;
114 RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
115 RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
116
117 if (strcmp(parkee_to_act_on, parkee_snapshot->base->uniqueid)) {
118 return;
119 }
120
121 if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
122 /* We only care about these two event types */
123 return;
124 }
125
126 parker = ast_channel_get_by_name(data->parker_uuid);
127 if (!parker) {
128 return;
129 }
130
131 ast_channel_lock(parker);
132 bridge_channel = ast_channel_get_bridge_channel(parker);
133 ast_channel_unlock(parker);
134 if (!bridge_channel) {
135 return;
136 }
137
138 /* This subscription callback will block for the duration of the announcement if
139 * parked_subscription_data is tracking a transfer_channel_data struct. */
140 if (message->event_type == PARKED_CALL) {
141 /* queue the saynum on the bridge channel and hangup */
142 snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
143 if (!data->transfer_data) {
144 ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
145 } else {
147 data->transfer_data->completed = 1;
148 }
150 } else if (message->event_type == PARKED_CALL_FAILED) {
151 if (!data->transfer_data) {
152 ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
153 } else {
154 ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
155 data->transfer_data->completed = 1;
156 }
158 }
159}
160
161static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
162{
164 struct parked_subscription_data *ps_data = data;
165 ao2_cleanup(ps_data->transfer_data);
166 ps_data->transfer_data = NULL;
167 ast_free(data);
168 return;
169 }
170
172 struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
173 parker_parked_call_message_response(parked_call_message, data, sub);
174 }
175}
176
177static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
178 struct transfer_channel_data *parked_channel_data)
179{
180 struct ast_datastore *datastore;
181 struct parked_subscription_datastore *parked_datastore;
182 struct parked_subscription_data *subscription_data;
183
185 size_t parker_uuid_size;
186 size_t parkee_uuid_size;
187
188 /* If there is already a subscription, get rid of it. */
190
191 if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
192 return -1;
193 }
194
195 if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
196 ast_datastore_free(datastore);
197 return -1;
198 }
199
200 parker_uuid_size = strlen(parker_uuid) + 1;
201 parkee_uuid_size = strlen(parkee_uuid) + 1;
202
203 if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
204 parkee_uuid_size))) {
205 ast_datastore_free(datastore);
206 ast_free(parked_datastore);
207 return -1;
208 }
209
210 if (parked_channel_data) {
211 subscription_data->transfer_data = parked_channel_data;
212 ao2_ref(parked_channel_data, +1);
213 }
214
215 subscription_data->hangup_after = hangup_after;
216 subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
217 ast_copy_string(subscription_data->parkee_uuid, parkee_uuid, parkee_uuid_size);
218 ast_copy_string(subscription_data->parker_uuid, parker_uuid, parker_uuid_size);
219
220 if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
221 return -1;
222 }
226
227 datastore->data = parked_datastore;
228
229 ast_channel_lock(chan);
230 ast_channel_datastore_add(chan, datastore);
231 ast_channel_unlock(chan);
232
233 return 0;
234}
235
237{
239}
240
241/*!
242 * \internal
243 * \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly
244 * identical to the dial_transfer function in bridge_basic.c, however it doesn't swap the
245 * local channel and the channel that instigated the park.
246 */
247static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
248{
249 char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
250 struct ast_channel *parkee;
251 struct ast_channel *parkee_side_2;
252 int cause;
253
254 /* Fill the variable with the extension and context we want to call */
255 snprintf(destination, sizeof(destination), "%s@%s", exten, context);
256
257 /* Now we request that chan_local prepare to call the destination */
258 parkee = ast_request("Local", ast_channel_nativeformats(parker), NULL, parker, destination,
259 &cause);
260 if (!parkee) {
261 return NULL;
262 }
263
264 /* Before we actually dial out let's inherit appropriate information. */
265 ast_channel_lock_both(parker, parkee);
267 ast_channel_parkinglot_set(parkee, ast_channel_parkinglot(parker));
269 ast_channel_inherit_variables(parker, parkee);
271 ast_channel_datastore_inherit(parker, parkee);
272 ast_channel_unlock(parker);
273
274 parkee_side_2 = ast_local_get_peer(parkee);
275 ast_assert(parkee_side_2 != NULL);
276 ast_channel_unlock(parkee);
277
278 /* We need to have the parker subscribe to the new local channel before hand. */
279 if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
280 ast_channel_unref(parkee_side_2);
281 ast_hangup(parkee);
282 return NULL;
283 }
284
285 ast_channel_unref(parkee_side_2);
286
287 /* Since the above worked fine now we actually call it and return the channel */
288 if (ast_call(parkee, destination, 0)) {
289 ast_hangup(parkee);
290 return NULL;
291 }
292
293 return parkee;
294}
295
296/*!
297 * \internal
298 * \brief Determine if an extension is a parking extension
299 */
300static int parking_is_exten_park(const char *context, const char *exten)
301{
302 struct ast_exten *exten_obj;
303 struct pbx_find_info info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
304 const char *app_at_exten;
305
306 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten, context);
307 exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH);
308 if (!exten_obj) {
309 return 0;
310 }
311
312 app_at_exten = ast_get_extension_app(exten_obj);
313 if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
314 return 0;
315 }
316
317 return 1;
318}
319
320/*!
321 * \internal
322 * \since 12.0.0
323 * \brief Perform a blind transfer to a parking lot
324 *
325 * In general, most parking features should work to call this function. This will safely
326 * park either a channel in the bridge with \p bridge_channel or will park the entire
327 * bridge if more than one channel is in the bridge. It will create the correct data to
328 * pass to the \ref AstBridging Bridging API to safely park the channel.
329 *
330 * \param bridge_channel The bridge_channel representing the channel performing the park
331 * \param context The context to blind transfer to
332 * \param exten The extension to blind transfer to
333 * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
334 * \param parked_channel_data Data for the parked_channel_cb
335 *
336 * \retval 0 on success
337 * \retval non-zero on error
338 */
339static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
340 const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
341 struct transfer_channel_data *parked_channel_data)
342{
343 RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
344 RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);
345
346 struct ast_exten *e;
347 struct pbx_find_info find_info = { .stacklen = 0 };
348 int peer_count;
349
350 if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
351 return -1;
352 }
353
354 if (!bridge_channel->in_bridge) {
355 return -1;
356 }
357
358 if (!parking_is_exten_park(context, exten)) {
359 return -1;
360 }
361
362 ast_bridge_channel_lock_bridge(bridge_channel);
363 peer_count = bridge_channel->bridge->num_channels;
364 if (peer_count == 2) {
365 other = ast_bridge_channel_peer(bridge_channel);
366 ao2_ref(other, +1);
367 other_chan = other->chan;
368 ast_channel_ref(other_chan);
369 }
370 ast_bridge_unlock(bridge_channel->bridge);
371
372 if (peer_count < 2) {
373 /* There is nothing to do if there is no one to park. */
374 return -1;
375 }
376
377 /* With a multiparty bridge, we need to do a regular blind transfer. We link the
378 * existing bridge to the parking lot with a Local channel rather than
379 * transferring others. */
380 if (peer_count > 2) {
381 struct ast_channel *transfer_chan = NULL;
382
383 transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
384 if (!transfer_chan) {
385 return -1;
386 }
387 ast_channel_ref(transfer_chan);
388
389 if (parked_channel_cb) {
390 parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
391 }
392
393 if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
395 ast_hangup(transfer_chan);
396 ast_channel_unref(transfer_chan);
397 return -1;
398 }
399
400 ast_channel_unref(transfer_chan);
401
402 return 0;
403 }
404
405 /* Subscribe to park messages with the other channel entering */
406 if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
407 return -1;
408 }
409
410 if (parked_channel_cb) {
411 parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
412 }
413
414 e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
415
416 /* Write the park frame with the intended recipient and other data out to the bridge. */
418 ast_channel_uniqueid(other_chan),
421
422 return 0;
423}
424
425/*!
426 * \internal
427 * \since 12.0.0
428 * \brief Perform a direct park on a channel in a bridge
429 *
430 * \note This will be called from within the \ref AstBridging Bridging API
431 *
432 * \param bridge_channel The bridge_channel representing the channel to be parked
433 * \param uuid_parkee The UUID of the channel being parked
434 * \param uuid_parker The UUID of the channel performing the park
435 * \param app_data Application parseable data to pass to the parking application
436 */
437static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
438{
439 RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
440 RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup);
441 RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
442
443 if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
444 /* We aren't the parkee, so ignore this action. */
445 return -1;
446 }
447
448 parker = ast_channel_get_by_name(uuid_parker);
449
450 if (!parker) {
451 ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
453 return -1;
454 }
455
456 if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
458 return -1;
459 }
460
462
463 /* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
465
466 original_bridge = bridge_channel->bridge;
467 if (!original_bridge) {
470 return -1;
471 }
472
473 ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */
474
476
477 if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) {
478 ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
480 return -1;
481 }
482
483 return 0;
484}
485
486/*!
487 * \internal
488 * \since 12.0.0
489 * \brief Park a call
490 *
491 * \param parker The bridge_channel parking the call
492 * \param exten Optional. The extension where the call was parked.
493 * \param length Optional. If \c exten is specified, the length of the buffer.
494 *
495 * \note This will determine the context and extension to park the channel based on
496 * the configuration of the \ref ast_channel associated with \p parker. It will then
497 * park either the channel or the entire bridge.
498 *
499 * \retval 0 on success
500 * \retval -1 on error
501 */
502static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
503{
504 RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
505 const char *lot_name;
506
507 ast_channel_lock(parker->chan);
509 ast_channel_unlock(parker->chan);
510
511 lot = parking_lot_find_by_name(lot_name);
512 if (!lot) {
513 lot = parking_create_dynamic_lot(lot_name, parker->chan);
514 }
515 if (!lot) {
516 ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n",
517 ast_channel_name(parker->chan), lot_name);
518 return -1;
519 }
520
521 if (exten) {
522 ast_copy_string(exten, lot->cfg->parkext, length);
523 }
524 return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
525}
526
527static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
528{
529 SCOPED_MODULE_USE(AST_MODULE_SELF);
530
532 return 0;
533}
534
535/*!
536 * \internal
537 * \brief Setup the caller features for when that channel is dialed.
538 * \since 12.0.0
539 *
540 * \param chan Parked channel leaving the parking lot.
541 * \param cfg Parking lot configuration.
542 */
544{
545 char features[5];
546 char *pos;
547
548 /*
549 * We are setting the callee Dial flag values because in the
550 * timeout case, the caller is who is being called back.
551 */
552 pos = features;
554 *pos++ = 't';
555 }
557 *pos++ = 'k';
558 }
560 *pos++ = 'h';
561 }
563 *pos++ = 'x';
564 }
565 *pos = '\0';
566
567 pbx_builtin_setvar_helper(chan, "BRIDGE_FEATURES", features);
568}
569
570/*! \internal
571 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
572 *
573 * \param bridge_channel bridge channel this interval hook is being executed on
574 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
575 */
577{
578 struct parked_user *user = hook_pvt;
579 struct ast_channel *chan = user->chan;
580 struct ast_context *park_dial_context;
581 const char *dial_string;
582 char *dial_string_flat;
583 char parking_space[AST_MAX_EXTENSION];
584
585 char returnexten[AST_MAX_EXTENSION];
586 char *duplicate_returnexten;
587 struct ast_exten *existing_exten;
588 struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */
589
590
591 /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
592 to deal with this, lock the parked user, check and set resolution. */
593 ao2_lock(user);
594 if (user->resolution != PARK_UNSET) {
595 /* Abandon timeout since something else has resolved the parked user before we got to it. */
597 return -1;
598 }
599 user->resolution = PARK_TIMEOUT;
601
604
605 dial_string = user->parker_dial_string;
606 dial_string_flat = ast_strdupa(dial_string);
607 flatten_dial_string(dial_string_flat);
608
609 /* Set parking timeout channel variables */
610 snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
611 ast_channel_lock(chan);
613 pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
614 pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
615 pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
616 pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
619 ast_channel_unlock(chan);
620
621 /* Dialplan generation for park-dial extensions */
622
623 if (ast_wrlock_contexts()) {
624 ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
625 return -1;
626 }
627
629 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
630 if (ast_unlock_contexts()) {
631 ast_assert(0);
632 }
633 goto abandon_extension_creation;
634 }
635
636 if (ast_wrlock_context(park_dial_context)) {
637 ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
638 if (ast_unlock_contexts()) {
639 ast_assert(0);
640 }
641 goto abandon_extension_creation;
642 }
643
644 if (ast_unlock_contexts()) {
645 ast_assert(0);
646 }
647
648 snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
649 user->lot->cfg->comebackdialtime);
650
651 duplicate_returnexten = ast_strdup(returnexten);
652 if (!duplicate_returnexten) {
653 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
654 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
655 }
656
657 /* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
658 if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
659 (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
660 ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
661 dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
662 } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
663 "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR, NULL, 0)) {
664 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
665 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
666 }
667
668 if (ast_unlock_context(park_dial_context)) {
669 ast_assert(0);
670 }
671
672abandon_extension_creation:
673
674 /* async_goto the proper PBX destination - this should happen when we come out of the bridge */
675 if (!ast_strlen_zero(user->comeback)) {
676 ast_async_parseable_goto(chan, user->comeback);
677 } else {
678 comeback_goto(user, user->lot);
679 }
680
681 return -1;
682}
683
684void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
685{
686 unsigned int numeric_value;
687 unsigned int hangup_after;
688
689 if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
690 /* If say_parking_space is called with a non-numeric string, we have a problem. */
691 ast_assert(0);
692 ast_bridge_channel_leave_bridge(bridge_channel,
694 return;
695 }
696
697 ast_say_digits(bridge_channel->chan, numeric_value, "",
698 ast_channel_language(bridge_channel->chan));
699
700 if (hangup_after) {
701 ast_bridge_channel_leave_bridge(bridge_channel,
703 }
704}
705
707{
708 unsigned int time_limit;
709
710 time_limit = user->time_limit * 1000;
711
712 if (!time_limit) {
713 /* There is no duration limit that we need to apply. */
714 return;
715 }
716
717 /* If the time limit has already been passed, set a really low time limit so we can kick them out immediately. */
718 time_limit = ast_remaining_ms(user->start, time_limit);
719 if (time_limit <= 0) {
720 time_limit = 1;
721 }
722
723 /* The interval hook is going to need a reference to the parked_user */
724 ao2_ref(user, +1);
725
726 if (ast_bridge_interval_hook(features, 0, time_limit,
728 ast_log(LOG_ERROR, "Failed to apply duration limit to the parked call.\n");
729 ao2_ref(user, -1);
730 }
731}
732
733/*! \brief Dial plan function to get the parking lot channel of an occupied parking lot */
734static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
735{
736 RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
737 RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
738 unsigned int space = 0;
739 const char *content = NULL;
740
742 AST_APP_ARG(parking_space);
744 AST_APP_ARG(other);
745 );
746
747 /* Parse the arguments. */
749
750 if (args.argc < 2) {
751 /* Didn't receive enough arguments to do anything */
752 ast_log(LOG_ERROR, "Usage: %s(<parking_space>,<parking_lot>)\n",
753 function);
754 return -1;
755 }
756
757 lot = parking_lot_find_by_name(args.parking_lot);
758 if (!lot) {
759 ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", args.parking_lot);
760 return -1;
761 }
762
763 if (!ast_strlen_zero(args.parking_space)) {
764 if (ast_str_to_uint(args.parking_space, &space) != 0) {
765 ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n",
766 args.parking_space);
767 return -1;
768 }
769 }
770
771 pu = parking_lot_inspect_parked_user(lot, space);
772 if (!pu) {
773 return -1;
774 }
775
776 content = ast_channel_name(pu->chan);
777 ast_copy_string(buf, content, len);
778
779 return 0;
780}
781
783 .name = "PARK_GET_CHANNEL",
785};
786
789 .module_name = __FILE__,
790 .parking_is_exten_park = parking_is_exten_park,
791 .parking_blind_transfer_park = parking_blind_transfer_park,
792 .parking_park_bridge_channel = parking_park_bridge_channel,
793 .parking_park_call = parking_park_call,
794};
795
797{
801}
802
804{
805 parking_provider.module = AST_MODULE_SELF;
806
808
810 return -1;
811 }
812
814 return -1;
815 }
816
817 return 0;
818}
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
Bridging API.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:485
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
Definition: bridge.c:1947
@ AST_BRIDGE_TRANSFER_SINGLE_PARTY
Definition: bridge.h:1115
@ AST_BRIDGE_TRANSFER_MULTI_PARTY
Definition: bridge.h:1117
void(* transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data, enum ast_transfer_type transfer_type)
Callback function type called during blind transfers.
Definition: bridge.h:1147
void ast_bridge_set_transfer_variables(struct ast_channel *chan, const char *value, int is_attended)
Set the relevant transfer variables for a single channel.
Definition: bridge.c:4421
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:594
int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
Move a channel from one bridge to another.
Definition: bridge.c:2529
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
struct ast_bridge_channel * ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
Get the peer bridge channel of a two party bridge.
@ BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE
int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Queue a bridge action play file frame onto the bridge channel.
int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Synchronously queue a bridge action play file frame onto the bridge channel.
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
Have a bridge channel park a channel in the bridge.
Channel Bridging API.
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
Unregister a handler for a built in feature.
Definition: bridge.c:3147
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
Definition: bridge.c:3388
@ AST_BRIDGE_HOOK_REMOVE_ON_PULL
@ AST_BRIDGE_BUILTIN_PARKCALL
int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf)
Register a handler for a built in feature.
Definition: bridge.c:3131
Private Bridging API.
Internal Asterisk hangup causes.
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
const char * ast_channel_name(const struct ast_channel *chan)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6478
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2414
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2423
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2570
@ AST_CHANNEL_REQUESTOR_REPLACEMENT
Definition: channel.h:1525
#define ast_channel_lock(chan)
Definition: channel.h:2970
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2995
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2977
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2397
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6451
const char * ast_channel_parkinglot(const struct ast_channel *chan)
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6793
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3006
#define AST_MAX_CONTEXT
Definition: channel.h:135
const char * ast_channel_language(const struct ast_channel *chan)
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
Definition: channel.c:10608
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8319
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3017
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6371
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#define AST_MAX_EXTENSION
Definition: channel.h:134
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2428
Conversion utility functions.
int ast_str_to_uint(const char *str, unsigned int *res)
Convert the given string to an unsigned integer.
Definition: conversions.c:56
Local proxy channel special access.
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition: core_local.c:288
Asterisk datastore objects.
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:85
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
@ E_MATCH
Definition: extconf.h:217
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
@ AST_FEATURE_FLAG_BYCALLER
Definition: features.h:38
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition: parking.c:67
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Support for logging to various files, console and syslog Configuration in file logger....
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_NOTICE
Asterisk module definitions.
#define SCOPED_MODULE_USE(module)
Definition: module.h:679
def info(msg)
int ast_parking_unregister_bridge_features(const char *module_name)
Unregister the current parking provider.
Definition: parking.c:223
int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
Register a parking provider.
Definition: parking.c:196
@ PARKED_CALL
Definition: parking.h:47
@ PARKED_CALL_FAILED
Definition: parking.h:51
#define PARK_APPLICATION
The default parking application that Asterisk expects.
Definition: parking.h:35
#define PARKING_MODULE_VERSION
Definition: parking.h:119
struct ast_bridge * park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data, int *silence_announcements)
Function to prepare a channel for parking by determining which parking bridge should be used,...
static void wipe_subscription_datastore(struct ast_channel *chan)
static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
void unload_parking_bridge_features(void)
Unregister features registered by load_parking_bridge_features.
static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data, struct stasis_subscription *sub)
static void parking_timeout_set_caller_features(struct ast_channel *chan, struct parking_lot_cfg *cfg)
void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
Setup timeout interval feature on an ast_bridge_features for parking.
static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
struct ast_parking_bridge_feature_fn_table parking_provider
static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
static const struct ast_datastore_info parked_subscription_info
int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
Create a parking announcement subscription.
static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
static void parked_subscription_datastore_destroy(void *data)
void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
custom callback function for ast_bridge_channel_queue_playfile which plays a parking space and option...
static struct ast_channel * park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Dial plan function to get the parking lot channel of an occupied parking lot.
int load_parking_bridge_features(void)
Register bridge features for parking.
static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
static struct ast_custom_function getparkingslotchannel_function
static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after, struct transfer_channel_data *parked_channel_data)
static int parking_is_exten_park(const char *context, const char *exten)
struct parked_user * parking_lot_inspect_parked_user(struct parking_lot *lot, int target)
Determine if there is a parked user in a parking space and return it if there is.
void flatten_dial_string(char *dialstring)
Flattens a dial string so that it can be written to/found from PBX extensions.
int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
Set a channel's position in the PBX after timeout using the parking lot settings.
void publish_parked_call_failure(struct ast_channel *parkee)
Publish a stasis parked call message for the channel indicating failure to park.
Core PBX routines and definitions.
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8577
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8478
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8496
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8572
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6164
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8506
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8886
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Same as ast_add_extension2, but assumes you have already locked context.
Definition: pbx.c:7281
struct ast_exten * pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, struct pbx_find_info *q, const char *context, const char *exten, int priority, const char *label, const char *callerid, enum ext_match_t action)
Definition: ael_main.c:152
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8488
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8547
struct stasis_forward * sub
Definition: res_corosync.c:240
Call Parking Resource Internal API.
@ PARK_TIMEOUT
Definition: res_parking.h:43
@ PARK_UNSET
Definition: res_parking.h:41
#define BASE_REGISTRAR
Definition: res_parking.h:36
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
Definition: res_parking.c:1120
#define PARK_DIAL_CONTEXT
Definition: res_parking.h:37
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
Definition: res_parking.c:668
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:662
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8279
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1050
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1104
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:680
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1201
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:998
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Structure that contains information regarding a channel in a bridge.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * chan
unsigned int in_bridge
Structure that contains features information.
Structure that contains information about a bridge.
Definition: bridge.h:353
unsigned int num_channels
Definition: bridge.h:377
const ast_string_field uniqueid
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
Main Channel structure associated with a channel.
struct ast_bridge_channel * bridge_channel
char exten[AST_MAX_EXTENSION]
ast_context: An extension context
Definition: pbx.c:299
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
Definition: pbx.c:252
A parked call message payload.
Definition: parking.h:59
A function table providing parking functionality to the Bridging API Bridging API and other consumers...
Definition: parking.h:127
unsigned int module_version
The version of this function table. If the ABI for this table changes, the module version (/ref PARKI...
Definition: parking.h:134
const char * module_name
The name of the module that provides this parking functionality.
Definition: parking.h:139
struct ast_module * module
The module info for the module registering this parking provider.
Definition: parking.h:202
struct transfer_channel_data * transfer_data
struct stasis_subscription * parked_subscription
int parkedcalltransfers
Definition: res_parking.h:76
int parkedcallreparking
Definition: res_parking.h:77
int parkedcallrecording
Definition: res_parking.h:79
int stacklen
Definition: extconf.h:237
const char * data
Definition: extconf.h:240
AO2 object that wraps data for transfer_channel_cb.
Definition: bridge.h:1123
structure to hold users read from users.conf
const char * args
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739