Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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"
38 #include "asterisk/conversions.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 
71  char *parkee_uuid;
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 
91 static void wipe_subscription_datastore(struct ast_channel *chan)
92 {
93  struct ast_datastore *datastore;
94 
95  ast_channel_lock(chan);
96 
97  datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL);
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 {
143  ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
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 
158 static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
159 {
160  if (stasis_subscription_final_message(sub, message)) {
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 
168  if (stasis_message_type(message) == ast_parked_call_type()) {
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 
174 static 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 {
235  return create_parked_subscription_full(chan, parkee_uuid, hangup_after, NULL);
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  */
244 static 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  */
297 static 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 \ref 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  */
336 static 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. */
414  ast_bridge_channel_write_park(bridge_channel,
415  ast_channel_uniqueid(other_chan),
416  ast_channel_uniqueid(bridge_channel->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  */
434 static 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);
449  publish_parked_call_failure(bridge_channel->chan);
450  return -1;
451  }
452 
453  if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) {
454  publish_parked_call_failure(bridge_channel->chan);
455  return -1;
456  }
457 
458  ast_bridge_set_transfer_variables(bridge_channel->chan, ast_channel_name(parker), 0);
459 
460  /* bridge_channel must be locked so we can get a reference to the bridge it is currently on */
461  ao2_lock(bridge_channel);
462 
463  original_bridge = bridge_channel->bridge;
464  if (!original_bridge) {
465  ao2_unlock(bridge_channel);
466  publish_parked_call_failure(bridge_channel->chan);
467  return -1;
468  }
469 
470  ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */
471 
472  ao2_unlock(bridge_channel);
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",
476  ast_channel_name(bridge_channel->chan));
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 \ref 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  */
499 static 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);
505  lot_name = ast_strdupa(find_channel_parking_lot_name(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 
524 static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
525 {
526  SCOPED_MODULE_USE(AST_MODULE_SELF);
527 
528  parking_park_call(bridge_channel, NULL, 0);
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  *
540  * \return Nothing
541  */
543 {
544  char features[5];
545  char *pos;
546 
547  /*
548  * We are setting the callee Dial flag values because in the
549  * timeout case, the caller is who is being called back.
550  */
551  pos = features;
553  *pos++ = 't';
554  }
556  *pos++ = 'k';
557  }
559  *pos++ = 'h';
560  }
562  *pos++ = 'x';
563  }
564  *pos = '\0';
565 
566  pbx_builtin_setvar_helper(chan, "BRIDGE_FEATURES", features);
567 }
568 
569 /*! \internal
570  * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
571  *
572  * \param bridge_channel bridge channel this interval hook is being executed on
573  * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
574  */
575 static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
576 {
577  struct parked_user *user = hook_pvt;
578  struct ast_channel *chan = user->chan;
579  struct ast_context *park_dial_context;
580  const char *dial_string;
581  char *dial_string_flat;
582  char parking_space[AST_MAX_EXTENSION];
583 
584  char returnexten[AST_MAX_EXTENSION];
585  char *duplicate_returnexten;
586  struct ast_exten *existing_exten;
587  struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */
588 
589 
590  /* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
591  to deal with this, lock the parked user, check and set resolution. */
592  ao2_lock(user);
593  if (user->resolution != PARK_UNSET) {
594  /* Abandon timeout since something else has resolved the parked user before we got to it. */
595  ao2_unlock(user);
596  return -1;
597  }
598  user->resolution = PARK_TIMEOUT;
599  ao2_unlock(user);
600 
603 
604  dial_string = user->parker_dial_string;
605  dial_string_flat = ast_strdupa(dial_string);
606  flatten_dial_string(dial_string_flat);
607 
608  /* Set parking timeout channel variables */
609  snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
610  ast_channel_lock(chan);
612  pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
613  pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
614  pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
615  pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
618  ast_channel_unlock(chan);
619 
620  /* Dialplan generation for park-dial extensions */
621 
622  if (ast_wrlock_contexts()) {
623  ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
624  return -1;
625  }
626 
627  if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
628  ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
629  if (ast_unlock_contexts()) {
630  ast_assert(0);
631  }
632  goto abandon_extension_creation;
633  }
634 
635  if (ast_wrlock_context(park_dial_context)) {
636  ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
637  if (ast_unlock_contexts()) {
638  ast_assert(0);
639  }
640  goto abandon_extension_creation;
641  }
642 
643  if (ast_unlock_contexts()) {
644  ast_assert(0);
645  }
646 
647  snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
648  user->lot->cfg->comebackdialtime);
649 
650  duplicate_returnexten = ast_strdup(returnexten);
651  if (!duplicate_returnexten) {
652  ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
653  dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
654  }
655 
656  /* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
657  if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
658  (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
659  ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
660  dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
661  } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
662  "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR, NULL, 0)) {
663  ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
664  dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
665  }
666 
667  if (ast_unlock_context(park_dial_context)) {
668  ast_assert(0);
669  }
670 
671 abandon_extension_creation:
672 
673  /* async_goto the proper PBX destination - this should happen when we come out of the bridge */
674  if (!ast_strlen_zero(user->comeback)) {
675  ast_async_parseable_goto(chan, user->comeback);
676  } else {
677  comeback_goto(user, user->lot);
678  }
679 
680  return -1;
681 }
682 
683 void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
684 {
685  unsigned int numeric_value;
686  unsigned int hangup_after;
687 
688  if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
689  /* If say_parking_space is called with a non-numeric string, we have a problem. */
690  ast_assert(0);
691  ast_bridge_channel_leave_bridge(bridge_channel,
693  return;
694  }
695 
696  ast_say_digits(bridge_channel->chan, numeric_value, "",
697  ast_channel_language(bridge_channel->chan));
698 
699  if (hangup_after) {
700  ast_bridge_channel_leave_bridge(bridge_channel,
702  }
703 }
704 
706 {
707  unsigned int time_limit;
708 
709  time_limit = user->time_limit * 1000;
710 
711  if (!time_limit) {
712  /* There is no duration limit that we need to apply. */
713  return;
714  }
715 
716  /* If the time limit has already been passed, set a really low time limit so we can kick them out immediately. */
717  time_limit = ast_remaining_ms(user->start, time_limit);
718  if (time_limit <= 0) {
719  time_limit = 1;
720  }
721 
722  /* The interval hook is going to need a reference to the parked_user */
723  ao2_ref(user, +1);
724 
725  if (ast_bridge_interval_hook(features, 0, time_limit,
727  ast_log(LOG_ERROR, "Failed to apply duration limit to the parked call.\n");
728  ao2_ref(user, -1);
729  }
730 }
731 
732 /*! \brief Dial plan function to get the parking lot channel of an occupied parking lot */
733 static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
734 {
735  RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup);
736  RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
737  unsigned int space = 0;
738  const char *content = NULL;
739 
741  AST_APP_ARG(parking_space);
743  AST_APP_ARG(other);
744  );
745 
746  /* Parse the arguments. */
748 
749  if (args.argc < 2) {
750  /* Didn't receive enough arguments to do anything */
751  ast_log(LOG_ERROR, "Usage: %s(<parking_space>,<parking_lot>)\n",
752  function);
753  return -1;
754  }
755 
756  lot = parking_lot_find_by_name(args.parking_lot);
757  if (!lot) {
758  ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", args.parking_lot);
759  return -1;
760  }
761 
762  if (!ast_strlen_zero(args.parking_space)) {
763  if (ast_str_to_uint(args.parking_space, &space) != 0) {
764  ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n",
765  args.parking_space);
766  return -1;
767  }
768  }
769 
770  pu = parking_lot_inspect_parked_user(lot, space);
771  if (!pu) {
772  return -1;
773  }
774 
775  content = ast_channel_name(pu->chan);
776  ast_copy_string(buf, content, len);
777 
778  return 0;
779 }
780 
782  .name = "PARK_GET_CHANNEL",
784 };
785 
788  .module_name = __FILE__,
789  .parking_is_exten_park = parking_is_exten_park,
790  .parking_blind_transfer_park = parking_blind_transfer_park,
791  .parking_park_bridge_channel = parking_park_bridge_channel,
792  .parking_park_call = parking_park_call,
793 };
794 
796 {
799  ast_custom_function_unregister(&getparkingslotchannel_function);
800 }
801 
803 {
804  parking_provider.module = AST_MODULE_SELF;
805 
806  ast_custom_function_register(&getparkingslotchannel_function);
807 
808  if (ast_parking_register_bridge_features(&parking_provider)) {
809  return -1;
810  }
811 
813  return -1;
814  }
815 
816  return 0;
817 }
const char * name
Definition: pbx.h:119
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * type
Definition: datastore.h:32
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
Local proxy channel special access.
static void parking_timeout_set_caller_features(struct ast_channel *chan, struct parking_lot_cfg *cfg)
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
Definition: res_parking.c:1059
unsigned int comebackdialtime
Definition: res_parking.h:70
const char * ast_get_extension_registrar(struct ast_exten *e)
Definition: pbx.c:8571
int parkedcallreparking
Definition: res_parking.h:77
Structure that contains features information.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
struct ast_bridge_channel * ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
Get the peer bridge channel of a two party bridge.
#define BASE_REGISTRAR
Definition: res_parking.h:36
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
void __ao2_cleanup(void *obj)
Definition: astobj2.c:674
#define PARK_DIAL_CONTEXT
Definition: res_parking.h:37
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6553
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.
#define AST_LOG_WARNING
Definition: logger.h:279
Structure representing a snapshot of channel state.
unsigned int time_limit
Definition: res_parking.h:110
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
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:1079
Structure for a data store type.
Definition: datastore.h:31
static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data)
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8349
const ast_string_field uniqueid
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8601
static const struct ast_datastore_info parked_subscription_info
#define ast_assert(a)
Definition: utils.h:695
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8502
void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
Setup timeout interval feature on an ast_bridge_features for parking.
#define ao2_unlock(a)
Definition: astobj2.h:730
void flatten_dial_string(char *dialstring)
Flattens a dial string so that it can be written to/found from PBX extensions.
static void parker_update_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
A parked call message payload.
Definition: parking.h:59
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
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:2404
const char * args
#define NULL
Definition: resample.c:96
const char * module_name
The name of the module that provides this parking functionality.
Definition: parking.h:139
struct parking_lot * lot
Definition: res_parking.h:111
enum ast_parked_call_event_type event_type
Definition: parking.h:62
struct timeval start
Definition: res_parking.h:106
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1771
struct stasis_subscription * parked_subscription
void unload_parking_bridge_features(void)
Unregister features registered by load_parking_bridge_features.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
struct ast_bridge * bridge
Bridge this channel is participating in.
Utility functions.
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
Definition: core_local.c:276
#define ast_strlen_zero(foo)
Definition: strings.h:52
void publish_parked_call_failure(struct ast_channel *parkee)
Publish a stasis parked call message for the channel indicating failure to park.
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:6444
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. ...
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
Unregister a handler for a built in feature.
Definition: bridge.c:3139
Asterisk datastore objects.
A function table providing parking functionality to the Bridging API Bridging API and other consumers...
Definition: parking.h:127
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2373
static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
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)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
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:1924
struct ast_channel_snapshot * parkee
Definition: parking.h:60
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...
int load_parking_bridge_features(void)
Register bridge features for parking.
const char * data
Definition: extconf.h:241
#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:911
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
char * parker_dial_string
Definition: res_parking.h:109
struct transfer_channel_data * transfer_data
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:105
int parking_space
Definition: res_parking.h:107
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2992
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Conversion utility functions.
#define ao2_lock(a)
Definition: astobj2.h:718
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:3382
#define PARKING_MODULE_VERSION
Definition: parking.h:119
int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
Register a parking provider.
Definition: parking.c:196
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:6526
enum park_call_resolution resolution
Definition: res_parking.h:112
Core PBX routines and definitions.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_module * module
The module info for the module registering this parking provider.
Definition: parking.h:202
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
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
Structure that contains information about a bridge.
Definition: bridge.h:357
static int parking_is_exten_park(const char *context, const char *exten)
#define LOG_ERROR
Definition: logger.h:285
int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
Set a channel&#39;s position in the PBX after timeout using the parking lot settings. ...
static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
char comeback[80]
Definition: res_parking.h:108
static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data, struct stasis_subscription *sub)
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: main/utils.c:2033
unsigned int parkingspace
Definition: parking.h:65
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct ast_parking_bridge_feature_fn_table parking_provider
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:3123
#define stasis_subscribe_pool(topic, callback, data)
Definition: stasis.h:682
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.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:973
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...
#define LOG_NOTICE
Definition: logger.h:263
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8520
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).
#define PARK_APPLICATION
The default parking application that Asterisk expects.
Definition: parking.h:35
static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after, struct transfer_channel_data *parked_channel_data)
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:1176
unsigned int in_bridge
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:493
#define AST_MAX_CONTEXT
Definition: channel.h:136
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:6866
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static struct ast_custom_function getparkingslotchannel_function
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2548
int stacklen
Definition: extconf.h:238
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:4404
const ast_string_field name
Definition: res_parking.h:100
static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
#define SCOPED_MODULE_USE(module)
Definition: module.h:665
int ast_str_to_uint(const char *str, unsigned int *res)
Convert the given string to an unsigned integer.
Definition: conversions.c:56
structure to hold users read from users.conf
static void wipe_subscription_datastore(struct ast_channel *chan)
int parkedcalltransfers
Definition: res_parking.h:76
Support for logging to various files, console and syslog Configuration in file logger.conf.
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel&#39;s bridge pointer.
Definition: channel.c:10783
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8864
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
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...
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2952
void * data
Definition: datastore.h:70
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
Definition: parking.c:67
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
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:2508
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2970
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
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:8389
const char * ast_channel_name(const struct ast_channel *chan)
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.
AO2 object that wraps data for transfer_channel_cb.
Definition: bridge.h:1136
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:1025
int parkedcallrecording
Definition: res_parking.h:79
struct stasis_forward * sub
Definition: res_corosync.c:240
Internal Asterisk hangup causes.
const char * ast_channel_language(const struct ast_channel *chan)
static struct ast_channel * park_local_transfer(struct ast_channel *parker, const char *context, const char *exten, struct transfer_channel_data *parked_channel_data)
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:1160
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Definition: res_parking.c:601
Call Parking Resource Internal API.
Private Bridging API.
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
Definition: res_parking.c:607
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.
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
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:6198
Say numbers and dates (maybe words one day too)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
Bridging API.
Asterisk module definitions.
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_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
struct ast_channel * chan
Definition: res_parking.h:104
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
unsigned int num_channels
Definition: bridge.h:381
const char * ast_channel_parkinglot(const struct ast_channel *chan)
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static void parked_subscription_datastore_destroy(void *data)
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:7308
Channel Bridging API.
#define AST_APP_ARG(name)
Define an application argument.
int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
Create a parking announcement subscription.
struct parking_lot_cfg * cfg
Definition: res_parking.h:96
int ast_parking_unregister_bridge_features(const char *module_name)
Unregister the current parking provider.
Definition: parking.c:223