Asterisk - The Open Source Telephony Project GIT-master-77d630f
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"
44#include "asterisk/test.h"
45#include "pbx_private.h"
46
47/*** DOCUMENTATION
48 <application name="Set" language="en_US">
49 <since>
50 <version>13.8.0</version>
51 </since>
52 <synopsis>
53 Set channel variable or function value.
54 </synopsis>
55 <syntax argsep="=">
56 <parameter name="name" required="true" />
57 <parameter name="value" required="true" />
58 </syntax>
59 <description>
60 <para>This function can be used to set the value of channel variables or dialplan functions.
61 When setting variables, if the variable name is prefixed with <literal>_</literal>,
62 the variable will be inherited into channels created from the current channel.
63 If the variable name is prefixed with <literal>__</literal>, the variable will be
64 inherited into channels created from the current channel and all children channels.</para>
65 <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
66 a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
67 the behavior of this app changes, and strips surrounding quotes from the right hand side as
68 it did previously in 1.4.
69 The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
70 were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
71 protect separators and quotes in various database access strings has been greatly
72 reduced by these changes.</para></note>
73 </description>
74 <see-also>
75 <ref type="application">MSet</ref>
76 <ref type="function">GLOBAL</ref>
77 <ref type="function">SET</ref>
78 <ref type="function">ENV</ref>
79 </see-also>
80 </application>
81 <application name="MSet" language="en_US">
82 <since>
83 <version>13.8.0</version>
84 </since>
85 <synopsis>
86 Set channel variable(s) or function value(s).
87 </synopsis>
88 <syntax>
89 <parameter name="set1" required="true" argsep="=">
90 <argument name="name1" required="true" />
91 <argument name="value1" required="true" />
92 </parameter>
93 <parameter name="set2" multiple="true" argsep="=">
94 <argument name="name2" required="true" />
95 <argument name="value2" required="true" />
96 </parameter>
97 </syntax>
98 <description>
99 <para>This function can be used to set the value of channel variables or dialplan functions.
100 When setting variables, if the variable name is prefixed with <literal>_</literal>,
101 the variable will be inherited into channels created from the current channel
102 If the variable name is prefixed with <literal>__</literal>, the variable will be
103 inherited into channels created from the current channel and all children channels.
104 MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
105 prone to doing things that you may not expect. For example, it strips surrounding
106 double-quotes from the right-hand side (value). If you need to put a separator
107 character (comma or vert-bar), you will need to escape them by inserting a backslash
108 before them. Avoid its use if possible.</para>
109 <para>This application allows up to 99 variables to be set at once.</para>
110 </description>
111 <see-also>
112 <ref type="application">Set</ref>
113 </see-also>
114 </application>
115 ***/
116
119
120/*!
121 * \brief extract offset:length from variable name.
122 * \return 1 if there is a offset:length part, which is
123 * trimmed off (values go into variables)
124 */
125static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
126{
127 int parens = 0;
128
129 *offset = 0;
130 *length = INT_MAX;
131 *isfunc = 0;
132 for (; *var; var++) {
133 if (*var == '(') {
134 (*isfunc)++;
135 parens++;
136 } else if (*var == ')') {
137 parens--;
138 } else if (*var == ':' && parens == 0) {
139 *var++ = '\0';
140 sscanf(var, "%30d:%30d", offset, length);
141 return 1; /* offset:length valid */
142 }
143 }
144 return 0;
145}
146
147/*!
148 *\brief takes a substring. It is ok to call with value == workspace.
149 * \param value
150 * \param offset < 0 means start from the end of the string and set the beginning
151 * to be that many characters back.
152 * \param length is the length of the substring, a value less than 0 means to leave
153 * that many off the end.
154 * \param workspace
155 * \param workspace_len
156 * Always return a copy in workspace.
157 */
158static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
159{
160 char *ret = workspace;
161 int lr; /* length of the input string after the copy */
162
163 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
164
165 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
166
167 /* Quick check if no need to do anything */
168 if (offset == 0 && length >= lr) /* take the whole string */
169 return ret;
170
171 if (offset < 0) { /* translate negative offset into positive ones */
172 offset = lr + offset;
173 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
174 offset = 0;
175 }
176
177 /* too large offset result in empty string so we know what to return */
178 if (offset >= lr)
179 return ret + lr; /* the final '\0' */
180
181 ret += offset; /* move to the start position */
182 if (length >= 0 && length < lr - offset) /* truncate if necessary */
183 ret[length] = '\0';
184 else if (length < 0) {
185 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
186 ret[lr + length - offset] = '\0';
187 else
188 ret[0] = '\0';
189 }
190
191 return ret;
192}
193
194static const char *ast_str_substring(struct ast_str *value, int offset, int length)
195{
196 int lr; /* length of the input string after the copy */
197
198 lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
199
200 ast_assert(lr == strlen(ast_str_buffer(value))); /* ast_str_strlen should always agree with strlen */
201
202 /* Quick check if no need to do anything */
203 if (offset == 0 && length >= lr) /* take the whole string */
204 return ast_str_buffer(value);
205
206 if (offset < 0) { /* translate negative offset into positive ones */
207 offset = lr + offset;
208 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
209 offset = 0;
210 }
211
212 /* too large offset result in empty string so we know what to return */
213 if (offset >= lr) {
215 return ast_str_buffer(value);
216 }
217
218 if (offset > 0) {
219 /* Go ahead and chop off the beginning */
220 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
221 lr -= offset;
222 }
223
224 if (length >= 0 && length < lr) { /* truncate if necessary */
225 ast_str_truncate(value, length);
226 } else if (length < 0) {
227 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
228 ast_str_truncate(value, lr + length);
229 } else {
231 }
232 } else {
233 /* Nothing to do, but update the buffer length */
235 }
236
237 return ast_str_buffer(value);
238}
239
240/*! \brief Support for Asterisk built-in variables in the dialplan
241
242\note See also
243 - \ref AstVar Channel variables
244 - \ref AstCauses The HANGUPCAUSE variable
245 */
246void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
247{
248 struct ast_str *str = ast_str_create(16);
249 const char *cret;
250
251 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
252 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
253 *ret = cret ? workspace : NULL;
254 ast_free(str);
255}
256
257const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
258{
259 const char not_found = '\0';
260 char *tmpvar;
261 const char *ret;
262 const char *s; /* the result */
263 int offset, length;
264 int i, need_substring;
265 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
266 char workspace[20];
267
268 if (c) {
270 places[0] = ast_channel_varshead(c);
271 }
272 /*
273 * Make a copy of var because parse_variable_name() modifies the string.
274 * Then if called directly, we might need to run substring() on the result;
275 * remember this for later in 'need_substring', 'offset' and 'length'
276 */
277 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
278 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
279
280 /*
281 * Look first into predefined variables, then into variable lists.
282 * Variable 's' points to the result, according to the following rules:
283 * s == &not_found (set at the beginning) means that we did not find a
284 * matching variable and need to look into more places.
285 * If s != &not_found, s is a valid result string as follows:
286 * s = NULL if the variable does not have a value;
287 * you typically do this when looking for an unset predefined variable.
288 * s = workspace if the result has been assembled there;
289 * typically done when the result is built e.g. with an snprintf(),
290 * so we don't need to do an additional copy.
291 * s != workspace in case we have a string, that needs to be copied
292 * (the ast_copy_string is done once for all at the end).
293 * Typically done when the result is already available in some string.
294 */
295 s = &not_found; /* default value */
296 if (c) { /* This group requires a valid channel */
297 /* Names with common parts are looked up a piece at a time using strncmp. */
298 if (!strncmp(var, "CALL", 4)) {
299 if (!strncmp(var + 4, "ING", 3)) {
300 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
301 ast_str_set(str, maxlen, "%d",
303 s = ast_str_buffer(*str);
304 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
305 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
306 s = ast_str_buffer(*str);
307 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
308 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
309 s = ast_str_buffer(*str);
310 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
311 ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
312 s = ast_str_buffer(*str);
313 }
314 }
315 } else if (!strcmp(var, "HINT")) {
317 } else if (!strcmp(var, "HINTNAME")) {
319 } else if (!strcmp(var, "EXTEN")) {
320 s = ast_channel_exten(c);
321 } else if (!strcmp(var, "CONTEXT")) {
323 } else if (!strcmp(var, "PRIORITY")) {
324 ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
325 s = ast_str_buffer(*str);
326 } else if (!strcmp(var, "CHANNEL")) {
327 s = ast_channel_name(c);
328 } else if (!strcmp(var, "UNIQUEID")) {
330 } else if (!strcmp(var, "HANGUPCAUSE")) {
331 ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
332 s = ast_str_buffer(*str);
333 }
334 }
335 if (s == &not_found) { /* look for more */
336 if (!strcmp(var, "EPOCH")) {
337 ast_str_set(str, maxlen, "%d", (int) time(NULL));
338 s = ast_str_buffer(*str);
339 } else if (!strcmp(var, "SYSTEMNAME")) {
341 } else if (!strcmp(var, "ASTCACHEDIR")) {
343 } else if (!strcmp(var, "ASTETCDIR")) {
345 } else if (!strcmp(var, "ASTMODDIR")) {
347 } else if (!strcmp(var, "ASTVARLIBDIR")) {
349 } else if (!strcmp(var, "ASTDBDIR")) {
351 } else if (!strcmp(var, "ASTKEYDIR")) {
353 } else if (!strcmp(var, "ASTDATADIR")) {
355 } else if (!strcmp(var, "ASTAGIDIR")) {
357 } else if (!strcmp(var, "ASTSPOOLDIR")) {
359 } else if (!strcmp(var, "ASTRUNDIR")) {
361 } else if (!strcmp(var, "ASTLOGDIR")) {
363 } else if (!strcmp(var, "ASTSBINDIR")) {
365 } else if (!strcmp(var, "ENTITYID")) {
366 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
367 s = workspace;
368 }
369 }
370 /* if not found, look into chanvars or global vars */
371 for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
372 struct ast_var_t *variables;
373 if (!places[i])
374 continue;
375 if (places[i] == &globals)
377 AST_LIST_TRAVERSE(places[i], variables, entries) {
378 if (!strcmp(ast_var_name(variables), var)) {
379 s = ast_var_value(variables);
380 break;
381 }
382 }
383 if (places[i] == &globals)
385 }
386 if (s == &not_found || s == NULL) {
387 ast_debug(5, "Result of '%s' is NULL\n", var);
388 ret = NULL;
389 } else {
390 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
391 if (s != ast_str_buffer(*str)) {
392 ast_str_set(str, maxlen, "%s", s);
393 }
394 ret = ast_str_buffer(*str);
395 if (need_substring) {
396 ret = ast_str_substring(*str, offset, length);
397 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
398 }
399 }
400
401 if (c) {
403 }
404 return ret;
405}
406
407void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,
408 struct ast_channel *c, struct varshead *headp, const char *templ,
409 size_t *used, int use_both)
410{
411 /* Substitutes variables into buf, based on string templ */
412 const char *whereweare;
413 struct ast_str *substr1 = ast_str_create(16);
414 struct ast_str *substr2 = NULL;
415 struct ast_str *substr3 = ast_str_create(16);
416
418
419 if (!substr1 || !substr3) {
420 if (used) {
421 *used = ast_str_strlen(*buf);
422 }
423 ast_free(substr1);
424 ast_free(substr3);
425 return;
426 }
427
428 whereweare = templ;
429 while (!ast_strlen_zero(whereweare)) {
430 const char *nextvar = NULL;
431 const char *nextexp = NULL;
432 const char *nextthing;
433 const char *vars;
434 const char *vare;
435 char *finalvars;
436 int pos;
437 int brackets;
438 int needsub;
439 int len;
440
441 /* reset our buffer */
442 ast_str_reset(substr3);
443
444 /* Determine how much simply needs to be copied to the output buf. */
445 nextthing = strchr(whereweare, '$');
446 if (nextthing) {
447 pos = nextthing - whereweare;
448 switch (nextthing[1]) {
449 case '{':
450 /* Variable substitution */
451 nextvar = nextthing;
452 break;
453 case '[':
454 /* Expression substitution */
455 nextexp = nextthing;
456 break;
457 default:
458 /* '$' is not part of a substitution so include it too. */
459 ++pos;
460 break;
461 }
462 } else {
463 /* We're copying the whole remaining string */
464 pos = strlen(whereweare);
465 }
466
467 if (pos) {
468 /* Copy that many bytes */
469 ast_str_append_substr(buf, maxlen, whereweare, pos);
470
471 whereweare += pos;
472 }
473
474 if (nextvar) {
475 int offset;
476 int offset2;
477 int isfunction;
478 int res;
479
480 /* We have a variable. Find the start and end, and determine
481 if we are going to have to recursively call ourselves on the
482 contents */
483 vars = vare = nextvar + 2;
484 brackets = 1;
485 needsub = 0;
486
487 /* Find the end of it */
488 while (brackets && *vare) {
489 if ((vare[0] == '$') && (vare[1] == '{')) {
490 needsub++;
491 brackets++;
492 vare++;
493 } else if (vare[0] == '{') {
494 brackets++;
495 } else if (vare[0] == '}') {
496 brackets--;
497 } else if ((vare[0] == '$') && (vare[1] == '[')) {
498 needsub++;
499 vare++;
500 }
501 vare++;
502 }
503 len = vare - vars;
504 if (brackets) {
505 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
506 } else {
507 /* Don't count the closing '}' in the length. */
508 --len;
509 }
510
511 /* Skip totally over variable string */
512 whereweare = vare;
513
514 /* Store variable name expression to lookup. */
515 ast_str_set_substr(&substr1, 0, vars, len);
516 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n",
517 ast_str_buffer(substr1), vars, len);
518
519 /* Substitute if necessary */
520 if (needsub) {
521 if (!substr2) {
522 substr2 = ast_str_create(16);
523 if (!substr2) {
524 continue;
525 }
526 }
527 ast_str_substitute_variables_full2(&substr2, 0, c, headp,
528 ast_str_buffer(substr1), NULL, use_both);
529 finalvars = ast_str_buffer(substr2);
530 } else {
531 finalvars = ast_str_buffer(substr1);
532 }
533
534 parse_variable_name(finalvars, &offset, &offset2, &isfunction);
535 if (isfunction) {
536 /* Evaluate function */
537 res = -1;
538 if (c) {
539 res = ast_func_read2(c, finalvars, &substr3, 0);
540 ast_debug(2, "Function %s result is '%s' from channel\n",
541 finalvars, res ? "" : ast_str_buffer(substr3));
542 }
543 if (!c || (c && res < 0 && use_both)) {
544 struct varshead old;
545 struct ast_channel *bogus;
546
547 bogus = ast_dummy_channel_alloc();
548 if (bogus) {
549 old = *ast_channel_varshead(bogus);
550 if (headp) {
551 *ast_channel_varshead(bogus) = *headp;
552 }
553 res = ast_func_read2(bogus, finalvars, &substr3, 0);
554 /* Don't deallocate the varshead that was passed in */
555 if (headp) {
556 *ast_channel_varshead(bogus) = old;
557 }
558 ast_channel_unref(bogus);
559 } else {
560 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
561 res = -1;
562 }
563 ast_debug(2, "Function %s result is '%s' from headp\n",
564 finalvars, res ? "" : ast_str_buffer(substr3));
565 }
566 } else {
567 const char *result;
568 if (c) {
569 result = ast_str_retrieve_variable(&substr3, 0, c, NULL, finalvars);
570 ast_debug(2, "Variable %s result is '%s' from channel\n",
571 finalvars, S_OR(result, ""));
572 }
573 if (!c || (c && !result && use_both)) {
574 result = ast_str_retrieve_variable(&substr3, 0, NULL, headp, finalvars);
575 ast_debug(2, "Variable %s result is '%s' from headp\n",
576 finalvars, S_OR(result, ""));
577 }
578 res = (result ? 0 : -1);
579 }
580 if (!res) {
581 ast_str_substring(substr3, offset, offset2);
582 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
583 }
584 } else if (nextexp) {
585 /* We have an expression. Find the start and end, and determine
586 if we are going to have to recursively call ourselves on the
587 contents */
588 vars = vare = nextexp + 2;
589 brackets = 1;
590 needsub = 0;
591
592 /* Find the end of it */
593 while (brackets && *vare) {
594 if ((vare[0] == '$') && (vare[1] == '[')) {
595 needsub++;
596 brackets++;
597 vare++;
598 } else if (vare[0] == '[') {
599 brackets++;
600 } else if (vare[0] == ']') {
601 brackets--;
602 } else if ((vare[0] == '$') && (vare[1] == '{')) {
603 needsub++;
604 vare++;
605 }
606 vare++;
607 }
608 len = vare - vars;
609 if (brackets) {
610 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
611 } else {
612 /* Don't count the closing ']' in the length. */
613 --len;
614 }
615
616 /* Skip totally over expression */
617 whereweare = vare;
618
619 /* Store expression to evaluate. */
620 ast_str_set_substr(&substr1, 0, vars, len);
621
622 /* Substitute if necessary */
623 if (needsub) {
624 if (!substr2) {
625 substr2 = ast_str_create(16);
626 if (!substr2) {
627 continue;
628 }
629 }
630 ast_str_substitute_variables_full2(&substr2, 0, c, headp,
631 ast_str_buffer(substr1), NULL, use_both);
632 finalvars = ast_str_buffer(substr2);
633 } else {
634 finalvars = ast_str_buffer(substr1);
635 }
636
637 if (ast_str_expr(&substr3, 0, c, finalvars)) {
638 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
639 }
640 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
641 }
642 }
643 if (used) {
644 *used = ast_str_strlen(*buf);
645 }
646 ast_free(substr1);
647 ast_free(substr2);
648 ast_free(substr3);
649}
650
651void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen,
652 struct ast_channel *chan, struct varshead *headp, const char *templ, size_t *used)
653{
654 ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);
655}
656
657void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
658{
659 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
660}
661
662void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
663{
664 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
665}
666
667void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
668{
669 pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
670}
671
672/*! \brief Thread local keeping track of recursion depth */
674
675#define MAX_VARIABLE_SUB_RECURSE_DEPTH 15
676
677void 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)
678{
679 /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
680 const char *whereweare;
681 const char *orig_cp2 = cp2;
682 char ltmp[VAR_BUF_SIZE];
683 char var[VAR_BUF_SIZE];
684 int *recurse_depth;
685
686 *cp2 = 0; /* just in case nothing ends up there */
687
688 /* It is possible to craft dialplan that will recurse indefinitely and cause a stack overflow.
689 * This is symptomatic of a dialplan bug, so abort substitution rather than crash. */
690 recurse_depth = ast_threadstorage_get(&varsub_recurse_level, sizeof(*recurse_depth));
691 if (!recurse_depth) {
692 return;
693 }
694 if ((*recurse_depth)++ >= MAX_VARIABLE_SUB_RECURSE_DEPTH) {
695 ast_log(LOG_ERROR, "Exceeded maximum variable substitution recursion depth (%d) - possible infinite recursion in dialplan?\n", MAX_VARIABLE_SUB_RECURSE_DEPTH);
696 (*recurse_depth)--;
697 return;
698 }
699
700 whereweare = cp1;
701 while (!ast_strlen_zero(whereweare) && count) {
702 char *nextvar = NULL;
703 char *nextexp = NULL;
704 char *nextthing;
705 char *vars;
706 char *vare;
707 int length;
708 int pos;
709 int brackets;
710 int needsub;
711 int len;
712
713 /* Determine how much simply needs to be copied to the output buf. */
714 nextthing = strchr(whereweare, '$');
715 if (nextthing) {
716 pos = nextthing - whereweare;
717 switch (nextthing[1]) {
718 case '{':
719 /* Variable substitution */
720 nextvar = nextthing;
721 break;
722 case '[':
723 /* Expression substitution */
724 nextexp = nextthing;
725 break;
726 default:
727 /* '$' is not part of a substitution so include it too. */
728 ++pos;
729 break;
730 }
731 } else {
732 /* We're copying the whole remaining string */
733 pos = strlen(whereweare);
734 }
735
736 if (pos) {
737 /* Can't copy more than 'count' bytes */
738 if (pos > count)
739 pos = count;
740
741 /* Copy that many bytes */
742 memcpy(cp2, whereweare, pos);
743
744 count -= pos;
745 cp2 += pos;
746 whereweare += pos;
747 *cp2 = 0;
748 }
749
750 if (nextvar) {
751 int offset;
752 int offset2;
753 int isfunction;
754 char *cp4 = NULL;
755 char workspace[VAR_BUF_SIZE] = "";
756
757 /* We have a variable. Find the start and end, and determine
758 if we are going to have to recursively call ourselves on the
759 contents */
760 vars = vare = nextvar + 2;
761 brackets = 1;
762 needsub = 0;
763
764 /* Find the end of it */
765 while (brackets && *vare) {
766 if ((vare[0] == '$') && (vare[1] == '{')) {
767 needsub++;
768 brackets++;
769 vare++;
770 } else if (vare[0] == '{') {
771 brackets++;
772 } else if (vare[0] == '}') {
773 brackets--;
774 } else if ((vare[0] == '$') && (vare[1] == '[')) {
775 needsub++;
776 vare++;
777 }
778 vare++;
779 }
780 len = vare - vars;
781 if (brackets) {
782 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
783 } else {
784 /* Don't count the closing '}' in the length. */
785 --len;
786 }
787
788 /* Skip totally over variable string */
789 whereweare = vare;
790
791 /* Store variable name expression to lookup (and truncate). */
792 ast_copy_string(var, vars, len + 1);
793
794 /* Substitute if necessary */
795 if (needsub) {
797 vars = ltmp;
798 } else {
799 vars = var;
800 }
801
802 parse_variable_name(vars, &offset, &offset2, &isfunction);
803 if (isfunction) {
804 /* Evaluate function */
805 if (c || !headp)
806 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
807 else {
808 struct varshead old;
809 struct ast_channel *bogus;
810
811 bogus = ast_dummy_channel_alloc();
812 if (bogus) {
813 old = *ast_channel_varshead(bogus);
814 *ast_channel_varshead(bogus) = *headp;
815 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
816 /* Don't deallocate the varshead that was passed in */
817 *ast_channel_varshead(bogus) = old;
818 ast_channel_unref(bogus);
819 } else {
820 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
821 cp4 = NULL;
822 }
823 }
824 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
825 } else {
826 /* Retrieve variable value */
827 /* For dialplan location, if we were told what to substitute explicitly, use that instead */
828 if (exten && !strcmp(vars, "EXTEN")) {
830 cp4 = workspace;
831 } else if (context && !strcmp(vars, "CONTEXT")) {
833 cp4 = workspace;
834 } else if (pri && !strcmp(vars, "PRIORITY")) {
835 snprintf(workspace, VAR_BUF_SIZE, "%d", pri);
836 cp4 = workspace;
837 } else {
838 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
839 }
840 }
841 if (cp4) {
842 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
843
844 length = strlen(cp4);
845 if (length > count)
846 length = count;
847 memcpy(cp2, cp4, length);
848 count -= length;
849 cp2 += length;
850 *cp2 = 0;
851 }
852 } else if (nextexp) {
853 /* We have an expression. Find the start and end, and determine
854 if we are going to have to recursively call ourselves on the
855 contents */
856 vars = vare = nextexp + 2;
857 brackets = 1;
858 needsub = 0;
859
860 /* Find the end of it */
861 while (brackets && *vare) {
862 if ((vare[0] == '$') && (vare[1] == '[')) {
863 needsub++;
864 brackets++;
865 vare++;
866 } else if (vare[0] == '[') {
867 brackets++;
868 } else if (vare[0] == ']') {
869 brackets--;
870 } else if ((vare[0] == '$') && (vare[1] == '{')) {
871 needsub++;
872 vare++;
873 }
874 vare++;
875 }
876 len = vare - vars;
877 if (brackets) {
878 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
879 } else {
880 /* Don't count the closing ']' in the length. */
881 --len;
882 }
883
884 /* Skip totally over expression */
885 whereweare = vare;
886
887 /* Store expression to evaluate (and truncate). */
888 ast_copy_string(var, vars, len + 1);
889
890 /* Substitute if necessary */
891 if (needsub) {
893 vars = ltmp;
894 } else {
895 vars = var;
896 }
897
898 length = ast_expr(vars, cp2, count, c);
899 if (length) {
900 ast_debug(1, "Expression result is '%s'\n", cp2);
901 count -= length;
902 cp2 += length;
903 *cp2 = 0;
904 }
905 }
906 }
907 if (used) {
908 *used = cp2 - orig_cp2;
909 }
910 (*recurse_depth)--;
911}
912
913void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
914{
916}
917
918void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
919{
920 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
921}
922
923/*! \brief CLI support for listing global variables in a parseable way */
924static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
925{
926 int i = 0;
927 struct ast_var_t *newvariable;
928
929 switch (cmd) {
930 case CLI_INIT:
931 e->command = "dialplan show globals";
932 e->usage =
933 "Usage: dialplan show globals\n"
934 " List current global dialplan variables and their values\n";
935 return NULL;
936 case CLI_GENERATE:
937 return NULL;
938 }
939
941 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
942 i++;
943 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
944 }
946 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
947
948 return CLI_SUCCESS;
949}
950
951/*! \brief CLI support for listing chanvar's variables in a parseable way */
952static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
953{
954 struct ast_channel *chan;
955 struct ast_var_t *var;
956
957 switch (cmd) {
958 case CLI_INIT:
959 e->command = "dialplan show chanvar";
960 e->usage =
961 "Usage: dialplan show chanvar <channel>\n"
962 " List current channel variables and their values\n";
963 return NULL;
964 case CLI_GENERATE:
965 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
966 }
967
968 if (a->argc != e->args + 1) {
969 return CLI_SHOWUSAGE;
970 }
971
972 chan = ast_channel_get_by_name(a->argv[e->args]);
973 if (!chan) {
974 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
975 return CLI_FAILURE;
976 }
977
978 ast_channel_lock(chan);
980 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
981 }
982 ast_channel_unlock(chan);
983
984 ast_channel_unref(chan);
985 return CLI_SUCCESS;
986}
987
988static const struct ast_channel_tech mock_channel_tech = {
989};
990
991static int cli_chan = 0;
992
993/*! \brief CLI support for executing function */
994static char *handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
995{
996 struct ast_channel *c = NULL;
997 const char *fn, *substituted;
998 int ret;
999 char workspace[1024];
1000 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1001
1002 switch (cmd) {
1003 case CLI_INIT:
1004 e->command = "dialplan eval function";
1005 e->usage =
1006 "Usage: dialplan eval function <name(args)>\n"
1007 " Evaluate a dialplan function call\n"
1008 " A dummy channel is used to evaluate\n"
1009 " the function call, so only global\n"
1010 " variables should be used.\n";
1011 return NULL;
1012 case CLI_GENERATE:
1013 return NULL;
1014 }
1015
1016 if (a->argc != e->args + 1) {
1017 return CLI_SHOWUSAGE;
1018 }
1019
1020 if (a->argc != e->args + 1 && a->argc != e->args + 2) {
1021 return CLI_SHOWUSAGE;
1022 }
1023
1025 if (!caps) {
1026 ast_log(LOG_WARNING, "Could not allocate an empty format capabilities structure\n");
1027 return CLI_FAILURE;
1028 }
1029
1030 if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
1031 ast_log(LOG_WARNING, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
1032 return CLI_FAILURE;
1033 }
1034
1035 if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
1036 ast_log(LOG_WARNING, "Failed to append an alaw format to capabilities for channel nativeformats\n");
1037 return CLI_FAILURE;
1038 }
1039
1040 if (ast_format_cap_append(caps, ast_format_h264, 0)) {
1041 ast_log(LOG_WARNING, "Failed to append an h264 format to capabilities for channel nativeformats\n");
1042 return CLI_FAILURE;
1043 }
1044
1045 c = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CLIEval/%d", ++cli_chan);
1046 if (!c) {
1047 ast_cli(a->fd, "Unable to allocate mock channel for application execution.\n");
1048 return CLI_FAILURE;
1049 }
1057
1058 fn = a->argv[3];
1059 pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
1060 substituted = ast_strdupa(workspace);
1061 workspace[0] = '\0';
1062 ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
1063
1064 ast_hangup(c); /* no need to unref separately */
1065
1066 ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
1067 ast_cli(a->fd, "Result: %s\n", workspace);
1068
1069 return CLI_SUCCESS;
1070}
1071
1072static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1073{
1074 switch (cmd) {
1075 case CLI_INIT:
1076 e->command = "dialplan set global";
1077 e->usage =
1078 "Usage: dialplan set global <name> <value>\n"
1079 " Set global dialplan variable <name> to <value>\n";
1080 return NULL;
1081 case CLI_GENERATE:
1082 return NULL;
1083 }
1084
1085 if (a->argc != e->args + 2)
1086 return CLI_SHOWUSAGE;
1087
1088 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
1089 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
1090
1091 return CLI_SUCCESS;
1092}
1093
1094static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1095{
1096 struct ast_channel *chan;
1097 const char *chan_name, *var_name, *var_value;
1098
1099 switch (cmd) {
1100 case CLI_INIT:
1101 e->command = "dialplan set chanvar";
1102 e->usage =
1103 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
1104 " Set channel variable <varname> to <value>\n";
1105 return NULL;
1106 case CLI_GENERATE:
1107 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1108 }
1109
1110 if (a->argc != e->args + 3)
1111 return CLI_SHOWUSAGE;
1112
1113 chan_name = a->argv[e->args];
1114 var_name = a->argv[e->args + 1];
1115 var_value = a->argv[e->args + 2];
1116
1117 if (!(chan = ast_channel_get_by_name(chan_name))) {
1118 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
1119 return CLI_FAILURE;
1120 }
1121
1122 pbx_builtin_setvar_helper(chan, var_name, var_value);
1123
1124 chan = ast_channel_unref(chan);
1125
1126 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
1127
1128 return CLI_SUCCESS;
1129}
1130
1132{
1133 struct ast_var_t *variables;
1134 const char *var, *val;
1135 int total = 0;
1136
1137 if (!chan)
1138 return 0;
1139
1141
1142 ast_channel_lock(chan);
1143
1145 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1146 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1147 ) {
1148 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1149 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1150 break;
1151 } else
1152 total++;
1153 } else
1154 break;
1155 }
1156
1157 ast_channel_unlock(chan);
1158
1159 return total;
1160}
1161
1162const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
1163{
1164 struct ast_var_t *variables;
1165 const char *ret = NULL;
1166 int i;
1167 struct varshead *places[2] = { NULL, &globals };
1168
1169 if (!name)
1170 return NULL;
1171
1172 if (chan) {
1173 ast_channel_lock(chan);
1174 places[0] = ast_channel_varshead(chan);
1175 }
1176
1177 for (i = 0; i < 2; i++) {
1178 if (!places[i])
1179 continue;
1180 if (places[i] == &globals)
1182 AST_LIST_TRAVERSE(places[i], variables, entries) {
1183 if (!strcmp(name, ast_var_name(variables))) {
1184 ret = ast_var_value(variables);
1185 break;
1186 }
1187 }
1188 if (places[i] == &globals)
1190 if (ret)
1191 break;
1192 }
1193
1194 if (chan)
1195 ast_channel_unlock(chan);
1196
1197 return ret;
1198}
1199
1200void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
1201{
1202 struct ast_var_t *newvariable;
1203 struct varshead *headp;
1204
1205 if (name[strlen(name)-1] == ')') {
1206 char *function = ast_strdupa(name);
1207
1208 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1209 ast_func_write(chan, function, value);
1210 return;
1211 }
1212
1213 if (chan) {
1214 ast_channel_lock(chan);
1215 headp = ast_channel_varshead(chan);
1216 } else {
1218 headp = &globals;
1219 }
1220
1221 if (value && (newvariable = ast_var_assign(name, value))) {
1222 if (headp == &globals)
1223 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1224 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1225 }
1226
1227 if (chan)
1228 ast_channel_unlock(chan);
1229 else
1231}
1232
1233int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1234{
1235 struct ast_var_t *newvariable;
1236 struct varshead *headp;
1237 const char *nametail = name;
1238 /*! True if the old value was not an empty string. */
1239 int old_value_existed = 0;
1240
1241 if (name[strlen(name) - 1] == ')') {
1242 char *function = ast_strdupa(name);
1243
1244 return ast_func_write(chan, function, value);
1245 }
1246
1247 if (chan) {
1248 ast_channel_lock(chan);
1249 headp = ast_channel_varshead(chan);
1250 } else {
1252 headp = &globals;
1253 }
1254
1255 /* For comparison purposes, we have to strip leading underscores */
1256 if (*nametail == '_') {
1257 nametail++;
1258 if (*nametail == '_')
1259 nametail++;
1260 }
1261
1262 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1263 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1264 /* there is already such a variable, delete it */
1265 AST_LIST_REMOVE_CURRENT(entries);
1266 old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1267 ast_var_delete(newvariable);
1268 break;
1269 }
1270 }
1272
1273 if (value && (newvariable = ast_var_assign(name, value))) {
1274 if (headp == &globals) {
1275 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1276 }
1277 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1279 } else if (old_value_existed) {
1280 /* We just deleted a non-empty dialplan variable. */
1282 }
1283
1284 if (chan)
1285 ast_channel_unlock(chan);
1286 else
1288 return 0;
1289}
1290
1291int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1292{
1293 char *name, *value, *mydata;
1294
1295 if (ast_strlen_zero(data)) {
1296 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1297 return 0;
1298 }
1299
1300 mydata = ast_strdupa(data);
1301 name = strsep(&mydata, "=");
1302 value = mydata;
1303 if (!value) {
1304 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1305 return 0;
1306 }
1307
1308 if (strchr(name, ' ')) {
1309 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1310 }
1311
1313
1314 return 0;
1315}
1316
1317int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1318{
1319 char *data;
1320 int x;
1322 AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1323 );
1327 );
1328
1329 if (ast_strlen_zero(vdata)) {
1330 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1331 return 0;
1332 }
1333
1334 data = ast_strdupa(vdata);
1336
1337 for (x = 0; x < args.argc; x++) {
1338 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1339 if (pair.argc == 2) {
1341 if (strchr(pair.name, ' '))
1342 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);
1343 } else if (!chan) {
1344 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1345 } else {
1346 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));
1347 }
1348 }
1349
1350 return 0;
1351}
1352
1354{
1355 struct ast_var_t *vardata;
1356
1358 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1359 ast_var_delete(vardata);
1361}
1362
1363#ifdef TEST_FRAMEWORK
1364AST_TEST_DEFINE(test_variable_substrings)
1365{
1366 int i, res = AST_TEST_PASS;
1367 struct ast_channel *chan; /* dummy channel */
1368 struct ast_str *str; /* fancy string for holding comparing value */
1369
1370 const char *test_strings[][5] = {
1371 {"somevaluehere", "CALLERID(num):0:25", "somevaluehere"},
1372 {"somevaluehere", "CALLERID(num):0:5", "somev"},
1373 {"somevaluehere", "CALLERID(num):4:5", "value"},
1374 {"somevaluehere", "CALLERID(num):0:-4", "somevalue"},
1375 {"somevaluehere", "CALLERID(num):-4", "here"},
1376 };
1377
1378 switch (cmd) {
1379 case TEST_INIT:
1380 info->name = "variable_substrings";
1381 info->category = "/main/pbx/";
1382 info->summary = "Test variable substring resolution";
1383 info->description = "Verify that variable substrings are calculated correctly";
1384 return AST_TEST_NOT_RUN;
1385 case TEST_EXECUTE:
1386 break;
1387 }
1388
1389 if (!(chan = ast_dummy_channel_alloc())) {
1390 ast_test_status_update(test, "Unable to allocate dummy channel\n");
1391 return AST_TEST_FAIL;
1392 }
1393
1394 if (!(str = ast_str_create(64))) {
1395 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1396 ast_channel_release(chan);
1397 return AST_TEST_FAIL;
1398 }
1399
1400 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
1401 char substituted[512], tmp[512] = "";
1402
1403 ast_set_callerid(chan, test_strings[i][0], NULL, test_strings[i][0]);
1404
1405 snprintf(tmp, sizeof(tmp), "${%s}", test_strings[i][1]);
1406
1407 /* test ast_str_substitute_variables */
1408 ast_str_substitute_variables(&str, 0, chan, tmp);
1409 ast_debug(1, "Comparing STR %s with %s\n", ast_str_buffer(str), test_strings[i][2]);
1410 if (strcmp(test_strings[i][2], ast_str_buffer(str))) {
1411 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]);
1412 res = AST_TEST_FAIL;
1413 }
1414
1415 /* test pbx_substitute_variables_helper */
1417 ast_debug(1, "Comparing PBX %s with %s\n", substituted, test_strings[i][2]);
1418 if (strcmp(test_strings[i][2], substituted)) {
1419 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]);
1420 res = AST_TEST_FAIL;
1421 }
1422 }
1423 ast_free(str);
1424
1425 ast_channel_release(chan);
1426
1427 return res;
1428}
1429#endif
1430
1431static struct ast_cli_entry vars_cli[] = {
1432 AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1433 AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1434 AST_CLI_DEFINE(handle_eval_function, "Evaluate dialplan function"),
1435 AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1436 AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1437};
1438
1439static void unload_pbx_variables(void)
1440{
1445 AST_TEST_UNREGISTER(test_variable_substrings);
1446}
1447
1449{
1450 int res = 0;
1451
1456 AST_TEST_REGISTER(test_variable_substrings);
1457
1458 return res;
1459}
Prototypes for public functions only of internal interest,.
const char * str
Definition: app_jack.c:150
#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
char * strsep(char **str, const char *delims)
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
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
static PGresult * result
Definition: cel_pgsql.c:84
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
struct varshead * ast_channel_varshead(struct ast_channel *chan)
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1789
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
Definition: channel.h:2972
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:7316
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
int ast_channel_hangupcause(const struct ast_channel *chan)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
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:1552
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
#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)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_STATE_DOWN
Definition: channelstate.h:36
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:2469
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:1842
@ 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
Media Format Cache API.
struct ast_format * ast_format_h264
Built-in cached h264 format.
Definition: format_cache.c:176
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
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.
#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:243
#define ast_rwlock_rdlock(a)
Definition: lock.h:242
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:550
#define ast_rwlock_unlock(a)
Definition: lock.h:241
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:104
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:162
const char * ast_config_AST_CACHE_DIR
Definition: options.c:151
const char * ast_config_AST_MODULE_DIR
Definition: options.c:154
const char * ast_config_AST_RUN_DIR
Definition: options.c:163
const char * ast_config_AST_DATA_DIR
Definition: options.c:159
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:152
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:155
const char * ast_config_AST_AGI_DIR
Definition: options.c:161
const char * ast_config_AST_VAR_DIR
Definition: options.c:158
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:171
const char * ast_config_AST_SBIN_DIR
Definition: options.c:164
const char * ast_config_AST_LOG_DIR
Definition: options.c:160
const char * ast_config_AST_DB
Definition: options.c:166
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:4176
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.
static int cli_chan
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 const struct ast_channel_tech mock_channel_tech
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
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition: channel.h:648
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
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Support for dynamic strings.
Definition: strings.h:623
struct ast_var_t::@216 entries
Number structure.
Definition: app_followme.c:157
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 RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978
#define ast_assert(a)
Definition: utils.h:776
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2875
#define ARRAY_LEN(a)
Definition: utils.h:703
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:94