Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
pbx_variables.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2016, CFWare, LLC
5 *
6 * Corey Farrell <git@cfware.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief PBX variables routines.
22 *
23 * \author Corey Farrell <git@cfware.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/_private.h"
33#include "asterisk/app.h"
34#include "asterisk/ast_expr.h"
35#include "asterisk/chanvars.h"
36#include "asterisk/cli.h"
38#include "asterisk/lock.h"
39#include "asterisk/module.h"
40#include "asterisk/paths.h"
41#include "asterisk/pbx.h"
43#include "asterisk/test.h"
44#include "pbx_private.h"
45
46/*** DOCUMENTATION
47 <application name="Set" language="en_US">
48 <synopsis>
49 Set channel variable or function value.
50 </synopsis>
51 <syntax argsep="=">
52 <parameter name="name" required="true" />
53 <parameter name="value" required="true" />
54 </syntax>
55 <description>
56 <para>This function can be used to set the value of channel variables or dialplan functions.
57 When setting variables, if the variable name is prefixed with <literal>_</literal>,
58 the variable will be inherited into channels created from the current channel.
59 If the variable name is prefixed with <literal>__</literal>, the variable will be
60 inherited into channels created from the current channel and all children channels.</para>
61 <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
62 a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
63 the behavior of this app changes, and strips surrounding quotes from the right hand side as
64 it did previously in 1.4.
65 The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
66 were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
67 protect separators and quotes in various database access strings has been greatly
68 reduced by these changes.</para></note>
69 </description>
70 <see-also>
71 <ref type="application">MSet</ref>
72 <ref type="function">GLOBAL</ref>
73 <ref type="function">SET</ref>
74 <ref type="function">ENV</ref>
75 </see-also>
76 </application>
77 <application name="MSet" language="en_US">
78 <synopsis>
79 Set channel variable(s) or function value(s).
80 </synopsis>
81 <syntax>
82 <parameter name="set1" required="true" argsep="=">
83 <argument name="name1" required="true" />
84 <argument name="value1" required="true" />
85 </parameter>
86 <parameter name="set2" multiple="true" argsep="=">
87 <argument name="name2" required="true" />
88 <argument name="value2" required="true" />
89 </parameter>
90 </syntax>
91 <description>
92 <para>This function can be used to set the value of channel variables or dialplan functions.
93 When setting variables, if the variable name is prefixed with <literal>_</literal>,
94 the variable will be inherited into channels created from the current channel
95 If the variable name is prefixed with <literal>__</literal>, the variable will be
96 inherited into channels created from the current channel and all children channels.
97 MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
98 prone to doing things that you may not expect. For example, it strips surrounding
99 double-quotes from the right-hand side (value). If you need to put a separator
100 character (comma or vert-bar), you will need to escape them by inserting a backslash
101 before them. Avoid its use if possible.</para>
102 <para>This application allows up to 99 variables to be set at once.</para>
103 </description>
104 <see-also>
105 <ref type="application">Set</ref>
106 </see-also>
107 </application>
108 ***/
109
112
113/*!
114 * \brief extract offset:length from variable name.
115 * \return 1 if there is a offset:length part, which is
116 * trimmed off (values go into variables)
117 */
118static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
119{
120 int parens = 0;
121
122 *offset = 0;
123 *length = INT_MAX;
124 *isfunc = 0;
125 for (; *var; var++) {
126 if (*var == '(') {
127 (*isfunc)++;
128 parens++;
129 } else if (*var == ')') {
130 parens--;
131 } else if (*var == ':' && parens == 0) {
132 *var++ = '\0';
133 sscanf(var, "%30d:%30d", offset, length);
134 return 1; /* offset:length valid */
135 }
136 }
137 return 0;
138}
139
140/*!
141 *\brief takes a substring. It is ok to call with value == workspace.
142 * \param value
143 * \param offset < 0 means start from the end of the string and set the beginning
144 * to be that many characters back.
145 * \param length is the length of the substring, a value less than 0 means to leave
146 * that many off the end.
147 * \param workspace
148 * \param workspace_len
149 * Always return a copy in workspace.
150 */
151static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
152{
153 char *ret = workspace;
154 int lr; /* length of the input string after the copy */
155
156 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
157
158 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
159
160 /* Quick check if no need to do anything */
161 if (offset == 0 && length >= lr) /* take the whole string */
162 return ret;
163
164 if (offset < 0) { /* translate negative offset into positive ones */
165 offset = lr + offset;
166 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
167 offset = 0;
168 }
169
170 /* too large offset result in empty string so we know what to return */
171 if (offset >= lr)
172 return ret + lr; /* the final '\0' */
173
174 ret += offset; /* move to the start position */
175 if (length >= 0 && length < lr - offset) /* truncate if necessary */
176 ret[length] = '\0';
177 else if (length < 0) {
178 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
179 ret[lr + length - offset] = '\0';
180 else
181 ret[0] = '\0';
182 }
183
184 return ret;
185}
186
187static const char *ast_str_substring(struct ast_str *value, int offset, int length)
188{
189 int lr; /* length of the input string after the copy */
190
191 lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
192
193 ast_assert(lr == strlen(ast_str_buffer(value))); /* ast_str_strlen should always agree with strlen */
194
195 /* Quick check if no need to do anything */
196 if (offset == 0 && length >= lr) /* take the whole string */
197 return ast_str_buffer(value);
198
199 if (offset < 0) { /* translate negative offset into positive ones */
200 offset = lr + offset;
201 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
202 offset = 0;
203 }
204
205 /* too large offset result in empty string so we know what to return */
206 if (offset >= lr) {
208 return ast_str_buffer(value);
209 }
210
211 if (offset > 0) {
212 /* Go ahead and chop off the beginning */
213 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
214 lr -= offset;
215 }
216
217 if (length >= 0 && length < lr) { /* truncate if necessary */
218 ast_str_truncate(value, length);
219 } else if (length < 0) {
220 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
221 ast_str_truncate(value, lr + length);
222 } else {
224 }
225 } else {
226 /* Nothing to do, but update the buffer length */
228 }
229
230 return ast_str_buffer(value);
231}
232
233/*! \brief Support for Asterisk built-in variables in the dialplan
234
235\note See also
236 - \ref AstVar Channel variables
237 - \ref AstCauses The HANGUPCAUSE variable
238 */
239void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
240{
241 struct ast_str *str = ast_str_create(16);
242 const char *cret;
243
244 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
245 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
246 *ret = cret ? workspace : NULL;
247 ast_free(str);
248}
249
250const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
251{
252 const char not_found = '\0';
253 char *tmpvar;
254 const char *ret;
255 const char *s; /* the result */
256 int offset, length;
257 int i, need_substring;
258 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
259 char workspace[20];
260
261 if (c) {
263 places[0] = ast_channel_varshead(c);
264 }
265 /*
266 * Make a copy of var because parse_variable_name() modifies the string.
267 * Then if called directly, we might need to run substring() on the result;
268 * remember this for later in 'need_substring', 'offset' and 'length'
269 */
270 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
271 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
272
273 /*
274 * Look first into predefined variables, then into variable lists.
275 * Variable 's' points to the result, according to the following rules:
276 * s == &not_found (set at the beginning) means that we did not find a
277 * matching variable and need to look into more places.
278 * If s != &not_found, s is a valid result string as follows:
279 * s = NULL if the variable does not have a value;
280 * you typically do this when looking for an unset predefined variable.
281 * s = workspace if the result has been assembled there;
282 * typically done when the result is built e.g. with an snprintf(),
283 * so we don't need to do an additional copy.
284 * s != workspace in case we have a string, that needs to be copied
285 * (the ast_copy_string is done once for all at the end).
286 * Typically done when the result is already available in some string.
287 */
288 s = &not_found; /* default value */
289 if (c) { /* This group requires a valid channel */
290 /* Names with common parts are looked up a piece at a time using strncmp. */
291 if (!strncmp(var, "CALL", 4)) {
292 if (!strncmp(var + 4, "ING", 3)) {
293 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
294 ast_str_set(str, maxlen, "%d",
296 s = ast_str_buffer(*str);
297 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
298 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
299 s = ast_str_buffer(*str);
300 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
301 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
302 s = ast_str_buffer(*str);
303 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
304 ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
305 s = ast_str_buffer(*str);
306 }
307 }
308 } else if (!strcmp(var, "HINT")) {
310 } else if (!strcmp(var, "HINTNAME")) {
312 } else if (!strcmp(var, "EXTEN")) {
313 s = ast_channel_exten(c);
314 } else if (!strcmp(var, "CONTEXT")) {
316 } else if (!strcmp(var, "PRIORITY")) {
317 ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
318 s = ast_str_buffer(*str);
319 } else if (!strcmp(var, "CHANNEL")) {
320 s = ast_channel_name(c);
321 } else if (!strcmp(var, "UNIQUEID")) {
323 } else if (!strcmp(var, "HANGUPCAUSE")) {
324 ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
325 s = ast_str_buffer(*str);
326 }
327 }
328 if (s == &not_found) { /* look for more */
329 if (!strcmp(var, "EPOCH")) {
330 ast_str_set(str, maxlen, "%d", (int) time(NULL));
331 s = ast_str_buffer(*str);
332 } else if (!strcmp(var, "SYSTEMNAME")) {
334 } else if (!strcmp(var, "ASTCACHEDIR")) {
336 } else if (!strcmp(var, "ASTETCDIR")) {
338 } else if (!strcmp(var, "ASTMODDIR")) {
340 } else if (!strcmp(var, "ASTVARLIBDIR")) {
342 } else if (!strcmp(var, "ASTDBDIR")) {
344 } else if (!strcmp(var, "ASTKEYDIR")) {
346 } else if (!strcmp(var, "ASTDATADIR")) {
348 } else if (!strcmp(var, "ASTAGIDIR")) {
350 } else if (!strcmp(var, "ASTSPOOLDIR")) {
352 } else if (!strcmp(var, "ASTRUNDIR")) {
354 } else if (!strcmp(var, "ASTLOGDIR")) {
356 } else if (!strcmp(var, "ASTSBINDIR")) {
358 } else if (!strcmp(var, "ENTITYID")) {
359 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
360 s = workspace;
361 }
362 }
363 /* if not found, look into chanvars or global vars */
364 for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
365 struct ast_var_t *variables;
366 if (!places[i])
367 continue;
368 if (places[i] == &globals)
370 AST_LIST_TRAVERSE(places[i], variables, entries) {
371 if (!strcmp(ast_var_name(variables), var)) {
372 s = ast_var_value(variables);
373 break;
374 }
375 }
376 if (places[i] == &globals)
378 }
379 if (s == &not_found || s == NULL) {
380 ast_debug(5, "Result of '%s' is NULL\n", var);
381 ret = NULL;
382 } else {
383 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
384 if (s != ast_str_buffer(*str)) {
385 ast_str_set(str, maxlen, "%s", s);
386 }
387 ret = ast_str_buffer(*str);
388 if (need_substring) {
389 ret = ast_str_substring(*str, offset, length);
390 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
391 }
392 }
393
394 if (c) {
396 }
397 return ret;
398}
399
400void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,
401 struct ast_channel *c, struct varshead *headp, const char *templ,
402 size_t *used, int use_both)
403{
404 /* Substitutes variables into buf, based on string templ */
405 const char *whereweare;
406 struct ast_str *substr1 = ast_str_create(16);
407 struct ast_str *substr2 = NULL;
408 struct ast_str *substr3 = ast_str_create(16);
409
411
412 if (!substr1 || !substr3) {
413 if (used) {
414 *used = ast_str_strlen(*buf);
415 }
416 ast_free(substr1);
417 ast_free(substr3);
418 return;
419 }
420
421 whereweare = templ;
422 while (!ast_strlen_zero(whereweare)) {
423 const char *nextvar = NULL;
424 const char *nextexp = NULL;
425 const char *nextthing;
426 const char *vars;
427 const char *vare;
428 char *finalvars;
429 int pos;
430 int brackets;
431 int needsub;
432 int len;
433
434 /* reset our buffer */
435 ast_str_reset(substr3);
436
437 /* Determine how much simply needs to be copied to the output buf. */
438 nextthing = strchr(whereweare, '$');
439 if (nextthing) {
440 pos = nextthing - whereweare;
441 switch (nextthing[1]) {
442 case '{':
443 /* Variable substitution */
444 nextvar = nextthing;
445 break;
446 case '[':
447 /* Expression substitution */
448 nextexp = nextthing;
449 break;
450 default:
451 /* '$' is not part of a substitution so include it too. */
452 ++pos;
453 break;
454 }
455 } else {
456 /* We're copying the whole remaining string */
457 pos = strlen(whereweare);
458 }
459
460 if (pos) {
461 /* Copy that many bytes */
462 ast_str_append_substr(buf, maxlen, whereweare, pos);
463
464 whereweare += pos;
465 }
466
467 if (nextvar) {
468 int offset;
469 int offset2;
470 int isfunction;
471 int res;
472
473 /* We have a variable. Find the start and end, and determine
474 if we are going to have to recursively call ourselves on the
475 contents */
476 vars = vare = nextvar + 2;
477 brackets = 1;
478 needsub = 0;
479
480 /* Find the end of it */
481 while (brackets && *vare) {
482 if ((vare[0] == '$') && (vare[1] == '{')) {
483 needsub++;
484 brackets++;
485 vare++;
486 } else if (vare[0] == '{') {
487 brackets++;
488 } else if (vare[0] == '}') {
489 brackets--;
490 } else if ((vare[0] == '$') && (vare[1] == '[')) {
491 needsub++;
492 vare++;
493 }
494 vare++;
495 }
496 len = vare - vars;
497 if (brackets) {
498 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
499 } else {
500 /* Don't count the closing '}' in the length. */
501 --len;
502 }
503
504 /* Skip totally over variable string */
505 whereweare = vare;
506
507 /* Store variable name expression to lookup. */
508 ast_str_set_substr(&substr1, 0, vars, len);
509 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n",
510 ast_str_buffer(substr1), vars, len);
511
512 /* Substitute if necessary */
513 if (needsub) {
514 if (!substr2) {
515 substr2 = ast_str_create(16);
516 if (!substr2) {
517 continue;
518 }
519 }
520 ast_str_substitute_variables_full2(&substr2, 0, c, headp,
521 ast_str_buffer(substr1), NULL, use_both);
522 finalvars = ast_str_buffer(substr2);
523 } else {
524 finalvars = ast_str_buffer(substr1);
525 }
526
527 parse_variable_name(finalvars, &offset, &offset2, &isfunction);
528 if (isfunction) {
529 /* Evaluate function */
530 res = -1;
531 if (c) {
532 res = ast_func_read2(c, finalvars, &substr3, 0);
533 ast_debug(2, "Function %s result is '%s' from channel\n",
534 finalvars, res ? "" : ast_str_buffer(substr3));
535 }
536 if (!c || (c && res < 0 && use_both)) {
537 struct varshead old;
538 struct ast_channel *bogus;
539
540 bogus = ast_dummy_channel_alloc();
541 if (bogus) {
542 old = *ast_channel_varshead(bogus);
543 if (headp) {
544 *ast_channel_varshead(bogus) = *headp;
545 }
546 res = ast_func_read2(bogus, finalvars, &substr3, 0);
547 /* Don't deallocate the varshead that was passed in */
548 if (headp) {
549 *ast_channel_varshead(bogus) = old;
550 }
551 ast_channel_unref(bogus);
552 } else {
553 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
554 res = -1;
555 }
556 ast_debug(2, "Function %s result is '%s' from headp\n",
557 finalvars, res ? "" : ast_str_buffer(substr3));
558 }
559 } else {
560 const char *result;
561 if (c) {
562 result = ast_str_retrieve_variable(&substr3, 0, c, NULL, finalvars);
563 ast_debug(2, "Variable %s result is '%s' from channel\n",
564 finalvars, S_OR(result, ""));
565 }
566 if (!c || (c && !result && use_both)) {
567 result = ast_str_retrieve_variable(&substr3, 0, NULL, headp, finalvars);
568 ast_debug(2, "Variable %s result is '%s' from headp\n",
569 finalvars, S_OR(result, ""));
570 }
571 res = (result ? 0 : -1);
572 }
573 if (!res) {
574 ast_str_substring(substr3, offset, offset2);
575 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
576 }
577 } else if (nextexp) {
578 /* We have an expression. Find the start and end, and determine
579 if we are going to have to recursively call ourselves on the
580 contents */
581 vars = vare = nextexp + 2;
582 brackets = 1;
583 needsub = 0;
584
585 /* Find the end of it */
586 while (brackets && *vare) {
587 if ((vare[0] == '$') && (vare[1] == '[')) {
588 needsub++;
589 brackets++;
590 vare++;
591 } else if (vare[0] == '[') {
592 brackets++;
593 } else if (vare[0] == ']') {
594 brackets--;
595 } else if ((vare[0] == '$') && (vare[1] == '{')) {
596 needsub++;
597 vare++;
598 }
599 vare++;
600 }
601 len = vare - vars;
602 if (brackets) {
603 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
604 } else {
605 /* Don't count the closing ']' in the length. */
606 --len;
607 }
608
609 /* Skip totally over expression */
610 whereweare = vare;
611
612 /* Store expression to evaluate. */
613 ast_str_set_substr(&substr1, 0, vars, len);
614
615 /* Substitute if necessary */
616 if (needsub) {
617 if (!substr2) {
618 substr2 = ast_str_create(16);
619 if (!substr2) {
620 continue;
621 }
622 }
623 ast_str_substitute_variables_full2(&substr2, 0, c, headp,
624 ast_str_buffer(substr1), NULL, use_both);
625 finalvars = ast_str_buffer(substr2);
626 } else {
627 finalvars = ast_str_buffer(substr1);
628 }
629
630 if (ast_str_expr(&substr3, 0, c, finalvars)) {
631 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
632 }
633 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
634 }
635 }
636 if (used) {
637 *used = ast_str_strlen(*buf);
638 }
639 ast_free(substr1);
640 ast_free(substr2);
641 ast_free(substr3);
642}
643
644void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen,
645 struct ast_channel *chan, struct varshead *headp, const char *templ, size_t *used)
646{
647 ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);
648}
649
650void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
651{
652 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
653}
654
655void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
656{
657 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
658}
659
660void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
661{
662 pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
663}
664
665/*! \brief Thread local keeping track of recursion depth */
667
668#define MAX_VARIABLE_SUB_RECURSE_DEPTH 15
669
670void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, const char *context, const char *exten, int pri)
671{
672 /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
673 const char *whereweare;
674 const char *orig_cp2 = cp2;
675 char ltmp[VAR_BUF_SIZE];
676 char var[VAR_BUF_SIZE];
677 int *recurse_depth;
678
679 *cp2 = 0; /* just in case nothing ends up there */
680
681 /* It is possible to craft dialplan that will recurse indefinitely and cause a stack overflow.
682 * This is symptomatic of a dialplan bug, so abort substitution rather than crash. */
683 recurse_depth = ast_threadstorage_get(&varsub_recurse_level, sizeof(*recurse_depth));
684 if (!recurse_depth) {
685 return;
686 }
687 if ((*recurse_depth)++ >= MAX_VARIABLE_SUB_RECURSE_DEPTH) {
688 ast_log(LOG_ERROR, "Exceeded maximum variable substitution recursion depth (%d) - possible infinite recursion in dialplan?\n", MAX_VARIABLE_SUB_RECURSE_DEPTH);
689 (*recurse_depth)--;
690 return;
691 }
692
693 whereweare = cp1;
694 while (!ast_strlen_zero(whereweare) && count) {
695 char *nextvar = NULL;
696 char *nextexp = NULL;
697 char *nextthing;
698 char *vars;
699 char *vare;
700 int length;
701 int pos;
702 int brackets;
703 int needsub;
704 int len;
705
706 /* Determine how much simply needs to be copied to the output buf. */
707 nextthing = strchr(whereweare, '$');
708 if (nextthing) {
709 pos = nextthing - whereweare;
710 switch (nextthing[1]) {
711 case '{':
712 /* Variable substitution */
713 nextvar = nextthing;
714 break;
715 case '[':
716 /* Expression substitution */
717 nextexp = nextthing;
718 break;
719 default:
720 /* '$' is not part of a substitution so include it too. */
721 ++pos;
722 break;
723 }
724 } else {
725 /* We're copying the whole remaining string */
726 pos = strlen(whereweare);
727 }
728
729 if (pos) {
730 /* Can't copy more than 'count' bytes */
731 if (pos > count)
732 pos = count;
733
734 /* Copy that many bytes */
735 memcpy(cp2, whereweare, pos);
736
737 count -= pos;
738 cp2 += pos;
739 whereweare += pos;
740 *cp2 = 0;
741 }
742
743 if (nextvar) {
744 int offset;
745 int offset2;
746 int isfunction;
747 char *cp4 = NULL;
748 char workspace[VAR_BUF_SIZE] = "";
749
750 /* We have a variable. Find the start and end, and determine
751 if we are going to have to recursively call ourselves on the
752 contents */
753 vars = vare = nextvar + 2;
754 brackets = 1;
755 needsub = 0;
756
757 /* Find the end of it */
758 while (brackets && *vare) {
759 if ((vare[0] == '$') && (vare[1] == '{')) {
760 needsub++;
761 brackets++;
762 vare++;
763 } else if (vare[0] == '{') {
764 brackets++;
765 } else if (vare[0] == '}') {
766 brackets--;
767 } else if ((vare[0] == '$') && (vare[1] == '[')) {
768 needsub++;
769 vare++;
770 }
771 vare++;
772 }
773 len = vare - vars;
774 if (brackets) {
775 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
776 } else {
777 /* Don't count the closing '}' in the length. */
778 --len;
779 }
780
781 /* Skip totally over variable string */
782 whereweare = vare;
783
784 /* Store variable name expression to lookup (and truncate). */
785 ast_copy_string(var, vars, len + 1);
786
787 /* Substitute if necessary */
788 if (needsub) {
790 vars = ltmp;
791 } else {
792 vars = var;
793 }
794
795 parse_variable_name(vars, &offset, &offset2, &isfunction);
796 if (isfunction) {
797 /* Evaluate function */
798 if (c || !headp)
799 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
800 else {
801 struct varshead old;
802 struct ast_channel *bogus;
803
804 bogus = ast_dummy_channel_alloc();
805 if (bogus) {
806 old = *ast_channel_varshead(bogus);
807 *ast_channel_varshead(bogus) = *headp;
808 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
809 /* Don't deallocate the varshead that was passed in */
810 *ast_channel_varshead(bogus) = old;
811 ast_channel_unref(bogus);
812 } else {
813 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
814 cp4 = NULL;
815 }
816 }
817 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
818 } else {
819 /* Retrieve variable value */
820 /* For dialplan location, if we were told what to substitute explicitly, use that instead */
821 if (exten && !strcmp(vars, "EXTEN")) {
823 cp4 = workspace;
824 } else if (context && !strcmp(vars, "CONTEXT")) {
826 cp4 = workspace;
827 } else if (pri && !strcmp(vars, "PRIORITY")) {
828 snprintf(workspace, VAR_BUF_SIZE, "%d", pri);
829 cp4 = workspace;
830 } else {
831 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
832 }
833 }
834 if (cp4) {
835 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
836
837 length = strlen(cp4);
838 if (length > count)
839 length = count;
840 memcpy(cp2, cp4, length);
841 count -= length;
842 cp2 += length;
843 *cp2 = 0;
844 }
845 } else if (nextexp) {
846 /* We have an expression. Find the start and end, and determine
847 if we are going to have to recursively call ourselves on the
848 contents */
849 vars = vare = nextexp + 2;
850 brackets = 1;
851 needsub = 0;
852
853 /* Find the end of it */
854 while (brackets && *vare) {
855 if ((vare[0] == '$') && (vare[1] == '[')) {
856 needsub++;
857 brackets++;
858 vare++;
859 } else if (vare[0] == '[') {
860 brackets++;
861 } else if (vare[0] == ']') {
862 brackets--;
863 } else if ((vare[0] == '$') && (vare[1] == '{')) {
864 needsub++;
865 vare++;
866 }
867 vare++;
868 }
869 len = vare - vars;
870 if (brackets) {
871 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
872 } else {
873 /* Don't count the closing ']' in the length. */
874 --len;
875 }
876
877 /* Skip totally over expression */
878 whereweare = vare;
879
880 /* Store expression to evaluate (and truncate). */
881 ast_copy_string(var, vars, len + 1);
882
883 /* Substitute if necessary */
884 if (needsub) {
886 vars = ltmp;
887 } else {
888 vars = var;
889 }
890
891 length = ast_expr(vars, cp2, count, c);
892 if (length) {
893 ast_debug(1, "Expression result is '%s'\n", cp2);
894 count -= length;
895 cp2 += length;
896 *cp2 = 0;
897 }
898 }
899 }
900 if (used) {
901 *used = cp2 - orig_cp2;
902 }
903 (*recurse_depth)--;
904}
905
906void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
907{
909}
910
911void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
912{
913 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
914}
915
916/*! \brief CLI support for listing global variables in a parseable way */
917static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
918{
919 int i = 0;
920 struct ast_var_t *newvariable;
921
922 switch (cmd) {
923 case CLI_INIT:
924 e->command = "dialplan show globals";
925 e->usage =
926 "Usage: dialplan show globals\n"
927 " List current global dialplan variables and their values\n";
928 return NULL;
929 case CLI_GENERATE:
930 return NULL;
931 }
932
934 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
935 i++;
936 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
937 }
939 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
940
941 return CLI_SUCCESS;
942}
943
944/*! \brief CLI support for listing chanvar's variables in a parseable way */
945static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
946{
947 struct ast_channel *chan;
948 struct ast_var_t *var;
949
950 switch (cmd) {
951 case CLI_INIT:
952 e->command = "dialplan show chanvar";
953 e->usage =
954 "Usage: dialplan show chanvar <channel>\n"
955 " List current channel variables and their values\n";
956 return NULL;
957 case CLI_GENERATE:
958 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
959 }
960
961 if (a->argc != e->args + 1) {
962 return CLI_SHOWUSAGE;
963 }
964
965 chan = ast_channel_get_by_name(a->argv[e->args]);
966 if (!chan) {
967 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
968 return CLI_FAILURE;
969 }
970
971 ast_channel_lock(chan);
973 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
974 }
975 ast_channel_unlock(chan);
976
977 ast_channel_unref(chan);
978 return CLI_SUCCESS;
979}
980
981/*! \brief CLI support for executing function */
982static char *handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
983{
984 struct ast_channel *c = NULL;
985 char *fn, *substituted;
986 int ret;
987 char workspace[1024];
988
989 switch (cmd) {
990 case CLI_INIT:
991 e->command = "dialplan eval function";
992 e->usage =
993 "Usage: dialplan eval function <name(args)>\n"
994 " Evaluate a dialplan function call\n"
995 " A dummy channel is used to evaluate\n"
996 " the function call, so only global\n"
997 " variables should be used.\n";
998 return NULL;
999 case CLI_GENERATE:
1000 return NULL;
1001 }
1002
1003 if (a->argc != e->args + 1) {
1004 return CLI_SHOWUSAGE;
1005 }
1006
1008 if (!c) {
1009 ast_cli(a->fd, "Unable to allocate bogus channel for function evaluation.\n");
1010 return CLI_FAILURE;
1011 }
1012
1013 fn = (char *) a->argv[3];
1014 pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
1015 substituted = ast_strdupa(workspace);
1016 workspace[0] = '\0';
1017 ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
1018
1020
1021 ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
1022 ast_cli(a->fd, "Result: %s\n", workspace);
1023
1024 return CLI_SUCCESS;
1025}
1026
1027static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1028{
1029 switch (cmd) {
1030 case CLI_INIT:
1031 e->command = "dialplan set global";
1032 e->usage =
1033 "Usage: dialplan set global <name> <value>\n"
1034 " Set global dialplan variable <name> to <value>\n";
1035 return NULL;
1036 case CLI_GENERATE:
1037 return NULL;
1038 }
1039
1040 if (a->argc != e->args + 2)
1041 return CLI_SHOWUSAGE;
1042
1043 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
1044 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
1045
1046 return CLI_SUCCESS;
1047}
1048
1049static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1050{
1051 struct ast_channel *chan;
1052 const char *chan_name, *var_name, *var_value;
1053
1054 switch (cmd) {
1055 case CLI_INIT:
1056 e->command = "dialplan set chanvar";
1057 e->usage =
1058 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
1059 " Set channel variable <varname> to <value>\n";
1060 return NULL;
1061 case CLI_GENERATE:
1062 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1063 }
1064
1065 if (a->argc != e->args + 3)
1066 return CLI_SHOWUSAGE;
1067
1068 chan_name = a->argv[e->args];
1069 var_name = a->argv[e->args + 1];
1070 var_value = a->argv[e->args + 2];
1071
1072 if (!(chan = ast_channel_get_by_name(chan_name))) {
1073 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
1074 return CLI_FAILURE;
1075 }
1076
1077 pbx_builtin_setvar_helper(chan, var_name, var_value);
1078
1079 chan = ast_channel_unref(chan);
1080
1081 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
1082
1083 return CLI_SUCCESS;
1084}
1085
1087{
1088 struct ast_var_t *variables;
1089 const char *var, *val;
1090 int total = 0;
1091
1092 if (!chan)
1093 return 0;
1094
1096
1097 ast_channel_lock(chan);
1098
1100 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1101 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1102 ) {
1103 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1104 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1105 break;
1106 } else
1107 total++;
1108 } else
1109 break;
1110 }
1111
1112 ast_channel_unlock(chan);
1113
1114 return total;
1115}
1116
1117const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
1118{
1119 struct ast_var_t *variables;
1120 const char *ret = NULL;
1121 int i;
1122 struct varshead *places[2] = { NULL, &globals };
1123
1124 if (!name)
1125 return NULL;
1126
1127 if (chan) {
1128 ast_channel_lock(chan);
1129 places[0] = ast_channel_varshead(chan);
1130 }
1131
1132 for (i = 0; i < 2; i++) {
1133 if (!places[i])
1134 continue;
1135 if (places[i] == &globals)
1137 AST_LIST_TRAVERSE(places[i], variables, entries) {
1138 if (!strcmp(name, ast_var_name(variables))) {
1139 ret = ast_var_value(variables);
1140 break;
1141 }
1142 }
1143 if (places[i] == &globals)
1145 if (ret)
1146 break;
1147 }
1148
1149 if (chan)
1150 ast_channel_unlock(chan);
1151
1152 return ret;
1153}
1154
1155void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
1156{
1157 struct ast_var_t *newvariable;
1158 struct varshead *headp;
1159
1160 if (name[strlen(name)-1] == ')') {
1161 char *function = ast_strdupa(name);
1162
1163 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1164 ast_func_write(chan, function, value);
1165 return;
1166 }
1167
1168 if (chan) {
1169 ast_channel_lock(chan);
1170 headp = ast_channel_varshead(chan);
1171 } else {
1173 headp = &globals;
1174 }
1175
1176 if (value && (newvariable = ast_var_assign(name, value))) {
1177 if (headp == &globals)
1178 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1179 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1180 }
1181
1182 if (chan)
1183 ast_channel_unlock(chan);
1184 else
1186}
1187
1188int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1189{
1190 struct ast_var_t *newvariable;
1191 struct varshead *headp;
1192 const char *nametail = name;
1193 /*! True if the old value was not an empty string. */
1194 int old_value_existed = 0;
1195
1196 if (name[strlen(name) - 1] == ')') {
1197 char *function = ast_strdupa(name);
1198
1199 return ast_func_write(chan, function, value);
1200 }
1201
1202 if (chan) {
1203 ast_channel_lock(chan);
1204 headp = ast_channel_varshead(chan);
1205 } else {
1207 headp = &globals;
1208 }
1209
1210 /* For comparison purposes, we have to strip leading underscores */
1211 if (*nametail == '_') {
1212 nametail++;
1213 if (*nametail == '_')
1214 nametail++;
1215 }
1216
1217 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1218 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1219 /* there is already such a variable, delete it */
1220 AST_LIST_REMOVE_CURRENT(entries);
1221 old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1222 ast_var_delete(newvariable);
1223 break;
1224 }
1225 }
1227
1228 if (value && (newvariable = ast_var_assign(name, value))) {
1229 if (headp == &globals) {
1230 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1231 }
1232 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1234 } else if (old_value_existed) {
1235 /* We just deleted a non-empty dialplan variable. */
1237 }
1238
1239 if (chan)
1240 ast_channel_unlock(chan);
1241 else
1243 return 0;
1244}
1245
1246int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1247{
1248 char *name, *value, *mydata;
1249
1250 if (ast_strlen_zero(data)) {
1251 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1252 return 0;
1253 }
1254
1255 mydata = ast_strdupa(data);
1256 name = strsep(&mydata, "=");
1257 value = mydata;
1258 if (!value) {
1259 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1260 return 0;
1261 }
1262
1263 if (strchr(name, ' ')) {
1264 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1265 }
1266
1268
1269 return 0;
1270}
1271
1272int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1273{
1274 char *data;
1275 int x;
1277 AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1278 );
1282 );
1283
1284 if (ast_strlen_zero(vdata)) {
1285 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1286 return 0;
1287 }
1288
1289 data = ast_strdupa(vdata);
1291
1292 for (x = 0; x < args.argc; x++) {
1293 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1294 if (pair.argc == 2) {
1296 if (strchr(pair.name, ' '))
1297 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
1298 } else if (!chan) {
1299 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1300 } else {
1301 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
1302 }
1303 }
1304
1305 return 0;
1306}
1307
1309{
1310 struct ast_var_t *vardata;
1311
1313 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1314 ast_var_delete(vardata);
1316}
1317
1318#ifdef TEST_FRAMEWORK
1319AST_TEST_DEFINE(test_variable_substrings)
1320{
1321 int i, res = AST_TEST_PASS;
1322 struct ast_channel *chan; /* dummy channel */
1323 struct ast_str *str; /* fancy string for holding comparing value */
1324
1325 const char *test_strings[][5] = {
1326 {"somevaluehere", "CALLERID(num):0:25", "somevaluehere"},
1327 {"somevaluehere", "CALLERID(num):0:5", "somev"},
1328 {"somevaluehere", "CALLERID(num):4:5", "value"},
1329 {"somevaluehere", "CALLERID(num):0:-4", "somevalue"},
1330 {"somevaluehere", "CALLERID(num):-4", "here"},
1331 };
1332
1333 switch (cmd) {
1334 case TEST_INIT:
1335 info->name = "variable_substrings";
1336 info->category = "/main/pbx/";
1337 info->summary = "Test variable substring resolution";
1338 info->description = "Verify that variable substrings are calculated correctly";
1339 return AST_TEST_NOT_RUN;
1340 case TEST_EXECUTE:
1341 break;
1342 }
1343
1344 if (!(chan = ast_dummy_channel_alloc())) {
1345 ast_test_status_update(test, "Unable to allocate dummy channel\n");
1346 return AST_TEST_FAIL;
1347 }
1348
1349 if (!(str = ast_str_create(64))) {
1350 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1351 ast_channel_release(chan);
1352 return AST_TEST_FAIL;
1353 }
1354
1355 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
1356 char substituted[512], tmp[512] = "";
1357
1358 ast_set_callerid(chan, test_strings[i][0], NULL, test_strings[i][0]);
1359
1360 snprintf(tmp, sizeof(tmp), "${%s}", test_strings[i][1]);
1361
1362 /* test ast_str_substitute_variables */
1364 ast_debug(1, "Comparing STR %s with %s\n", ast_str_buffer(str), test_strings[i][2]);
1365 if (strcmp(test_strings[i][2], ast_str_buffer(str))) {
1366 ast_test_status_update(test, "Format string '%s' substituted to '%s' using str sub. Expected '%s'.\n", test_strings[i][0], ast_str_buffer(str), test_strings[i][2]);
1367 res = AST_TEST_FAIL;
1368 }
1369
1370 /* test pbx_substitute_variables_helper */
1372 ast_debug(1, "Comparing PBX %s with %s\n", substituted, test_strings[i][2]);
1373 if (strcmp(test_strings[i][2], substituted)) {
1374 ast_test_status_update(test, "Format string '%s' substituted to '%s' using pbx sub. Expected '%s'.\n", test_strings[i][0], substituted, test_strings[i][2]);
1375 res = AST_TEST_FAIL;
1376 }
1377 }
1378 ast_free(str);
1379
1380 ast_channel_release(chan);
1381
1382 return res;
1383}
1384#endif
1385
1386static struct ast_cli_entry vars_cli[] = {
1387 AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1388 AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1389 AST_CLI_DEFINE(handle_eval_function, "Evaluate dialplan function"),
1390 AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1391 AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1392};
1393
1394static void unload_pbx_variables(void)
1395{
1400 AST_TEST_UNREGISTER(test_variable_substrings);
1401}
1402
1404{
1405 int res = 0;
1406
1411 AST_TEST_REGISTER(test_variable_substrings);
1412
1413 return res;
1414}
Prototypes for public functions only of internal interest,.
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:605
int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
Evaluate the given expression.
Definition: ast_expr2f.c:2433
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2391
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
static PGresult * result
Definition: cel_pgsql.c:84
const char * ast_channel_name(const struct ast_channel *chan)
struct varshead * ast_channel_varshead(struct ast_channel *chan)
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1840
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7356
int ast_channel_hangupcause(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1603
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1328
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
Channel Variables.
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define ast_var_assign(name, value)
Definition: chanvars.h:40
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1872
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
char * strsep(char **str, const char *delims)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:252
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
Asterisk locking-related definitions:
#define ast_rwlock_wrlock(a)
Definition: lock.h:236
#define ast_rwlock_rdlock(a)
Definition: lock.h:235
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:543
#define ast_rwlock_unlock(a)
Definition: lock.h:234
Asterisk module definitions.
int ast_register_application2(const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
Register an application.
Definition: pbx_app.c:103
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
def info(msg)
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_KEY_DIR
Definition: options.c:161
const char * ast_config_AST_CACHE_DIR
Definition: options.c:150
const char * ast_config_AST_MODULE_DIR
Definition: options.c:153
const char * ast_config_AST_RUN_DIR
Definition: options.c:162
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * ast_config_AST_AGI_DIR
Definition: options.c:160
const char * ast_config_AST_VAR_DIR
Definition: options.c:157
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
const char * ast_config_AST_SBIN_DIR
Definition: options.c:163
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
const char * ast_config_AST_DB
Definition: options.c:165
Core PBX routines and definitions.
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
executes a read operation on a function
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4155
Private include file for pbx.
#define VAR_BUF_SIZE
Definition: pbx_private.h:68
int load_pbx_variables(void)
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, struct varshead *headp, const char *templ, size_t *used)
int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an '=' character...
static char * substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
takes a substring. It is ok to call with value == workspace.
void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used, int use_both)
Perform variable/function/expression substitution on an ast_str.
static struct ast_cli_entry vars_cli[]
static ast_rwlock_t globalslock
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
static char * handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI support for listing global variables in a parseable way.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
const char * ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
static char * handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
static void unload_pbx_variables(void)
void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, const char *context, const char *exten, int pri)
Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the contex...
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
Create a human-readable string, specifying all variables and their corresponding values.
void pbx_builtin_clear_globals(void)
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value.
static const char * ast_str_substring(struct ast_str *value, int offset, int length)
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
Support for Asterisk built-in variables in the dialplan.
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name.
static char * handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI support for listing chanvar's variables in a parseable way.
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
Parse and set multiple channel variables, where the pairs are separated by the ',' character,...
static char * handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI support for executing function.
static struct varshead globals
static struct ast_threadstorage varsub_recurse_level
#define MAX_VARIABLE_SUB_RECURSE_DEPTH
static char * handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int total
Definition: res_adsi.c:970
static char * substituted(struct ast_channel *channel, const char *string)
#define NULL
Definition: resample.c:96
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1062
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
char * ast_str_set_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Set a dynamic string to a non-NULL terminated substring.
Definition: strings.h:1055
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Main Channel structure associated with a channel.
char exten[AST_MAX_EXTENSION]
descriptor for a cli entry.
Definition: cli.h:171
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Support for dynamic strings.
Definition: strings.h:623
struct ast_var_t::@211 entries
Number structure.
Definition: app_followme.c:154
const char * name
Definition: test_config.c:85
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_FAIL
Definition: test.h:196
@ AST_TEST_NOT_RUN
Definition: test.h:194
static char * test_strings[][2]
const char * args
static struct test_val a
static struct test_val c
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:86
#define ast_assert(a)
Definition: utils.h:739
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
#define ARRAY_LEN(a)
Definition: utils.h:666
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93