2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2007 - 2009, Digium, Inc.
6 * Richard Mudgett <rmudgett@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief After Bridge Execution API
23 * \author Richard Mudgett <rmudgett@digium.com>
26 * \arg \ref AstCREDITS
30 <support_level>core</support_level>
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/bridge_after.h"
42 struct after_bridge_cb_node {
43 /*! Next list node. */
44 AST_LIST_ENTRY(after_bridge_cb_node) list;
45 /*! Desired callback function. */
46 ast_bridge_after_cb callback;
47 /*! After bridge callback will not be called and destroy any resources data may contain. */
48 ast_bridge_after_cb_failed failed;
49 /*! Extra data to pass to the callback. */
51 /*! Reason the after bridge callback failed. */
52 enum ast_bridge_after_cb_reason reason;
55 struct after_bridge_cb_ds {
56 /*! After bridge callbacks container. */
57 AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
62 * \brief Indicate after bridge callback failed.
65 * \param node After bridge callback node.
69 static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
72 node->failed(node->reason, node->data);
79 * \brief Run discarding any after bridge callbacks.
82 * \param after_bridge After bridge callback container process.
83 * \param reason Why are we doing this.
87 static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
89 struct after_bridge_cb_node *node;
92 AST_LIST_LOCK(&after_bridge->callbacks);
93 node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
94 AST_LIST_UNLOCK(&after_bridge->callbacks);
99 node->reason = reason;
101 after_bridge_cb_failed(node);
108 * \brief Destroy the after bridge callback datastore.
111 * \param data After bridge callback data to destroy.
115 static void after_bridge_cb_destroy(void *data)
117 struct after_bridge_cb_ds *after_bridge = data;
119 after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
121 AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
122 ast_free(after_bridge);
125 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
129 * \brief Fixup the after bridge callback datastore.
132 * \param data After bridge callback data to fixup.
133 * \param old_chan The datastore is moving from this channel.
134 * \param new_chan The datastore is moving to this channel.
138 static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
140 struct after_bridge_cb_ds *after_bridge;
141 struct after_bridge_cb_node *node;
143 after_bridge = after_bridge_cb_find(new_chan);
148 AST_LIST_LOCK(&after_bridge->callbacks);
149 node = AST_LIST_LAST(&after_bridge->callbacks);
150 if (node && !node->reason) {
151 node->reason = AST_BRIDGE_AFTER_CB_REASON_MASQUERADE;
153 AST_LIST_UNLOCK(&after_bridge->callbacks);
156 static const struct ast_datastore_info after_bridge_cb_info = {
157 .type = "after-bridge-cb",
158 .destroy = after_bridge_cb_destroy,
159 .chan_fixup = after_bridge_cb_fixup,
164 * \brief Find an after bridge callback datastore container.
167 * \param chan Channel to find the after bridge callback container on.
169 * \retval after_bridge datastore container on success.
170 * \retval NULL on error.
172 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
174 struct ast_datastore *datastore;
175 SCOPED_CHANNELLOCK(lock, chan);
177 datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
181 return datastore->data;
186 * \brief Setup/create an after bridge callback datastore container.
189 * \param chan Channel to setup/create the after bridge callback container on.
191 * \retval after_bridge datastore container on success.
192 * \retval NULL on error.
194 static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
196 struct ast_datastore *datastore;
197 struct after_bridge_cb_ds *after_bridge;
198 SCOPED_CHANNELLOCK(lock, chan);
200 datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
202 return datastore->data;
205 /* Create a new datastore. */
206 datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
210 after_bridge = ast_calloc(1, sizeof(*after_bridge));
212 ast_datastore_free(datastore);
215 AST_LIST_HEAD_INIT(&after_bridge->callbacks);
216 datastore->data = after_bridge;
217 ast_channel_datastore_add(chan, datastore);
219 return datastore->data;
222 void ast_bridge_run_after_callback(struct ast_channel *chan)
224 struct after_bridge_cb_ds *after_bridge;
225 struct after_bridge_cb_node *node;
227 after_bridge = after_bridge_cb_find(chan);
233 AST_LIST_LOCK(&after_bridge->callbacks);
234 node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
235 AST_LIST_UNLOCK(&after_bridge->callbacks);
240 after_bridge_cb_failed(node);
243 node->callback(chan, node->data);
249 void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
251 struct after_bridge_cb_ds *after_bridge;
253 after_bridge = after_bridge_cb_find(chan);
258 after_bridge_cb_run_discard(after_bridge, reason);
261 int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
263 struct after_bridge_cb_ds *after_bridge;
264 struct after_bridge_cb_node *new_node;
265 struct after_bridge_cb_node *last_node;
268 ast_assert(chan != NULL);
269 if (!chan || !callback) {
273 after_bridge = after_bridge_cb_setup(chan);
278 /* Create a new callback node. */
279 new_node = ast_calloc(1, sizeof(*new_node));
283 new_node->callback = callback;
284 new_node->failed = failed;
285 new_node->data = data;
287 /* Put it in the container disabling any previously active one. */
288 AST_LIST_LOCK(&after_bridge->callbacks);
289 last_node = AST_LIST_LAST(&after_bridge->callbacks);
290 if (last_node && !last_node->reason) {
291 last_node->reason = AST_BRIDGE_AFTER_CB_REASON_REPLACED;
293 AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
294 AST_LIST_UNLOCK(&after_bridge->callbacks);
298 const char *reason_strings[] = {
299 [AST_BRIDGE_AFTER_CB_REASON_DESTROY] = "Channel destroyed (hungup)",
300 [AST_BRIDGE_AFTER_CB_REASON_REPLACED] = "Callback was replaced",
301 [AST_BRIDGE_AFTER_CB_REASON_MASQUERADE] = "Channel masqueraded",
302 [AST_BRIDGE_AFTER_CB_REASON_DEPART] = "Channel was departed from bridge",
303 [AST_BRIDGE_AFTER_CB_REASON_REMOVED] = "Callback was removed",
306 const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
308 if (reason < AST_BRIDGE_AFTER_CB_REASON_DESTROY
309 || AST_BRIDGE_AFTER_CB_REASON_REMOVED < reason
310 || !reason_strings[reason]) {
314 return reason_strings[reason];
317 struct after_bridge_goto_ds {
318 /*! Goto string that can be parsed by ast_parseable_goto(). */
319 const char *parseable_goto;
320 /*! Specific goto context or default context for parseable_goto. */
322 /*! Specific goto exten or default exten for parseable_goto. */
324 /*! Specific goto priority or default priority for parseable_goto. */
326 /*! TRUE if the peer should run the h exten. */
327 unsigned int run_h_exten:1;
328 /*! Specific goto location */
329 unsigned int specific:1;
334 * \brief Destroy the after bridge goto datastore.
337 * \param data After bridge goto data to destroy.
341 static void after_bridge_goto_destroy(void *data)
343 struct after_bridge_goto_ds *after_bridge = data;
345 ast_free((char *) after_bridge->parseable_goto);
346 ast_free((char *) after_bridge->context);
347 ast_free((char *) after_bridge->exten);
352 * \brief Fixup the after bridge goto datastore.
355 * \param data After bridge goto data to fixup.
356 * \param old_chan The datastore is moving from this channel.
357 * \param new_chan The datastore is moving to this channel.
361 static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
363 /* There can be only one. Discard any already on the new channel. */
364 ast_bridge_discard_after_goto(new_chan);
367 static const struct ast_datastore_info after_bridge_goto_info = {
368 .type = "after-bridge-goto",
369 .destroy = after_bridge_goto_destroy,
370 .chan_fixup = after_bridge_goto_fixup,
375 * \brief Remove channel goto location after the bridge and return it.
378 * \param chan Channel to remove after bridge goto location.
380 * \retval datastore on success.
381 * \retval NULL on error or not found.
383 static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
385 struct ast_datastore *datastore;
387 ast_channel_lock(chan);
388 datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
389 if (datastore && ast_channel_datastore_remove(chan, datastore)) {
392 ast_channel_unlock(chan);
397 void ast_bridge_discard_after_goto(struct ast_channel *chan)
399 struct ast_datastore *datastore;
401 datastore = after_bridge_goto_remove(chan);
403 ast_datastore_free(datastore);
407 void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
409 struct ast_datastore *datastore;
410 struct after_bridge_goto_ds *after_bridge;
411 char *current_pos = buffer;
412 size_t remaining_size = buf_size;
414 SCOPED_CHANNELLOCK(lock, chan);
416 datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
422 after_bridge = datastore->data;
424 if (after_bridge->parseable_goto) {
425 snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
429 if (!ast_strlen_zero(after_bridge->context)) {
430 snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
431 remaining_size = remaining_size - strlen(current_pos);
432 current_pos += strlen(current_pos);
435 if (after_bridge->run_h_exten) {
436 snprintf(current_pos, remaining_size, "h,");
437 remaining_size = remaining_size - strlen(current_pos);
438 current_pos += strlen(current_pos);
439 } else if (!ast_strlen_zero(after_bridge->exten)) {
440 snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
441 remaining_size = remaining_size - strlen(current_pos);
442 current_pos += strlen(current_pos);
445 snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
448 int ast_bridge_setup_after_goto(struct ast_channel *chan)
450 struct ast_datastore *datastore;
451 struct after_bridge_goto_ds *after_bridge;
452 int goto_failed = -1;
454 /* We are going to be leaving the bridging system now;
455 * clear any pending UNBRIDGE flags
457 ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_UNBRIDGE);
459 /* Determine if we are going to setup a dialplan location and where. */
460 if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
461 /* An async goto has already setup a location. */
462 ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
463 if (!ast_check_hangup(chan)) {
469 /* Get after bridge goto datastore. */
470 datastore = after_bridge_goto_remove(chan);
475 after_bridge = datastore->data;
476 if (after_bridge->run_h_exten) {
477 if (ast_exists_extension(chan, after_bridge->context, "h", 1,
478 S_COR(ast_channel_caller(chan)->id.number.valid,
479 ast_channel_caller(chan)->id.number.str, NULL))) {
480 ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
481 ast_channel_context(chan));
482 ast_pbx_h_exten_run(chan, after_bridge->context);
484 } else if (!ast_check_hangup(chan)) {
485 /* Clear the outgoing flag */
486 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
488 if (after_bridge->specific) {
489 goto_failed = ast_explicit_goto(chan, after_bridge->context,
490 after_bridge->exten, after_bridge->priority);
491 } else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
496 /* Option F(x) for Bridge(), Dial(), and Queue() */
498 /* Save current dialplan location in case of failure. */
499 context = ast_strdupa(ast_channel_context(chan));
500 exten = ast_strdupa(ast_channel_exten(chan));
501 priority = ast_channel_priority(chan);
503 /* Set current dialplan position to default dialplan position */
504 ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
505 after_bridge->priority);
507 /* Then perform the goto */
508 goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
510 /* Restore original dialplan location. */
511 ast_channel_context_set(chan, context);
512 ast_channel_exten_set(chan, exten);
513 ast_channel_priority_set(chan, priority);
516 /* Option F() for Bridge(), Dial(), and Queue() */
517 goto_failed = ast_goto_if_exists(chan, after_bridge->context,
518 after_bridge->exten, after_bridge->priority + 1);
521 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
522 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
525 ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
526 ast_channel_context(chan),
527 ast_channel_exten(chan),
528 ast_channel_priority(chan));
532 /* Discard after bridge goto datastore. */
533 ast_datastore_free(datastore);
538 void ast_bridge_run_after_goto(struct ast_channel *chan)
542 goto_failed = ast_bridge_setup_after_goto(chan);
543 if (goto_failed || ast_pbx_run(chan)) {
550 * \brief Set after bridge goto location of channel.
553 * \param chan Channel to setup after bridge goto location.
554 * \param run_h_exten TRUE if the h exten should be run.
555 * \param specific TRUE if the context/exten/priority is exactly specified.
556 * \param context Context to goto after bridge.
557 * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
558 * \param priority Priority to goto after bridge.
559 * \param parseable_goto User specified goto string. (Could be NULL)
561 * \details Add a channel datastore to setup the goto location
562 * when the channel leaves the bridge and run a PBX from there.
564 * If run_h_exten then execute the h exten found in the given context.
565 * Else if specific then goto the given context/exten/priority.
566 * Else if parseable_goto then use the given context/exten/priority
567 * as the relative position for the parseable_goto.
568 * Else goto the given context/exten/priority+1.
572 static void __after_bridge_set_goto(struct ast_channel *chan, int run_h_exten, int specific, const char *context, const char *exten, int priority, const char *parseable_goto)
574 struct ast_datastore *datastore;
575 struct after_bridge_goto_ds *after_bridge;
578 ast_assert(chan != NULL);
583 ast_assert(run_h_exten && context);
588 ast_assert(context && exten && 0 < priority);
589 if (!context || !exten || priority < 1) {
594 /* Create a new datastore. */
595 datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
599 after_bridge = ast_calloc(1, sizeof(*after_bridge));
601 ast_datastore_free(datastore);
606 after_bridge->parseable_goto = ast_strdup(parseable_goto);
607 after_bridge->context = ast_strdup(context);
608 after_bridge->exten = ast_strdup(exten);
609 after_bridge->priority = priority;
610 after_bridge->run_h_exten = run_h_exten ? 1 : 0;
611 after_bridge->specific = specific ? 1 : 0;
612 datastore->data = after_bridge;
613 if ((parseable_goto && !after_bridge->parseable_goto)
614 || (context && !after_bridge->context)
615 || (exten && !after_bridge->exten)) {
616 ast_datastore_free(datastore);
620 /* Put it on the channel replacing any existing one. */
621 ast_channel_lock(chan);
622 ast_bridge_discard_after_goto(chan);
623 ast_channel_datastore_add(chan, datastore);
624 ast_channel_unlock(chan);
627 void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
629 __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
632 void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
634 __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
637 void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
641 if (!ast_strlen_zero(parseable_goto)) {
642 p_goto = ast_strdupa(parseable_goto);
643 ast_replace_subargument_delimiter(p_goto);
647 __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);