func_channel.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2006, Digium, Inc.
  5. *
  6. * See http://www.asterisk.org for more information about
  7. * the Asterisk project. Please do not directly contact
  8. * any of the maintainers of this project for assistance;
  9. * the project provides a web site, mailing lists and IRC
  10. * channels for your use.
  11. *
  12. * This program is free software, distributed under the terms of
  13. * the GNU General Public License Version 2. See the LICENSE file
  14. * at the top of the source tree.
  15. */
  16. /*! \file
  17. *
  18. * \brief Channel info dialplan functions
  19. *
  20. * \author Kevin P. Fleming <kpfleming@digium.com>
  21. * \author Ben Winslow
  22. *
  23. * \ingroup functions
  24. */
  25. /*** MODULEINFO
  26. <support_level>core</support_level>
  27. ***/
  28. #include "asterisk.h"
  29. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  30. #include <regex.h>
  31. #include <ctype.h>
  32. #include "asterisk/module.h"
  33. #include "asterisk/channel.h"
  34. #include "asterisk/bridge.h"
  35. #include "asterisk/pbx.h"
  36. #include "asterisk/utils.h"
  37. #include "asterisk/app.h"
  38. #include "asterisk/indications.h"
  39. #include "asterisk/stringfields.h"
  40. #include "asterisk/global_datastores.h"
  41. #include "asterisk/bridge_basic.h"
  42. #include "asterisk/bridge_after.h"
  43. #include "asterisk/max_forwards.h"
  44. /*** DOCUMENTATION
  45. <function name="CHANNELS" language="en_US">
  46. <synopsis>
  47. Gets the list of channels, optionally filtering by a regular expression.
  48. </synopsis>
  49. <syntax>
  50. <parameter name="regular_expression" />
  51. </syntax>
  52. <description>
  53. <para>Gets the list of channels, optionally filtering by a <replaceable>regular_expression</replaceable>. If
  54. no argument is provided, all known channels are returned. The
  55. <replaceable>regular_expression</replaceable> must correspond to
  56. the POSIX.2 specification, as shown in <emphasis>regex(7)</emphasis>. The list returned
  57. will be space-delimited.</para>
  58. </description>
  59. </function>
  60. <function name="MASTER_CHANNEL" language="en_US">
  61. <synopsis>
  62. Gets or sets variables on the master channel
  63. </synopsis>
  64. <description>
  65. <para>Allows access to the oldest channel associated with the current
  66. channel if it still exists. If the channel is the master channel or
  67. the master channel no longer exists then access local channel variables
  68. instead. In other words, the master channel is the channel identified by
  69. the channel's linkedid.</para>
  70. </description>
  71. </function>
  72. <function name="CHANNEL" language="en_US">
  73. <synopsis>
  74. Gets/sets various pieces of information about the channel.
  75. </synopsis>
  76. <syntax>
  77. <parameter name="item" required="true">
  78. <para>Standard items (provided by all channel technologies) are:</para>
  79. <enumlist>
  80. <enum name="amaflags">
  81. <para>R/W the Automatic Message Accounting (AMA) flags on the channel.
  82. When read from a channel, the integer value will always be returned.
  83. When written to a channel, both the string format or integer value
  84. is accepted.</para>
  85. <enumlist>
  86. <enum name="1"><para><literal>OMIT</literal></para></enum>
  87. <enum name="2"><para><literal>BILLING</literal></para></enum>
  88. <enum name="3"><para><literal>DOCUMENTATION</literal></para></enum>
  89. </enumlist>
  90. </enum>
  91. <enum name="accountcode">
  92. <para>R/W the channel's account code.</para>
  93. </enum>
  94. <enum name="audioreadformat">
  95. <para>R/O format currently being read.</para>
  96. </enum>
  97. <enum name="audionativeformat">
  98. <para>R/O format used natively for audio.</para>
  99. </enum>
  100. <enum name="audiowriteformat">
  101. <para>R/O format currently being written.</para>
  102. </enum>
  103. <enum name="dtmf_features">
  104. <para>R/W The channel's DTMF bridge features.
  105. May include one or more of 'T' 'K' 'H' 'W' and 'X' in a similar manner to options
  106. in the <literal>Dial</literal> application. When setting it, the features string
  107. must be all upper case.</para>
  108. </enum>
  109. <enum name="callgroup">
  110. <para>R/W numeric call pickup groups that this channel is a member.</para>
  111. </enum>
  112. <enum name="pickupgroup">
  113. <para>R/W numeric call pickup groups this channel can pickup.</para>
  114. </enum>
  115. <enum name="namedcallgroup">
  116. <para>R/W named call pickup groups that this channel is a member.</para>
  117. </enum>
  118. <enum name="namedpickupgroup">
  119. <para>R/W named call pickup groups this channel can pickup.</para>
  120. </enum>
  121. <enum name="channeltype">
  122. <para>R/O technology used for channel.</para>
  123. </enum>
  124. <enum name="checkhangup">
  125. <para>R/O Whether the channel is hanging up (1/0)</para>
  126. </enum>
  127. <enum name="after_bridge_goto">
  128. <para>R/W the parseable goto string indicating where the channel is
  129. expected to return to in the PBX after exiting the next bridge it joins
  130. on the condition that it doesn't hang up. The parseable goto string uses
  131. the same syntax as the <literal>Goto</literal> application.</para>
  132. </enum>
  133. <enum name="hangup_handler_pop">
  134. <para>W/O Replace the most recently added hangup handler
  135. with a new hangup handler on the channel if supplied. The
  136. assigned string is passed to the Gosub application when
  137. the channel is hung up. Any optionally omitted context
  138. and exten are supplied by the channel pushing the handler
  139. before it is pushed.</para>
  140. </enum>
  141. <enum name="hangup_handler_push">
  142. <para>W/O Push a hangup handler onto the channel hangup
  143. handler stack. The assigned string is passed to the
  144. Gosub application when the channel is hung up. Any
  145. optionally omitted context and exten are supplied by the
  146. channel pushing the handler before it is pushed.</para>
  147. </enum>
  148. <enum name="hangup_handler_wipe">
  149. <para>W/O Wipe the entire hangup handler stack and replace
  150. with a new hangup handler on the channel if supplied. The
  151. assigned string is passed to the Gosub application when
  152. the channel is hung up. Any optionally omitted context
  153. and exten are supplied by the channel pushing the handler
  154. before it is pushed.</para>
  155. </enum>
  156. <enum name="language">
  157. <para>R/W language for sounds played.</para>
  158. </enum>
  159. <enum name="musicclass">
  160. <para>R/W class (from musiconhold.conf) for hold music.</para>
  161. </enum>
  162. <enum name="name">
  163. <para>The name of the channel</para>
  164. </enum>
  165. <enum name="parkinglot">
  166. <para>R/W parkinglot for parking.</para>
  167. </enum>
  168. <enum name="rxgain">
  169. <para>R/W set rxgain level on channel drivers that support it.</para>
  170. </enum>
  171. <enum name="secure_bridge_signaling">
  172. <para>Whether or not channels bridged to this channel require secure signaling (1/0)</para>
  173. </enum>
  174. <enum name="secure_bridge_media">
  175. <para>Whether or not channels bridged to this channel require secure media (1/0)</para>
  176. </enum>
  177. <enum name="state">
  178. <para>R/O state of the channel</para>
  179. </enum>
  180. <enum name="tonezone">
  181. <para>R/W zone for indications played</para>
  182. </enum>
  183. <enum name="transfercapability">
  184. <para>R/W ISDN Transfer Capability, one of:</para>
  185. <enumlist>
  186. <enum name="SPEECH" />
  187. <enum name="DIGITAL" />
  188. <enum name="RESTRICTED_DIGITAL" />
  189. <enum name="3K1AUDIO" />
  190. <enum name="DIGITAL_W_TONES" />
  191. <enum name="VIDEO" />
  192. </enumlist>
  193. </enum>
  194. <enum name="txgain">
  195. <para>R/W set txgain level on channel drivers that support it.</para>
  196. </enum>
  197. <enum name="videonativeformat">
  198. <para>R/O format used natively for video</para>
  199. </enum>
  200. <enum name="hangupsource">
  201. <para>R/W returns the channel responsible for hangup.</para>
  202. </enum>
  203. <enum name="appname">
  204. <para>R/O returns the internal application name.</para>
  205. </enum>
  206. <enum name="appdata">
  207. <para>R/O returns the application data if available.</para>
  208. </enum>
  209. <enum name="exten">
  210. <para>R/O returns the extension for an outbound channel.</para>
  211. </enum>
  212. <enum name="context">
  213. <para>R/O returns the context for an outbound channel.</para>
  214. </enum>
  215. <enum name="channame">
  216. <para>R/O returns the channel name for an outbound channel.</para>
  217. </enum>
  218. <enum name="uniqueid">
  219. <para>R/O returns the channel uniqueid.</para>
  220. </enum>
  221. <enum name="linkedid">
  222. <para>R/O returns the linkedid if available, otherwise returns the uniqueid.</para>
  223. </enum>
  224. <enum name="max_forwards">
  225. <para>R/W The maximum number of forwards allowed.</para>
  226. </enum>
  227. <enum name="callid">
  228. <para>R/O Call identifier log tag associated with the channel
  229. e.g., <literal>[C-00000000]</literal>.</para>
  230. </enum>
  231. </enumlist>
  232. <xi:include xpointer="xpointer(/docs/info[@name='CHANNEL'])" />
  233. </parameter>
  234. </syntax>
  235. <description>
  236. <para>Gets/sets various pieces of information about the channel, additional <replaceable>item</replaceable> may
  237. be available from the channel driver; see its documentation for details. Any <replaceable>item</replaceable>
  238. requested that is not available on the current channel will return an empty string.</para>
  239. <example title="Standard CHANNEL item examples">
  240. ; Push a hangup handler subroutine existing at dialplan
  241. ; location default,s,1 onto the current channel
  242. same => n,Set(CHANNEL(hangup_handler_push)=default,s,1)
  243. ; Set the current tonezone to Germany (de)
  244. same => n,Set(CHANNEL(tonezone)=de)
  245. ; Set the allowed maximum number of forwarding attempts
  246. same => n,Set(CHANNEL(max_forwards)=10)
  247. ; If this channel is ejected from its next bridge, and if
  248. ; the channel is not hung up, begin executing dialplan at
  249. ; location default,after-bridge,1
  250. same => n,Set(CHANNEL(after_bridge_goto)=default,after-bridge,1)
  251. ; Log the current state of the channel
  252. same => n,Log(NOTICE, This channel is: ${CHANNEL(state)})
  253. </example>
  254. <xi:include xpointer="xpointer(/docs/info[@name='CHANNEL_EXAMPLES'])" />
  255. </description>
  256. </function>
  257. ***/
  258. #define locked_copy_string(chan, dest, source, len) \
  259. do { \
  260. ast_channel_lock(chan); \
  261. ast_copy_string(dest, source, len); \
  262. ast_channel_unlock(chan); \
  263. } while (0)
  264. #define locked_string_field_set(chan, field, source) \
  265. do { \
  266. ast_channel_lock(chan); \
  267. ast_channel_##field##_set(chan, source); \
  268. ast_channel_unlock(chan); \
  269. } while (0)
  270. static const char * const transfercapability_table[0x20] = {
  271. "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
  272. "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
  273. "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK",
  274. "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", };
  275. static int func_channel_read(struct ast_channel *chan, const char *function,
  276. char *data, char *buf, size_t len)
  277. {
  278. int ret = 0;
  279. struct ast_format_cap *tmpcap;
  280. if (!chan) {
  281. ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
  282. return -1;
  283. }
  284. if (!strcasecmp(data, "audionativeformat")) {
  285. tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
  286. if (tmpcap) {
  287. struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
  288. ast_channel_lock(chan);
  289. ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO);
  290. ast_channel_unlock(chan);
  291. ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
  292. ao2_ref(tmpcap, -1);
  293. }
  294. } else if (!strcasecmp(data, "videonativeformat")) {
  295. tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
  296. if (tmpcap) {
  297. struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
  298. ast_channel_lock(chan);
  299. ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO);
  300. ast_channel_unlock(chan);
  301. ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
  302. ao2_ref(tmpcap, -1);
  303. }
  304. } else if (!strcasecmp(data, "audioreadformat")) {
  305. locked_copy_string(chan, buf, ast_format_get_name(ast_channel_readformat(chan)), len);
  306. } else if (!strcasecmp(data, "audiowriteformat")) {
  307. locked_copy_string(chan, buf, ast_format_get_name(ast_channel_writeformat(chan)), len);
  308. } else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) {
  309. locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len);
  310. } else if (!strcasecmp(data, "dtmf_features")) {
  311. if (ast_bridge_features_ds_get_string(chan, buf, len)) {
  312. buf[0] = '\0';
  313. }
  314. } else if (!strcasecmp(data, "language"))
  315. locked_copy_string(chan, buf, ast_channel_language(chan), len);
  316. else if (!strcasecmp(data, "musicclass"))
  317. locked_copy_string(chan, buf, ast_channel_musicclass(chan), len);
  318. else if (!strcasecmp(data, "name")) {
  319. locked_copy_string(chan, buf, ast_channel_name(chan), len);
  320. } else if (!strcasecmp(data, "parkinglot"))
  321. locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len);
  322. else if (!strcasecmp(data, "state"))
  323. locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len);
  324. else if (!strcasecmp(data, "channeltype"))
  325. locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len);
  326. else if (!strcasecmp(data, "accountcode"))
  327. locked_copy_string(chan, buf, ast_channel_accountcode(chan), len);
  328. else if (!strcasecmp(data, "checkhangup")) {
  329. locked_copy_string(chan, buf, ast_check_hangup(chan) ? "1" : "0", len);
  330. } else if (!strcasecmp(data, "peeraccount"))
  331. locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len);
  332. else if (!strcasecmp(data, "hangupsource"))
  333. locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len);
  334. else if (!strcasecmp(data, "appname") && ast_channel_appl(chan))
  335. locked_copy_string(chan, buf, ast_channel_appl(chan), len);
  336. else if (!strcasecmp(data, "appdata") && ast_channel_data(chan))
  337. locked_copy_string(chan, buf, ast_channel_data(chan), len);
  338. else if (!strcasecmp(data, "exten") && ast_channel_data(chan))
  339. locked_copy_string(chan, buf, ast_channel_exten(chan), len);
  340. else if (!strcasecmp(data, "context") && ast_channel_data(chan))
  341. locked_copy_string(chan, buf, ast_channel_context(chan), len);
  342. else if (!strcasecmp(data, "userfield") && ast_channel_data(chan))
  343. locked_copy_string(chan, buf, ast_channel_userfield(chan), len);
  344. else if (!strcasecmp(data, "channame") && ast_channel_data(chan))
  345. locked_copy_string(chan, buf, ast_channel_name(chan), len);
  346. else if (!strcasecmp(data, "linkedid")) {
  347. ast_channel_lock(chan);
  348. if (ast_strlen_zero(ast_channel_linkedid(chan))) {
  349. /* fall back on the channel's uniqueid if linkedid is unset */
  350. ast_copy_string(buf, ast_channel_uniqueid(chan), len);
  351. }
  352. else {
  353. ast_copy_string(buf, ast_channel_linkedid(chan), len);
  354. }
  355. ast_channel_unlock(chan);
  356. } else if (!strcasecmp(data, "peer")) {
  357. struct ast_channel *peer;
  358. peer = ast_channel_bridge_peer(chan);
  359. if (peer) {
  360. /* Only real channels could have a bridge peer this way. */
  361. ast_channel_lock(peer);
  362. ast_copy_string(buf, ast_channel_name(peer), len);
  363. ast_channel_unlock(peer);
  364. ast_channel_unref(peer);
  365. } else {
  366. buf[0] = '\0';
  367. ast_channel_lock(chan);
  368. if (!ast_channel_tech(chan)) {
  369. const char *pname;
  370. /*
  371. * A dummy channel can still pass along bridged peer info
  372. * via the BRIDGEPEER variable.
  373. *
  374. * A horrible kludge, but... how else?
  375. */
  376. pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
  377. if (!ast_strlen_zero(pname)) {
  378. ast_copy_string(buf, pname, len);
  379. }
  380. }
  381. ast_channel_unlock(chan);
  382. }
  383. } else if (!strcasecmp(data, "uniqueid")) {
  384. locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len);
  385. } else if (!strcasecmp(data, "transfercapability")) {
  386. locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len);
  387. } else if (!strcasecmp(data, "callgroup")) {
  388. char groupbuf[256];
  389. locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len);
  390. } else if (!strcasecmp(data, "pickupgroup")) {
  391. char groupbuf[256];
  392. locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len);
  393. } else if (!strcasecmp(data, "namedcallgroup")) {
  394. struct ast_str *tmp_str = ast_str_alloca(1024);
  395. locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_callgroups(chan)), len);
  396. } else if (!strcasecmp(data, "namedpickupgroup")) {
  397. struct ast_str *tmp_str = ast_str_alloca(1024);
  398. locked_copy_string(chan, buf, ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
  399. } else if (!strcasecmp(data, "after_bridge_goto")) {
  400. ast_bridge_read_after_goto(chan, buf, len);
  401. } else if (!strcasecmp(data, "amaflags")) {
  402. ast_channel_lock(chan);
  403. snprintf(buf, len, "%u", ast_channel_amaflags(chan));
  404. ast_channel_unlock(chan);
  405. } else if (!strncasecmp(data, "secure_bridge_", 14)) {
  406. struct ast_datastore *ds;
  407. buf[0] = '\0';
  408. ast_channel_lock(chan);
  409. if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
  410. struct ast_secure_call_store *encrypt = ds->data;
  411. if (!strcasecmp(data, "secure_bridge_signaling")) {
  412. snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
  413. } else if (!strcasecmp(data, "secure_bridge_media")) {
  414. snprintf(buf, len, "%s", encrypt->media ? "1" : "");
  415. }
  416. }
  417. ast_channel_unlock(chan);
  418. } else if (!strcasecmp(data, "max_forwards")) {
  419. ast_channel_lock(chan);
  420. snprintf(buf, len, "%d", ast_max_forwards_get(chan));
  421. ast_channel_unlock(chan);
  422. } else if (!strcasecmp(data, "callid")) {
  423. struct ast_callid *callid;
  424. buf[0] = '\0';
  425. ast_channel_lock(chan);
  426. callid = ast_channel_callid(chan);
  427. if (callid) {
  428. ast_callid_strnprint(buf, len, callid);
  429. ast_callid_unref(callid);
  430. }
  431. ast_channel_unlock(chan);
  432. } else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
  433. ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
  434. ret = -1;
  435. }
  436. return ret;
  437. }
  438. static int func_channel_write_real(struct ast_channel *chan, const char *function,
  439. char *data, const char *value)
  440. {
  441. int ret = 0;
  442. signed char gainset;
  443. if (!strcasecmp(data, "language"))
  444. locked_string_field_set(chan, language, value);
  445. else if (!strcasecmp(data, "parkinglot"))
  446. locked_string_field_set(chan, parkinglot, value);
  447. else if (!strcasecmp(data, "musicclass"))
  448. locked_string_field_set(chan, musicclass, value);
  449. else if (!strcasecmp(data, "accountcode"))
  450. locked_string_field_set(chan, accountcode, value);
  451. else if (!strcasecmp(data, "userfield"))
  452. locked_string_field_set(chan, userfield, value);
  453. else if (!strcasecmp(data, "after_bridge_goto")) {
  454. if (ast_strlen_zero(value)) {
  455. ast_bridge_discard_after_goto(chan);
  456. } else {
  457. ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
  458. }
  459. } else if (!strcasecmp(data, "amaflags")) {
  460. int amaflags;
  461. if (isdigit(*value)) {
  462. if (sscanf(value, "%30d", &amaflags) != 1) {
  463. amaflags = AST_AMA_NONE;
  464. }
  465. } else {
  466. amaflags = ast_channel_string2amaflag(value);
  467. }
  468. ast_channel_lock(chan);
  469. ast_channel_amaflags_set(chan, amaflags);
  470. ast_channel_unlock(chan);
  471. } else if (!strcasecmp(data, "peeraccount"))
  472. locked_string_field_set(chan, peeraccount, value);
  473. else if (!strcasecmp(data, "hangupsource"))
  474. /* XXX - should we be forcing this here? */
  475. ast_set_hangupsource(chan, value, 0);
  476. else if (!strcasecmp(data, "tonezone")) {
  477. struct ast_tone_zone *new_zone;
  478. if (!(new_zone = ast_get_indication_zone(value))) {
  479. ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
  480. ret = -1;
  481. } else {
  482. ast_channel_lock(chan);
  483. if (ast_channel_zone(chan)) {
  484. ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
  485. }
  486. ast_channel_zone_set(chan, ast_tone_zone_ref(new_zone));
  487. ast_channel_unlock(chan);
  488. new_zone = ast_tone_zone_unref(new_zone);
  489. }
  490. } else if (!strcasecmp(data, "dtmf_features")) {
  491. ret = ast_bridge_features_ds_set_string(chan, value);
  492. } else if (!strcasecmp(data, "callgroup")) {
  493. ast_channel_lock(chan);
  494. ast_channel_callgroup_set(chan, ast_get_group(value));
  495. ast_channel_unlock(chan);
  496. } else if (!strcasecmp(data, "pickupgroup")) {
  497. ast_channel_lock(chan);
  498. ast_channel_pickupgroup_set(chan, ast_get_group(value));
  499. ast_channel_unlock(chan);
  500. } else if (!strcasecmp(data, "namedcallgroup")) {
  501. struct ast_namedgroups *groups = ast_get_namedgroups(value);
  502. ast_channel_lock(chan);
  503. ast_channel_named_callgroups_set(chan, groups);
  504. ast_channel_unlock(chan);
  505. ast_unref_namedgroups(groups);
  506. } else if (!strcasecmp(data, "namedpickupgroup")) {
  507. struct ast_namedgroups *groups = ast_get_namedgroups(value);
  508. ast_channel_lock(chan);
  509. ast_channel_named_pickupgroups_set(chan, groups);
  510. ast_channel_unlock(chan);
  511. ast_unref_namedgroups(groups);
  512. } else if (!strcasecmp(data, "txgain")) {
  513. sscanf(value, "%4hhd", &gainset);
  514. ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
  515. } else if (!strcasecmp(data, "rxgain")) {
  516. sscanf(value, "%4hhd", &gainset);
  517. ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
  518. } else if (!strcasecmp(data, "transfercapability")) {
  519. unsigned short i;
  520. ast_channel_lock(chan);
  521. for (i = 0; i < 0x20; i++) {
  522. if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
  523. ast_channel_transfercapability_set(chan, i);
  524. break;
  525. }
  526. }
  527. ast_channel_unlock(chan);
  528. } else if (!strcasecmp(data, "hangup_handler_pop")) {
  529. /* Pop one hangup handler before pushing the new handler. */
  530. ast_pbx_hangup_handler_pop(chan);
  531. ast_pbx_hangup_handler_push(chan, value);
  532. } else if (!strcasecmp(data, "hangup_handler_push")) {
  533. ast_pbx_hangup_handler_push(chan, value);
  534. } else if (!strcasecmp(data, "hangup_handler_wipe")) {
  535. /* Pop all hangup handlers before pushing the new handler. */
  536. while (ast_pbx_hangup_handler_pop(chan)) {
  537. }
  538. ast_pbx_hangup_handler_push(chan, value);
  539. } else if (!strncasecmp(data, "secure_bridge_", 14)) {
  540. struct ast_datastore *ds;
  541. struct ast_secure_call_store *store;
  542. if (!chan || !value) {
  543. return -1;
  544. }
  545. ast_channel_lock(chan);
  546. if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
  547. if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
  548. ast_channel_unlock(chan);
  549. return -1;
  550. }
  551. if (!(store = ast_calloc(1, sizeof(*store)))) {
  552. ast_channel_unlock(chan);
  553. ast_free(ds);
  554. return -1;
  555. }
  556. ds->data = store;
  557. ast_channel_datastore_add(chan, ds);
  558. } else {
  559. store = ds->data;
  560. }
  561. if (!strcasecmp(data, "secure_bridge_signaling")) {
  562. store->signaling = ast_true(value) ? 1 : 0;
  563. } else if (!strcasecmp(data, "secure_bridge_media")) {
  564. store->media = ast_true(value) ? 1 : 0;
  565. }
  566. ast_channel_unlock(chan);
  567. } else if (!strcasecmp(data, "max_forwards")) {
  568. int max_forwards;
  569. if (sscanf(value, "%d", &max_forwards) != 1) {
  570. ast_log(LOG_WARNING, "Unable to set max forwards to '%s'\n", value);
  571. ret = -1;
  572. } else {
  573. ast_channel_lock(chan);
  574. ret = ast_max_forwards_set(chan, max_forwards);
  575. ast_channel_unlock(chan);
  576. }
  577. } else if (!ast_channel_tech(chan)->func_channel_write
  578. || ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
  579. ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
  580. data);
  581. ret = -1;
  582. }
  583. return ret;
  584. }
  585. static int func_channel_write(struct ast_channel *chan, const char *function, char *data, const char *value)
  586. {
  587. int res;
  588. ast_chan_write_info_t write_info = {
  589. .version = AST_CHAN_WRITE_INFO_T_VERSION,
  590. .write_fn = func_channel_write_real,
  591. .chan = chan,
  592. .function = function,
  593. .data = data,
  594. .value = value,
  595. };
  596. if (!chan) {
  597. ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
  598. return -1;
  599. }
  600. res = func_channel_write_real(chan, function, data, value);
  601. ast_channel_setoption(chan, AST_OPTION_CHANNEL_WRITE, &write_info, sizeof(write_info), 0);
  602. return res;
  603. }
  604. static struct ast_custom_function channel_function = {
  605. .name = "CHANNEL",
  606. .read = func_channel_read,
  607. .write = func_channel_write,
  608. };
  609. static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
  610. {
  611. struct ast_channel *c = NULL;
  612. regex_t re;
  613. int res;
  614. size_t buflen = 0;
  615. struct ast_channel_iterator *iter;
  616. buf[0] = '\0';
  617. if (!ast_strlen_zero(data)) {
  618. if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
  619. regerror(res, &re, buf, maxlen);
  620. ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
  621. return -1;
  622. }
  623. }
  624. if (!(iter = ast_channel_iterator_all_new())) {
  625. if (!ast_strlen_zero(data)) {
  626. regfree(&re);
  627. }
  628. return -1;
  629. }
  630. while ((c = ast_channel_iterator_next(iter))) {
  631. ast_channel_lock(c);
  632. if (ast_strlen_zero(data) || regexec(&re, ast_channel_name(c), 0, NULL, 0) == 0) {
  633. size_t namelen = strlen(ast_channel_name(c));
  634. if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
  635. if (!ast_strlen_zero(buf)) {
  636. strcat(buf, " ");
  637. buflen++;
  638. }
  639. strcat(buf, ast_channel_name(c));
  640. buflen += namelen;
  641. } else {
  642. ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space. Output will be truncated!\n");
  643. }
  644. }
  645. ast_channel_unlock(c);
  646. c = ast_channel_unref(c);
  647. }
  648. ast_channel_iterator_destroy(iter);
  649. if (!ast_strlen_zero(data)) {
  650. regfree(&re);
  651. }
  652. return 0;
  653. }
  654. static struct ast_custom_function channels_function = {
  655. .name = "CHANNELS",
  656. .read = func_channels_read,
  657. };
  658. static int func_mchan_read(struct ast_channel *chan, const char *function,
  659. char *data, struct ast_str **buf, ssize_t len)
  660. {
  661. struct ast_channel *mchan;
  662. char *template = ast_alloca(4 + strlen(data));
  663. if (!chan) {
  664. ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
  665. return -1;
  666. }
  667. mchan = ast_channel_get_by_name(ast_channel_linkedid(chan));
  668. sprintf(template, "${%s}", data); /* SAFE */
  669. ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template);
  670. if (mchan) {
  671. ast_channel_unref(mchan);
  672. }
  673. return 0;
  674. }
  675. static int func_mchan_write(struct ast_channel *chan, const char *function,
  676. char *data, const char *value)
  677. {
  678. struct ast_channel *mchan;
  679. if (!chan) {
  680. ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
  681. return -1;
  682. }
  683. mchan = ast_channel_get_by_name(ast_channel_linkedid(chan));
  684. pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value);
  685. if (mchan) {
  686. ast_channel_unref(mchan);
  687. }
  688. return 0;
  689. }
  690. static struct ast_custom_function mchan_function = {
  691. .name = "MASTER_CHANNEL",
  692. .read2 = func_mchan_read,
  693. .write = func_mchan_write,
  694. };
  695. static int unload_module(void)
  696. {
  697. int res = 0;
  698. res |= ast_custom_function_unregister(&channel_function);
  699. res |= ast_custom_function_unregister(&channels_function);
  700. res |= ast_custom_function_unregister(&mchan_function);
  701. return res;
  702. }
  703. static int load_module(void)
  704. {
  705. int res = 0;
  706. res |= ast_custom_function_register(&channel_function);
  707. res |= ast_custom_function_register(&channels_function);
  708. res |= ast_custom_function_register(&mchan_function);
  709. return res;
  710. }
  711. AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan functions");