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