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