Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
37 #include "asterisk/linkedlists.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/module.h"
40 #include "asterisk/paths.h"
41 #include "asterisk/pbx.h"
43 #include "pbx_private.h"
44 
45 /*** DOCUMENTATION
46  <application name="Set" language="en_US">
47  <synopsis>
48  Set channel variable or function value.
49  </synopsis>
50  <syntax argsep="=">
51  <parameter name="name" required="true" />
52  <parameter name="value" required="true" />
53  </syntax>
54  <description>
55  <para>This function can be used to set the value of channel variables or dialplan functions.
56  When setting variables, if the variable name is prefixed with <literal>_</literal>,
57  the variable will be inherited into channels created from the current channel.
58  If the variable name is prefixed with <literal>__</literal>, the variable will be
59  inherited into channels created from the current channel and all children channels.</para>
60  <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
61  a <literal>[compat]</literal> category, and you have <literal>app_set = 1.4</literal> under that, then
62  the behavior of this app changes, and strips surrounding quotes from the right hand side as
63  it did previously in 1.4.
64  The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
65  were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
66  protect separators and quotes in various database access strings has been greatly
67  reduced by these changes.</para></note>
68  </description>
69  <see-also>
70  <ref type="application">MSet</ref>
71  <ref type="function">GLOBAL</ref>
72  <ref type="function">SET</ref>
73  <ref type="function">ENV</ref>
74  </see-also>
75  </application>
76  <application name="MSet" language="en_US">
77  <synopsis>
78  Set channel variable(s) or function value(s).
79  </synopsis>
80  <syntax>
81  <parameter name="set1" required="true" argsep="=">
82  <argument name="name1" required="true" />
83  <argument name="value1" required="true" />
84  </parameter>
85  <parameter name="set2" multiple="true" argsep="=">
86  <argument name="name2" required="true" />
87  <argument name="value2" required="true" />
88  </parameter>
89  </syntax>
90  <description>
91  <para>This function can be used to set the value of channel variables or dialplan functions.
92  When setting variables, if the variable name is prefixed with <literal>_</literal>,
93  the variable will be inherited into channels created from the current channel
94  If the variable name is prefixed with <literal>__</literal>, the variable will be
95  inherited into channels created from the current channel and all children channels.
96  MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
97  prone to doing things that you may not expect. For example, it strips surrounding
98  double-quotes from the right-hand side (value). If you need to put a separator
99  character (comma or vert-bar), you will need to escape them by inserting a backslash
100  before them. Avoid its use if possible.</para>
101  <para>This application allows up to 99 variables to be set at once.</para>
102  </description>
103  <see-also>
104  <ref type="application">Set</ref>
105  </see-also>
106  </application>
107  ***/
108 
111 
112 /*!
113  * \brief extract offset:length from variable name.
114  * \return 1 if there is a offset:length part, which is
115  * trimmed off (values go into variables)
116  */
117 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
118 {
119  int parens = 0;
120 
121  *offset = 0;
122  *length = INT_MAX;
123  *isfunc = 0;
124  for (; *var; var++) {
125  if (*var == '(') {
126  (*isfunc)++;
127  parens++;
128  } else if (*var == ')') {
129  parens--;
130  } else if (*var == ':' && parens == 0) {
131  *var++ = '\0';
132  sscanf(var, "%30d:%30d", offset, length);
133  return 1; /* offset:length valid */
134  }
135  }
136  return 0;
137 }
138 
139 /*!
140  *\brief takes a substring. It is ok to call with value == workspace.
141  * \param value
142  * \param offset < 0 means start from the end of the string and set the beginning
143  * to be that many characters back.
144  * \param length is the length of the substring, a value less than 0 means to leave
145  * that many off the end.
146  * \param workspace
147  * \param workspace_len
148  * Always return a copy in workspace.
149  */
150 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
151 {
152  char *ret = workspace;
153  int lr; /* length of the input string after the copy */
154 
155  ast_copy_string(workspace, value, workspace_len); /* always make a copy */
156 
157  lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
158 
159  /* Quick check if no need to do anything */
160  if (offset == 0 && length >= lr) /* take the whole string */
161  return ret;
162 
163  if (offset < 0) { /* translate negative offset into positive ones */
164  offset = lr + offset;
165  if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
166  offset = 0;
167  }
168 
169  /* too large offset result in empty string so we know what to return */
170  if (offset >= lr)
171  return ret + lr; /* the final '\0' */
172 
173  ret += offset; /* move to the start position */
174  if (length >= 0 && length < lr - offset) /* truncate if necessary */
175  ret[length] = '\0';
176  else if (length < 0) {
177  if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
178  ret[lr + length - offset] = '\0';
179  else
180  ret[0] = '\0';
181  }
182 
183  return ret;
184 }
185 
186 static const char *ast_str_substring(struct ast_str *value, int offset, int length)
187 {
188  int lr; /* length of the input string after the copy */
189 
190  lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
191 
192  /* Quick check if no need to do anything */
193  if (offset == 0 && length >= lr) /* take the whole string */
194  return ast_str_buffer(value);
195 
196  if (offset < 0) { /* translate negative offset into positive ones */
197  offset = lr + offset;
198  if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
199  offset = 0;
200  }
201 
202  /* too large offset result in empty string so we know what to return */
203  if (offset >= lr) {
205  return ast_str_buffer(value);
206  }
207 
208  if (offset > 0) {
209  /* Go ahead and chop off the beginning */
210  memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
211  lr -= offset;
212  }
213 
214  if (length >= 0 && length < lr) { /* truncate if necessary */
215  ast_str_truncate(value, length);
216  } else if (length < 0) {
217  if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
218  ast_str_truncate(value, lr + length);
219  } else {
221  }
222  } else {
223  /* Nothing to do, but update the buffer length */
225  }
226 
227  return ast_str_buffer(value);
228 }
229 
230 /*! \brief Support for Asterisk built-in variables in the dialplan
231 
232 \note See also
233  - \ref AstVar Channel variables
234  - \ref AstCauses The HANGUPCAUSE variable
235  */
236 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
237 {
238  struct ast_str *str = ast_str_create(16);
239  const char *cret;
240 
241  cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
242  ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
243  *ret = cret ? workspace : NULL;
244  ast_free(str);
245 }
246 
247 const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
248 {
249  const char not_found = '\0';
250  char *tmpvar;
251  const char *ret;
252  const char *s; /* the result */
253  int offset, length;
254  int i, need_substring;
255  struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
256  char workspace[20];
257 
258  if (c) {
260  places[0] = ast_channel_varshead(c);
261  }
262  /*
263  * Make a copy of var because parse_variable_name() modifies the string.
264  * Then if called directly, we might need to run substring() on the result;
265  * remember this for later in 'need_substring', 'offset' and 'length'
266  */
267  tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
268  need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
269 
270  /*
271  * Look first into predefined variables, then into variable lists.
272  * Variable 's' points to the result, according to the following rules:
273  * s == &not_found (set at the beginning) means that we did not find a
274  * matching variable and need to look into more places.
275  * If s != &not_found, s is a valid result string as follows:
276  * s = NULL if the variable does not have a value;
277  * you typically do this when looking for an unset predefined variable.
278  * s = workspace if the result has been assembled there;
279  * typically done when the result is built e.g. with an snprintf(),
280  * so we don't need to do an additional copy.
281  * s != workspace in case we have a string, that needs to be copied
282  * (the ast_copy_string is done once for all at the end).
283  * Typically done when the result is already available in some string.
284  */
285  s = &not_found; /* default value */
286  if (c) { /* This group requires a valid channel */
287  /* Names with common parts are looked up a piece at a time using strncmp. */
288  if (!strncmp(var, "CALL", 4)) {
289  if (!strncmp(var + 4, "ING", 3)) {
290  if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
291  ast_str_set(str, maxlen, "%d",
293  s = ast_str_buffer(*str);
294  } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
295  ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
296  s = ast_str_buffer(*str);
297  } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
298  ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
299  s = ast_str_buffer(*str);
300  } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
301  ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
302  s = ast_str_buffer(*str);
303  }
304  }
305  } else if (!strcmp(var, "HINT")) {
307  } else if (!strcmp(var, "HINTNAME")) {
309  } else if (!strcmp(var, "EXTEN")) {
310  s = ast_channel_exten(c);
311  } else if (!strcmp(var, "CONTEXT")) {
312  s = ast_channel_context(c);
313  } else if (!strcmp(var, "PRIORITY")) {
314  ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
315  s = ast_str_buffer(*str);
316  } else if (!strcmp(var, "CHANNEL")) {
317  s = ast_channel_name(c);
318  } else if (!strcmp(var, "UNIQUEID")) {
319  s = ast_channel_uniqueid(c);
320  } else if (!strcmp(var, "HANGUPCAUSE")) {
321  ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
322  s = ast_str_buffer(*str);
323  }
324  }
325  if (s == &not_found) { /* look for more */
326  if (!strcmp(var, "EPOCH")) {
327  ast_str_set(str, maxlen, "%d", (int) time(NULL));
328  s = ast_str_buffer(*str);
329  } else if (!strcmp(var, "SYSTEMNAME")) {
331  } else if (!strcmp(var, "ASTCACHEDIR")) {
333  } else if (!strcmp(var, "ASTETCDIR")) {
335  } else if (!strcmp(var, "ASTMODDIR")) {
337  } else if (!strcmp(var, "ASTVARLIBDIR")) {
339  } else if (!strcmp(var, "ASTDBDIR")) {
340  s = ast_config_AST_DB;
341  } else if (!strcmp(var, "ASTKEYDIR")) {
343  } else if (!strcmp(var, "ASTDATADIR")) {
345  } else if (!strcmp(var, "ASTAGIDIR")) {
347  } else if (!strcmp(var, "ASTSPOOLDIR")) {
349  } else if (!strcmp(var, "ASTRUNDIR")) {
351  } else if (!strcmp(var, "ASTLOGDIR")) {
353  } else if (!strcmp(var, "ASTSBINDIR")) {
355  } else if (!strcmp(var, "ENTITYID")) {
356  ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
357  s = workspace;
358  }
359  }
360  /* if not found, look into chanvars or global vars */
361  for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
362  struct ast_var_t *variables;
363  if (!places[i])
364  continue;
365  if (places[i] == &globals)
367  AST_LIST_TRAVERSE(places[i], variables, entries) {
368  if (!strcmp(ast_var_name(variables), var)) {
369  s = ast_var_value(variables);
370  break;
371  }
372  }
373  if (places[i] == &globals)
375  }
376  if (s == &not_found || s == NULL) {
377  ast_debug(5, "Result of '%s' is NULL\n", var);
378  ret = NULL;
379  } else {
380  ast_debug(5, "Result of '%s' is '%s'\n", var, s);
381  if (s != ast_str_buffer(*str)) {
382  ast_str_set(str, maxlen, "%s", s);
383  }
384  ret = ast_str_buffer(*str);
385  if (need_substring) {
386  ret = ast_str_substring(*str, offset, length);
387  ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
388  }
389  }
390 
391  if (c) {
393  }
394  return ret;
395 }
396 
397 void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
398 {
399  /* Substitutes variables into buf, based on string templ */
400  const char *whereweare;
401  struct ast_str *substr1 = ast_str_create(16);
402  struct ast_str *substr2 = NULL;
403  struct ast_str *substr3 = ast_str_create(16);
404 
405  ast_str_reset(*buf);
406 
407  if (!substr1 || !substr3) {
408  if (used) {
409  *used = ast_str_strlen(*buf);
410  }
411  ast_free(substr1);
412  ast_free(substr3);
413  return;
414  }
415 
416  whereweare = templ;
417  while (!ast_strlen_zero(whereweare)) {
418  const char *nextvar = NULL;
419  const char *nextexp = NULL;
420  const char *nextthing;
421  const char *vars;
422  const char *vare;
423  char *finalvars;
424  int pos;
425  int brackets;
426  int needsub;
427  int len;
428 
429  /* reset our buffer */
430  ast_str_reset(substr3);
431 
432  /* Determine how much simply needs to be copied to the output buf. */
433  nextthing = strchr(whereweare, '$');
434  if (nextthing) {
435  pos = nextthing - whereweare;
436  switch (nextthing[1]) {
437  case '{':
438  /* Variable substitution */
439  nextvar = nextthing;
440  break;
441  case '[':
442  /* Expression substitution */
443  nextexp = nextthing;
444  break;
445  default:
446  /* '$' is not part of a substitution so include it too. */
447  ++pos;
448  break;
449  }
450  } else {
451  /* We're copying the whole remaining string */
452  pos = strlen(whereweare);
453  }
454 
455  if (pos) {
456  /* Copy that many bytes */
457  ast_str_append_substr(buf, maxlen, whereweare, pos);
458 
459  whereweare += pos;
460  }
461 
462  if (nextvar) {
463  int offset;
464  int offset2;
465  int isfunction;
466  int res;
467 
468  /* We have a variable. Find the start and end, and determine
469  if we are going to have to recursively call ourselves on the
470  contents */
471  vars = vare = nextvar + 2;
472  brackets = 1;
473  needsub = 0;
474 
475  /* Find the end of it */
476  while (brackets && *vare) {
477  if ((vare[0] == '$') && (vare[1] == '{')) {
478  needsub++;
479  brackets++;
480  vare++;
481  } else if (vare[0] == '{') {
482  brackets++;
483  } else if (vare[0] == '}') {
484  brackets--;
485  } else if ((vare[0] == '$') && (vare[1] == '[')) {
486  needsub++;
487  vare++;
488  }
489  vare++;
490  }
491  len = vare - vars;
492  if (brackets) {
493  ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
494  } else {
495  /* Don't count the closing '}' in the length. */
496  --len;
497  }
498 
499  /* Skip totally over variable string */
500  whereweare = vare;
501 
502  /* Store variable name expression to lookup. */
503  ast_str_set_substr(&substr1, 0, vars, len);
504  ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
505 
506  /* Substitute if necessary */
507  if (needsub) {
508  if (!substr2) {
509  substr2 = ast_str_create(16);
510  if (!substr2) {
511  continue;
512  }
513  }
514  ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
515  finalvars = ast_str_buffer(substr2);
516  } else {
517  finalvars = ast_str_buffer(substr1);
518  }
519 
520  parse_variable_name(finalvars, &offset, &offset2, &isfunction);
521  if (isfunction) {
522  /* Evaluate function */
523  if (c || !headp) {
524  res = ast_func_read2(c, finalvars, &substr3, 0);
525  } else {
526  struct varshead old;
527  struct ast_channel *bogus;
528 
529  bogus = ast_dummy_channel_alloc();
530  if (bogus) {
531  old = *ast_channel_varshead(bogus);
532  *ast_channel_varshead(bogus) = *headp;
533  res = ast_func_read2(bogus, finalvars, &substr3, 0);
534  /* Don't deallocate the varshead that was passed in */
535  *ast_channel_varshead(bogus) = old;
536  ast_channel_unref(bogus);
537  } else {
538  ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
539  res = -1;
540  }
541  }
542  ast_debug(2, "Function %s result is '%s'\n",
543  finalvars, res ? "" : ast_str_buffer(substr3));
544  } else {
545  /* Retrieve variable value */
546  ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
547  res = 0;
548  }
549  if (!res) {
550  ast_str_substring(substr3, offset, offset2);
551  ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
552  }
553  } else if (nextexp) {
554  /* We have an expression. Find the start and end, and determine
555  if we are going to have to recursively call ourselves on the
556  contents */
557  vars = vare = nextexp + 2;
558  brackets = 1;
559  needsub = 0;
560 
561  /* Find the end of it */
562  while (brackets && *vare) {
563  if ((vare[0] == '$') && (vare[1] == '[')) {
564  needsub++;
565  brackets++;
566  vare++;
567  } else if (vare[0] == '[') {
568  brackets++;
569  } else if (vare[0] == ']') {
570  brackets--;
571  } else if ((vare[0] == '$') && (vare[1] == '{')) {
572  needsub++;
573  vare++;
574  }
575  vare++;
576  }
577  len = vare - vars;
578  if (brackets) {
579  ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
580  } else {
581  /* Don't count the closing ']' in the length. */
582  --len;
583  }
584 
585  /* Skip totally over expression */
586  whereweare = vare;
587 
588  /* Store expression to evaluate. */
589  ast_str_set_substr(&substr1, 0, vars, len);
590 
591  /* Substitute if necessary */
592  if (needsub) {
593  if (!substr2) {
594  substr2 = ast_str_create(16);
595  if (!substr2) {
596  continue;
597  }
598  }
599  ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), NULL);
600  finalvars = ast_str_buffer(substr2);
601  } else {
602  finalvars = ast_str_buffer(substr1);
603  }
604 
605  if (ast_str_expr(&substr3, 0, c, finalvars)) {
606  ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
607  }
608  ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
609  }
610  }
611  if (used) {
612  *used = ast_str_strlen(*buf);
613  }
614  ast_free(substr1);
615  ast_free(substr2);
616  ast_free(substr3);
617 }
618 
619 void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
620 {
621  ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
622 }
623 
624 void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
625 {
626  ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
627 }
628 
629 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
630 {
631  pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
632 }
633 
634 void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, char *context, char *exten, int pri)
635 {
636  /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
637  const char *whereweare;
638  const char *orig_cp2 = cp2;
639  char ltmp[VAR_BUF_SIZE];
640  char var[VAR_BUF_SIZE];
641 
642  *cp2 = 0; /* just in case nothing ends up there */
643  whereweare = cp1;
644  while (!ast_strlen_zero(whereweare) && count) {
645  char *nextvar = NULL;
646  char *nextexp = NULL;
647  char *nextthing;
648  char *vars;
649  char *vare;
650  int length;
651  int pos;
652  int brackets;
653  int needsub;
654  int len;
655 
656  /* Determine how much simply needs to be copied to the output buf. */
657  nextthing = strchr(whereweare, '$');
658  if (nextthing) {
659  pos = nextthing - whereweare;
660  switch (nextthing[1]) {
661  case '{':
662  /* Variable substitution */
663  nextvar = nextthing;
664  break;
665  case '[':
666  /* Expression substitution */
667  nextexp = nextthing;
668  break;
669  default:
670  /* '$' is not part of a substitution so include it too. */
671  ++pos;
672  break;
673  }
674  } else {
675  /* We're copying the whole remaining string */
676  pos = strlen(whereweare);
677  }
678 
679  if (pos) {
680  /* Can't copy more than 'count' bytes */
681  if (pos > count)
682  pos = count;
683 
684  /* Copy that many bytes */
685  memcpy(cp2, whereweare, pos);
686 
687  count -= pos;
688  cp2 += pos;
689  whereweare += pos;
690  *cp2 = 0;
691  }
692 
693  if (nextvar) {
694  int offset;
695  int offset2;
696  int isfunction;
697  char *cp4 = NULL;
698  char workspace[VAR_BUF_SIZE] = "";
699 
700  /* We have a variable. Find the start and end, and determine
701  if we are going to have to recursively call ourselves on the
702  contents */
703  vars = vare = nextvar + 2;
704  brackets = 1;
705  needsub = 0;
706 
707  /* Find the end of it */
708  while (brackets && *vare) {
709  if ((vare[0] == '$') && (vare[1] == '{')) {
710  needsub++;
711  brackets++;
712  vare++;
713  } else if (vare[0] == '{') {
714  brackets++;
715  } else if (vare[0] == '}') {
716  brackets--;
717  } else if ((vare[0] == '$') && (vare[1] == '[')) {
718  needsub++;
719  vare++;
720  }
721  vare++;
722  }
723  len = vare - vars;
724  if (brackets) {
725  ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
726  } else {
727  /* Don't count the closing '}' in the length. */
728  --len;
729  }
730 
731  /* Skip totally over variable string */
732  whereweare = vare;
733 
734  /* Store variable name expression to lookup (and truncate). */
735  ast_copy_string(var, vars, len + 1);
736 
737  /* Substitute if necessary */
738  if (needsub) {
740  vars = ltmp;
741  } else {
742  vars = var;
743  }
744 
745  parse_variable_name(vars, &offset, &offset2, &isfunction);
746  if (isfunction) {
747  /* Evaluate function */
748  if (c || !headp)
749  cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
750  else {
751  struct varshead old;
752  struct ast_channel *bogus;
753 
754  bogus = ast_dummy_channel_alloc();
755  if (bogus) {
756  old = *ast_channel_varshead(bogus);
757  *ast_channel_varshead(bogus) = *headp;
758  cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
759  /* Don't deallocate the varshead that was passed in */
760  *ast_channel_varshead(bogus) = old;
761  ast_channel_unref(bogus);
762  } else {
763  ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
764  cp4 = NULL;
765  }
766  }
767  ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
768  } else {
769  /* Retrieve variable value */
770  /* For dialplan location, if we were told what to substitute explicitly, use that instead */
771  if (exten && !strcmp(vars, "EXTEN")) {
772  ast_copy_string(workspace, exten, VAR_BUF_SIZE);
773  cp4 = workspace;
774  } else if (context && !strcmp(vars, "CONTEXT")) {
775  ast_copy_string(workspace, context, VAR_BUF_SIZE);
776  cp4 = workspace;
777  } else if (pri && !strcmp(vars, "PRIORITY")) {
778  snprintf(workspace, VAR_BUF_SIZE, "%d", pri);
779  cp4 = workspace;
780  } else {
781  pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
782  }
783  }
784  if (cp4) {
785  cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
786 
787  length = strlen(cp4);
788  if (length > count)
789  length = count;
790  memcpy(cp2, cp4, length);
791  count -= length;
792  cp2 += length;
793  *cp2 = 0;
794  }
795  } else if (nextexp) {
796  /* We have an expression. Find the start and end, and determine
797  if we are going to have to recursively call ourselves on the
798  contents */
799  vars = vare = nextexp + 2;
800  brackets = 1;
801  needsub = 0;
802 
803  /* Find the end of it */
804  while (brackets && *vare) {
805  if ((vare[0] == '$') && (vare[1] == '[')) {
806  needsub++;
807  brackets++;
808  vare++;
809  } else if (vare[0] == '[') {
810  brackets++;
811  } else if (vare[0] == ']') {
812  brackets--;
813  } else if ((vare[0] == '$') && (vare[1] == '{')) {
814  needsub++;
815  vare++;
816  }
817  vare++;
818  }
819  len = vare - vars;
820  if (brackets) {
821  ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
822  } else {
823  /* Don't count the closing ']' in the length. */
824  --len;
825  }
826 
827  /* Skip totally over expression */
828  whereweare = vare;
829 
830  /* Store expression to evaluate (and truncate). */
831  ast_copy_string(var, vars, len + 1);
832 
833  /* Substitute if necessary */
834  if (needsub) {
836  vars = ltmp;
837  } else {
838  vars = var;
839  }
840 
841  length = ast_expr(vars, cp2, count, c);
842  if (length) {
843  ast_debug(1, "Expression result is '%s'\n", cp2);
844  count -= length;
845  cp2 += length;
846  *cp2 = 0;
847  }
848  }
849  }
850  if (used) {
851  *used = cp2 - orig_cp2;
852  }
853 }
854 
855 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
856 {
858 }
859 
860 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
861 {
862  pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
863 }
864 
865 /*! \brief CLI support for listing global variables in a parseable way */
866 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
867 {
868  int i = 0;
869  struct ast_var_t *newvariable;
870 
871  switch (cmd) {
872  case CLI_INIT:
873  e->command = "dialplan show globals";
874  e->usage =
875  "Usage: dialplan show globals\n"
876  " List current global dialplan variables and their values\n";
877  return NULL;
878  case CLI_GENERATE:
879  return NULL;
880  }
881 
883  AST_LIST_TRAVERSE (&globals, newvariable, entries) {
884  i++;
885  ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
886  }
888  ast_cli(a->fd, "\n -- %d variable(s)\n", i);
889 
890  return CLI_SUCCESS;
891 }
892 
893 /*! \brief CLI support for listing chanvar's variables in a parseable way */
894 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
895 {
896  struct ast_channel *chan;
897  struct ast_var_t *var;
898 
899  switch (cmd) {
900  case CLI_INIT:
901  e->command = "dialplan show chanvar";
902  e->usage =
903  "Usage: dialplan show chanvar <channel>\n"
904  " List current channel variables and their values\n";
905  return NULL;
906  case CLI_GENERATE:
907  return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
908  }
909 
910  if (a->argc != e->args + 1) {
911  return CLI_SHOWUSAGE;
912  }
913 
914  chan = ast_channel_get_by_name(a->argv[e->args]);
915  if (!chan) {
916  ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
917  return CLI_FAILURE;
918  }
919 
920  ast_channel_lock(chan);
922  ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
923  }
924  ast_channel_unlock(chan);
925 
926  ast_channel_unref(chan);
927  return CLI_SUCCESS;
928 }
929 
930 /*! \brief CLI support for executing function */
931 static char *handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
932 {
933  struct ast_channel *c = NULL;
934  char *fn, *substituted;
935  int ret;
936  char workspace[1024];
937 
938  switch (cmd) {
939  case CLI_INIT:
940  e->command = "dialplan eval function";
941  e->usage =
942  "Usage: dialplan eval function <name(args)>\n"
943  " Evaluate a dialplan function call\n"
944  " A dummy channel is used to evaluate\n"
945  " the function call, so only global\n"
946  " variables should be used.\n";
947  return NULL;
948  case CLI_GENERATE:
949  return NULL;
950  }
951 
952  if (a->argc != e->args + 1) {
953  return CLI_SHOWUSAGE;
954  }
955 
957  if (!c) {
958  ast_cli(a->fd, "Unable to allocate bogus channel for function evaluation.\n");
959  return CLI_FAILURE;
960  }
961 
962  fn = (char *) a->argv[3];
963  pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
964  substituted = ast_strdupa(workspace);
965  workspace[0] = '\0';
966  ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
967 
968  c = ast_channel_unref(c);
969 
970  ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
971  ast_cli(a->fd, "Result: %s\n", workspace);
972 
973  return CLI_SUCCESS;
974 }
975 
976 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
977 {
978  switch (cmd) {
979  case CLI_INIT:
980  e->command = "dialplan set global";
981  e->usage =
982  "Usage: dialplan set global <name> <value>\n"
983  " Set global dialplan variable <name> to <value>\n";
984  return NULL;
985  case CLI_GENERATE:
986  return NULL;
987  }
988 
989  if (a->argc != e->args + 2)
990  return CLI_SHOWUSAGE;
991 
992  pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
993  ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
994 
995  return CLI_SUCCESS;
996 }
997 
998 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
999 {
1000  struct ast_channel *chan;
1001  const char *chan_name, *var_name, *var_value;
1002 
1003  switch (cmd) {
1004  case CLI_INIT:
1005  e->command = "dialplan set chanvar";
1006  e->usage =
1007  "Usage: dialplan set chanvar <channel> <varname> <value>\n"
1008  " Set channel variable <varname> to <value>\n";
1009  return NULL;
1010  case CLI_GENERATE:
1011  return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1012  }
1013 
1014  if (a->argc != e->args + 3)
1015  return CLI_SHOWUSAGE;
1016 
1017  chan_name = a->argv[e->args];
1018  var_name = a->argv[e->args + 1];
1019  var_value = a->argv[e->args + 2];
1020 
1021  if (!(chan = ast_channel_get_by_name(chan_name))) {
1022  ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
1023  return CLI_FAILURE;
1024  }
1025 
1026  pbx_builtin_setvar_helper(chan, var_name, var_value);
1027 
1028  chan = ast_channel_unref(chan);
1029 
1030  ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
1031 
1032  return CLI_SUCCESS;
1033 }
1034 
1036 {
1037  struct ast_var_t *variables;
1038  const char *var, *val;
1039  int total = 0;
1040 
1041  if (!chan)
1042  return 0;
1043 
1044  ast_str_reset(*buf);
1045 
1046  ast_channel_lock(chan);
1047 
1048  AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
1049  if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1050  /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1051  ) {
1052  if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1053  ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1054  break;
1055  } else
1056  total++;
1057  } else
1058  break;
1059  }
1060 
1061  ast_channel_unlock(chan);
1062 
1063  return total;
1064 }
1065 
1066 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
1067 {
1068  struct ast_var_t *variables;
1069  const char *ret = NULL;
1070  int i;
1071  struct varshead *places[2] = { NULL, &globals };
1072 
1073  if (!name)
1074  return NULL;
1075 
1076  if (chan) {
1077  ast_channel_lock(chan);
1078  places[0] = ast_channel_varshead(chan);
1079  }
1080 
1081  for (i = 0; i < 2; i++) {
1082  if (!places[i])
1083  continue;
1084  if (places[i] == &globals)
1086  AST_LIST_TRAVERSE(places[i], variables, entries) {
1087  if (!strcmp(name, ast_var_name(variables))) {
1088  ret = ast_var_value(variables);
1089  break;
1090  }
1091  }
1092  if (places[i] == &globals)
1094  if (ret)
1095  break;
1096  }
1097 
1098  if (chan)
1099  ast_channel_unlock(chan);
1100 
1101  return ret;
1102 }
1103 
1104 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
1105 {
1106  struct ast_var_t *newvariable;
1107  struct varshead *headp;
1108 
1109  if (name[strlen(name)-1] == ')') {
1110  char *function = ast_strdupa(name);
1111 
1112  ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1113  ast_func_write(chan, function, value);
1114  return;
1115  }
1116 
1117  if (chan) {
1118  ast_channel_lock(chan);
1119  headp = ast_channel_varshead(chan);
1120  } else {
1122  headp = &globals;
1123  }
1124 
1125  if (value && (newvariable = ast_var_assign(name, value))) {
1126  if (headp == &globals)
1127  ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1128  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1129  }
1130 
1131  if (chan)
1132  ast_channel_unlock(chan);
1133  else
1135 }
1136 
1137 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
1138 {
1139  struct ast_var_t *newvariable;
1140  struct varshead *headp;
1141  const char *nametail = name;
1142  /*! True if the old value was not an empty string. */
1143  int old_value_existed = 0;
1144 
1145  if (name[strlen(name) - 1] == ')') {
1146  char *function = ast_strdupa(name);
1147 
1148  return ast_func_write(chan, function, value);
1149  }
1150 
1151  if (chan) {
1152  ast_channel_lock(chan);
1153  headp = ast_channel_varshead(chan);
1154  } else {
1156  headp = &globals;
1157  }
1158 
1159  /* For comparison purposes, we have to strip leading underscores */
1160  if (*nametail == '_') {
1161  nametail++;
1162  if (*nametail == '_')
1163  nametail++;
1164  }
1165 
1166  AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1167  if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1168  /* there is already such a variable, delete it */
1169  AST_LIST_REMOVE_CURRENT(entries);
1170  old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1171  ast_var_delete(newvariable);
1172  break;
1173  }
1174  }
1176 
1177  if (value && (newvariable = ast_var_assign(name, value))) {
1178  if (headp == &globals) {
1179  ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1180  }
1181  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1183  } else if (old_value_existed) {
1184  /* We just deleted a non-empty dialplan variable. */
1185  ast_channel_publish_varset(chan, name, "");
1186  }
1187 
1188  if (chan)
1189  ast_channel_unlock(chan);
1190  else
1192  return 0;
1193 }
1194 
1195 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
1196 {
1197  char *name, *value, *mydata;
1198 
1199  if (ast_strlen_zero(data)) {
1200  ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1201  return 0;
1202  }
1203 
1204  mydata = ast_strdupa(data);
1205  name = strsep(&mydata, "=");
1206  value = mydata;
1207  if (!value) {
1208  ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1209  return 0;
1210  }
1211 
1212  if (strchr(name, ' ')) {
1213  ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1214  }
1215 
1217 
1218  return 0;
1219 }
1220 
1221 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
1222 {
1223  char *data;
1224  int x;
1226  AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1227  );
1229  AST_APP_ARG(name);
1230  AST_APP_ARG(value);
1231  );
1232 
1233  if (ast_strlen_zero(vdata)) {
1234  ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1235  return 0;
1236  }
1237 
1238  data = ast_strdupa(vdata);
1239  AST_STANDARD_APP_ARGS(args, data);
1240 
1241  for (x = 0; x < args.argc; x++) {
1242  AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1243  if (pair.argc == 2) {
1244  pbx_builtin_setvar_helper(chan, pair.name, pair.value);
1245  if (strchr(pair.name, ' '))
1246  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);
1247  } else if (!chan) {
1248  ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1249  } else {
1250  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));
1251  }
1252  }
1253 
1254  return 0;
1255 }
1256 
1258 {
1259  struct ast_var_t *vardata;
1260 
1262  while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1263  ast_var_delete(vardata);
1265 }
1266 
1267 static struct ast_cli_entry vars_cli[] = {
1268  AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
1269  AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
1270  AST_CLI_DEFINE(handle_eval_function, "Evaluate dialplan function"),
1271  AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
1272  AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
1273 };
1274 
1275 static void unload_pbx_variables(void)
1276 {
1281 }
1282 
1284 {
1285  int res = 0;
1286 
1291 
1292  return res;
1293 }
Prototypes for public functions only of internal interest,.
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:614
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:2447
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2405
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 char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1815
const char * ast_channel_uniqueid(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2922
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
int ast_channel_hangupcause(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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:1448
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
struct varshead * ast_channel_varshead(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
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:2472
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
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:1862
#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
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
char * strsep(char **str, const char *delims)
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
A set of macros to manage forward-linked lists.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_HEAD_NOLOCK_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD_NOLOCK.
Definition: linkedlists.h:252
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
Asterisk locking-related definitions:
#define ast_rwlock_wrlock(a)
Definition: lock.h:234
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
#define ast_rwlock_unlock(a)
Definition: lock.h:232
Asterisk module definitions.
int ast_register_application2(const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
Register an application.
Definition: pbx_app.c:103
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
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:4162
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_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, char *context, char *exten, int pri)
Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the contex...
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
static char * handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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(struct ast_channel *chan, const char *data)
Parse and set a single channel variable, where the name and value are separated with an '=' character...
void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
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)
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
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)
static char * handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
const char * ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
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 ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
static char * handle_eval_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
CLI support for executing function.
void pbx_builtin_clear_globals(void)
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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.
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 * 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.
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 const char * ast_str_substring(struct ast_str *value, int offset, int length)
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.
static struct varshead globals
static int total
Definition: res_adsi.c:968
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:764
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:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
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:1040
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:674
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
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:1091
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:684
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:711
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:1033
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406
Main Channel structure associated with a channel.
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:604
struct ast_var_t::@239 entries
Number structure.
Definition: app_followme.c:154
const char * name
Definition: test_config.c:85
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
const char * args
static struct test_val a
static struct test_val c
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: main/utils.c:2735
#define ARRAY_LEN(a)
Definition: utils.h:661
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93