bridge_builtin_features.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2009, Digium, Inc.
  5. *
  6. * Joshua Colp <jcolp@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. /*! \file
  19. *
  20. * \brief Built in bridging features
  21. *
  22. * \author Joshua Colp <jcolp@digium.com>
  23. *
  24. * \ingroup bridges
  25. */
  26. /*** MODULEINFO
  27. <support_level>core</support_level>
  28. ***/
  29. #include "asterisk.h"
  30. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #include "asterisk/module.h"
  37. #include "asterisk/channel.h"
  38. #include "asterisk/bridging.h"
  39. #include "asterisk/bridging_technology.h"
  40. #include "asterisk/frame.h"
  41. #include "asterisk/file.h"
  42. #include "asterisk/app.h"
  43. #include "asterisk/astobj2.h"
  44. /*! \brief Helper function that presents dialtone and grabs extension */
  45. static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len, const char *context)
  46. {
  47. int res;
  48. /* Play the simple "transfer" prompt out and wait */
  49. res = ast_stream_and_wait(chan, "pbx-transfer", AST_DIGIT_ANY);
  50. ast_stopstream(chan);
  51. /* If the person hit a DTMF digit while the above played back stick it into the buffer */
  52. if (res) {
  53. exten[0] = (char)res;
  54. }
  55. /* Drop to dialtone so they can enter the extension they want to transfer to */
  56. res = ast_app_dtget(chan, context, exten, exten_len, 100, 1000);
  57. return res;
  58. }
  59. /*! \brief Helper function that creates an outgoing channel and returns it immediately */
  60. static struct ast_channel *dial_transfer(struct ast_channel *caller, const char *exten, const char *context)
  61. {
  62. char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
  63. struct ast_channel *chan;
  64. int cause;
  65. /* Fill the variable with the extension and context we want to call */
  66. snprintf(destination, sizeof(destination), "%s@%s", exten, context);
  67. /* Now we request that chan_local prepare to call the destination */
  68. if (!(chan = ast_request("Local", ast_channel_nativeformats(caller), caller, destination, &cause))) {
  69. return NULL;
  70. }
  71. /* Before we actually dial out let's inherit appropriate information. */
  72. ast_channel_lock_both(caller, chan);
  73. ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(caller));
  74. ast_channel_inherit_variables(caller, chan);
  75. ast_channel_datastore_inherit(caller, chan);
  76. ast_channel_unlock(chan);
  77. ast_channel_unlock(caller);
  78. /* Since the above worked fine now we actually call it and return the channel */
  79. if (ast_call(chan, destination, 0)) {
  80. ast_hangup(chan);
  81. return NULL;
  82. }
  83. return chan;
  84. }
  85. /*! \brief Internal built in feature for blind transfers */
  86. static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
  87. {
  88. char exten[AST_MAX_EXTENSION] = "";
  89. struct ast_channel *chan = NULL;
  90. struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt;
  91. const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : ast_channel_context(bridge_channel->chan));
  92. /* Grab the extension to transfer to */
  93. if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
  94. ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
  95. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  96. return 0;
  97. }
  98. /* Get a channel that is the destination we wish to call */
  99. if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
  100. ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
  101. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  102. return 0;
  103. }
  104. /* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */
  105. ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL, 1);
  106. return 0;
  107. }
  108. /*! \brief Attended transfer feature to turn it into a threeway call */
  109. static int attended_threeway_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
  110. {
  111. /* This is sort of abusing the depart state but in this instance it is only going to be handled in the below function so it is okay */
  112. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_DEPART);
  113. return 0;
  114. }
  115. /*! \brief Attended transfer abort feature */
  116. static int attended_abort_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
  117. {
  118. struct ast_bridge_channel *called_bridge_channel = NULL;
  119. /* It is possible (albeit unlikely) that the bridge channels list may change, so we have to ensure we do all of our magic while locked */
  120. ao2_lock(bridge);
  121. if (AST_LIST_FIRST(&bridge->channels) != bridge_channel) {
  122. called_bridge_channel = AST_LIST_FIRST(&bridge->channels);
  123. } else {
  124. called_bridge_channel = AST_LIST_LAST(&bridge->channels);
  125. }
  126. /* Now we basically eject the other channel from the bridge. This will cause their thread to hang them up, and our own code to consider the transfer failed. */
  127. if (called_bridge_channel) {
  128. ast_bridge_change_state(called_bridge_channel, AST_BRIDGE_CHANNEL_STATE_HANGUP);
  129. }
  130. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
  131. ao2_unlock(bridge);
  132. return 0;
  133. }
  134. /*! \brief Internal built in feature for attended transfers */
  135. static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
  136. {
  137. char exten[AST_MAX_EXTENSION] = "";
  138. struct ast_channel *chan = NULL;
  139. struct ast_bridge *attended_bridge = NULL;
  140. struct ast_bridge_features caller_features, called_features;
  141. enum ast_bridge_channel_state attended_bridge_result;
  142. struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt;
  143. const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : ast_channel_context(bridge_channel->chan));
  144. /* Grab the extension to transfer to */
  145. if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) {
  146. ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY);
  147. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  148. return 0;
  149. }
  150. /* Get a channel that is the destination we wish to call */
  151. if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) {
  152. ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
  153. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  154. return 0;
  155. }
  156. /* Create a bridge to use to talk to the person we are calling */
  157. if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) {
  158. ast_hangup(chan);
  159. ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
  160. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  161. return 0;
  162. }
  163. /* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */
  164. ast_bridge_features_init(&called_features);
  165. ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE);
  166. /* This is how this is going down, we are imparting the channel we called above into this bridge first */
  167. ast_bridge_impart(attended_bridge, chan, NULL, &called_features, 1);
  168. /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */
  169. ast_bridge_features_init(&caller_features);
  170. ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP,
  171. (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL);
  172. ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"),
  173. attended_threeway_transfer, NULL, NULL);
  174. ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"),
  175. attended_abort_transfer, NULL, NULL);
  176. /* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */
  177. attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features, NULL);
  178. /* Since the above returned the caller features structure is of no more use */
  179. ast_bridge_features_cleanup(&caller_features);
  180. /* Drop the channel we are transferring to out of the above bridge since it has ended */
  181. if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) {
  182. /* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */
  183. if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) {
  184. /* We want to impart them upon the bridge and just have us return to it as normal */
  185. ast_bridge_impart(bridge, chan, NULL, NULL, 1);
  186. } else {
  187. ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL, 1);
  188. }
  189. } else {
  190. ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY);
  191. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT);
  192. }
  193. /* Now that all channels are out of it we can destroy the bridge and the called features structure */
  194. ast_bridge_features_cleanup(&called_features);
  195. ast_bridge_destroy(attended_bridge);
  196. return 0;
  197. }
  198. /*! \brief Internal built in feature for hangup */
  199. static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
  200. {
  201. /* This is very simple, we basically change the state on the bridge channel to end and the core takes care of the rest */
  202. ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_END);
  203. return 0;
  204. }
  205. static int unload_module(void)
  206. {
  207. ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_HANGUP);
  208. ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER);
  209. ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_BLINDTRANSFER);
  210. return 0;
  211. }
  212. static int load_module(void)
  213. {
  214. ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
  215. ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
  216. ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
  217. /* This module cannot be unloaded until shutdown */
  218. ast_module_shutdown_ref(ast_module_info->self);
  219. return AST_MODULE_LOAD_SUCCESS;
  220. }
  221. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Built in bridging features");