bridge_after.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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. * \file
  20. * \brief After Bridge Execution API
  21. *
  22. * \author Richard Mudgett <rmudgett@digium.com>
  23. *
  24. * See Also:
  25. * \arg \ref AstCREDITS
  26. */
  27. /*** MODULEINFO
  28. <support_level>core</support_level>
  29. ***/
  30. #include "asterisk.h"
  31. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  32. #include "asterisk/logger.h"
  33. #include "asterisk/channel.h"
  34. #include "asterisk/pbx.h"
  35. #include "asterisk/bridge_after.h"
  36. struct after_bridge_cb_node {
  37. /*! Next list node. */
  38. AST_LIST_ENTRY(after_bridge_cb_node) list;
  39. /*! Desired callback function. */
  40. ast_bridge_after_cb callback;
  41. /*! After bridge callback will not be called and destroy any resources data may contain. */
  42. ast_bridge_after_cb_failed failed;
  43. /*! Extra data to pass to the callback. */
  44. void *data;
  45. /*! Reason the after bridge callback failed. */
  46. enum ast_bridge_after_cb_reason reason;
  47. };
  48. struct after_bridge_cb_ds {
  49. /*! After bridge callbacks container. */
  50. AST_LIST_HEAD(, after_bridge_cb_node) callbacks;
  51. };
  52. /*!
  53. * \internal
  54. * \brief Indicate after bridge callback failed.
  55. * \since 12.0.0
  56. *
  57. * \param node After bridge callback node.
  58. *
  59. * \return Nothing
  60. */
  61. static void after_bridge_cb_failed(struct after_bridge_cb_node *node)
  62. {
  63. if (node->failed) {
  64. node->failed(node->reason, node->data);
  65. node->failed = NULL;
  66. }
  67. }
  68. /*!
  69. * \internal
  70. * \brief Run discarding any after bridge callbacks.
  71. * \since 12.0.0
  72. *
  73. * \param after_bridge After bridge callback container process.
  74. * \param reason Why are we doing this.
  75. *
  76. * \return Nothing
  77. */
  78. static void after_bridge_cb_run_discard(struct after_bridge_cb_ds *after_bridge, enum ast_bridge_after_cb_reason reason)
  79. {
  80. struct after_bridge_cb_node *node;
  81. for (;;) {
  82. AST_LIST_LOCK(&after_bridge->callbacks);
  83. node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
  84. AST_LIST_UNLOCK(&after_bridge->callbacks);
  85. if (!node) {
  86. break;
  87. }
  88. if (!node->reason) {
  89. node->reason = reason;
  90. }
  91. after_bridge_cb_failed(node);
  92. ast_free(node);
  93. }
  94. }
  95. /*!
  96. * \internal
  97. * \brief Destroy the after bridge callback datastore.
  98. * \since 12.0.0
  99. *
  100. * \param data After bridge callback data to destroy.
  101. *
  102. * \return Nothing
  103. */
  104. static void after_bridge_cb_destroy(void *data)
  105. {
  106. struct after_bridge_cb_ds *after_bridge = data;
  107. after_bridge_cb_run_discard(after_bridge, AST_BRIDGE_AFTER_CB_REASON_DESTROY);
  108. AST_LIST_HEAD_DESTROY(&after_bridge->callbacks);
  109. ast_free(after_bridge);
  110. }
  111. static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan);
  112. /*!
  113. * \internal
  114. * \brief Fixup the after bridge callback datastore.
  115. * \since 12.0.0
  116. *
  117. * \param data After bridge callback data to fixup.
  118. * \param old_chan The datastore is moving from this channel.
  119. * \param new_chan The datastore is moving to this channel.
  120. *
  121. * \return Nothing
  122. */
  123. static void after_bridge_cb_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
  124. {
  125. struct after_bridge_cb_ds *after_bridge;
  126. struct after_bridge_cb_node *node;
  127. after_bridge = after_bridge_cb_find(new_chan);
  128. if (!after_bridge) {
  129. return;
  130. }
  131. AST_LIST_LOCK(&after_bridge->callbacks);
  132. node = AST_LIST_LAST(&after_bridge->callbacks);
  133. if (node && !node->reason) {
  134. node->reason = AST_BRIDGE_AFTER_CB_REASON_MASQUERADE;
  135. }
  136. AST_LIST_UNLOCK(&after_bridge->callbacks);
  137. }
  138. static const struct ast_datastore_info after_bridge_cb_info = {
  139. .type = "after-bridge-cb",
  140. .destroy = after_bridge_cb_destroy,
  141. .chan_fixup = after_bridge_cb_fixup,
  142. };
  143. /*!
  144. * \internal
  145. * \brief Find an after bridge callback datastore container.
  146. * \since 12.0.0
  147. *
  148. * \param chan Channel to find the after bridge callback container on.
  149. *
  150. * \retval after_bridge datastore container on success.
  151. * \retval NULL on error.
  152. */
  153. static struct after_bridge_cb_ds *after_bridge_cb_find(struct ast_channel *chan)
  154. {
  155. struct ast_datastore *datastore;
  156. SCOPED_CHANNELLOCK(lock, chan);
  157. datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
  158. if (!datastore) {
  159. return NULL;
  160. }
  161. return datastore->data;
  162. }
  163. /*!
  164. * \internal
  165. * \brief Setup/create an after bridge callback datastore container.
  166. * \since 12.0.0
  167. *
  168. * \param chan Channel to setup/create the after bridge callback container on.
  169. *
  170. * \retval after_bridge datastore container on success.
  171. * \retval NULL on error.
  172. */
  173. static struct after_bridge_cb_ds *after_bridge_cb_setup(struct ast_channel *chan)
  174. {
  175. struct ast_datastore *datastore;
  176. struct after_bridge_cb_ds *after_bridge;
  177. SCOPED_CHANNELLOCK(lock, chan);
  178. datastore = ast_channel_datastore_find(chan, &after_bridge_cb_info, NULL);
  179. if (datastore) {
  180. return datastore->data;
  181. }
  182. /* Create a new datastore. */
  183. datastore = ast_datastore_alloc(&after_bridge_cb_info, NULL);
  184. if (!datastore) {
  185. return NULL;
  186. }
  187. after_bridge = ast_calloc(1, sizeof(*after_bridge));
  188. if (!after_bridge) {
  189. ast_datastore_free(datastore);
  190. return NULL;
  191. }
  192. AST_LIST_HEAD_INIT(&after_bridge->callbacks);
  193. datastore->data = after_bridge;
  194. ast_channel_datastore_add(chan, datastore);
  195. return datastore->data;
  196. }
  197. void ast_bridge_run_after_callback(struct ast_channel *chan)
  198. {
  199. struct after_bridge_cb_ds *after_bridge;
  200. struct after_bridge_cb_node *node;
  201. after_bridge = after_bridge_cb_find(chan);
  202. if (!after_bridge) {
  203. return;
  204. }
  205. for (;;) {
  206. AST_LIST_LOCK(&after_bridge->callbacks);
  207. node = AST_LIST_REMOVE_HEAD(&after_bridge->callbacks, list);
  208. AST_LIST_UNLOCK(&after_bridge->callbacks);
  209. if (!node) {
  210. break;
  211. }
  212. if (node->reason) {
  213. after_bridge_cb_failed(node);
  214. } else {
  215. node->failed = NULL;
  216. node->callback(chan, node->data);
  217. }
  218. ast_free(node);
  219. }
  220. }
  221. void ast_bridge_discard_after_callback(struct ast_channel *chan, enum ast_bridge_after_cb_reason reason)
  222. {
  223. struct after_bridge_cb_ds *after_bridge;
  224. after_bridge = after_bridge_cb_find(chan);
  225. if (!after_bridge) {
  226. return;
  227. }
  228. after_bridge_cb_run_discard(after_bridge, reason);
  229. }
  230. int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
  231. {
  232. struct after_bridge_cb_ds *after_bridge;
  233. struct after_bridge_cb_node *new_node;
  234. struct after_bridge_cb_node *last_node;
  235. /* Sanity checks. */
  236. ast_assert(chan != NULL);
  237. if (!chan || !callback) {
  238. return -1;
  239. }
  240. after_bridge = after_bridge_cb_setup(chan);
  241. if (!after_bridge) {
  242. return -1;
  243. }
  244. /* Create a new callback node. */
  245. new_node = ast_calloc(1, sizeof(*new_node));
  246. if (!new_node) {
  247. return -1;
  248. }
  249. new_node->callback = callback;
  250. new_node->failed = failed;
  251. new_node->data = data;
  252. /* Put it in the container disabling any previously active one. */
  253. AST_LIST_LOCK(&after_bridge->callbacks);
  254. last_node = AST_LIST_LAST(&after_bridge->callbacks);
  255. if (last_node && !last_node->reason) {
  256. last_node->reason = AST_BRIDGE_AFTER_CB_REASON_REPLACED;
  257. }
  258. AST_LIST_INSERT_TAIL(&after_bridge->callbacks, new_node, list);
  259. AST_LIST_UNLOCK(&after_bridge->callbacks);
  260. return 0;
  261. }
  262. const char *ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
  263. {
  264. switch (reason) {
  265. case AST_BRIDGE_AFTER_CB_REASON_DESTROY:
  266. return "Channel destroyed (hungup)";
  267. case AST_BRIDGE_AFTER_CB_REASON_REPLACED:
  268. return "Callback was replaced";
  269. case AST_BRIDGE_AFTER_CB_REASON_MASQUERADE:
  270. return "Channel masqueraded";
  271. case AST_BRIDGE_AFTER_CB_REASON_DEPART:
  272. return "Channel was departed from bridge";
  273. case AST_BRIDGE_AFTER_CB_REASON_REMOVED:
  274. return "Callback was removed";
  275. case AST_BRIDGE_AFTER_CB_REASON_IMPART_FAILED:
  276. return "Channel failed joining the bridge";
  277. }
  278. return "Unknown";
  279. }
  280. struct after_bridge_goto_ds {
  281. /*! Goto string that can be parsed by ast_parseable_goto(). */
  282. const char *parseable_goto;
  283. /*! Specific goto context or default context for parseable_goto. */
  284. const char *context;
  285. /*! Specific goto exten or default exten for parseable_goto. */
  286. const char *exten;
  287. /*! Specific goto priority or default priority for parseable_goto. */
  288. int priority;
  289. /*! TRUE if the peer should run the h exten. */
  290. unsigned int run_h_exten:1;
  291. /*! Specific goto location */
  292. unsigned int specific:1;
  293. };
  294. /*!
  295. * \internal
  296. * \brief Destroy the after bridge goto datastore.
  297. * \since 12.0.0
  298. *
  299. * \param data After bridge goto data to destroy.
  300. *
  301. * \return Nothing
  302. */
  303. static void after_bridge_goto_destroy(void *data)
  304. {
  305. struct after_bridge_goto_ds *after_bridge = data;
  306. ast_free((char *) after_bridge->parseable_goto);
  307. ast_free((char *) after_bridge->context);
  308. ast_free((char *) after_bridge->exten);
  309. ast_free((char *) after_bridge);
  310. }
  311. /*!
  312. * \internal
  313. * \brief Fixup the after bridge goto datastore.
  314. * \since 12.0.0
  315. *
  316. * \param data After bridge goto data to fixup.
  317. * \param old_chan The datastore is moving from this channel.
  318. * \param new_chan The datastore is moving to this channel.
  319. *
  320. * \return Nothing
  321. */
  322. static void after_bridge_goto_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
  323. {
  324. /* There can be only one. Discard any already on the new channel. */
  325. ast_bridge_discard_after_goto(new_chan);
  326. }
  327. static const struct ast_datastore_info after_bridge_goto_info = {
  328. .type = "after-bridge-goto",
  329. .destroy = after_bridge_goto_destroy,
  330. .chan_fixup = after_bridge_goto_fixup,
  331. };
  332. /*!
  333. * \internal
  334. * \brief Remove channel goto location after the bridge and return it.
  335. * \since 12.0.0
  336. *
  337. * \param chan Channel to remove after bridge goto location.
  338. *
  339. * \retval datastore on success.
  340. * \retval NULL on error or not found.
  341. */
  342. static struct ast_datastore *after_bridge_goto_remove(struct ast_channel *chan)
  343. {
  344. struct ast_datastore *datastore;
  345. ast_channel_lock(chan);
  346. datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
  347. if (datastore && ast_channel_datastore_remove(chan, datastore)) {
  348. datastore = NULL;
  349. }
  350. ast_channel_unlock(chan);
  351. return datastore;
  352. }
  353. void ast_bridge_discard_after_goto(struct ast_channel *chan)
  354. {
  355. struct ast_datastore *datastore;
  356. datastore = after_bridge_goto_remove(chan);
  357. if (datastore) {
  358. ast_datastore_free(datastore);
  359. }
  360. }
  361. void ast_bridge_read_after_goto(struct ast_channel *chan, char *buffer, size_t buf_size)
  362. {
  363. struct ast_datastore *datastore;
  364. struct after_bridge_goto_ds *after_bridge;
  365. char *current_pos = buffer;
  366. size_t remaining_size = buf_size;
  367. SCOPED_CHANNELLOCK(lock, chan);
  368. datastore = ast_channel_datastore_find(chan, &after_bridge_goto_info, NULL);
  369. if (!datastore) {
  370. buffer[0] = '\0';
  371. return;
  372. }
  373. after_bridge = datastore->data;
  374. if (after_bridge->parseable_goto) {
  375. snprintf(buffer, buf_size, "%s", after_bridge->parseable_goto);
  376. return;
  377. }
  378. if (!ast_strlen_zero(after_bridge->context)) {
  379. snprintf(current_pos, remaining_size, "%s,", after_bridge->context);
  380. remaining_size = remaining_size - strlen(current_pos);
  381. current_pos += strlen(current_pos);
  382. }
  383. if (after_bridge->run_h_exten) {
  384. snprintf(current_pos, remaining_size, "h,");
  385. remaining_size = remaining_size - strlen(current_pos);
  386. current_pos += strlen(current_pos);
  387. } else if (!ast_strlen_zero(after_bridge->exten)) {
  388. snprintf(current_pos, remaining_size, "%s,", after_bridge->exten);
  389. remaining_size = remaining_size - strlen(current_pos);
  390. current_pos += strlen(current_pos);
  391. }
  392. snprintf(current_pos, remaining_size, "%d", after_bridge->priority);
  393. }
  394. int ast_bridge_setup_after_goto(struct ast_channel *chan)
  395. {
  396. struct ast_datastore *datastore;
  397. struct after_bridge_goto_ds *after_bridge;
  398. int goto_failed = -1;
  399. /* We are going to be leaving the bridging system now;
  400. * clear any pending unbridge flags
  401. */
  402. ast_channel_set_unbridged(chan, 0);
  403. /* Determine if we are going to setup a dialplan location and where. */
  404. if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
  405. /* An async goto has already setup a location. */
  406. ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
  407. if (!ast_check_hangup(chan)) {
  408. goto_failed = 0;
  409. }
  410. return goto_failed;
  411. }
  412. /* Get after bridge goto datastore. */
  413. datastore = after_bridge_goto_remove(chan);
  414. if (!datastore) {
  415. return goto_failed;
  416. }
  417. after_bridge = datastore->data;
  418. if (after_bridge->run_h_exten) {
  419. if (ast_exists_extension(chan, after_bridge->context, "h", 1,
  420. S_COR(ast_channel_caller(chan)->id.number.valid,
  421. ast_channel_caller(chan)->id.number.str, NULL))) {
  422. ast_debug(1, "Running after bridge goto h exten %s,h,1\n",
  423. ast_channel_context(chan));
  424. ast_pbx_h_exten_run(chan, after_bridge->context);
  425. }
  426. } else if (!ast_check_hangup(chan)) {
  427. /* Clear the outgoing flag */
  428. ast_channel_clear_flag(chan, AST_FLAG_OUTGOING);
  429. if (after_bridge->specific) {
  430. goto_failed = ast_explicit_goto(chan, after_bridge->context,
  431. after_bridge->exten, after_bridge->priority);
  432. } else if (!ast_strlen_zero(after_bridge->parseable_goto)) {
  433. char *context;
  434. char *exten;
  435. int priority;
  436. /* Option F(x) for Bridge(), Dial(), and Queue() */
  437. /* Save current dialplan location in case of failure. */
  438. context = ast_strdupa(ast_channel_context(chan));
  439. exten = ast_strdupa(ast_channel_exten(chan));
  440. priority = ast_channel_priority(chan);
  441. /* Set current dialplan position to default dialplan position */
  442. ast_explicit_goto(chan, after_bridge->context, after_bridge->exten,
  443. after_bridge->priority);
  444. /* Then perform the goto */
  445. goto_failed = ast_parseable_goto(chan, after_bridge->parseable_goto);
  446. if (goto_failed) {
  447. /* Restore original dialplan location. */
  448. ast_channel_context_set(chan, context);
  449. ast_channel_exten_set(chan, exten);
  450. ast_channel_priority_set(chan, priority);
  451. }
  452. } else {
  453. /* Option F() for Bridge(), Dial(), and Queue() */
  454. goto_failed = ast_goto_if_exists(chan, after_bridge->context,
  455. after_bridge->exten, after_bridge->priority + 1);
  456. }
  457. if (!goto_failed) {
  458. if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
  459. ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
  460. }
  461. ast_debug(1, "Setup after bridge goto location to %s,%s,%d.\n",
  462. ast_channel_context(chan),
  463. ast_channel_exten(chan),
  464. ast_channel_priority(chan));
  465. }
  466. }
  467. /* Discard after bridge goto datastore. */
  468. ast_datastore_free(datastore);
  469. return goto_failed;
  470. }
  471. void ast_bridge_run_after_goto(struct ast_channel *chan)
  472. {
  473. int goto_failed;
  474. goto_failed = ast_bridge_setup_after_goto(chan);
  475. if (goto_failed || ast_pbx_run(chan)) {
  476. ast_hangup(chan);
  477. }
  478. }
  479. /*!
  480. * \internal
  481. * \brief Set after bridge goto location of channel.
  482. * \since 12.0.0
  483. *
  484. * \param chan Channel to setup after bridge goto location.
  485. * \param run_h_exten TRUE if the h exten should be run.
  486. * \param specific TRUE if the context/exten/priority is exactly specified.
  487. * \param context Context to goto after bridge.
  488. * \param exten Exten to goto after bridge. (Could be NULL if run_h_exten)
  489. * \param priority Priority to goto after bridge.
  490. * \param parseable_goto User specified goto string. (Could be NULL)
  491. *
  492. * \details Add a channel datastore to setup the goto location
  493. * when the channel leaves the bridge and run a PBX from there.
  494. *
  495. * If run_h_exten then execute the h exten found in the given context.
  496. * Else if specific then goto the given context/exten/priority.
  497. * Else if parseable_goto then use the given context/exten/priority
  498. * as the relative position for the parseable_goto.
  499. * Else goto the given context/exten/priority+1.
  500. *
  501. * \return Nothing
  502. */
  503. 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)
  504. {
  505. struct ast_datastore *datastore;
  506. struct after_bridge_goto_ds *after_bridge;
  507. /* Sanity checks. */
  508. ast_assert(chan != NULL);
  509. if (!chan) {
  510. return;
  511. }
  512. if (run_h_exten) {
  513. ast_assert(run_h_exten && context);
  514. if (!context) {
  515. return;
  516. }
  517. } else {
  518. ast_assert(context && exten && 0 < priority);
  519. if (!context || !exten || priority < 1) {
  520. return;
  521. }
  522. }
  523. /* Create a new datastore. */
  524. datastore = ast_datastore_alloc(&after_bridge_goto_info, NULL);
  525. if (!datastore) {
  526. return;
  527. }
  528. after_bridge = ast_calloc(1, sizeof(*after_bridge));
  529. if (!after_bridge) {
  530. ast_datastore_free(datastore);
  531. return;
  532. }
  533. /* Initialize it. */
  534. after_bridge->parseable_goto = ast_strdup(parseable_goto);
  535. after_bridge->context = ast_strdup(context);
  536. after_bridge->exten = ast_strdup(exten);
  537. after_bridge->priority = priority;
  538. after_bridge->run_h_exten = run_h_exten ? 1 : 0;
  539. after_bridge->specific = specific ? 1 : 0;
  540. datastore->data = after_bridge;
  541. if ((parseable_goto && !after_bridge->parseable_goto)
  542. || (context && !after_bridge->context)
  543. || (exten && !after_bridge->exten)) {
  544. ast_datastore_free(datastore);
  545. return;
  546. }
  547. /* Put it on the channel replacing any existing one. */
  548. ast_channel_lock(chan);
  549. ast_bridge_discard_after_goto(chan);
  550. ast_channel_datastore_add(chan, datastore);
  551. ast_channel_unlock(chan);
  552. }
  553. void ast_bridge_set_after_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
  554. {
  555. __after_bridge_set_goto(chan, 0, 1, context, exten, priority, NULL);
  556. }
  557. void ast_bridge_set_after_h(struct ast_channel *chan, const char *context)
  558. {
  559. __after_bridge_set_goto(chan, 1, 0, context, NULL, 1, NULL);
  560. }
  561. void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
  562. {
  563. char *p_goto;
  564. if (!ast_strlen_zero(parseable_goto)) {
  565. p_goto = ast_strdupa(parseable_goto);
  566. ast_replace_subargument_delimiter(p_goto);
  567. } else {
  568. p_goto = NULL;
  569. }
  570. __after_bridge_set_goto(chan, 0, 0, context, exten, priority, p_goto);
  571. }