app_chanisavail.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. * James Golovich <james@gnuinter.net>
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief Check if Channel is Available
  22. *
  23. * \author Mark Spencer <markster@digium.com>
  24. * \author James Golovich <james@gnuinter.net>
  25. * \ingroup applications
  26. */
  27. /*** MODULEINFO
  28. <support_level>extended</support_level>
  29. ***/
  30. #include "asterisk.h"
  31. #include <sys/ioctl.h>
  32. #include "asterisk/lock.h"
  33. #include "asterisk/file.h"
  34. #include "asterisk/channel.h"
  35. #include "asterisk/pbx.h"
  36. #include "asterisk/module.h"
  37. #include "asterisk/app.h"
  38. #include "asterisk/devicestate.h"
  39. static const char app[] = "ChanIsAvail";
  40. /*** DOCUMENTATION
  41. <application name="ChanIsAvail" language="en_US">
  42. <synopsis>
  43. Check channel availability
  44. </synopsis>
  45. <syntax>
  46. <parameter name="Technology/Resource" required="false" argsep="&amp;">
  47. <argument name="Technology/Resource" required="true">
  48. <para>Specification of the device(s) to check. These must be in the format of
  49. <literal>Technology/Resource</literal>, where <replaceable>Technology</replaceable>
  50. represents a particular channel driver, and <replaceable>Resource</replaceable>
  51. represents a resource available to that particular channel driver.</para>
  52. </argument>
  53. <argument name="Technology2/Resource2" multiple="true">
  54. <para>Optional extra devices to check</para>
  55. <para>If you need more than one enter them as
  56. Technology2/Resource2&amp;Technology3/Resource3&amp;.....</para>
  57. </argument>
  58. </parameter>
  59. <parameter name="options" required="false">
  60. <optionlist>
  61. <option name="a">
  62. <para>Check for all available channels, not only the first one</para>
  63. </option>
  64. <option name="s">
  65. <para>Consider the channel unavailable if the channel is in use at all</para>
  66. </option>
  67. <option name="t" implies="s">
  68. <para>Simply checks if specified channels exist in the channel list</para>
  69. </option>
  70. </optionlist>
  71. </parameter>
  72. </syntax>
  73. <description>
  74. <para>This application will check to see if any of the specified channels are available.</para>
  75. <para>This application sets the following channel variables:</para>
  76. <variablelist>
  77. <variable name="AVAILCHAN">
  78. <para>The name of the available channel, if one exists</para>
  79. </variable>
  80. <variable name="AVAILORIGCHAN">
  81. <para>The canonical channel name that was used to create the channel</para>
  82. </variable>
  83. <variable name="AVAILSTATUS">
  84. <para>The device state for the device</para>
  85. </variable>
  86. <variable name="AVAILCAUSECODE">
  87. <para>The cause code returned when requesting the channel</para>
  88. </variable>
  89. </variablelist>
  90. </description>
  91. </application>
  92. ***/
  93. static int chanavail_exec(struct ast_channel *chan, const char *data)
  94. {
  95. int inuse = -1;
  96. int option_state = 0;
  97. int string_compare = 0;
  98. int option_all_avail = 0;
  99. int status;
  100. char *info;
  101. char trychan[512];
  102. char *rest;
  103. char *tech;
  104. char *number;
  105. struct ast_str *tmp_availchan = ast_str_alloca(2048);
  106. struct ast_str *tmp_availorig = ast_str_alloca(2048);
  107. struct ast_str *tmp_availstat = ast_str_alloca(2048);
  108. struct ast_str *tmp_availcause = ast_str_alloca(2048);
  109. struct ast_channel *tempchan;
  110. struct ast_custom_function *cdr_prop_func = ast_custom_function_find("CDR_PROP");
  111. struct ast_format_cap *caps = NULL;
  112. AST_DECLARE_APP_ARGS(args,
  113. AST_APP_ARG(reqchans);
  114. AST_APP_ARG(options);
  115. );
  116. info = ast_strdupa(data ?: "");
  117. AST_STANDARD_APP_ARGS(args, info);
  118. ao2_lock(chan);
  119. caps = ao2_bump(ast_channel_nativeformats(chan));
  120. ao2_unlock(chan);
  121. if (args.options) {
  122. if (strchr(args.options, 'a')) {
  123. option_all_avail = 1;
  124. }
  125. if (strchr(args.options, 's')) {
  126. option_state = 1;
  127. }
  128. if (strchr(args.options, 't')) {
  129. string_compare = 1;
  130. }
  131. }
  132. rest = args.reqchans;
  133. if (!rest) {
  134. rest = "";
  135. }
  136. while ((tech = strsep(&rest, "&"))) {
  137. tech = ast_strip(tech);
  138. number = strchr(tech, '/');
  139. if (!number) {
  140. if (!ast_strlen_zero(tech)) {
  141. ast_log(LOG_WARNING, "Invalid ChanIsAvail technology/resource argument: '%s'\n",
  142. tech);
  143. }
  144. ast_str_append(&tmp_availstat, 0, "%s%d",
  145. ast_str_strlen(tmp_availstat) ? "&" : "", AST_DEVICE_INVALID);
  146. continue;
  147. }
  148. *number++ = '\0';
  149. status = AST_DEVICE_UNKNOWN;
  150. if (string_compare) {
  151. /* ast_parse_device_state checks for "SIP/1234" as a channel name.
  152. ast_device_state will ask the SIP driver for the channel state. */
  153. snprintf(trychan, sizeof(trychan), "%s/%s", tech, number);
  154. status = inuse = ast_parse_device_state(trychan);
  155. } else if (option_state) {
  156. /* If the pbx says in use then don't bother trying further.
  157. This is to permit testing if someone's on a call, even if the
  158. channel can permit more calls (ie callwaiting, sip calls, etc). */
  159. snprintf(trychan, sizeof(trychan), "%s/%s", tech, number);
  160. status = inuse = ast_device_state(trychan);
  161. }
  162. ast_str_append(&tmp_availstat, 0, "%s%d", ast_str_strlen(tmp_availstat) ? "&" : "", status);
  163. if ((inuse <= (int) AST_DEVICE_NOT_INUSE)
  164. && (tempchan = ast_request(tech, caps, NULL, chan, number, &status))) {
  165. ast_str_append(&tmp_availchan, 0, "%s%s",
  166. ast_str_strlen(tmp_availchan) ? "&" : "", ast_channel_name(tempchan));
  167. ast_str_append(&tmp_availorig, 0, "%s%s/%s",
  168. ast_str_strlen(tmp_availorig) ? "&" : "", tech, number);
  169. ast_str_append(&tmp_availcause, 0, "%s%d",
  170. ast_str_strlen(tmp_availcause) ? "&" : "", status);
  171. /* Disable CDR for this temporary channel. */
  172. if (cdr_prop_func) {
  173. ast_func_write(tempchan, "CDR_PROP(disable)", "1");
  174. }
  175. ast_hangup(tempchan);
  176. tempchan = NULL;
  177. if (!option_all_avail) {
  178. break;
  179. }
  180. }
  181. }
  182. ao2_cleanup(caps);
  183. pbx_builtin_setvar_helper(chan, "AVAILCHAN", ast_str_buffer(tmp_availchan));
  184. /* Store the originally used channel too */
  185. pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", ast_str_buffer(tmp_availorig));
  186. pbx_builtin_setvar_helper(chan, "AVAILSTATUS", ast_str_buffer(tmp_availstat));
  187. pbx_builtin_setvar_helper(chan, "AVAILCAUSECODE", ast_str_buffer(tmp_availcause));
  188. return 0;
  189. }
  190. static int unload_module(void)
  191. {
  192. return ast_unregister_application(app);
  193. }
  194. static int load_module(void)
  195. {
  196. return ast_register_application_xml(app, chanavail_exec) ?
  197. AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
  198. }
  199. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Check channel availability",
  200. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  201. .load = load_module,
  202. .unload = unload_module,
  203. .optional_modules = "func_cdr"
  204. );