Asterisk - The Open Source Telephony Project  21.4.1
Macros | Functions | Variables
pbx_variables.c File Reference

PBX variables routines. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/app.h"
#include "asterisk/ast_expr.h"
#include "asterisk/chanvars.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.h"
#include "asterisk/lock.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
#include "asterisk/pbx.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/test.h"
#include "pbx_private.h"

Go to the source code of this file.

Macros

#define MAX_VARIABLE_SUB_RECURSE_DEPTH   15
 

Functions

static void __init_varsub_recurse_level (void)
 Thread local keeping track of recursion depth.
 
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)
 
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)
 
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. More...
 
void ast_str_substitute_variables_varshead (struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
 
static const char * ast_str_substring (struct ast_str *value, int offset, int length)
 
static char * handle_eval_function (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 CLI support for executing function.
 
static char * handle_set_chanvar (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * handle_set_global (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.
 
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.
 
int load_pbx_variables (void)
 
static int parse_variable_name (char *var, int *offset, int *length, int *isfunc)
 extract offset:length from variable name. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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, and name and value are separated with an '=' character. More...
 
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. More...
 
void pbx_substitute_variables_helper (struct ast_channel *c, const char *cp1, char *cp2, int count)
 
void pbx_substitute_variables_helper_full (struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
 
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 context, extension, and priority in.
 
void pbx_substitute_variables_varshead (struct varshead *headp, const char *cp1, char *cp2, int count)
 
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. More...
 
static void unload_pbx_variables (void)
 

Variables

static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
 
static ast_rwlock_t globalslock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
 
static struct ast_cli_entry vars_cli []
 
static struct ast_threadstorage varsub_recurse_level = { .once = PTHREAD_ONCE_INIT , .key_init = __init_varsub_recurse_level , .custom_init = NULL , }
 

Detailed Description

PBX variables routines.

Author
Corey Farrell git@c.nosp@m.fwar.nosp@m.e.com

Definition in file pbx_variables.c.

Function Documentation

const char* ast_str_retrieve_variable ( struct ast_str **  buf,
ssize_t  maxlen,
struct ast_channel chan,
struct varshead headp,
const char *  var 
)
Parameters
bufResult will be placed in this buffer.
maxlen-1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
chanChannel variables from which to extract values, and channel to pass to any dialplan functions.
headpIf no channel is specified, a channel list from which to extract variable values
varVariable name to retrieve.

Definition at line 250 of file pbx_variables.c.

References ast_debug, ast_eid_default, ast_eid_to_str(), AST_LIST_TRAVERSE, ast_party_id_presentation(), ast_str_buffer(), ast_str_get_hint(), ast_str_set(), ast_strdupa, and parse_variable_name().

Referenced by ast_ari_asterisk_get_global_var(), ast_ari_channels_get_channel_var(), ast_str_substitute_variables_full2(), and pbx_retrieve_variable().

251 {
252  const char not_found = '\0';
253  char *tmpvar;
254  const char *ret;
255  const char *s; /* the result */
256  int offset, length;
257  int i, need_substring;
258  struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
259  char workspace[20];
260 
261  if (c) {
262  ast_channel_lock(c);
263  places[0] = ast_channel_varshead(c);
264  }
265  /*
266  * Make a copy of var because parse_variable_name() modifies the string.
267  * Then if called directly, we might need to run substring() on the result;
268  * remember this for later in 'need_substring', 'offset' and 'length'
269  */
270  tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
271  need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
272 
273  /*
274  * Look first into predefined variables, then into variable lists.
275  * Variable 's' points to the result, according to the following rules:
276  * s == &not_found (set at the beginning) means that we did not find a
277  * matching variable and need to look into more places.
278  * If s != &not_found, s is a valid result string as follows:
279  * s = NULL if the variable does not have a value;
280  * you typically do this when looking for an unset predefined variable.
281  * s = workspace if the result has been assembled there;
282  * typically done when the result is built e.g. with an snprintf(),
283  * so we don't need to do an additional copy.
284  * s != workspace in case we have a string, that needs to be copied
285  * (the ast_copy_string is done once for all at the end).
286  * Typically done when the result is already available in some string.
287  */
288  s = &not_found; /* default value */
289  if (c) { /* This group requires a valid channel */
290  /* Names with common parts are looked up a piece at a time using strncmp. */
291  if (!strncmp(var, "CALL", 4)) {
292  if (!strncmp(var + 4, "ING", 3)) {
293  if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
294  ast_str_set(str, maxlen, "%d",
295  ast_party_id_presentation(&ast_channel_caller(c)->id));
296  s = ast_str_buffer(*str);
297  } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
298  ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
299  s = ast_str_buffer(*str);
300  } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
301  ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
302  s = ast_str_buffer(*str);
303  } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
304  ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
305  s = ast_str_buffer(*str);
306  }
307  }
308  } else if (!strcmp(var, "HINT")) {
309  s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
310  } else if (!strcmp(var, "HINTNAME")) {
311  s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
312  } else if (!strcmp(var, "EXTEN")) {
313  s = ast_channel_exten(c);
314  } else if (!strcmp(var, "CONTEXT")) {
315  s = ast_channel_context(c);
316  } else if (!strcmp(var, "PRIORITY")) {
317  ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
318  s = ast_str_buffer(*str);
319  } else if (!strcmp(var, "CHANNEL")) {
320  s = ast_channel_name(c);
321  } else if (!strcmp(var, "UNIQUEID")) {
322  s = ast_channel_uniqueid(c);
323  } else if (!strcmp(var, "HANGUPCAUSE")) {
324  ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
325  s = ast_str_buffer(*str);
326  }
327  }
328  if (s == &not_found) { /* look for more */
329  if (!strcmp(var, "EPOCH")) {
330  ast_str_set(str, maxlen, "%d", (int) time(NULL));
331  s = ast_str_buffer(*str);
332  } else if (!strcmp(var, "SYSTEMNAME")) {
333  s = ast_config_AST_SYSTEM_NAME;
334  } else if (!strcmp(var, "ASTCACHEDIR")) {
335  s = ast_config_AST_CACHE_DIR;
336  } else if (!strcmp(var, "ASTETCDIR")) {
337  s = ast_config_AST_CONFIG_DIR;
338  } else if (!strcmp(var, "ASTMODDIR")) {
339  s = ast_config_AST_MODULE_DIR;
340  } else if (!strcmp(var, "ASTVARLIBDIR")) {
341  s = ast_config_AST_VAR_DIR;
342  } else if (!strcmp(var, "ASTDBDIR")) {
343  s = ast_config_AST_DB;
344  } else if (!strcmp(var, "ASTKEYDIR")) {
345  s = ast_config_AST_KEY_DIR;
346  } else if (!strcmp(var, "ASTDATADIR")) {
347  s = ast_config_AST_DATA_DIR;
348  } else if (!strcmp(var, "ASTAGIDIR")) {
349  s = ast_config_AST_AGI_DIR;
350  } else if (!strcmp(var, "ASTSPOOLDIR")) {
351  s = ast_config_AST_SPOOL_DIR;
352  } else if (!strcmp(var, "ASTRUNDIR")) {
353  s = ast_config_AST_RUN_DIR;
354  } else if (!strcmp(var, "ASTLOGDIR")) {
355  s = ast_config_AST_LOG_DIR;
356  } else if (!strcmp(var, "ASTSBINDIR")) {
357  s = ast_config_AST_SBIN_DIR;
358  } else if (!strcmp(var, "ENTITYID")) {
359  ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
360  s = workspace;
361  }
362  }
363  /* if not found, look into chanvars or global vars */
364  for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
365  struct ast_var_t *variables;
366  if (!places[i])
367  continue;
368  if (places[i] == &globals)
369  ast_rwlock_rdlock(&globalslock);
370  AST_LIST_TRAVERSE(places[i], variables, entries) {
371  if (!strcmp(ast_var_name(variables), var)) {
372  s = ast_var_value(variables);
373  break;
374  }
375  }
376  if (places[i] == &globals)
377  ast_rwlock_unlock(&globalslock);
378  }
379  if (s == &not_found || s == NULL) {
380  ast_debug(5, "Result of '%s' is NULL\n", var);
381  ret = NULL;
382  } else {
383  ast_debug(5, "Result of '%s' is '%s'\n", var, s);
384  if (s != ast_str_buffer(*str)) {
385  ast_str_set(str, maxlen, "%s", s);
386  }
387  ret = ast_str_buffer(*str);
388  if (need_substring) {
389  ret = ast_str_substring(*str, offset, length);
390  ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
391  }
392  }
393 
394  if (c) {
395  ast_channel_unlock(c);
396  }
397  return ret;
398 }
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1821
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4155
Number structure.
Definition: app_followme.c:154
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
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93
void ast_str_substitute_variables ( struct ast_str **  buf,
ssize_t  maxlen,
struct ast_channel chan,
const char *  templ 
)
Parameters
bufResult will be placed in this buffer.
maxlen-1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
chanChannel variables from which to extract values, and channel to pass to any dialplan functions.
templVariable template to expand.

Definition at line 650 of file pbx_variables.c.

References ast_str_substitute_variables_full().

Referenced by acf_odbc_write(), ast_pbx_exec_application(), destroy_curl(), handle_exec(), make_email_file(), realtime_curl(), realtime_multi_curl(), store_curl(), and update_curl().

651 {
652  ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
653 }
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)
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 
)
Parameters
bufResult will be placed in this buffer.
maxlen-1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
cChannel variables from which to extract values, and channel to pass to any dialplan functions.
headpIf no channel is specified, a channel list from which to extract variable values
templVariable template to expand.
usedNumber of bytes read from the template. (May be NULL)

Definition at line 644 of file pbx_variables.c.

References ast_str_substitute_variables_full2().

Referenced by ast_str_substitute_variables(), and ast_str_substitute_variables_varshead().

646 {
647  ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);
648 }
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.
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.

Parameters
bufResult will be placed in this buffer.
maxlen-1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
cA channel from which to extract values, and to pass to any dialplan functions.
headpA channel variables list to also search for variables.
templVariable template to expand.
usedNumber of bytes read from the template. (May be NULL)
use_bothNormally, if a channel is specified, headp is ignored. If this parameter is set to 1 and both a channel and headp are specified, the channel will be searched for variables first and any not found will be searched for in headp.

Definition at line 400 of file pbx_variables.c.

References ast_channel_unref, ast_debug, ast_dummy_channel_alloc, ast_func_read2(), ast_str_append(), ast_str_append_substr(), ast_str_buffer(), ast_str_create, ast_str_expr(), ast_str_reset(), ast_str_retrieve_variable(), ast_str_set_substr(), ast_str_strlen(), parse_variable_name(), and S_OR.

Referenced by ast_str_substitute_variables_full().

403 {
404  /* Substitutes variables into buf, based on string templ */
405  const char *whereweare;
406  struct ast_str *substr1 = ast_str_create(16);
407  struct ast_str *substr2 = NULL;
408  struct ast_str *substr3 = ast_str_create(16);
409 
410  ast_str_reset(*buf);
411 
412  if (!substr1 || !substr3) {
413  if (used) {
414  *used = ast_str_strlen(*buf);
415  }
416  ast_free(substr1);
417  ast_free(substr3);
418  return;
419  }
420 
421  whereweare = templ;
422  while (!ast_strlen_zero(whereweare)) {
423  const char *nextvar = NULL;
424  const char *nextexp = NULL;
425  const char *nextthing;
426  const char *vars;
427  const char *vare;
428  char *finalvars;
429  int pos;
430  int brackets;
431  int needsub;
432  int len;
433 
434  /* reset our buffer */
435  ast_str_reset(substr3);
436 
437  /* Determine how much simply needs to be copied to the output buf. */
438  nextthing = strchr(whereweare, '$');
439  if (nextthing) {
440  pos = nextthing - whereweare;
441  switch (nextthing[1]) {
442  case '{':
443  /* Variable substitution */
444  nextvar = nextthing;
445  break;
446  case '[':
447  /* Expression substitution */
448  nextexp = nextthing;
449  break;
450  default:
451  /* '$' is not part of a substitution so include it too. */
452  ++pos;
453  break;
454  }
455  } else {
456  /* We're copying the whole remaining string */
457  pos = strlen(whereweare);
458  }
459 
460  if (pos) {
461  /* Copy that many bytes */
462  ast_str_append_substr(buf, maxlen, whereweare, pos);
463 
464  whereweare += pos;
465  }
466 
467  if (nextvar) {
468  int offset;
469  int offset2;
470  int isfunction;
471  int res;
472 
473  /* We have a variable. Find the start and end, and determine
474  if we are going to have to recursively call ourselves on the
475  contents */
476  vars = vare = nextvar + 2;
477  brackets = 1;
478  needsub = 0;
479 
480  /* Find the end of it */
481  while (brackets && *vare) {
482  if ((vare[0] == '$') && (vare[1] == '{')) {
483  needsub++;
484  brackets++;
485  vare++;
486  } else if (vare[0] == '{') {
487  brackets++;
488  } else if (vare[0] == '}') {
489  brackets--;
490  } else if ((vare[0] == '$') && (vare[1] == '[')) {
491  needsub++;
492  vare++;
493  }
494  vare++;
495  }
496  len = vare - vars;
497  if (brackets) {
498  ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
499  } else {
500  /* Don't count the closing '}' in the length. */
501  --len;
502  }
503 
504  /* Skip totally over variable string */
505  whereweare = vare;
506 
507  /* Store variable name expression to lookup. */
508  ast_str_set_substr(&substr1, 0, vars, len);
509  ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n",
510  ast_str_buffer(substr1), vars, len);
511 
512  /* Substitute if necessary */
513  if (needsub) {
514  if (!substr2) {
515  substr2 = ast_str_create(16);
516  if (!substr2) {
517  continue;
518  }
519  }
520  ast_str_substitute_variables_full2(&substr2, 0, c, headp,
521  ast_str_buffer(substr1), NULL, use_both);
522  finalvars = ast_str_buffer(substr2);
523  } else {
524  finalvars = ast_str_buffer(substr1);
525  }
526 
527  parse_variable_name(finalvars, &offset, &offset2, &isfunction);
528  if (isfunction) {
529  /* Evaluate function */
530  res = -1;
531  if (c) {
532  res = ast_func_read2(c, finalvars, &substr3, 0);
533  ast_debug(2, "Function %s result is '%s' from channel\n",
534  finalvars, res ? "" : ast_str_buffer(substr3));
535  }
536  if (!c || (c && res < 0 && use_both)) {
537  struct varshead old;
538  struct ast_channel *bogus;
539 
540  bogus = ast_dummy_channel_alloc();
541  if (bogus) {
542  old = *ast_channel_varshead(bogus);
543  if (headp) {
544  *ast_channel_varshead(bogus) = *headp;
545  }
546  res = ast_func_read2(bogus, finalvars, &substr3, 0);
547  /* Don't deallocate the varshead that was passed in */
548  if (headp) {
549  *ast_channel_varshead(bogus) = old;
550  }
551  ast_channel_unref(bogus);
552  } else {
553  ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
554  res = -1;
555  }
556  ast_debug(2, "Function %s result is '%s' from headp\n",
557  finalvars, res ? "" : ast_str_buffer(substr3));
558  }
559  } else {
560  const char *result;
561  if (c) {
562  result = ast_str_retrieve_variable(&substr3, 0, c, NULL, finalvars);
563  ast_debug(2, "Variable %s result is '%s' from channel\n",
564  finalvars, S_OR(result, ""));
565  }
566  if (!c || (c && !result && use_both)) {
567  result = ast_str_retrieve_variable(&substr3, 0, NULL, headp, finalvars);
568  ast_debug(2, "Variable %s result is '%s' from headp\n",
569  finalvars, S_OR(result, ""));
570  }
571  res = (result ? 0 : -1);
572  }
573  if (!res) {
574  ast_str_substring(substr3, offset, offset2);
575  ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
576  }
577  } else if (nextexp) {
578  /* We have an expression. Find the start and end, and determine
579  if we are going to have to recursively call ourselves on the
580  contents */
581  vars = vare = nextexp + 2;
582  brackets = 1;
583  needsub = 0;
584 
585  /* Find the end of it */
586  while (brackets && *vare) {
587  if ((vare[0] == '$') && (vare[1] == '[')) {
588  needsub++;
589  brackets++;
590  vare++;
591  } else if (vare[0] == '[') {
592  brackets++;
593  } else if (vare[0] == ']') {
594  brackets--;
595  } else if ((vare[0] == '$') && (vare[1] == '{')) {
596  needsub++;
597  vare++;
598  }
599  vare++;
600  }
601  len = vare - vars;
602  if (brackets) {
603  ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
604  } else {
605  /* Don't count the closing ']' in the length. */
606  --len;
607  }
608 
609  /* Skip totally over expression */
610  whereweare = vare;
611 
612  /* Store expression to evaluate. */
613  ast_str_set_substr(&substr1, 0, vars, len);
614 
615  /* Substitute if necessary */
616  if (needsub) {
617  if (!substr2) {
618  substr2 = ast_str_create(16);
619  if (!substr2) {
620  continue;
621  }
622  }
623  ast_str_substitute_variables_full2(&substr2, 0, c, headp,
624  ast_str_buffer(substr1), NULL, use_both);
625  finalvars = ast_str_buffer(substr2);
626  } else {
627  finalvars = ast_str_buffer(substr1);
628  }
629 
630  if (ast_str_expr(&substr3, 0, c, finalvars)) {
631  ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
632  }
633  ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
634  }
635  }
636  if (used) {
637  *used = ast_str_strlen(*buf);
638  }
639  ast_free(substr1);
640  ast_free(substr2);
641  ast_free(substr3);
642 }
Main Channel structure associated with a channel.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
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
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
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
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.
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1282
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
#define ast_debug(level,...)
Log a DEBUG message.
Support for dynamic strings.
Definition: strings.h:623
int ast_str_expr(struct ast_str **str, ssize_t maxlen, struct ast_channel *chan, char *expr)
Evaluate the given expression.
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
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
#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
const char * ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
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
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
void ast_str_substitute_variables_varshead ( struct ast_str **  buf,
ssize_t  maxlen,
struct varshead headp,
const char *  templ 
)
Parameters
bufResult will be placed in this buffer.
maxlen-1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
headpIf no channel is specified, a channel list from which to extract variable values
templVariable template to expand.

Definition at line 655 of file pbx_variables.c.

References ast_str_substitute_variables_full().

656 {
657  ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
658 }
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 load_pbx_variables ( void  )

Provided by pbx_variables.c

Definition at line 1403 of file pbx_variables.c.

References ast_cli_register_multiple, ast_register_application2(), ast_register_cleanup(), pbx_builtin_setvar(), and pbx_builtin_setvar_multiple().

1404 {
1405  int res = 0;
1406 
1407  res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));
1408  res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);
1409  res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);
1410  ast_register_cleanup(unload_pbx_variables);
1411  AST_TEST_REGISTER(test_variable_substrings);
1412 
1413  return res;
1414 }
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
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...
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 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 int parse_variable_name ( char *  var,
int *  offset,
int *  length,
int *  isfunc 
)
static

extract offset:length from variable name.

Returns
1 if there is a offset:length part, which is trimmed off (values go into variables)

Definition at line 118 of file pbx_variables.c.

Referenced by ast_str_retrieve_variable(), ast_str_substitute_variables_full2(), and pbx_substitute_variables_helper_full_location().

119 {
120  int parens = 0;
121 
122  *offset = 0;
123  *length = INT_MAX;
124  *isfunc = 0;
125  for (; *var; var++) {
126  if (*var == '(') {
127  (*isfunc)++;
128  parens++;
129  } else if (*var == ')') {
130  parens--;
131  } else if (*var == ':' && parens == 0) {
132  *var++ = '\0';
133  sscanf(var, "%30d:%30d", offset, length);
134  return 1; /* offset:length valid */
135  }
136  }
137  return 0;
138 }
const char* pbx_builtin_getvar_helper ( struct ast_channel chan,
const char *  name 
)

Return a pointer to the value of the corresponding channel variable.

Note
Will lock the channel.
This function will return a pointer to the buffer inside the channel variable. This value should only be accessed with the channel locked. If the value needs to be kept around, it should be done by using the following thread-safe code:
1 const char *var;
2 
3 ast_channel_lock(chan);
4 if ((var = pbx_builtin_getvar_helper(chan, "MYVAR"))) {
5  var = ast_strdupa(var);
6 }
7 ast_channel_unlock(chan);

Definition at line 1117 of file pbx_variables.c.

References AST_LIST_TRAVERSE.

Referenced by __ast_pbx_run(), agent_request_exec(), ast_bridge_call_with_flags(), ast_bridge_timelimit(), ast_bridge_transfer_attended(), ast_call_forward(), ast_channel_connected_line_sub(), ast_channel_redirecting_sub(), ast_unreal_hangup(), dial_exec_full(), do_forward(), feature_blind_transfer(), find_by_mark(), find_channel_parking_lot_name(), generic_fax_exec(), handle_call_forward(), iax2_exec(), leave_voicemail(), notify_new_message(), permit_dtmf_interrupt(), pjsip_acf_parse_uri_read(), queue_exec(), receive_ademco_event(), report_receive_fax_status(), report_send_fax_status(), run_agi(), sig_pri_call(), speech_background(), and wait_for_answer().

1118 {
1119  struct ast_var_t *variables;
1120  const char *ret = NULL;
1121  int i;
1122  struct varshead *places[2] = { NULL, &globals };
1123 
1124  if (!name)
1125  return NULL;
1126 
1127  if (chan) {
1128  ast_channel_lock(chan);
1129  places[0] = ast_channel_varshead(chan);
1130  }
1131 
1132  for (i = 0; i < 2; i++) {
1133  if (!places[i])
1134  continue;
1135  if (places[i] == &globals)
1136  ast_rwlock_rdlock(&globalslock);
1137  AST_LIST_TRAVERSE(places[i], variables, entries) {
1138  if (!strcmp(name, ast_var_name(variables))) {
1139  ret = ast_var_value(variables);
1140  break;
1141  }
1142  }
1143  if (places[i] == &globals)
1144  ast_rwlock_unlock(&globalslock);
1145  if (ret)
1146  break;
1147  }
1148 
1149  if (chan)
1150  ast_channel_unlock(chan);
1151 
1152  return ret;
1153 }
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
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.

Note
Will lock the channel.

Definition at line 1155 of file pbx_variables.c.

References ast_func_write(), AST_LIST_INSERT_HEAD, and ast_strdupa.

Referenced by acf_odbc_write().

1156 {
1157  struct ast_var_t *newvariable;
1158  struct varshead *headp;
1159 
1160  if (name[strlen(name)-1] == ')') {
1161  char *function = ast_strdupa(name);
1162 
1163  ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1164  ast_func_write(chan, function, value);
1165  return;
1166  }
1167 
1168  if (chan) {
1169  ast_channel_lock(chan);
1170  headp = ast_channel_varshead(chan);
1171  } else {
1172  ast_rwlock_wrlock(&globalslock);
1173  headp = &globals;
1174  }
1175 
1176  if (value && (newvariable = ast_var_assign(name, value))) {
1177  if (headp == &globals)
1178  ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1179  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1180  }
1181 
1182  if (chan)
1183  ast_channel_unlock(chan);
1184  else
1185  ast_rwlock_unlock(&globalslock);
1186 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
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.

Parameters
chanChannel from which to read variables
bufDynamic string in which to place the result (should be allocated with ast_str_create).
See also
ast_str_create
Note
Will lock the channel.

Definition at line 1086 of file pbx_variables.c.

References AST_LIST_TRAVERSE, ast_str_append(), and ast_str_reset().

1087 {
1088  struct ast_var_t *variables;
1089  const char *var, *val;
1090  int total = 0;
1091 
1092  if (!chan)
1093  return 0;
1094 
1095  ast_str_reset(*buf);
1096 
1097  ast_channel_lock(chan);
1098 
1099  AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
1100  if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1101  /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1102  ) {
1103  if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1104  ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1105  break;
1106  } else
1107  total++;
1108  } else
1109  break;
1110  }
1111 
1112  ast_channel_unlock(chan);
1113 
1114  return total;
1115 }
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
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
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
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.

Note
Will lock the channel.

Definition at line 1246 of file pbx_variables.c.

References ast_strdupa, and pbx_builtin_setvar_helper().

Referenced by load_pbx_variables().

1247 {
1248  char *name, *value, *mydata;
1249 
1250  if (ast_strlen_zero(data)) {
1251  ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1252  return 0;
1253  }
1254 
1255  mydata = ast_strdupa(data);
1256  name = strsep(&mydata, "=");
1257  value = mydata;
1258  if (!value) {
1259  ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1260  return 0;
1261  }
1262 
1263  if (strchr(name, ' ')) {
1264  ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1265  }
1266 
1267  pbx_builtin_setvar_helper(chan, name, value);
1268 
1269  return 0;
1270 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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...
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.

Note
Will lock the channel. May also be used to set a channel dialplan function to a particular value.
See also
ast_func_write
Returns
-1 if the dialplan function fails to be set
Version
1.8 changed the function to return an error code

True if the old value was not an empty string.

Definition at line 1188 of file pbx_variables.c.

References ast_channel_publish_varset(), ast_func_write(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, and ast_strdupa.

Referenced by __ast_pbx_run(), acf_odbc_write(), admin_exec(), agent_login_exec(), agent_request_exec(), app_exec(), aqm_exec(), ast_ari_asterisk_set_global_var(), ast_bridge_set_transfer_variables(), ast_bridge_vars_set(), ast_call_forward(), ast_cc_agent_set_interfaces_chanvar(), ast_iax2_new(), ast_pbx_outgoing_exten_predial(), ast_pickup_call(), ast_rtp_instance_set_stats_vars(), ast_set_cc_interfaces_chanvar(), ast_set_variables(), ast_unreal_hangup(), attended_transfer_bridge(), audiosocket_request(), begin_dial_channel(), bridge_exec(), chan_pjsip_cng_tone_detected(), chan_pjsip_new(), confbridge_exec(), count_exec(), dial_exec_full(), dial_transfer(), do_forward(), dtmf_store_framehook(), fax_detect_framehook(), handle_response_cmgr(), leave_queue(), leave_voicemail(), lua_set_variable(), lua_set_variable_value(), minivm_accmess_exec(), pbx_builtin_setvar(), pbx_builtin_setvar_multiple(), pqm_exec(), queue_exec(), read_mf_digits(), read_sf_digits(), receivefax_exec(), record_abandoned(), ring_entry(), rqm_exec(), sendfax_exec(), set_channel_variables(), set_queue_result(), sla_calc_trunk_timeouts(), speech_create(), unicast_rtp_request(), update_qe_rule(), upqm_exec(), and wait_for_answer().

1189 {
1190  struct ast_var_t *newvariable;
1191  struct varshead *headp;
1192  const char *nametail = name;
1193  /*! True if the old value was not an empty string. */
1194  int old_value_existed = 0;
1195 
1196  if (name[strlen(name) - 1] == ')') {
1197  char *function = ast_strdupa(name);
1198 
1199  return ast_func_write(chan, function, value);
1200  }
1201 
1202  if (chan) {
1203  ast_channel_lock(chan);
1204  headp = ast_channel_varshead(chan);
1205  } else {
1206  ast_rwlock_wrlock(&globalslock);
1207  headp = &globals;
1208  }
1209 
1210  /* For comparison purposes, we have to strip leading underscores */
1211  if (*nametail == '_') {
1212  nametail++;
1213  if (*nametail == '_')
1214  nametail++;
1215  }
1216 
1217  AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1218  if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1219  /* there is already such a variable, delete it */
1220  AST_LIST_REMOVE_CURRENT(entries);
1221  old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1222  ast_var_delete(newvariable);
1223  break;
1224  }
1225  }
1227 
1228  if (value && (newvariable = ast_var_assign(name, value))) {
1229  if (headp == &globals) {
1230  ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1231  }
1232  AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1233  ast_channel_publish_varset(chan, name, value);
1234  } else if (old_value_existed) {
1235  /* We just deleted a non-empty dialplan variable. */
1236  ast_channel_publish_varset(chan, name, "");
1237  }
1238 
1239  if (chan)
1240  ast_channel_unlock(chan);
1241  else
1242  ast_rwlock_unlock(&globalslock);
1243  return 0;
1244 }
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
#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
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
int pbx_builtin_setvar_multiple ( struct ast_channel chan,
const char *  data 
)

Parse and set multiple channel variables, where the pairs are separated by the ',' character, and name and value are separated with an '=' character.

Note
Will lock the channel.

Definition at line 1272 of file pbx_variables.c.

References AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, and pbx_builtin_setvar_helper().

Referenced by load_pbx_variables(), queue_function_var(), and set_queue_variables().

1273 {
1274  char *data;
1275  int x;
1276  AST_DECLARE_APP_ARGS(args,
1277  AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1278  );
1280  AST_APP_ARG(name);
1281  AST_APP_ARG(value);
1282  );
1283 
1284  if (ast_strlen_zero(vdata)) {
1285  ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1286  return 0;
1287  }
1288 
1289  data = ast_strdupa(vdata);
1290  AST_STANDARD_APP_ARGS(args, data);
1291 
1292  for (x = 0; x < args.argc; x++) {
1293  AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1294  if (pair.argc == 2) {
1295  pbx_builtin_setvar_helper(chan, pair.name, pair.value);
1296  if (strchr(pair.name, ' '))
1297  ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
1298  } else if (!chan) {
1299  ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1300  } else {
1301  ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
1302  }
1303  }
1304 
1305  return 0;
1306 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
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...
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_APP_ARG(name)
Define an application argument.
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.

Retrieve the value of a builtin variable or variable from the channel variable stack.

Note
See also

Definition at line 239 of file pbx_variables.c.

References ast_copy_string(), ast_str_buffer(), ast_str_create, and ast_str_retrieve_variable().

Referenced by lua_get_variable(), lua_get_variable_value(), and pbx_substitute_variables_helper_full_location().

240 {
241  struct ast_str *str = ast_str_create(16);
242  const char *cret;
243 
244  cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
245  ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
246  *ret = cret ? workspace : NULL;
247  ast_free(str);
248 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Support for dynamic strings.
Definition: strings.h:623
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
const char * ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
static char* substring ( const char *  value,
int  offset,
int  length,
char *  workspace,
size_t  workspace_len 
)
static

takes a substring. It is ok to call with value == workspace.

Parameters
value
offset< 0 means start from the end of the string and set the beginning to be that many characters back.
lengthis the length of the substring, a value less than 0 means to leave that many off the end.
workspace
workspace_lenAlways return a copy in workspace.

Definition at line 151 of file pbx_variables.c.

References ast_copy_string().

Referenced by pbx_substitute_variables_helper_full_location().

152 {
153  char *ret = workspace;
154  int lr; /* length of the input string after the copy */
155 
156  ast_copy_string(workspace, value, workspace_len); /* always make a copy */
157 
158  lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
159 
160  /* Quick check if no need to do anything */
161  if (offset == 0 && length >= lr) /* take the whole string */
162  return ret;
163 
164  if (offset < 0) { /* translate negative offset into positive ones */
165  offset = lr + offset;
166  if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
167  offset = 0;
168  }
169 
170  /* too large offset result in empty string so we know what to return */
171  if (offset >= lr)
172  return ret + lr; /* the final '\0' */
173 
174  ret += offset; /* move to the start position */
175  if (length >= 0 && length < lr - offset) /* truncate if necessary */
176  ret[length] = '\0';
177  else if (length < 0) {
178  if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
179  ret[lr + length - offset] = '\0';
180  else
181  ret[0] = '\0';
182  }
183 
184  return ret;
185 }
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425