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