Asterisk - The Open Source Telephony Project GIT-master-a358458
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 <synopsis>
50 Get the channel name of an occupied parking space in a parking lot.
51 </synopsis>
52 <syntax>
53 <parameter name="parking_space" required="true">
54 </parameter>
55 <parameter name="parking_lot" required="true">
56 </parameter>
57 </syntax>
58 <description>
59 <para>This function returns the channel of the specified parking space
60 if the parking lot space is occupied.</para>
61 </description>
62 </function>
63***/
64
67};
68
72 unsigned int hangup_after:1;
73 char parker_uuid[0];
74};
75
77{
78 struct parked_subscription_datastore *subscription_datastore = data;
79
80 stasis_unsubscribe(subscription_datastore->parked_subscription);
81 subscription_datastore->parked_subscription = NULL;
82
83 ast_free(subscription_datastore);
84}
85
87 .type = "park subscription",
89};
90
92{
93 struct ast_datastore *datastore;
94
95 ast_channel_lock(chan);
96
98 if (datastore) {
99 ast_channel_datastore_remove(chan, datastore);
100 ast_datastore_free(datastore);
101 }
102 ast_channel_unlock(chan);
103}
104
106 struct stasis_subscription *sub)
107{
108 const char *parkee_to_act_on = data->parkee_uuid;
109 char saynum_buf[16];
110 struct ast_channel_snapshot *parkee_snapshot = message->parkee;
111 RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
112 RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
113
114 if (strcmp(parkee_to_act_on, parkee_snapshot->base->uniqueid)) {
115 return;
116 }
117
118 if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
119 /* We only care about these two event types */
120 return;
121 }
122
123 parker = ast_channel_get_by_name(data->parker_uuid);
124 if (!parker) {
125 return;
126 }
127
128 ast_channel_lock(parker);
129 bridge_channel = ast_channel_get_bridge_channel(parker);
130 ast_channel_unlock(parker);
131 if (!bridge_channel) {
132 return;
133 }
134
135 /* This subscription callback will block for the duration of the announcement if
136 * parked_subscription_data is tracking a transfer_channel_data struct. */
137 if (message->event_type == PARKED_CALL) {
138 /* queue the saynum on the bridge channel and hangup */
139 snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
140 if (!data->transfer_data) {
141 ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
142 } else {
144 data->transfer_data->completed = 1;
145 }
147 } else if (message->event_type == PARKED_CALL_FAILED) {
148 if (!data->transfer_data) {
149 ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
150 } else {
151 ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
152 data->transfer_data->completed = 1;
153 }
155 }
156}
157
158static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
159{
161 struct parked_subscription_data *ps_data = data;
162 ao2_cleanup(ps_data->transfer_data);
163 ps_data->transfer_data = NULL;
164 ast_free(data);
165 return;
166 }
167
169 struct ast_parked_call_payload *parked_call_message = stasis_message_data(message);
170 parker_parked_call_message_response(parked_call_message, data, sub);
171 }
172}
173
174static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
175 struct transfer_channel_data *parked_channel_data)
176{
177 struct ast_datastore *datastore;
178 struct parked_subscription_datastore *parked_datastore;
179 struct parked_subscription_data *subscription_data;
180
182 size_t parker_uuid_size;
183 size_t parkee_uuid_size;
184
185 /* If there is already a subscription, get rid of it. */
187
188 if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
189 return -1;
190 }
191
192 if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
193 ast_datastore_free(datastore);
194 return -1;
195 }
196
197 parker_uuid_size = strlen(parker_uuid) + 1;
198 parkee_uuid_size = strlen(parkee_uuid) + 1;
199
200 if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
201 parkee_uuid_size))) {
202 ast_datastore_free(datastore);
203 ast_free(parked_datastore);
204 return -1;
205 }
206
207 if (parked_channel_data) {
208 subscription_data->transfer_data = parked_channel_data;
209 ao2_ref(parked_channel_data, +1);
210 }
211
212 subscription_data->hangup_after = hangup_after;
213 subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
214 ast_copy_string(subscription_data->parkee_uuid, parkee_uuid, parkee_uuid_size);
215 ast_copy_string(subscription_data->parker_uuid, parker_uuid, parker_uuid_size);
216
217 if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
218 return -1;
219 }
223
224 datastore->data = parked_datastore;
225
226 ast_channel_lock(chan);
227 ast_channel_datastore_add(chan, datastore);
228 ast_channel_unlock(chan);
229
230 return 0;
231}
232
234{
236}
237
238/*!
239 * \internal
240 * \brief Helper function that creates an outgoing channel and returns it immediately. This function is nearly
241 * identical to the dial_transfer function in bridge_basic.c, however it doesn't swap the
242 * local channel and the channel that instigated the park.
243 */
244static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
245{
246 char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
247 struct ast_channel *parkee;
248 struct ast_channel *parkee_side_2;
249 int cause;
250
251 /* Fill the variable with the extension and context we want to call */
252 snprintf(destination, sizeof(destination), "%s@%s", exten, context);
253
254 /* Now we request that chan_local prepare to call the destination */
255 parkee = ast_request("Local", ast_channel_nativeformats(parker), NULL, parker, destination,
256 &cause);
257 if (!parkee) {
258 return NULL;
259 }
260
261 /* Before we actually dial out let's inherit appropriate information. */
262 ast_channel_lock_both(parker, parkee);
264 ast_channel_parkinglot_set(parkee, ast_channel_parkinglot(parker));
266 ast_channel_inherit_variables(parker, parkee);
268 ast_channel_datastore_inherit(parker, parkee);
269 ast_channel_unlock(parker);
270
271 parkee_side_2 = ast_local_get_peer(parkee);
272 ast_assert(parkee_side_2 != NULL);
273 ast_channel_unlock(parkee);
274
275 /* We need to have the parker subscribe to the new local channel before hand. */
276 if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
277 ast_channel_unref(parkee_side_2);
278 ast_hangup(parkee);
279 return NULL;
280 }
281
282 ast_channel_unref(parkee_side_2);
283
284 /* Since the above worked fine now we actually call it and return the channel */
285 if (ast_call(parkee, destination, 0)) {
286 ast_hangup(parkee);
287 return NULL;
288 }
289
290 return parkee;
291}
292
293/*!
294 * \internal
295 * \brief Determine if an extension is a parking extension
296 */
297static int parking_is_exten_park(const char *context, const char *exten)
298{
299 struct ast_exten *exten_obj;
300 struct pbx_find_info info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
301 const char *app_at_exten;
302
303 ast_debug(4, "Checking if %s@%s is a parking exten\n", exten, context);
304 exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH);
305 if (!exten_obj) {
306 return 0;
307 }
308
309 app_at_exten = ast_get_extension_app(exten_obj);
310 if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) {
311 return 0;
312 }
313
314 return 1;
315}
316
317/*!
318 * \internal
319 * \since 12.0.0
320 * \brief Perform a blind transfer to a parking lot
321 *
322 * In general, most parking features should work to call this function. This will safely
323 * park either a channel in the bridge with \p bridge_channel or will park the entire
324 * bridge if more than one channel is in the bridge. It will create the correct data to
325 * pass to the \ref AstBridging Bridging API to safely park the channel.
326 *
327 * \param bridge_channel The bridge_channel representing the channel performing the park
328 * \param context The context to blind transfer to
329 * \param exten The extension to blind transfer to
330 * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge
331 * \param parked_channel_data Data for the parked_channel_cb
332 *
333 * \retval 0 on success
334 * \retval non-zero on error
335 */
336static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel,
337 const char *context, const char *exten, transfer_channel_cb parked_channel_cb,
338 struct transfer_channel_data *parked_channel_data)
339{
340 RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup);
341 RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup);
342
343 struct ast_exten *e;
344 struct pbx_find_info find_info = { .stacklen = 0 };
345 int peer_count;
346
347 if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
348 return -1;
349 }
350
351 if (!bridge_channel->in_bridge) {
352 return -1;
353 }
354
355 if (!parking_is_exten_park(context, exten)) {
356 return -1;
357 }
358
359 ast_bridge_channel_lock_bridge(bridge_channel);
360 peer_count = bridge_channel->bridge->num_channels;
361 if (peer_count == 2) {
362 other = ast_bridge_channel_peer(bridge_channel);
363 ao2_ref(other, +1);
364 other_chan = other->chan;
365 ast_channel_ref(other_chan);
366 }
367 ast_bridge_unlock(bridge_channel->bridge);
368
369 if (peer_count < 2) {
370 /* There is nothing to do if there is no one to park. */
371 return -1;
372 }
373
374 /* With a multiparty bridge, we need to do a regular blind transfer. We link the
375 * existing bridge to the parking lot with a Local channel rather than
376 * transferring others. */
377 if (peer_count > 2) {
378 struct ast_channel *transfer_chan = NULL;
379
380 transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data);
381 if (!transfer_chan) {
382 return -1;
383 }
384 ast_channel_ref(transfer_chan);
385
386 if (parked_channel_cb) {
387 parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY);
388 }
389
390 if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
392 ast_hangup(transfer_chan);
393 ast_channel_unref(transfer_chan);
394 return -1;
395 }
396
397 ast_channel_unref(transfer_chan);
398
399 return 0;
400 }
401
402 /* Subscribe to park messages with the other channel entering */
403 if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
404 return -1;
405 }
406
407 if (parked_channel_cb) {
408 parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY);
409 }
410
411 e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
412
413 /* Write the park frame with the intended recipient and other data out to the bridge. */
415 ast_channel_uniqueid(other_chan),
418
419 return 0;
420}
421
422/*!
423 * \internal
424 * \since 12.0.0
425 * \brief Perform a direct park on a channel in a bridge
426 *
427 * \note This will be called from within the \ref AstBridging Bridging API
428 *
429 * \param bridge_channel The bridge_channel representing the channel to be parked
430 * \param uuid_parkee The UUID of the channel being parked
431 * \param uuid_parker The UUID of the channel performing the park
432 * \param app_data Application parseable data to pass to the parking application
433 */
434static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
435{
436 RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);
437 RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup);
438 RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup);
439
440 if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) {
441 /* We aren't the parkee, so ignore this action. */
442 return -1;
443 }
444
445 parker = ast_channel_get_by_name(uuid_parker);
446
447 if (!parker) {
448 ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
450 return -1;
451 }
452
453 if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
455 return -1;
456 }
457
459
460 /* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
462
463 original_bridge = bridge_channel->bridge;
464 if (!original_bridge) {
467 return -1;
468 }
469
470 ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */
471
473
474 if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) {
475 ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n",
477 return -1;
478 }
479
480 return 0;
481}
482
483/*!
484 * \internal
485 * \since 12.0.0
486 * \brief Park a call
487 *
488 * \param parker The bridge_channel parking the call
489 * \param exten Optional. The extension where the call was parked.
490 * \param length Optional. If \c exten is specified, the length of the buffer.
491 *
492 * \note This will determine the context and extension to park the channel based on
493 * the configuration of the \ref ast_channel associated with \p parker. It will then
494 * park either the channel or the entire bridge.
495 *
496 * \retval 0 on success
497 * \retval -1 on error
498 */
499static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
500{
501 RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
502 const char *lot_name;
503
504 ast_channel_lock(parker->chan);
506 ast_channel_unlock(parker->chan);
507
508 lot = parking_lot_find_by_name(lot_name);
509 if (!lot) {
510 lot = parking_create_dynamic_lot(lot_name, parker->chan);
511 }
512 if (!lot) {
513 ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n",
514 ast_channel_name(parker->chan), lot_name);
515 return -1;
516 }
517
518 if (exten) {
519 ast_copy_string(exten, lot->cfg->parkext, length);
520 }
521 return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
522}
523
524static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
525{
526 SCOPED_MODULE_USE(AST_MODULE_SELF);
527
529 return 0;
530}
531
532/*!
533 * \internal
534 * \brief Setup the caller features for when that channel is dialed.
535 * \since 12.0.0
536 *
537 * \param chan Parked channel leaving the parking lot.
538 * \param cfg Parking lot configuration.
539 */
541{
542 char features[5];
543 char *pos;
544
545 /*
546 * We are setting the callee Dial flag values because in the
547 * timeout case, the caller is who is being called back.
548 */
549 pos = features;
551 *pos++ = 't';
552 }
554 *pos++ = 'k';
555 }
557 *pos++ = 'h';
558 }
560 *pos++ = 'x';
561 }
562 *pos = '\0';
563
564 pbx_builtin_setvar_helper(chan, "BRIDGE_FEATURES", features);
565}
566
567/*! \internal
568 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
569 *
570 * \param bridge_channel bridge channel this interval hook is being executed on
571 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
572 */
574{
575 struct parked_user *user = hook_pvt;
576 struct ast_channel *chan = user->chan;
577 struct ast_context *park_dial_context;
578 const char *dial_string;
579 char *dial_string_flat;
580 char parking_space[AST_MAX_EXTENSION];
581
582 char returnexten[AST_MAX_EXTENSION];
583 char *duplicate_returnexten;
584 struct ast_exten *existing_exten;
585 struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */
586
587
588 /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
589 to deal with this, lock the parked user, check and set resolution. */
590 ao2_lock(user);
591 if (user->resolution != PARK_UNSET) {
592 /* Abandon timeout since something else has resolved the parked user before we got to it. */
594 return -1;
595 }
596 user->resolution = PARK_TIMEOUT;
598
601
602 dial_string = user->parker_dial_string;
603 dial_string_flat = ast_strdupa(dial_string);
604 flatten_dial_string(dial_string_flat);
605
606 /* Set parking timeout channel variables */
607 snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
608 ast_channel_lock(chan);
610 pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
611 pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
612 pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
613 pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
616 ast_channel_unlock(chan);
617
618 /* Dialplan generation for park-dial extensions */
619
620 if (ast_wrlock_contexts()) {
621 ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
622 return -1;
623 }
624
626 ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
627 if (ast_unlock_contexts()) {
628 ast_assert(0);
629 }
630 goto abandon_extension_creation;
631 }
632
633 if (ast_wrlock_context(park_dial_context)) {
634 ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
635 if (ast_unlock_contexts()) {
636 ast_assert(0);
637 }
638 goto abandon_extension_creation;
639 }
640
641 if (ast_unlock_contexts()) {
642 ast_assert(0);
643 }
644
645 snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
646 user->lot->cfg->comebackdialtime);
647
648 duplicate_returnexten = ast_strdup(returnexten);
649 if (!duplicate_returnexten) {
650 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
651 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
652 }
653
654 /* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
655 if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
656 (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
657 ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
658 dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
659 } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
660 "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR, NULL, 0)) {
661 ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
662 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
663 }
664
665 if (ast_unlock_context(park_dial_context)) {
666 ast_assert(0);
667 }
668
669abandon_extension_creation:
670
671 /* async_goto the proper PBX destination - this should happen when we come out of the bridge */
672 if (!ast_strlen_zero(user->comeback)) {
673 ast_async_parseable_goto(chan, user->comeback);
674 } else {
675 comeback_goto(user, user->lot);
676 }
677
678 return -1;
679}
680
681void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
682{
683 unsigned int numeric_value;
684 unsigned int hangup_after;
685
686 if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
687 /* If say_parking_space is called with a non-numeric string, we have a problem. */
688 ast_assert(0);
689 ast_bridge_channel_leave_bridge(bridge_channel,
691 return;
692 }
693
694 ast_say_digits(bridge_channel->chan, numeric_value, "",
695 ast_channel_language(bridge_channel->chan));
696
697 if (hangup_after) {
698 ast_bridge_channel_leave_bridge(bridge_channel,
700 }
701}
702
704{
705 unsigned int time_limit;
706
707 time_limit = user->time_limit * 1000;
708
709 if (!time_limit) {
710 /* There is no duration limit that we need to apply. */
711 return;
712 }
713
714 /* If the time limit has already been passed, set a really low time limit so we can kick them out immediately. */
715 time_limit = ast_remaining_ms(user->start, time_limit);
716 if (time_limit <= 0) {
717 time_limit = 1;
718 }
719
720 /* The interval hook is going to need a reference to the parked_user */
721 ao2_ref(user, +1);
722
723 if (ast_bridge_interval_hook(features, 0, time_limit,
725 ast_log(LOG_ERROR, "Failed to apply duration limit to the parked call.\n");
726 ao2_ref(user, -1);
727 }
728}
729
730/*! \brief Dial plan function to get the parking lot channel of an occupied parking lot */
731static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
732{
733 RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
734 RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
735 unsigned int space = 0;
736 const char *content = NULL;
737
739 AST_APP_ARG(parking_space);
741 AST_APP_ARG(other);
742 );
743
744 /* Parse the arguments. */
746
747 if (args.argc < 2) {
748 /* Didn't receive enough arguments to do anything */
749 ast_log(LOG_ERROR, "Usage: %s(<parking_space>,<parking_lot>)\n",
750 function);
751 return -1;
752 }
753
754 lot = parking_lot_find_by_name(args.parking_lot);
755 if (!lot) {
756 ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", args.parking_lot);
757 return -1;
758 }
759
760 if (!ast_strlen_zero(args.parking_space)) {
761 if (ast_str_to_uint(args.parking_space, &space) != 0) {
762 ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n",
763 args.parking_space);
764 return -1;
765 }
766 }
767
768 pu = parking_lot_inspect_parked_user(lot, space);
769 if (!pu) {
770 return -1;
771 }
772
773 content = ast_channel_name(pu->chan);
774 ast_copy_string(buf, content, len);
775
776 return 0;
777}
778
780 .name = "PARK_GET_CHANNEL",
782};
783
786 .module_name = __FILE__,
787 .parking_is_exten_park = parking_is_exten_park,
788 .parking_blind_transfer_park = parking_blind_transfer_park,
789 .parking_park_bridge_channel = parking_park_bridge_channel,
790 .parking_park_call = parking_park_call,
791};
792
794{
798}
799
801{
802 parking_provider.module = AST_MODULE_SELF;
803
805
807 return -1;
808 }
809
811 return -1;
812 }
813
814 return 0;
815}
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:481
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:1878
@ AST_BRIDGE_TRANSFER_SINGLE_PARTY
Definition: bridge.h:1111
@ AST_BRIDGE_TRANSFER_MULTI_PARTY
Definition: bridge.h:1113
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:1143
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:4352
@ AST_BRIDGE_IMPART_CHAN_INDEPENDENT
Definition: bridge.h:590
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:2460
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:3078
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:3319
@ 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:3062
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:6461
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
@ AST_CHANNEL_REQUESTOR_REPLACEMENT
Definition: channel.h:1479
#define ast_channel_lock(chan)
Definition: channel.h:2922
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2929
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:2368
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:6434
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:6771
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
#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:10582
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:8293
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
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:6354
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#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:2399
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:276
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:665
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:8562
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8463
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8481
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8557
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:6149
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:8491
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
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:8871
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:7266
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:8473
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8532
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:1060
#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:608
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:602
#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:8253
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:1023
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:1077
#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:1174
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:971
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:349
unsigned int num_channels
Definition: bridge.h:373
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:284
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:237
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:1119
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