Asterisk - The Open Source Telephony Project  21.4.1
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"
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 
66  struct stasis_subscription *parked_subscription;
67 };
68 
71  char *parkee_uuid;
72  unsigned int hangup_after:1;
73  char parker_uuid[0];
74 };
75 
76 static void parked_subscription_datastore_destroy(void *data)
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 
86 static const struct ast_datastore_info parked_subscription_info = {
87  .type = "park subscription",
88  .destroy = parked_subscription_datastore_destroy,
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 
105 static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
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  }
146  wipe_subscription_datastore(parker);
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  }
154  wipe_subscription_datastore(parker);
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 
181  char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan));
182  size_t parker_uuid_size;
183  size_t parkee_uuid_size;
184 
185  /* If there is already a subscription, get rid of it. */
186  wipe_subscription_datastore(chan);
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  }
220  stasis_subscription_accept_message_type(parked_datastore->parked_subscription, ast_parked_call_type());
221  stasis_subscription_accept_message_type(parked_datastore->parked_subscription, stasis_subscription_change_type());
222  stasis_subscription_set_filter(parked_datastore->parked_subscription, STASIS_SUBSCRIPTION_FILTER_SELECTIVE);
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 
233 int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
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));
265  ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker));
266  ast_channel_inherit_variables(parker, parkee);
267  ast_bridge_set_transfer_variables(parkee, ast_channel_name(parker), 0);
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 \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  */
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),
417  e ? ast_get_extension_app_data(e) : NULL);
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 \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  */
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 static void parking_timeout_set_caller_features(struct ast_channel *chan, struct parking_lot_cfg *cfg)
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;
550  if (cfg->parkedcalltransfers & AST_FEATURE_FLAG_BYCALLER) {
551  *pos++ = 't';
552  }
553  if (cfg->parkedcallreparking & AST_FEATURE_FLAG_BYCALLER) {
554  *pos++ = 'k';
555  }
556  if (cfg->parkedcallhangup & AST_FEATURE_FLAG_BYCALLER) {
557  *pos++ = 'h';
558  }
559  if (cfg->parkedcallrecording & AST_FEATURE_FLAG_BYCALLER) {
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  */
573 static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
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. */
593  ao2_unlock(user);
594  return -1;
595  }
596  user->resolution = PARK_TIMEOUT;
597  ao2_unlock(user);
598 
600  AST_CAUSE_NORMAL_CLEARING);
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);
614  parking_timeout_set_caller_features(chan, user->lot->cfg);
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 
625  if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
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 
669 abandon_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 
681 void 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,
690  BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
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,
699  BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
700  }
701 }
702 
703 void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
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,
724  parking_duration_callback, user, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
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 */
731 static 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. */
745  AST_STANDARD_APP_ARGS(args, data);
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 
779 static struct ast_custom_function getparkingslotchannel_function = {
780  .name = "PARK_GET_CHANNEL",
782 };
783 
784 struct ast_parking_bridge_feature_fn_table parking_provider = {
785  .module_version = PARKING_MODULE_VERSION,
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 {
797  ast_custom_function_unregister(&getparkingslotchannel_function);
798 }
799 
801 {
802  parking_provider.module = AST_MODULE_SELF;
803 
804  ast_custom_function_register(&getparkingslotchannel_function);
805 
806  if (ast_parking_register_bridge_features(&parking_provider)) {
807  return -1;
808  }
809 
810  if (ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park_call, NULL)) {
811  return -1;
812  }
813 
814  return 0;
815 }
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8491
Main Channel structure associated with a channel.
Local proxy channel special access.
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'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:1060
unsigned int comebackdialtime
Definition: res_parking.h:70
int(* parking_is_exten_park)(const char *context, const char *exten)
Determine if the context/exten is a "parking" extension.
Definition: parking.h:147
int parkedcallreparking
Definition: res_parking.h:77
Structure that contains features information.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
struct ast_bridge_channel * ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
Get the peer bridge channel of a two party bridge.
char context[AST_MAX_CONTEXT]
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' 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
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6461
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.
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:1077
char comeback[80]
Definition: res_parking.h:108
Structure for a data store type.
Definition: datastore.h:31
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8253
const ast_string_field uniqueid
int ast_wrlock_contexts(void)
Write locks the context list.
Definition: pbx.c:8463
void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
Setup timeout interval feature on an ast_bridge_features for parking.
void flatten_dial_string(char *dialstring)
Flattens a dial string so that it can be written to/found from PBX extensions.
A parked call message payload.
Definition: parking.h:59
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
Structure for a data store object.
Definition: datastore.h:64
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
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: main/astmm.c:1739
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
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:6354
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:3078
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:2368
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
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.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
char * parker_dial_string
Definition: res_parking.h:109
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define AST_MAX_EXTENSION
Definition: channel.h:134
int parking_space
Definition: res_parking.h:107
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2969
Conversion utility functions.
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
#define ast_debug(level,...)
Log a DEBUG message.
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:6434
enum park_call_resolution resolution
Definition: res_parking.h:112
Core PBX routines and definitions.
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:349
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 * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2281
unsigned int parkingspace
Definition: parking.h:65
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8473
int(* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
Perform a blind transfer to a parking extension.
Definition: parking.h:181
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
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:971
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...
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
Definition: pbx.c:8481
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
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
unsigned int in_bridge
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
#define AST_MAX_CONTEXT
Definition: channel.h:135
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_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2541
Support for logging to various files, console and syslog Configuration in file logger.conf.
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
const ast_string_field name
Definition: res_parking.h:100
#define SCOPED_MODULE_USE(module)
Definition: module.h:679
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
int parkedcalltransfers
Definition: res_parking.h:76
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
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8871
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:2929
void * data
Definition: datastore.h:66
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:2460
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2947
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:425
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
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:1119
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 parkedcallrecording
Definition: res_parking.h:79
Internal Asterisk hangup causes.
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
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
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
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:608
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.
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:6149
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.
#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
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
int(* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
Perform a direct park on a channel in a bridge.
Definition: parking.h:199
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_context: An extension 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:2394
unsigned int num_channels
Definition: bridge.h:373
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
char exten[AST_MAX_EXTENSION]
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
Channel Bridging API.
int(* parking_park_call)(struct ast_bridge_channel *parker, char *exten, size_t length)
Park the bridge and/or callers that this channel is in.
Definition: parking.h:162
#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