fbe4e605a53873e27833a94cc862a9edaafaf206
[asterisk/asterisk.git] / main / bridge_after.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2007 - 2009, Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@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 /*!
20  * \file
21  * \brief After Bridge Execution API
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  *
25  * See Also:
26  * \arg \ref AstCREDITS
27  */
28
29 /*** MODULEINFO
30         <support_level>core</support_level>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/bridge_after.h"
41
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. */
50         void *data;
51         /*! Reason the after bridge callback failed. */
52         enum ast_bridge_after_cb_reason reason;
53 };
54
55 struct after_bridge_cb_ds {
56         /*! After bridge callbacks container. */
57         AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
58 };
59
60 /*!
61  * \internal
62  * \brief Indicate after bridge callback failed.
63  * \since 12.0.0
64  *
65  * \param node After bridge callback node.
66  *
67  * \return Nothing
68  */
69 static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
70 {
71         if (node->failed) {
72                 node->failed(node->reason, node->data);
73                 node->failed = NULL;
74         }
75 }
76
77 /*!
78  * \internal
79  * \brief Run discarding any after bridge callbacks.
80  * \since 12.0.0
81  *
82  * \param after_bridge After bridge callback container process.
83  * \param reason Why are we doing this.
84  *
85  * \return Nothing
86  */
87 static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
88 {
89         struct after_bridge_cb_node *node;
90
91         for (;;) {
92                 AST_LIST_LOCK(&after_bridge->callbacks);
93                 node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
94                 AST_LIST_UNLOCK(&after_bridge->callbacks);
95                 if (!node) {
96                         break;
97                 }
98                 if (!node->reason) {
99                         node->reason = reason;
100                 }
101                 after_bridge_cb_failed(node);
102                 ast_free(node);
103         }
104 }
105
106 /*!
107  * \internal
108  * \brief Destroy the after bridge callback datastore.
109  * \since 12.0.0
110  *
111  * \param data After bridge callback data to destroy.
112  *
113  * \return Nothing
114  */
115 static void after_bridge_cb_destroy(void *data)
116 {
117         struct after_bridge_cb_ds *after_bridge = data;
118
119         after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
120
121         AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
122         ast_free(after_bridge);
123 }
124
125 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
126
127 /*!
128  * \internal
129  * \brief Fixup the after bridge callback datastore.
130  * \since 12.0.0
131  *
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.
135  *
136  * \return Nothing
137  */
138 static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
139 {
140         struct after_bridge_cb_ds *after_bridge;
141         struct after_bridge_cb_node *node;
142
143         after_bridge = after_bridge_cb_find(new_chan);
144         if (!after_bridge) {
145                 return;
146         }
147
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;
152         }
153         AST_LIST_UNLOCK(&after_bridge->callbacks);
154 }
155
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,
160 };
161
162 /*!
163  * \internal
164  * \brief Find an after bridge callback datastore container.
165  * \since 12.0.0
166  *
167  * \param chan Channel to find the after bridge callback container on.
168  *
169  * \retval after_bridge datastore container on success.
170  * \retval NULL on error.
171  */
172 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
173 {
174         struct ast_datastore *datastore;
175         SCOPED_CHANNELLOCK(lock, chan);
176
177         datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
178         if (!datastore) {
179                 return NULL;
180         }
181         return datastore->data;
182 }
183
184 /*!
185  * \internal
186  * \brief Setup/create an after bridge callback datastore container.
187  * \since 12.0.0
188  *
189  * \param chan Channel to setup/create the after bridge callback container on.
190  *
191  * \retval after_bridge datastore container on success.
192  * \retval NULL on error.
193  */
194 static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
195 {
196         struct ast_datastore *datastore;
197         struct after_bridge_cb_ds *after_bridge;
198         SCOPED_CHANNELLOCK(lock, chan);
199
200         datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
201         if (datastore) {
202                 return datastore->data;
203         }
204
205         /* Create a new datastore. */
206         datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
207         if (!datastore) {
208                 return NULL;
209         }
210         after_bridge = ast_calloc(1, sizeof(*after_bridge));
211         if (!after_bridge) {
212                 ast_datastore_free(datastore);
213                 return NULL;
214         }
215         AST_LIST_HEAD_INIT(&after_bridge->callbacks);
216         datastore->data = after_bridge;
217         ast_channel_datastore_add(chan, datastore);
218
219         return datastore->data;
220 }
221
222 void ast_bridge_run_after_callback(struct ast_channel *chan)
223 {
224         struct after_bridge_cb_ds *after_bridge;
225         struct after_bridge_cb_node *node;
226
227         after_bridge = after_bridge_cb_find(chan);
228         if (!after_bridge) {
229                 return;
230         }
231
232         for (;;) {
233                 AST_LIST_LOCK(&after_bridge->callbacks);
234                 node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
235                 AST_LIST_UNLOCK(&after_bridge->callbacks);
236                 if (!node) {
237                         break;
238                 }
239                 if (node->reason) {
240                         after_bridge_cb_failed(node);
241                 } else {
242                         node->failed = NULL;
243                         node->callback(chan, node->data);
244                 }
245                 ast_free(node);
246         }
247 }
248
249 void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
250 {
251         struct after_bridge_cb_ds *after_bridge;
252
253         after_bridge = after_bridge_cb_find(chan);
254         if (!after_bridge) {
255                 return;
256         }
257
258         after_bridge_cb_run_discard(after_bridge, reason);
259 }
260
261 int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
262 {
263         struct after_bridge_cb_ds *after_bridge;
264         struct after_bridge_cb_node *new_node;
265         struct after_bridge_cb_node *last_node;
266
267         /* Sanity checks. */
268         ast_assert(chan != NULL);
269         if (!chan || !callback) {
270                 return -1;
271         }
272
273         after_bridge = after_bridge_cb_setup(chan);
274         if (!after_bridge) {
275                 return -1;
276         }
277
278         /* Create a new callback node. */
279         new_node = ast_calloc(1, sizeof(*new_node));
280         if (!new_node) {
281                 return -1;
282         }
283         new_node->callback = callback;
284         new_node->failed = failed;
285         new_node->data = data;
286
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;
292         }
293         AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
294         AST_LIST_UNLOCK(&after_bridge->callbacks);
295         return 0;
296 }
297
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",
304 };
305
306 const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
307 {
308         if (reason < AST_BRIDGE_AFTER_CB_REASON_DESTROY
309                 || AST_BRIDGE_AFTER_CB_REASON_REMOVED < reason
310                 || !reason_strings[reason]) {
311                 return "Unknown";
312         }
313
314         return reason_strings[reason];
315 }
316
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. */
321         const char *context;
322         /*! Specific goto exten or default exten for parseable_goto. */
323         const char *exten;
324         /*! Specific goto priority or default priority for parseable_goto. */
325         int priority;
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;
330 };
331
332 /*!
333  * \internal
334  * \brief Destroy the after bridge goto datastore.
335  * \since 12.0.0
336  *
337  * \param data After bridge goto data to destroy.
338  *
339  * \return Nothing
340  */
341 static void after_bridge_goto_destroy(void *data)
342 {
343         struct after_bridge_goto_ds *after_bridge = data;
344
345         ast_free((char *) after_bridge->parseable_goto);
346         ast_free((char *) after_bridge->context);
347         ast_free((char *) after_bridge->exten);
348 }
349
350 /*!
351  * \internal
352  * \brief Fixup the after bridge goto datastore.
353  * \since 12.0.0
354  *
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.
358  *
359  * \return Nothing
360  */
361 static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
362 {
363         /* There can be only one.  Discard any already on the new channel. */
364         ast_bridge_discard_after_goto(new_chan);
365 }
366
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,
371 };
372
373 /*!
374  * \internal
375  * \brief Remove channel goto location after the bridge and return it.
376  * \since 12.0.0
377  *
378  * \param chan Channel to remove after bridge goto location.
379  *
380  * \retval datastore on success.
381  * \retval NULL on error or not found.
382  */
383 static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
384 {
385         struct ast_datastore *datastore;
386
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)) {
390                 datastore = NULL;
391         }
392         ast_channel_unlock(chan);
393
394         return datastore;
395 }
396
397 void ast_bridge_discard_after_goto(struct ast_channel *chan)
398 {
399         struct ast_datastore *datastore;
400
401         datastore = after_bridge_goto_remove(chan);
402         if (datastore) {
403                 ast_datastore_free(datastore);
404         }
405 }
406
407 void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
408 {
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;
413
414         SCOPED_CHANNELLOCK(lock, chan);
415
416         datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
417         if (!datastore) {
418                 buffer[0] = '\0';
419                 return;
420         }
421
422         after_bridge = datastore->data;
423
424         if (after_bridge->parseable_goto) {
425                 snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
426                 return;
427         }
428
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);
433         }
434
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);
443         }
444
445         snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
446 }
447
448 int ast_bridge_setup_after_goto(struct ast_channel *chan)
449 {
450         struct ast_datastore *datastore;
451         struct after_bridge_goto_ds *after_bridge;
452         int goto_failed = -1;
453
454         /* We are going to be leaving the bridging system now;
455          * clear any pending UNBRIDGE flags
456          */
457         ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_UNBRIDGE);
458
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)) {
464                         goto_failed = 0;
465                 }
466                 return goto_failed;
467         }
468
469         /* Get after bridge goto datastore. */
470         datastore = after_bridge_goto_remove(chan);
471         if (!datastore) {
472                 return goto_failed;
473         }
474
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);
483                 }
484         } else if (!ast_check_hangup(chan)) {
485                 /* Clear the outgoing flag */
486                 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
487
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)) {
492                         char *context;
493                         char *exten;
494                         int priority;
495
496                         /* Option F(x) for Bridge(), Dial(), and Queue() */
497
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);
502
503                         /* Set current dialplan position to default dialplan position */
504                         ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
505                                 after_bridge->priority);
506
507                         /* Then perform the goto */
508                         goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
509                         if (goto_failed) {
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);
514                         }
515                 } else {
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);
519                 }
520                 if (!goto_failed) {
521                         if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
522                                 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
523                         }
524
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));
529                 }
530         }
531
532         /* Discard after bridge goto datastore. */
533         ast_datastore_free(datastore);
534
535         return goto_failed;
536 }
537
538 void ast_bridge_run_after_goto(struct ast_channel *chan)
539 {
540         int goto_failed;
541
542         goto_failed = ast_bridge_setup_after_goto(chan);
543         if (goto_failed || ast_pbx_run(chan)) {
544                 ast_hangup(chan);
545         }
546 }
547
548 /*!
549  * \internal
550  * \brief Set after bridge goto location of channel.
551  * \since 12.0.0
552  *
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)
560  *
561  * \details Add a channel datastore to setup the goto location
562  * when the channel leaves the bridge and run a PBX from there.
563  *
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.
569  *
570  * \return Nothing
571  */
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)
573 {
574         struct ast_datastore *datastore;
575         struct after_bridge_goto_ds *after_bridge;
576
577         /* Sanity checks. */
578         ast_assert(chan != NULL);
579         if (!chan) {
580                 return;
581         }
582         if (run_h_exten) {
583                 ast_assert(run_h_exten && context);
584                 if (!context) {
585                         return;
586                 }
587         } else {
588                 ast_assert(context && exten && 0 < priority);
589                 if (!context || !exten || priority < 1) {
590                         return;
591                 }
592         }
593
594         /* Create a new datastore. */
595         datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
596         if (!datastore) {
597                 return;
598         }
599         after_bridge = ast_calloc(1, sizeof(*after_bridge));
600         if (!after_bridge) {
601                 ast_datastore_free(datastore);
602                 return;
603         }
604
605         /* Initialize it. */
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);
617                 return;
618         }
619
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);
625 }
626
627 void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
628 {
629         __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
630 }
631
632 void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
633 {
634         __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
635 }
636
637 void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
638 {
639         char *p_goto;
640
641         if (!ast_strlen_zero(parseable_goto)) {
642                 p_goto = ast_strdupa(parseable_goto);
643                 ast_replace_subargument_delimiter(p_goto);
644         } else {
645                 p_goto = NULL;
646         }
647         __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
648 }