Asterisk - The Open Source Telephony Project  21.4.1
bridge_after.c
Go to the documentation of this file.
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 #include "asterisk/logger.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/bridge_after.h"
39 
41  /*! Next list node. */
43  /*! Desired callback function. */
45  /*! After bridge callback will not be called and destroy any resources data may contain. */
47  /*! Extra data to pass to the callback. */
48  void *data;
49  /*! Reason the after bridge callback failed. */
51 };
52 
54  /*! After bridge callbacks container. */
56 };
57 
58 /*!
59  * \internal
60  * \brief Indicate after bridge callback failed.
61  * \since 12.0.0
62  *
63  * \param node After bridge callback node.
64  */
65 static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
66 {
67  if (node->failed) {
68  node->failed(node->reason, node->data);
69  node->failed = NULL;
70  }
71 }
72 
73 /*!
74  * \internal
75  * \brief Run discarding any after bridge callbacks.
76  * \since 12.0.0
77  *
78  * \param after_bridge After bridge callback container process.
79  * \param reason Why are we doing this.
80  */
81 static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
82 {
83  struct after_bridge_cb_node *node;
84 
85  for (;;) {
86  AST_LIST_LOCK(&after_bridge->callbacks);
87  node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
88  AST_LIST_UNLOCK(&after_bridge->callbacks);
89  if (!node) {
90  break;
91  }
92  if (!node->reason) {
93  node->reason = reason;
94  }
95  after_bridge_cb_failed(node);
96  ast_free(node);
97  }
98 }
99 
100 /*!
101  * \internal
102  * \brief Destroy the after bridge callback datastore.
103  * \since 12.0.0
104  *
105  * \param data After bridge callback data to destroy.
106  */
107 static void after_bridge_cb_destroy(void *data)
108 {
109  struct after_bridge_cb_ds *after_bridge = data;
110 
111  after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
112 
113  AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
114  ast_free(after_bridge);
115 }
116 
117 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
118 
119 /*!
120  * \internal
121  * \brief Fixup the after bridge callback datastore.
122  * \since 12.0.0
123  *
124  * \param data After bridge callback data to fixup.
125  * \param old_chan The datastore is moving from this channel.
126  * \param new_chan The datastore is moving to this channel.
127  */
128 static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
129 {
130  struct after_bridge_cb_ds *after_bridge;
131  struct after_bridge_cb_node *node;
132 
133  after_bridge = after_bridge_cb_find(new_chan);
134  if (!after_bridge) {
135  return;
136  }
137 
138  AST_LIST_LOCK(&after_bridge->callbacks);
139  node = AST_LIST_LAST(&after_bridge->callbacks);
140  if (node && !node->reason) {
142  }
143  AST_LIST_UNLOCK(&after_bridge->callbacks);
144 }
145 
146 static const struct ast_datastore_info after_bridge_cb_info = {
147  .type = "after-bridge-cb",
148  .destroy = after_bridge_cb_destroy,
149  .chan_fixup = after_bridge_cb_fixup,
150 };
151 
152 /*!
153  * \internal
154  * \brief Find an after bridge callback datastore container.
155  * \since 12.0.0
156  *
157  * \param chan Channel to find the after bridge callback container on.
158  *
159  * \return after_bridge datastore container on success.
160  * \retval NULL on error.
161  */
162 static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
163 {
164  struct ast_datastore *datastore;
165  SCOPED_CHANNELLOCK(lock, chan);
166 
167  datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
168  if (!datastore) {
169  return NULL;
170  }
171  return datastore->data;
172 }
173 
174 /*!
175  * \internal
176  * \brief Setup/create an after bridge callback datastore container.
177  * \since 12.0.0
178  *
179  * \param chan Channel to setup/create the after bridge callback container on.
180  *
181  * \return after_bridge datastore container on success.
182  * \retval NULL on error.
183  */
184 static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
185 {
186  struct ast_datastore *datastore;
187  struct after_bridge_cb_ds *after_bridge;
188  SCOPED_CHANNELLOCK(lock, chan);
189 
190  datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
191  if (datastore) {
192  return datastore->data;
193  }
194 
195  /* Create a new datastore. */
196  datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
197  if (!datastore) {
198  return NULL;
199  }
200  after_bridge = ast_calloc(1, sizeof(*after_bridge));
201  if (!after_bridge) {
202  ast_datastore_free(datastore);
203  return NULL;
204  }
205  AST_LIST_HEAD_INIT(&after_bridge->callbacks);
206  datastore->data = after_bridge;
207  ast_channel_datastore_add(chan, datastore);
208 
209  return datastore->data;
210 }
211 
213 {
214  struct after_bridge_cb_ds *after_bridge;
215  struct after_bridge_cb_node *node;
216 
217  after_bridge = after_bridge_cb_find(chan);
218  if (!after_bridge) {
219  return;
220  }
221 
222  for (;;) {
223  AST_LIST_LOCK(&after_bridge->callbacks);
224  node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
225  AST_LIST_UNLOCK(&after_bridge->callbacks);
226  if (!node) {
227  break;
228  }
229  if (node->reason) {
230  after_bridge_cb_failed(node);
231  } else {
232  node->failed = NULL;
233  node->callback(chan, node->data);
234  }
235  ast_free(node);
236  }
237 }
238 
240 {
241  struct after_bridge_cb_ds *after_bridge;
242 
243  after_bridge = after_bridge_cb_find(chan);
244  if (!after_bridge) {
245  return;
246  }
247 
248  after_bridge_cb_run_discard(after_bridge, reason);
249 }
250 
252 {
253  struct after_bridge_cb_ds *after_bridge;
254  struct after_bridge_cb_node *new_node;
255  struct after_bridge_cb_node *last_node;
256 
257  /* Sanity checks. */
258  ast_assert(chan != NULL);
259  if (!chan || !callback) {
260  return -1;
261  }
262 
263  after_bridge = after_bridge_cb_setup(chan);
264  if (!after_bridge) {
265  return -1;
266  }
267 
268  /* Create a new callback node. */
269  new_node = ast_calloc(1, sizeof(*new_node));
270  if (!new_node) {
271  return -1;
272  }
273  new_node->callback = callback;
274  new_node->failed = failed;
275  new_node->data = data;
276 
277  /* Put it in the container disabling any previously active one. */
278  AST_LIST_LOCK(&after_bridge->callbacks);
279  last_node = AST_LIST_LAST(&after_bridge->callbacks);
280  if (last_node && !last_node->reason) {
282  }
283  AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
284  AST_LIST_UNLOCK(&after_bridge->callbacks);
285  return 0;
286 }
287 
289 {
290  switch (reason) {
292  return "Channel destroyed (hungup)";
294  return "Callback was replaced";
296  return "Channel masqueraded";
298  return "Channel was departed from bridge";
300  return "Callback was removed";
302  return "Channel failed joining the bridge";
303  }
304  return "Unknown";
305 }
306 
308  /*! Goto string that can be parsed by ast_parseable_goto(). */
309  const char *parseable_goto;
310  /*! Specific goto context or default context for parseable_goto. */
311  const char *context;
312  /*! Specific goto exten or default exten for parseable_goto. */
313  const char *exten;
314  /*! Specific goto priority or default priority for parseable_goto. */
315  int priority;
316  /*! TRUE if the peer should run the h exten. */
317  unsigned int run_h_exten:1;
318  /*! Specific goto location */
319  unsigned int specific:1;
320 };
321 
322 /*!
323  * \internal
324  * \brief Destroy the after bridge goto datastore.
325  * \since 12.0.0
326  *
327  * \param data After bridge goto data to destroy.
328  */
329 static void after_bridge_goto_destroy(void *data)
330 {
331  struct after_bridge_goto_ds *after_bridge = data;
332 
333  ast_free((char *) after_bridge->parseable_goto);
334  ast_free((char *) after_bridge->context);
335  ast_free((char *) after_bridge->exten);
336  ast_free((char *) after_bridge);
337 }
338 
339 /*!
340  * \internal
341  * \brief Fixup the after bridge goto datastore.
342  * \since 12.0.0
343  *
344  * \param data After bridge goto data to fixup.
345  * \param old_chan The datastore is moving from this channel.
346  * \param new_chan The datastore is moving to this channel.
347  */
348 static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
349 {
350  /* There can be only one. Discard any already on the new channel. */
352 }
353 
354 static const struct ast_datastore_info after_bridge_goto_info = {
355  .type = "after-bridge-goto",
356  .destroy = after_bridge_goto_destroy,
357  .chan_fixup = after_bridge_goto_fixup,
358 };
359 
360 /*!
361  * \internal
362  * \brief Remove channel goto location after the bridge and return it.
363  * \since 12.0.0
364  *
365  * \param chan Channel to remove after bridge goto location.
366  *
367  * \return datastore on success.
368  * \retval NULL on error or not found.
369  */
370 static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
371 {
372  struct ast_datastore *datastore;
373 
374  ast_channel_lock(chan);
375  datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
376  if (datastore && ast_channel_datastore_remove(chan, datastore)) {
377  datastore = NULL;
378  }
379  ast_channel_unlock(chan);
380 
381  return datastore;
382 }
383 
385 {
386  struct ast_datastore *datastore;
387 
388  datastore = after_bridge_goto_remove(chan);
389  if (datastore) {
390  ast_datastore_free(datastore);
391  }
392 }
393 
394 void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
395 {
396  struct ast_datastore *datastore;
397  struct after_bridge_goto_ds *after_bridge;
398  char *current_pos = buffer;
399  size_t remaining_size = buf_size;
400 
401  SCOPED_CHANNELLOCK(lock, chan);
402 
403  datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
404  if (!datastore) {
405  buffer[0] = '\0';
406  return;
407  }
408 
409  after_bridge = datastore->data;
410 
411  if (after_bridge->parseable_goto) {
412  snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
413  return;
414  }
415 
416  if (!ast_strlen_zero(after_bridge->context)) {
417  snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
418  remaining_size = remaining_size - strlen(current_pos);
419  current_pos += strlen(current_pos);
420  }
421 
422  if (after_bridge->run_h_exten) {
423  snprintf(current_pos, remaining_size, "h,");
424  remaining_size = remaining_size - strlen(current_pos);
425  current_pos += strlen(current_pos);
426  } else if (!ast_strlen_zero(after_bridge->exten)) {
427  snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
428  remaining_size = remaining_size - strlen(current_pos);
429  current_pos += strlen(current_pos);
430  }
431 
432  snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
433 }
434 
436 {
437  struct ast_datastore *datastore;
438  struct after_bridge_goto_ds *after_bridge;
439  int goto_failed = -1;
440 
441  /* We are going to be leaving the bridging system now;
442  * clear any pending unbridge flags
443  */
444  ast_channel_set_unbridged(chan, 0);
445 
446  /* Determine if we are going to setup a dialplan location and where. */
447  if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
448  /* An async goto has already setup a location. */
449  ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
450  if (!ast_check_hangup(chan)) {
451  goto_failed = 0;
452  }
453  return goto_failed;
454  }
455 
456  /* Get after bridge goto datastore. */
457  datastore = after_bridge_goto_remove(chan);
458  if (!datastore) {
459  return goto_failed;
460  }
461 
462  after_bridge = datastore->data;
463  if (after_bridge->run_h_exten) {
464  if (ast_exists_extension(chan, after_bridge->context, "h", 1,
465  S_COR(ast_channel_caller(chan)->id.number.valid,
466  ast_channel_caller(chan)->id.number.str, NULL))) {
467  ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
468  ast_channel_context(chan));
469  ast_pbx_h_exten_run(chan, after_bridge->context);
470  }
471  } else if (!ast_check_hangup(chan)) {
472  /* Clear the outgoing flag */
474 
475  if (after_bridge->specific) {
476  goto_failed = ast_explicit_goto(chan, after_bridge->context,
477  after_bridge->exten, after_bridge->priority);
478  } else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
479  char *context;
480  char *exten;
481  int priority;
482 
483  /* Option F(x) for Bridge(), Dial(), and Queue() */
484 
485  /* Save current dialplan location in case of failure. */
486  context = ast_strdupa(ast_channel_context(chan));
487  exten = ast_strdupa(ast_channel_exten(chan));
488  priority = ast_channel_priority(chan);
489 
490  /* Set current dialplan position to default dialplan position */
491  ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
492  after_bridge->priority);
493 
494  /* Then perform the goto */
495  goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
496  if (goto_failed) {
497  /* Restore original dialplan location. */
498  ast_channel_context_set(chan, context);
499  ast_channel_exten_set(chan, exten);
500  ast_channel_priority_set(chan, priority);
501  }
502  } else {
503  /* Option F() for Bridge(), Dial(), and Queue() */
504  goto_failed = ast_goto_if_exists(chan, after_bridge->context,
505  after_bridge->exten, after_bridge->priority + 1);
506  }
507  if (!goto_failed) {
508  if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
509  ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
510  }
511 
512  ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
513  ast_channel_context(chan),
514  ast_channel_exten(chan),
515  ast_channel_priority(chan));
516  }
517  }
518 
519  /* Discard after bridge goto datastore. */
520  ast_datastore_free(datastore);
521 
522  return goto_failed;
523 }
524 
526 {
527  int goto_failed;
528 
529  goto_failed = ast_bridge_setup_after_goto(chan);
530  if (goto_failed || ast_pbx_run(chan)) {
531  ast_hangup(chan);
532  }
533 }
534 
535 /*!
536  * \internal
537  * \brief Set after bridge goto location of channel.
538  * \since 12.0.0
539  *
540  * \param chan Channel to setup after bridge goto location.
541  * \param run_h_exten TRUE if the h exten should be run.
542  * \param specific TRUE if the context/exten/priority is exactly specified.
543  * \param context Context to goto after bridge.
544  * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
545  * \param priority Priority to goto after bridge.
546  * \param parseable_goto User specified goto string. (Could be NULL)
547  *
548  * \details Add a channel datastore to setup the goto location
549  * when the channel leaves the bridge and run a PBX from there.
550  *
551  * If run_h_exten then execute the h exten found in the given context.
552  * Else if specific then goto the given context/exten/priority.
553  * Else if parseable_goto then use the given context/exten/priority
554  * as the relative position for the parseable_goto.
555  * Else goto the given context/exten/priority+1.
556  */
557 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)
558 {
559  struct ast_datastore *datastore;
560  struct after_bridge_goto_ds *after_bridge;
561 
562  /* Sanity checks. */
563  ast_assert(chan != NULL);
564  if (!chan) {
565  return;
566  }
567  if (run_h_exten) {
568  ast_assert(run_h_exten && context);
569  if (!context) {
570  return;
571  }
572  } else {
573  ast_assert(context && exten && 0 < priority);
574  if (!context || !exten || priority < 1) {
575  return;
576  }
577  }
578 
579  /* Create a new datastore. */
580  datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
581  if (!datastore) {
582  return;
583  }
584  after_bridge = ast_calloc(1, sizeof(*after_bridge));
585  if (!after_bridge) {
586  ast_datastore_free(datastore);
587  return;
588  }
589 
590  /* Initialize it. */
591  after_bridge->parseable_goto = ast_strdup(parseable_goto);
592  after_bridge->context = ast_strdup(context);
593  after_bridge->exten = ast_strdup(exten);
594  after_bridge->priority = priority;
595  after_bridge->run_h_exten = run_h_exten ? 1 : 0;
596  after_bridge->specific = specific ? 1 : 0;
597  datastore->data = after_bridge;
598  if ((parseable_goto && !after_bridge->parseable_goto)
599  || (context && !after_bridge->context)
600  || (exten && !after_bridge->exten)) {
601  ast_datastore_free(datastore);
602  return;
603  }
604 
605  /* Put it on the channel replacing any existing one. */
606  ast_channel_lock(chan);
608  ast_channel_datastore_add(chan, datastore);
609  ast_channel_unlock(chan);
610 }
611 
612 void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
613 {
614  __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
615 }
616 
617 void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
618 {
619  __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
620 }
621 
622 void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
623 {
624  char *p_goto;
625 
626  if (!ast_strlen_zero(parseable_goto)) {
627  p_goto = ast_strdupa(parseable_goto);
629  } else {
630  p_goto = NULL;
631  }
632  __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
633 }
const char * type
Definition: datastore.h:32
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
Run the h exten from the given context.
Definition: pbx.c:4205
Main Channel structure associated with a channel.
Definition: test_heap.c:38
void ast_bridge_run_after_callback(struct ast_channel *chan)
Run any after bridge callback.
Definition: bridge_after.c:212
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
Definition: linkedlists.h:173
const char * parseable_goto
Definition: bridge_after.c:309
struct after_bridge_cb_node::@314 list
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
ast_bridge_after_cb callback
Definition: bridge_after.c:44
int ast_bridge_setup_after_goto(struct ast_channel *chan)
Setup any after bridge goto location to begin execution.
Definition: bridge_after.c:435
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11034
void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
Read after bridge goto if it exists.
Definition: bridge_after.c:394
Structure for a data store type.
Definition: datastore.h:31
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6945
#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
enum ast_bridge_after_cb_reason reason
Definition: bridge_after.c:50
void ast_bridge_run_after_goto(struct ast_channel *chan)
Run a PBX on any after bridge goto location.
Definition: bridge_after.c:525
int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
Setup an after bridge callback for when the channel leaves the bridging system.
Definition: bridge_after.c:251
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653
ast_bridge_after_cb_reason
Definition: bridge_after.h:37
Number structure.
Definition: app_followme.c:154
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343
ast_mutex_t lock
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:619
General Asterisk PBX channel definitions.
const char * ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
Get a string representation of an after bridge callback reason.
Definition: bridge_after.c:288
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2432
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8866
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
void ast_bridge_discard_after_goto(struct ast_channel *chan)
Discard channel after bridge goto location.
Definition: bridge_after.c:384
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
ast_bridge_after_cb_failed failed
Definition: bridge_after.c:46
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
unsigned int specific
Definition: bridge_after.c:319
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:622
const char * context
Definition: bridge_after.c:311
const char * exten
Definition: bridge_after.c:313
void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Set channel to goto specific location after the bridge.
Definition: bridge_after.c:612
#define AST_LIST_LAST(head)
Returns the last entry contained in a list.
Definition: linkedlists.h:429
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:626
#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 * data
Definition: datastore.h:66
After Bridge Execution API.
struct after_bridge_cb_ds::@315 callbacks
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Execute the PBX in the current thread.
Definition: pbx.c:4755
void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
Run discarding any after bridge callbacks.
Definition: bridge_after.c:239
void(* ast_bridge_after_cb)(struct ast_channel *chan, void *data)
After bridge callback function.
Definition: bridge_after.h:194
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2385
unsigned int run_h_exten
Definition: bridge_after.c:317
void(* ast_bridge_after_cb_failed)(enum ast_bridge_after_cb_reason reason, void *data)
After bridge callback failed.
Definition: bridge_after.h:185
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2394
void ast_channel_set_unbridged(struct ast_channel *chan, int value)
Sets the unbridged flag and queues a NULL frame on the channel to trigger a check by bridge_channel_w...
void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
Set channel to run the h exten after the bridge.
Definition: bridge_after.c:617