Asterisk - The Open Source Telephony Project GIT-master-77d630f
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/format_cache.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/test.h"
#include "pbx_private.h"
Include dependency graph for pbx_variables.c:

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. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
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 int cli_chan = 0
 
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
 
static ast_rwlock_t globalslock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
 
static const struct ast_channel_tech mock_channel_tech
 
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.

Macro Definition Documentation

◆ MAX_VARIABLE_SUB_RECURSE_DEPTH

#define MAX_VARIABLE_SUB_RECURSE_DEPTH   15

Definition at line 675 of file pbx_variables.c.

Function Documentation

◆ __init_varsub_recurse_level()

static void __init_varsub_recurse_level ( void  )
static

Thread local keeping track of recursion depth.

Definition at line 673 of file pbx_variables.c.

678{

◆ ast_str_retrieve_variable()

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 257 of file pbx_variables.c.

258{
259 const char not_found = '\0';
260 char *tmpvar;
261 const char *ret;
262 const char *s; /* the result */
263 int offset, length;
264 int i, need_substring;
265 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
266 char workspace[20];
267
268 if (c) {
270 places[0] = ast_channel_varshead(c);
271 }
272 /*
273 * Make a copy of var because parse_variable_name() modifies the string.
274 * Then if called directly, we might need to run substring() on the result;
275 * remember this for later in 'need_substring', 'offset' and 'length'
276 */
277 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
278 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
279
280 /*
281 * Look first into predefined variables, then into variable lists.
282 * Variable 's' points to the result, according to the following rules:
283 * s == &not_found (set at the beginning) means that we did not find a
284 * matching variable and need to look into more places.
285 * If s != &not_found, s is a valid result string as follows:
286 * s = NULL if the variable does not have a value;
287 * you typically do this when looking for an unset predefined variable.
288 * s = workspace if the result has been assembled there;
289 * typically done when the result is built e.g. with an snprintf(),
290 * so we don't need to do an additional copy.
291 * s != workspace in case we have a string, that needs to be copied
292 * (the ast_copy_string is done once for all at the end).
293 * Typically done when the result is already available in some string.
294 */
295 s = &not_found; /* default value */
296 if (c) { /* This group requires a valid channel */
297 /* Names with common parts are looked up a piece at a time using strncmp. */
298 if (!strncmp(var, "CALL", 4)) {
299 if (!strncmp(var + 4, "ING", 3)) {
300 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
301 ast_str_set(str, maxlen, "%d",
303 s = ast_str_buffer(*str);
304 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
305 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
306 s = ast_str_buffer(*str);
307 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
308 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
309 s = ast_str_buffer(*str);
310 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
311 ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
312 s = ast_str_buffer(*str);
313 }
314 }
315 } else if (!strcmp(var, "HINT")) {
317 } else if (!strcmp(var, "HINTNAME")) {
319 } else if (!strcmp(var, "EXTEN")) {
320 s = ast_channel_exten(c);
321 } else if (!strcmp(var, "CONTEXT")) {
323 } else if (!strcmp(var, "PRIORITY")) {
324 ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
325 s = ast_str_buffer(*str);
326 } else if (!strcmp(var, "CHANNEL")) {
327 s = ast_channel_name(c);
328 } else if (!strcmp(var, "UNIQUEID")) {
330 } else if (!strcmp(var, "HANGUPCAUSE")) {
331 ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
332 s = ast_str_buffer(*str);
333 }
334 }
335 if (s == &not_found) { /* look for more */
336 if (!strcmp(var, "EPOCH")) {
337 ast_str_set(str, maxlen, "%d", (int) time(NULL));
338 s = ast_str_buffer(*str);
339 } else if (!strcmp(var, "SYSTEMNAME")) {
341 } else if (!strcmp(var, "ASTCACHEDIR")) {
343 } else if (!strcmp(var, "ASTETCDIR")) {
345 } else if (!strcmp(var, "ASTMODDIR")) {
347 } else if (!strcmp(var, "ASTVARLIBDIR")) {
349 } else if (!strcmp(var, "ASTDBDIR")) {
351 } else if (!strcmp(var, "ASTKEYDIR")) {
353 } else if (!strcmp(var, "ASTDATADIR")) {
355 } else if (!strcmp(var, "ASTAGIDIR")) {
357 } else if (!strcmp(var, "ASTSPOOLDIR")) {
359 } else if (!strcmp(var, "ASTRUNDIR")) {
361 } else if (!strcmp(var, "ASTLOGDIR")) {
363 } else if (!strcmp(var, "ASTSBINDIR")) {
365 } else if (!strcmp(var, "ENTITYID")) {
366 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
367 s = workspace;
368 }
369 }
370 /* if not found, look into chanvars or global vars */
371 for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
372 struct ast_var_t *variables;
373 if (!places[i])
374 continue;
375 if (places[i] == &globals)
377 AST_LIST_TRAVERSE(places[i], variables, entries) {
378 if (!strcmp(ast_var_name(variables), var)) {
379 s = ast_var_value(variables);
380 break;
381 }
382 }
383 if (places[i] == &globals)
385 }
386 if (s == &not_found || s == NULL) {
387 ast_debug(5, "Result of '%s' is NULL\n", var);
388 ret = NULL;
389 } else {
390 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
391 if (s != ast_str_buffer(*str)) {
392 ast_str_set(str, maxlen, "%s", s);
393 }
394 ret = ast_str_buffer(*str);
395 if (need_substring) {
396 ret = ast_str_substring(*str, offset, length);
397 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
398 }
399 }
400
401 if (c) {
403 }
404 return ret;
405}
const char * str
Definition: app_jack.c:150
#define var
Definition: ast_expr2f.c:605
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
const char * ast_channel_name(const struct ast_channel *chan)
struct varshead * ast_channel_varshead(struct ast_channel *chan)
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1789
#define ast_channel_lock(chan)
Definition: channel.h:2972
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
int ast_channel_hangupcause(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
#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
#define ast_rwlock_rdlock(a)
Definition: lock.h:242
#define ast_rwlock_unlock(a)
Definition: lock.h:241
const char * ast_config_AST_KEY_DIR
Definition: options.c:162
const char * ast_config_AST_CACHE_DIR
Definition: options.c:151
const char * ast_config_AST_MODULE_DIR
Definition: options.c:154
const char * ast_config_AST_RUN_DIR
Definition: options.c:163
const char * ast_config_AST_DATA_DIR
Definition: options.c:159
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:152
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:155
const char * ast_config_AST_AGI_DIR
Definition: options.c:161
const char * ast_config_AST_VAR_DIR
Definition: options.c:158
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:171
const char * ast_config_AST_SBIN_DIR
Definition: options.c:164
const char * ast_config_AST_LOG_DIR
Definition: options.c:160
const char * ast_config_AST_DB
Definition: options.c:166
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4176
static ast_rwlock_t globalslock
static const char * ast_str_substring(struct ast_str *value, int offset, int length)
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
extract offset:length from variable name.
static struct varshead globals
#define NULL
Definition: resample.c:96
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_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
struct ast_var_t::@216 entries
Number structure.
Definition: app_followme.c:157
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: utils.c:2875
#define ARRAY_LEN(a)
Definition: utils.h:703
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:94

References ARRAY_LEN, ast_channel_caller(), ast_channel_context(), ast_channel_dialed(), ast_channel_exten(), ast_channel_hangupcause(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_uniqueid(), ast_channel_unlock, ast_channel_varshead(), ast_config_AST_AGI_DIR, ast_config_AST_CACHE_DIR, ast_config_AST_CONFIG_DIR, ast_config_AST_DATA_DIR, ast_config_AST_DB, ast_config_AST_KEY_DIR, ast_config_AST_LOG_DIR, ast_config_AST_MODULE_DIR, ast_config_AST_RUN_DIR, ast_config_AST_SBIN_DIR, ast_config_AST_SPOOL_DIR, ast_config_AST_SYSTEM_NAME, ast_config_AST_VAR_DIR, ast_debug, ast_eid_default, ast_eid_to_str(), AST_LIST_TRAVERSE, ast_party_id_presentation(), ast_rwlock_rdlock, ast_rwlock_unlock, ast_str_buffer(), ast_str_get_hint(), ast_str_set(), ast_str_substring(), ast_strdupa, ast_var_name(), ast_var_value(), c, ast_var_t::entries, globals, globalslock, NULL, parse_variable_name(), str, and var.

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

◆ ast_str_substitute_variables()

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 657 of file pbx_variables.c.

658{
659 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
660}
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
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)

References ast_str_substitute_variables_full(), buf, and NULL.

Referenced by acf_odbc_read(), acf_odbc_write(), ast_pbx_exec_application(), AST_TEST_DEFINE(), cli_odbc_read(), cli_odbc_write(), config_curl(), custom_log(), cut_internal(), destroy_curl(), do_notify(), exec_exec(), func_mchan_read(), function_eval2(), function_fieldnum_helper(), function_fieldqty_helper(), handle_exec(), handle_getvariablefull(), import_helper(), json_decode_read(), listfilter(), make_email_file(), realtime_curl(), realtime_multi_curl(), replace(), require_curl(), sendmail(), sendpage(), shift_pop(), store_curl(), strbetween(), strreplace(), test_2way_function(), test_chan_function(), test_chan_integer(), test_chan_integer_accessor(), test_chan_string(), test_chan_variable(), test_expected_result(), tryexec_exec(), unshift_push(), update2_curl(), and update_curl().

◆ ast_str_substitute_variables_full()

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 651 of file pbx_variables.c.

653{
654 ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);
655}
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.

References ast_str_substitute_variables_full2(), and buf.

Referenced by ast_str_substitute_variables(), and ast_str_substitute_variables_varshead().

◆ ast_str_substitute_variables_full2()

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 407 of file pbx_variables.c.

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

References ast_channel_unref, ast_channel_varshead(), ast_debug, ast_dummy_channel_alloc, ast_free, ast_func_read2(), ast_log, 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(), ast_str_substitute_variables_full2(), ast_str_substring(), ast_strlen_zero(), buf, c, len(), LOG_ERROR, LOG_WARNING, NULL, parse_variable_name(), result, and S_OR.

Referenced by ast_str_substitute_variables_full(), ast_str_substitute_variables_full2(), and geoloc_eprofile_resolve_varlist().

◆ ast_str_substitute_variables_varshead()

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 662 of file pbx_variables.c.

663{
664 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, NULL);
665}

References ast_str_substitute_variables_full(), buf, and NULL.

Referenced by add_user_extension(), build_user_routes(), handle_aor(), handle_registrations(), phoneprov_callback(), pp_each_extension_helper(), and pp_each_user_helper().

◆ ast_str_substring()

static const char * ast_str_substring ( struct ast_str value,
int  offset,
int  length 
)
static

Definition at line 194 of file pbx_variables.c.

195{
196 int lr; /* length of the input string after the copy */
197
198 lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
199
200 ast_assert(lr == strlen(ast_str_buffer(value))); /* ast_str_strlen should always agree with strlen */
201
202 /* Quick check if no need to do anything */
203 if (offset == 0 && length >= lr) /* take the whole string */
204 return ast_str_buffer(value);
205
206 if (offset < 0) { /* translate negative offset into positive ones */
207 offset = lr + offset;
208 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
209 offset = 0;
210 }
211
212 /* too large offset result in empty string so we know what to return */
213 if (offset >= lr) {
215 return ast_str_buffer(value);
216 }
217
218 if (offset > 0) {
219 /* Go ahead and chop off the beginning */
220 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
221 lr -= offset;
222 }
223
224 if (length >= 0 && length < lr) { /* truncate if necessary */
225 ast_str_truncate(value, length);
226 } else if (length < 0) {
227 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
228 ast_str_truncate(value, lr + length);
229 } else {
231 }
232 } else {
233 /* Nothing to do, but update the buffer length */
235 }
236
237 return ast_str_buffer(value);
238}
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:703
int value
Definition: syslog.c:37
#define ast_assert(a)
Definition: utils.h:776

References ast_assert, ast_str_buffer(), ast_str_reset(), ast_str_strlen(), ast_str_truncate(), ast_str_update(), and value.

Referenced by ast_str_retrieve_variable(), and ast_str_substitute_variables_full2().

◆ handle_eval_function()

static char * handle_eval_function ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

CLI support for executing function.

Definition at line 994 of file pbx_variables.c.

995{
996 struct ast_channel *c = NULL;
997 const char *fn, *substituted;
998 int ret;
999 char workspace[1024];
1000 RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
1001
1002 switch (cmd) {
1003 case CLI_INIT:
1004 e->command = "dialplan eval function";
1005 e->usage =
1006 "Usage: dialplan eval function <name(args)>\n"
1007 " Evaluate a dialplan function call\n"
1008 " A dummy channel is used to evaluate\n"
1009 " the function call, so only global\n"
1010 " variables should be used.\n";
1011 return NULL;
1012 case CLI_GENERATE:
1013 return NULL;
1014 }
1015
1016 if (a->argc != e->args + 1) {
1017 return CLI_SHOWUSAGE;
1018 }
1019
1020 if (a->argc != e->args + 1 && a->argc != e->args + 2) {
1021 return CLI_SHOWUSAGE;
1022 }
1023
1025 if (!caps) {
1026 ast_log(LOG_WARNING, "Could not allocate an empty format capabilities structure\n");
1027 return CLI_FAILURE;
1028 }
1029
1030 if (ast_format_cap_append(caps, ast_format_ulaw, 0)) {
1031 ast_log(LOG_WARNING, "Failed to append a ulaw format to capabilities for channel nativeformats\n");
1032 return CLI_FAILURE;
1033 }
1034
1035 if (ast_format_cap_append(caps, ast_format_alaw, 0)) {
1036 ast_log(LOG_WARNING, "Failed to append an alaw format to capabilities for channel nativeformats\n");
1037 return CLI_FAILURE;
1038 }
1039
1040 if (ast_format_cap_append(caps, ast_format_h264, 0)) {
1041 ast_log(LOG_WARNING, "Failed to append an h264 format to capabilities for channel nativeformats\n");
1042 return CLI_FAILURE;
1043 }
1044
1045 c = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "CLIEval/%d", ++cli_chan);
1046 if (!c) {
1047 ast_cli(a->fd, "Unable to allocate mock channel for application execution.\n");
1048 return CLI_FAILURE;
1049 }
1057
1058 fn = a->argv[3];
1059 pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
1060 substituted = ast_strdupa(workspace);
1061 workspace[0] = '\0';
1062 ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
1063
1064 ast_hangup(c); /* no need to unref separately */
1065
1066 ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
1067 ast_cli(a->fd, "Result: %s\n", workspace);
1068
1069 return CLI_SUCCESS;
1070}
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1299
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
@ AST_STATE_DOWN
Definition: channelstate.h:36
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
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
struct ast_format * ast_format_h264
Built-in cached h264 format.
Definition: format_cache.c:176
struct ast_format * ast_format_ulaw
Built-in cached ulaw format.
Definition: format_cache.c:86
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_format_alaw
Built-in cached alaw format.
Definition: format_cache.c:91
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
static int cli_chan
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
static const struct ast_channel_tech mock_channel_tech
static char * substituted(struct ast_channel *channel, const char *string)
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
static struct test_val a
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978

References a, ao2_cleanup, ast_cli_entry::args, ast_channel_alloc, ast_channel_nativeformats_set(), ast_channel_set_rawreadformat(), ast_channel_set_rawwriteformat(), ast_channel_set_readformat(), ast_channel_set_writeformat(), ast_channel_tech_set(), ast_channel_unlock, ast_cli(), ast_format_alaw, ast_format_cap_alloc, ast_format_cap_append, AST_FORMAT_CAP_FLAG_DEFAULT, ast_format_h264, ast_format_slin, ast_format_ulaw, ast_func_read(), ast_hangup(), ast_log, AST_STATE_DOWN, ast_strdupa, c, cli_chan, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, LOG_WARNING, mock_channel_tech, NULL, pbx_substitute_variables_helper(), RAII_VAR, substituted(), and ast_cli_entry::usage.

◆ handle_set_chanvar()

static char * handle_set_chanvar ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1094 of file pbx_variables.c.

1095{
1096 struct ast_channel *chan;
1097 const char *chan_name, *var_name, *var_value;
1098
1099 switch (cmd) {
1100 case CLI_INIT:
1101 e->command = "dialplan set chanvar";
1102 e->usage =
1103 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
1104 " Set channel variable <varname> to <value>\n";
1105 return NULL;
1106 case CLI_GENERATE:
1107 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1108 }
1109
1110 if (a->argc != e->args + 3)
1111 return CLI_SHOWUSAGE;
1112
1113 chan_name = a->argv[e->args];
1114 var_name = a->argv[e->args + 1];
1115 var_value = a->argv[e->args + 2];
1116
1117 if (!(chan = ast_channel_get_by_name(chan_name))) {
1118 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
1119 return CLI_FAILURE;
1120 }
1121
1122 pbx_builtin_setvar_helper(chan, var_name, var_value);
1123
1124 chan = ast_channel_unref(chan);
1125
1126 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
1127
1128 return CLI_SUCCESS;
1129}
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1842
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.

References a, ast_cli_entry::args, ast_channel_get_by_name(), ast_channel_unref, ast_cli(), ast_complete_channels(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, pbx_builtin_setvar_helper(), and ast_cli_entry::usage.

◆ handle_set_global()

static char * handle_set_global ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1072 of file pbx_variables.c.

1073{
1074 switch (cmd) {
1075 case CLI_INIT:
1076 e->command = "dialplan set global";
1077 e->usage =
1078 "Usage: dialplan set global <name> <value>\n"
1079 " Set global dialplan variable <name> to <value>\n";
1080 return NULL;
1081 case CLI_GENERATE:
1082 return NULL;
1083 }
1084
1085 if (a->argc != e->args + 2)
1086 return CLI_SHOWUSAGE;
1087
1088 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
1089 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
1090
1091 return CLI_SUCCESS;
1092}

References a, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, pbx_builtin_setvar_helper(), and ast_cli_entry::usage.

◆ handle_show_chanvar()

static char * handle_show_chanvar ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

CLI support for listing chanvar's variables in a parseable way.

Definition at line 952 of file pbx_variables.c.

953{
954 struct ast_channel *chan;
955 struct ast_var_t *var;
956
957 switch (cmd) {
958 case CLI_INIT:
959 e->command = "dialplan show chanvar";
960 e->usage =
961 "Usage: dialplan show chanvar <channel>\n"
962 " List current channel variables and their values\n";
963 return NULL;
964 case CLI_GENERATE:
965 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
966 }
967
968 if (a->argc != e->args + 1) {
969 return CLI_SHOWUSAGE;
970 }
971
972 chan = ast_channel_get_by_name(a->argv[e->args]);
973 if (!chan) {
974 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
975 return CLI_FAILURE;
976 }
977
978 ast_channel_lock(chan);
980 ast_cli(a->fd, "%s=%s\n", ast_var_name(var), ast_var_value(var));
981 }
982 ast_channel_unlock(chan);
983
984 ast_channel_unref(chan);
985 return CLI_SUCCESS;
986}

References a, ast_cli_entry::args, ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_channel_varshead(), ast_cli(), ast_complete_channels(), AST_LIST_TRAVERSE, ast_var_name(), ast_var_value(), CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_var_t::entries, NULL, ast_cli_entry::usage, and var.

◆ handle_show_globals()

static char * handle_show_globals ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

CLI support for listing global variables in a parseable way.

Definition at line 924 of file pbx_variables.c.

925{
926 int i = 0;
927 struct ast_var_t *newvariable;
928
929 switch (cmd) {
930 case CLI_INIT:
931 e->command = "dialplan show globals";
932 e->usage =
933 "Usage: dialplan show globals\n"
934 " List current global dialplan variables and their values\n";
935 return NULL;
936 case CLI_GENERATE:
937 return NULL;
938 }
939
941 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
942 i++;
943 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
944 }
946 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
947
948 return CLI_SUCCESS;
949}

References a, ast_cli(), AST_LIST_TRAVERSE, ast_rwlock_rdlock, ast_rwlock_unlock, ast_var_name(), ast_var_value(), CLI_GENERATE, CLI_INIT, CLI_SUCCESS, ast_cli_entry::command, ast_var_t::entries, globals, globalslock, NULL, and ast_cli_entry::usage.

◆ load_pbx_variables()

int load_pbx_variables ( void  )

Provided by pbx_variables.c

Definition at line 1448 of file pbx_variables.c.

1449{
1450 int res = 0;
1451
1456 AST_TEST_REGISTER(test_variable_substrings);
1457
1458 return res;
1459}
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int ast_register_application2(const char *app, int(*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
Register an application.
Definition: pbx_app.c:104
int 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 struct ast_cli_entry vars_cli[]
static void unload_pbx_variables(void)
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,...
#define AST_TEST_REGISTER(cb)
Definition: test.h:127

References ARRAY_LEN, ast_cli_register_multiple, ast_register_application2(), ast_register_cleanup(), AST_TEST_REGISTER, NULL, pbx_builtin_setvar(), pbx_builtin_setvar_multiple(), unload_pbx_variables(), and vars_cli.

Referenced by asterisk_daemon().

◆ parse_variable_name()

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 125 of file pbx_variables.c.

126{
127 int parens = 0;
128
129 *offset = 0;
130 *length = INT_MAX;
131 *isfunc = 0;
132 for (; *var; var++) {
133 if (*var == '(') {
134 (*isfunc)++;
135 parens++;
136 } else if (*var == ')') {
137 parens--;
138 } else if (*var == ':' && parens == 0) {
139 *var++ = '\0';
140 sscanf(var, "%30d:%30d", offset, length);
141 return 1; /* offset:length valid */
142 }
143 }
144 return 0;
145}

References var.

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

◆ pbx_builtin_clear_globals()

void pbx_builtin_clear_globals ( void  )

Definition at line 1353 of file pbx_variables.c.

1354{
1355 struct ast_var_t *vardata;
1356
1358 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1359 ast_var_delete(vardata);
1361}
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2469
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_rwlock_wrlock(a)
Definition: lock.h:243

References AST_LIST_REMOVE_HEAD, ast_rwlock_unlock, ast_rwlock_wrlock, ast_var_delete(), ast_var_t::entries, globals, and globalslock.

Referenced by handle_cli_dialplan_reload(), reload(), and unload_pbx_variables().

◆ pbx_builtin_getvar_helper()

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:
const char *var;
if ((var = pbx_builtin_getvar_helper(chan, "MYVAR"))) {
}
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.

Definition at line 1162 of file pbx_variables.c.

1163{
1164 struct ast_var_t *variables;
1165 const char *ret = NULL;
1166 int i;
1167 struct varshead *places[2] = { NULL, &globals };
1168
1169 if (!name)
1170 return NULL;
1171
1172 if (chan) {
1173 ast_channel_lock(chan);
1174 places[0] = ast_channel_varshead(chan);
1175 }
1176
1177 for (i = 0; i < 2; i++) {
1178 if (!places[i])
1179 continue;
1180 if (places[i] == &globals)
1182 AST_LIST_TRAVERSE(places[i], variables, entries) {
1183 if (!strcmp(name, ast_var_name(variables))) {
1184 ret = ast_var_value(variables);
1185 break;
1186 }
1187 }
1188 if (places[i] == &globals)
1190 if (ret)
1191 break;
1192 }
1193
1194 if (chan)
1195 ast_channel_unlock(chan);
1196
1197 return ret;
1198}
static const char name[]
Definition: format_mp3.c:68

References ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), AST_LIST_TRAVERSE, ast_rwlock_rdlock, ast_rwlock_unlock, ast_var_name(), ast_var_value(), globals, globalslock, name, and NULL.

Referenced by __ast_pbx_run(), _while_exec(), action_agents(), add_header_from_channel_var(), agent_handle_show_specific(), agent_login_channel_config(), agent_request_exec(), agent_show_requested(), analog_call(), analog_callwaiting_deluxe(), array(), ast_bridge_add_channel(), 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_eivr_getvariable(), ast_get_chan_applicationmap(), ast_unreal_hangup(), attended_transfer_exec(), bridge_parking_push(), channel_get_external_vars(), check_bridge_play_sound(), common_exec(), conf_run(), create_dynamic_lot_full(), crement_function_read(), dahdi_hangup(), dial_exec_full(), do_forward(), dundi_exec(), eagi_exec(), eval_sub_read(), feature_automixmonitor(), feature_blind_transfer(), find_by_mark(), find_channel_parking_lot_name(), find_conf_realtime(), func_channel_read(), generate_parked_user(), generic_fax_exec(), get_index(), get_transfer_context(), get_transfer_exten(), global_exists_read(), global_read(), gosub_run(), handle_call_forward(), handle_exec(), handle_gosub(), handle_hangup(), hash_read(), iax2_call(), iax2_exec(), if_helper(), leave_voicemail(), local_read(), manager_mixmonitor(), meetme_menu_admin_extended(), minivm_delete_exec(), minivm_notify_exec(), morsecode_exec(), notify_new_message(), ooh323_call(), ooh323_hangup(), park_app_exec(), pbx_builtin_gotoiftime(), permit_dtmf_interrupt(), pjsip_acf_parse_uri_read(), pre_bridge_setup(), queue_exec(), receive_ademco_event(), refer_blind_callback(), report_receive_fax_status(), report_send_fax_status(), retrydial_exec(), run_agi(), sayunixtime_exec(), sendtext_exec(), set_from_header(), set_touch_variable(), set_transfer_variables_all(), setup_mixmonitor(), setup_park_common_datastore(), sla_trunk_exec(), speech_background(), transfer_refer(), try_calling(), variable_exists_read(), and wait_for_answer().

◆ pbx_builtin_pushvar_helper()

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 1200 of file pbx_variables.c.

1201{
1202 struct ast_var_t *newvariable;
1203 struct varshead *headp;
1204
1205 if (name[strlen(name)-1] == ')') {
1206 char *function = ast_strdupa(name);
1207
1208 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1209 ast_func_write(chan, function, value);
1210 return;
1211 }
1212
1213 if (chan) {
1214 ast_channel_lock(chan);
1215 headp = ast_channel_varshead(chan);
1216 } else {
1218 headp = &globals;
1219 }
1220
1221 if (value && (newvariable = ast_var_assign(name, value))) {
1222 if (headp == &globals)
1223 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1224 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1225 }
1226
1227 if (chan)
1228 ast_channel_unlock(chan);
1229 else
1231}
#define ast_var_assign(name, value)
Definition: chanvars.h:40
#define ast_verb(level,...)
#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

References ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), ast_func_write(), AST_LIST_INSERT_HEAD, ast_log, ast_rwlock_unlock, ast_rwlock_wrlock, ast_strdupa, ast_var_assign, ast_verb, globals, globalslock, LOG_WARNING, name, and value.

Referenced by acf_odbc_read(), acf_odbc_write(), cli_odbc_read(), cli_odbc_write(), and frame_set_var().

◆ pbx_builtin_serialize_variables()

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 1131 of file pbx_variables.c.

1132{
1133 struct ast_var_t *variables;
1134 const char *var, *val;
1135 int total = 0;
1136
1137 if (!chan)
1138 return 0;
1139
1141
1142 ast_channel_lock(chan);
1143
1145 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1146 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1147 ) {
1148 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1149 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1150 break;
1151 } else
1152 total++;
1153 } else
1154 break;
1155 }
1156
1157 ast_channel_unlock(chan);
1158
1159 return total;
1160}
static int total
Definition: res_adsi.c:970
Definition: ast_expr2.c:325

References ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), AST_LIST_TRAVERSE, ast_log, ast_str_append(), ast_str_reset(), ast_var_name(), ast_var_value(), buf, ast_var_t::entries, LOG_ERROR, total, and var.

Referenced by ast_var_channels_table(), and dumpchan_exec().

◆ pbx_builtin_setvar()

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 1291 of file pbx_variables.c.

1292{
1293 char *name, *value, *mydata;
1294
1295 if (ast_strlen_zero(data)) {
1296 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1297 return 0;
1298 }
1299
1300 mydata = ast_strdupa(data);
1301 name = strsep(&mydata, "=");
1302 value = mydata;
1303 if (!value) {
1304 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1305 return 0;
1306 }
1307
1308 if (strchr(name, ' ')) {
1309 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1310 }
1311
1313
1314 return 0;
1315}
char * strsep(char **str, const char *delims)

References ast_log, ast_strdupa, ast_strlen_zero(), LOG_WARNING, name, pbx_builtin_setvar_helper(), strsep(), and value.

Referenced by ast_compile_ael2(), and load_pbx_variables().

◆ pbx_builtin_setvar_helper()

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 1233 of file pbx_variables.c.

1234{
1235 struct ast_var_t *newvariable;
1236 struct varshead *headp;
1237 const char *nametail = name;
1238 /*! True if the old value was not an empty string. */
1239 int old_value_existed = 0;
1240
1241 if (name[strlen(name) - 1] == ')') {
1242 char *function = ast_strdupa(name);
1243
1244 return ast_func_write(chan, function, value);
1245 }
1246
1247 if (chan) {
1248 ast_channel_lock(chan);
1249 headp = ast_channel_varshead(chan);
1250 } else {
1252 headp = &globals;
1253 }
1254
1255 /* For comparison purposes, we have to strip leading underscores */
1256 if (*nametail == '_') {
1257 nametail++;
1258 if (*nametail == '_')
1259 nametail++;
1260 }
1261
1262 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1263 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1264 /* there is already such a variable, delete it */
1265 AST_LIST_REMOVE_CURRENT(entries);
1266 old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1267 ast_var_delete(newvariable);
1268 break;
1269 }
1270 }
1272
1273 if (value && (newvariable = ast_var_assign(name, value))) {
1274 if (headp == &globals) {
1275 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1276 }
1277 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1279 } else if (old_value_existed) {
1280 /* We just deleted a non-empty dialplan variable. */
1282 }
1283
1284 if (chan)
1285 ast_channel_unlock(chan);
1286 else
1288 return 0;
1289}
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_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#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

References ast_channel_lock, ast_channel_publish_varset(), ast_channel_unlock, ast_channel_varshead(), ast_func_write(), AST_LIST_INSERT_HEAD, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_rwlock_unlock, ast_rwlock_wrlock, ast_strdupa, ast_strlen_zero(), ast_var_assign, ast_var_delete(), ast_var_name(), ast_var_value(), ast_verb, globals, globalslock, name, and value.

Referenced by __analog_ss_thread(), __ast_pbx_run(), _while_exec(), acf_curl_helper(), acf_fetch(), acf_odbc_read(), acf_odbc_write(), acf_transaction_write(), action_atxfer(), action_kick_last(), action_setvar(), admin_exec(), agent_login_exec(), agent_request_exec(), agi_exec_full(), analog_ss_thread(), app_control_set_channel_var(), app_exec(), aqm_exec(), array(), 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_eivr_setvariable(), 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_TEST_DEFINE(), ast_unreal_hangup(), asyncgoto_exec(), attended_transfer_bridge(), attended_transfer_exec(), audiosocket_request(), background_detect_exec(), begin_dial_channel(), blind_transfer_bridge(), blind_transfer_exec(), bridge_channel_internal_push_full(), bridge_exec(), bridgeadd_exec(), calendar_write_exec(), caller_joined_bridge(), caller_safety_timeout(), cccancel_exec(), ccreq_exec(), chan_pjsip_cng_tone_detected(), chan_pjsip_new(), chanavail_exec(), channel_spy(), check_bridge_play_sound(), clear_agent_status(), commit_exec(), conf_run(), confbridge_exec(), confkick_exec(), controlplayback_exec(), count_exec(), crement_function_read(), dahdi_handle_dtmf(), dahdi_new(), delete_write(), dial_exec_full(), dial_transfer(), directory_exec(), disa_exec(), do_directory(), do_forward(), do_notify(), do_waiting(), dtmf_store_framehook(), dynamic_dtmf_hook_callback(), end_bridge_callback(), execute_menu_entry(), fax_detect_framehook(), frame_set_var(), func_export_write(), func_mchan_write(), function_db_delete(), function_db_exists(), function_db_read(), function_realtime_store(), generic_recall(), geoloc_profile_read(), geoloc_profile_write(), global_delete_write(), global_write(), gosub_release_frame(), gosub_run(), handle_controlstreamfile(), handle_gosub(), handle_incoming_request(), handle_outgoing_response(), handle_response_cmgr(), handle_set_chanvar(), handle_set_global(), handle_setvariable(), handle_streamfile(), hash_read(), hash_write(), if_helper(), isAnsweringMachine(), kick_conference_participant(), launch_monitor_thread(), leave_marked(), leave_queue(), leave_voicemail(), lua_set_variable(), lua_set_variable_value(), manager_park(), mbl_status_exec(), minivm_accmess_exec(), minivm_delete_exec(), minivm_greet_exec(), minivm_notify_exec(), minivm_record_exec(), mixmonitor_exec(), msg_send_exec(), my_get_callerid(), my_handle_dtmf(), onModeChanged(), ooh323_new(), ooh323_rtp_read(), originate_exec(), parking_duration_callback(), parking_timeout_set_caller_features(), pbx_builtin_background(), pbx_builtin_gotoiftime(), pbx_builtin_setvar(), pbx_builtin_setvar_multiple(), pbx_builtin_waitdigit(), pbx_load_config(), play_message_datetime(), playback_exec(), pqm_exec(), prep_email_sub_vars(), privacy_exec(), queue_exec(), read_exec(), read_mf_digits(), read_mf_exec(), read_sf_digits(), read_sf_exec(), readexten_exec(), realtimefield_read(), receivefax_exec(), record_abandoned(), record_exec(), recvtext_exec(), refer_blind_callback(), reload_exec(), reload_module(), return_exec(), ring_entry(), rollback_exec(), rotate_file(), rqm_exec(), scan_exec(), select_entry(), select_item_menu(), select_item_seq(), sendfax_exec(), sendtext_exec(), set(), set_channel_variables(), set_duration_var(), set_queue_result(), set_sipdomain_variable(), shift_pop(), signal_exec(), sla_calc_trunk_timeouts(), sla_station_exec(), sla_trunk_exec(), speech_create(), start_automixmonitor(), system_exec_helper(), test_chan_variable(), testtime_write(), transfer_exec(), tryexec_exec(), unicast_rtp_request(), unshift_push(), update_qe_rule(), upqm_exec(), user_timeout(), vm_exec(), vm_playmsgexec(), vmauthenticate(), wait_exec(), wait_for_answer(), wait_for_signal_or_hangup(), waitforcond_exec(), waitsignal_exec(), waituntil_exec(), and zapateller_exec().

◆ pbx_builtin_setvar_multiple()

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 1317 of file pbx_variables.c.

1318{
1319 char *data;
1320 int x;
1322 AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1323 );
1327 );
1328
1329 if (ast_strlen_zero(vdata)) {
1330 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1331 return 0;
1332 }
1333
1334 data = ast_strdupa(vdata);
1336
1337 for (x = 0; x < args.argc; x++) {
1338 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1339 if (pair.argc == 2) {
1341 if (strchr(pair.name, ' '))
1342 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
1343 } else if (!chan) {
1344 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1345 } else {
1346 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
1347 }
1348 }
1349
1350 return 0;
1351}
#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.
const char * name
Definition: test_config.c:85
const char * args

References args, AST_APP_ARG, ast_channel_context(), ast_channel_exten(), ast_channel_priority(), AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_APP_ARGS, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, name, pair::name, pbx_builtin_setvar_helper(), and value.

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

◆ pbx_retrieve_variable()

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 246 of file pbx_variables.c.

247{
248 struct ast_str *str = ast_str_create(16);
249 const char *cret;
250
251 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
252 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
253 *ret = cret ? workspace : NULL;
254 ast_free(str);
255}
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425

References ast_copy_string(), ast_free, ast_str_buffer(), ast_str_create, ast_str_retrieve_variable(), c, NULL, str, and var.

Referenced by action_getvar(), generate_status(), handle_getvariable(), lua_get_variable(), lua_get_variable_value(), and pbx_substitute_variables_helper_full_location().

◆ pbx_substitute_variables_helper()

void pbx_substitute_variables_helper ( struct ast_channel c,
const char *  cp1,
char *  cp2,
int  count 
)

Definition at line 913 of file pbx_variables.c.

914{
916}
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)

References ast_channel_varshead(), c, NULL, and pbx_substitute_variables_helper_full().

Referenced by handle_eval_function().

◆ pbx_substitute_variables_helper_full()

void pbx_substitute_variables_helper_full ( struct ast_channel c,
struct varshead headp,
const char *  cp1,
char *  cp2,
int  count,
size_t *  used 
)

Definition at line 667 of file pbx_variables.c.

668{
669 pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
670}
void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, const char *context, const char *exten, int pri)
Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the contex...

References c, NULL, and pbx_substitute_variables_helper_full_location().

Referenced by pbx_substitute_variables_helper(), and pbx_substitute_variables_varshead().

◆ pbx_substitute_variables_helper_full_location()

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.

Definition at line 677 of file pbx_variables.c.

678{
679 /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!! */
680 const char *whereweare;
681 const char *orig_cp2 = cp2;
682 char ltmp[VAR_BUF_SIZE];
683 char var[VAR_BUF_SIZE];
684 int *recurse_depth;
685
686 *cp2 = 0; /* just in case nothing ends up there */
687
688 /* It is possible to craft dialplan that will recurse indefinitely and cause a stack overflow.
689 * This is symptomatic of a dialplan bug, so abort substitution rather than crash. */
690 recurse_depth = ast_threadstorage_get(&varsub_recurse_level, sizeof(*recurse_depth));
691 if (!recurse_depth) {
692 return;
693 }
694 if ((*recurse_depth)++ >= MAX_VARIABLE_SUB_RECURSE_DEPTH) {
695 ast_log(LOG_ERROR, "Exceeded maximum variable substitution recursion depth (%d) - possible infinite recursion in dialplan?\n", MAX_VARIABLE_SUB_RECURSE_DEPTH);
696 (*recurse_depth)--;
697 return;
698 }
699
700 whereweare = cp1;
701 while (!ast_strlen_zero(whereweare) && count) {
702 char *nextvar = NULL;
703 char *nextexp = NULL;
704 char *nextthing;
705 char *vars;
706 char *vare;
707 int length;
708 int pos;
709 int brackets;
710 int needsub;
711 int len;
712
713 /* Determine how much simply needs to be copied to the output buf. */
714 nextthing = strchr(whereweare, '$');
715 if (nextthing) {
716 pos = nextthing - whereweare;
717 switch (nextthing[1]) {
718 case '{':
719 /* Variable substitution */
720 nextvar = nextthing;
721 break;
722 case '[':
723 /* Expression substitution */
724 nextexp = nextthing;
725 break;
726 default:
727 /* '$' is not part of a substitution so include it too. */
728 ++pos;
729 break;
730 }
731 } else {
732 /* We're copying the whole remaining string */
733 pos = strlen(whereweare);
734 }
735
736 if (pos) {
737 /* Can't copy more than 'count' bytes */
738 if (pos > count)
739 pos = count;
740
741 /* Copy that many bytes */
742 memcpy(cp2, whereweare, pos);
743
744 count -= pos;
745 cp2 += pos;
746 whereweare += pos;
747 *cp2 = 0;
748 }
749
750 if (nextvar) {
751 int offset;
752 int offset2;
753 int isfunction;
754 char *cp4 = NULL;
755 char workspace[VAR_BUF_SIZE] = "";
756
757 /* We have a variable. Find the start and end, and determine
758 if we are going to have to recursively call ourselves on the
759 contents */
760 vars = vare = nextvar + 2;
761 brackets = 1;
762 needsub = 0;
763
764 /* Find the end of it */
765 while (brackets && *vare) {
766 if ((vare[0] == '$') && (vare[1] == '{')) {
767 needsub++;
768 brackets++;
769 vare++;
770 } else if (vare[0] == '{') {
771 brackets++;
772 } else if (vare[0] == '}') {
773 brackets--;
774 } else if ((vare[0] == '$') && (vare[1] == '[')) {
775 needsub++;
776 vare++;
777 }
778 vare++;
779 }
780 len = vare - vars;
781 if (brackets) {
782 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
783 } else {
784 /* Don't count the closing '}' in the length. */
785 --len;
786 }
787
788 /* Skip totally over variable string */
789 whereweare = vare;
790
791 /* Store variable name expression to lookup (and truncate). */
792 ast_copy_string(var, vars, len + 1);
793
794 /* Substitute if necessary */
795 if (needsub) {
797 vars = ltmp;
798 } else {
799 vars = var;
800 }
801
802 parse_variable_name(vars, &offset, &offset2, &isfunction);
803 if (isfunction) {
804 /* Evaluate function */
805 if (c || !headp)
806 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
807 else {
808 struct varshead old;
809 struct ast_channel *bogus;
810
811 bogus = ast_dummy_channel_alloc();
812 if (bogus) {
813 old = *ast_channel_varshead(bogus);
814 *ast_channel_varshead(bogus) = *headp;
815 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
816 /* Don't deallocate the varshead that was passed in */
817 *ast_channel_varshead(bogus) = old;
818 ast_channel_unref(bogus);
819 } else {
820 ast_log(LOG_ERROR, "Unable to allocate bogus channel for function value substitution.\n");
821 cp4 = NULL;
822 }
823 }
824 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
825 } else {
826 /* Retrieve variable value */
827 /* For dialplan location, if we were told what to substitute explicitly, use that instead */
828 if (exten && !strcmp(vars, "EXTEN")) {
830 cp4 = workspace;
831 } else if (context && !strcmp(vars, "CONTEXT")) {
833 cp4 = workspace;
834 } else if (pri && !strcmp(vars, "PRIORITY")) {
835 snprintf(workspace, VAR_BUF_SIZE, "%d", pri);
836 cp4 = workspace;
837 } else {
838 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
839 }
840 }
841 if (cp4) {
842 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
843
844 length = strlen(cp4);
845 if (length > count)
846 length = count;
847 memcpy(cp2, cp4, length);
848 count -= length;
849 cp2 += length;
850 *cp2 = 0;
851 }
852 } else if (nextexp) {
853 /* We have an expression. Find the start and end, and determine
854 if we are going to have to recursively call ourselves on the
855 contents */
856 vars = vare = nextexp + 2;
857 brackets = 1;
858 needsub = 0;
859
860 /* Find the end of it */
861 while (brackets && *vare) {
862 if ((vare[0] == '$') && (vare[1] == '[')) {
863 needsub++;
864 brackets++;
865 vare++;
866 } else if (vare[0] == '[') {
867 brackets++;
868 } else if (vare[0] == ']') {
869 brackets--;
870 } else if ((vare[0] == '$') && (vare[1] == '{')) {
871 needsub++;
872 vare++;
873 }
874 vare++;
875 }
876 len = vare - vars;
877 if (brackets) {
878 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
879 } else {
880 /* Don't count the closing ']' in the length. */
881 --len;
882 }
883
884 /* Skip totally over expression */
885 whereweare = vare;
886
887 /* Store expression to evaluate (and truncate). */
888 ast_copy_string(var, vars, len + 1);
889
890 /* Substitute if necessary */
891 if (needsub) {
893 vars = ltmp;
894 } else {
895 vars = var;
896 }
897
898 length = ast_expr(vars, cp2, count, c);
899 if (length) {
900 ast_debug(1, "Expression result is '%s'\n", cp2);
901 count -= length;
902 cp2 += length;
903 *cp2 = 0;
904 }
905 }
906 }
907 if (used) {
908 *used = cp2 - orig_cp2;
909 }
910 (*recurse_depth)--;
911}
int ast_expr(char *expr, char *buf, int length, struct ast_channel *chan)
Evaluate the given expression.
Definition: ast_expr2f.c:2391
#define VAR_BUF_SIZE
Definition: pbx_private.h:68
static char * substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
takes a substring. It is ok to call with value == workspace.
void pbx_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 struct ast_threadstorage varsub_recurse_level
#define MAX_VARIABLE_SUB_RECURSE_DEPTH
char exten[AST_MAX_EXTENSION]
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_channel_unref, ast_channel_varshead(), ast_copy_string(), ast_debug, ast_dummy_channel_alloc, ast_expr(), ast_func_read(), ast_log, ast_strlen_zero(), ast_threadstorage_get(), c, voicemailpwcheck::context, ast_channel::exten, len(), LOG_ERROR, LOG_WARNING, MAX_VARIABLE_SUB_RECURSE_DEPTH, NULL, parse_variable_name(), pbx_retrieve_variable(), pbx_substitute_variables_helper_full_location(), substring(), var, VAR_BUF_SIZE, and varsub_recurse_level.

Referenced by eval_exten_read(), pbx_substitute_variables_helper_full(), and pbx_substitute_variables_helper_full_location().

◆ pbx_substitute_variables_varshead()

void pbx_substitute_variables_varshead ( struct varshead headp,
const char *  cp1,
char *  cp2,
int  count 
)

Definition at line 918 of file pbx_variables.c.

919{
920 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, NULL);
921}

References NULL, and pbx_substitute_variables_helper_full().

Referenced by do_say(), dundi_lookup_local(), get_mapping_weight(), and loopback_subst().

◆ substring()

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 158 of file pbx_variables.c.

159{
160 char *ret = workspace;
161 int lr; /* length of the input string after the copy */
162
163 ast_copy_string(workspace, value, workspace_len); /* always make a copy */
164
165 lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
166
167 /* Quick check if no need to do anything */
168 if (offset == 0 && length >= lr) /* take the whole string */
169 return ret;
170
171 if (offset < 0) { /* translate negative offset into positive ones */
172 offset = lr + offset;
173 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
174 offset = 0;
175 }
176
177 /* too large offset result in empty string so we know what to return */
178 if (offset >= lr)
179 return ret + lr; /* the final '\0' */
180
181 ret += offset; /* move to the start position */
182 if (length >= 0 && length < lr - offset) /* truncate if necessary */
183 ret[length] = '\0';
184 else if (length < 0) {
185 if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
186 ret[lr + length - offset] = '\0';
187 else
188 ret[0] = '\0';
189 }
190
191 return ret;
192}

References ast_copy_string(), and value.

Referenced by pbx_substitute_variables_helper_full_location().

◆ unload_pbx_variables()

static void unload_pbx_variables ( void  )
static

Definition at line 1439 of file pbx_variables.c.

1440{
1445 AST_TEST_UNREGISTER(test_variable_substrings);
1446}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
void pbx_builtin_clear_globals(void)
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128

References ARRAY_LEN, ast_cli_unregister_multiple(), AST_TEST_UNREGISTER, ast_unregister_application(), pbx_builtin_clear_globals(), and vars_cli.

Referenced by load_pbx_variables().

Variable Documentation

◆ cli_chan

int cli_chan = 0
static

Definition at line 991 of file pbx_variables.c.

Referenced by handle_eval_function().

◆ globals

struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
static

◆ globalslock

ast_rwlock_t globalslock = { PTHREAD_RWLOCK_INITIALIZER , NULL, {1, 0} }
static

◆ mock_channel_tech

const struct ast_channel_tech mock_channel_tech
static
Initial value:
= {
}

Definition at line 988 of file pbx_variables.c.

Referenced by handle_eval_function().

◆ vars_cli

struct ast_cli_entry vars_cli[]
static

Definition at line 1431 of file pbx_variables.c.

Referenced by load_pbx_variables(), and unload_pbx_variables().

◆ varsub_recurse_level

struct ast_threadstorage varsub_recurse_level = { .once = PTHREAD_ONCE_INIT , .key_init = __init_varsub_recurse_level , .custom_init = NULL , }
static

Definition at line 673 of file pbx_variables.c.

Referenced by pbx_substitute_variables_helper_full_location().