Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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"
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 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.

Macro Definition Documentation

◆ MAX_VARIABLE_SUB_RECURSE_DEPTH

#define MAX_VARIABLE_SUB_RECURSE_DEPTH   15

Definition at line 674 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 672 of file pbx_variables.c.

677{

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

257{
258 const char not_found = '\0';
259 char *tmpvar;
260 const char *ret;
261 const char *s; /* the result */
262 int offset, length;
263 int i, need_substring;
264 struct varshead *places[2] = { headp, &globals }; /* list of places where we may look */
265 char workspace[20];
266
267 if (c) {
269 places[0] = ast_channel_varshead(c);
270 }
271 /*
272 * Make a copy of var because parse_variable_name() modifies the string.
273 * Then if called directly, we might need to run substring() on the result;
274 * remember this for later in 'need_substring', 'offset' and 'length'
275 */
276 tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
277 need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
278
279 /*
280 * Look first into predefined variables, then into variable lists.
281 * Variable 's' points to the result, according to the following rules:
282 * s == &not_found (set at the beginning) means that we did not find a
283 * matching variable and need to look into more places.
284 * If s != &not_found, s is a valid result string as follows:
285 * s = NULL if the variable does not have a value;
286 * you typically do this when looking for an unset predefined variable.
287 * s = workspace if the result has been assembled there;
288 * typically done when the result is built e.g. with an snprintf(),
289 * so we don't need to do an additional copy.
290 * s != workspace in case we have a string, that needs to be copied
291 * (the ast_copy_string is done once for all at the end).
292 * Typically done when the result is already available in some string.
293 */
294 s = &not_found; /* default value */
295 if (c) { /* This group requires a valid channel */
296 /* Names with common parts are looked up a piece at a time using strncmp. */
297 if (!strncmp(var, "CALL", 4)) {
298 if (!strncmp(var + 4, "ING", 3)) {
299 if (!strcmp(var + 7, "PRES")) { /* CALLINGPRES */
300 ast_str_set(str, maxlen, "%d",
302 s = ast_str_buffer(*str);
303 } else if (!strcmp(var + 7, "ANI2")) { /* CALLINGANI2 */
304 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
305 s = ast_str_buffer(*str);
306 } else if (!strcmp(var + 7, "TON")) { /* CALLINGTON */
307 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
308 s = ast_str_buffer(*str);
309 } else if (!strcmp(var + 7, "TNS")) { /* CALLINGTNS */
310 ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
311 s = ast_str_buffer(*str);
312 }
313 }
314 } else if (!strcmp(var, "HINT")) {
316 } else if (!strcmp(var, "HINTNAME")) {
318 } else if (!strcmp(var, "EXTEN")) {
319 s = ast_channel_exten(c);
320 } else if (!strcmp(var, "CONTEXT")) {
322 } else if (!strcmp(var, "PRIORITY")) {
323 ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
324 s = ast_str_buffer(*str);
325 } else if (!strcmp(var, "CHANNEL")) {
326 s = ast_channel_name(c);
327 } else if (!strcmp(var, "UNIQUEID")) {
329 } else if (!strcmp(var, "HANGUPCAUSE")) {
330 ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
331 s = ast_str_buffer(*str);
332 }
333 }
334 if (s == &not_found) { /* look for more */
335 if (!strcmp(var, "EPOCH")) {
336 ast_str_set(str, maxlen, "%d", (int) time(NULL));
337 s = ast_str_buffer(*str);
338 } else if (!strcmp(var, "SYSTEMNAME")) {
340 } else if (!strcmp(var, "ASTCACHEDIR")) {
342 } else if (!strcmp(var, "ASTETCDIR")) {
344 } else if (!strcmp(var, "ASTMODDIR")) {
346 } else if (!strcmp(var, "ASTVARLIBDIR")) {
348 } else if (!strcmp(var, "ASTDBDIR")) {
350 } else if (!strcmp(var, "ASTKEYDIR")) {
352 } else if (!strcmp(var, "ASTDATADIR")) {
354 } else if (!strcmp(var, "ASTAGIDIR")) {
356 } else if (!strcmp(var, "ASTSPOOLDIR")) {
358 } else if (!strcmp(var, "ASTRUNDIR")) {
360 } else if (!strcmp(var, "ASTLOGDIR")) {
362 } else if (!strcmp(var, "ASTSBINDIR")) {
364 } else if (!strcmp(var, "ENTITYID")) {
365 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
366 s = workspace;
367 }
368 }
369 /* if not found, look into chanvars or global vars */
370 for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
371 struct ast_var_t *variables;
372 if (!places[i])
373 continue;
374 if (places[i] == &globals)
376 AST_LIST_TRAVERSE(places[i], variables, entries) {
377 if (!strcmp(ast_var_name(variables), var)) {
378 s = ast_var_value(variables);
379 break;
380 }
381 }
382 if (places[i] == &globals)
384 }
385 if (s == &not_found || s == NULL) {
386 ast_debug(5, "Result of '%s' is NULL\n", var);
387 ret = NULL;
388 } else {
389 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
390 if (s != ast_str_buffer(*str)) {
391 ast_str_set(str, maxlen, "%s", s);
392 }
393 ret = ast_str_buffer(*str);
394 if (need_substring) {
395 ret = ast_str_substring(*str, offset, length);
396 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
397 }
398 }
399
400 if (c) {
402 }
403 return ret;
404}
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:1848
#define ast_channel_lock(chan)
Definition: channel.h:2970
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
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:2971
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:239
#define ast_rwlock_unlock(a)
Definition: lock.h:238
const char * ast_config_AST_KEY_DIR
Definition: options.c:161
const char * ast_config_AST_CACHE_DIR
Definition: options.c:150
const char * ast_config_AST_MODULE_DIR
Definition: options.c:153
const char * ast_config_AST_RUN_DIR
Definition: options.c:162
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * ast_config_AST_AGI_DIR
Definition: options.c:160
const char * ast_config_AST_VAR_DIR
Definition: options.c:157
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
const char * ast_config_AST_SBIN_DIR
Definition: options.c:163
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
const char * ast_config_AST_DB
Definition: options.c:165
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4170
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::@213 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:2839
#define ARRAY_LEN(a)
Definition: utils.h:666
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93

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

657{
658 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, NULL);
659}
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 650 of file pbx_variables.c.

652{
653 ast_str_substitute_variables_full2(buf, maxlen, chan, headp, templ, used, 0);
654}
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 406 of file pbx_variables.c.

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

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

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

194{
195 int lr; /* length of the input string after the copy */
196
197 lr = ast_str_strlen(value); /* compute length after copy, so we never go out of the workspace */
198
199 ast_assert(lr == strlen(ast_str_buffer(value))); /* ast_str_strlen should always agree with strlen */
200
201 /* Quick check if no need to do anything */
202 if (offset == 0 && length >= lr) /* take the whole string */
203 return ast_str_buffer(value);
204
205 if (offset < 0) { /* translate negative offset into positive ones */
206 offset = lr + offset;
207 if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
208 offset = 0;
209 }
210
211 /* too large offset result in empty string so we know what to return */
212 if (offset >= lr) {
214 return ast_str_buffer(value);
215 }
216
217 if (offset > 0) {
218 /* Go ahead and chop off the beginning */
219 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
220 lr -= offset;
221 }
222
223 if (length >= 0 && length < lr) { /* truncate if necessary */
224 ast_str_truncate(value, length);
225 } else if (length < 0) {
226 if (lr > -length) { /* After we remove from the front and from the rear, is there anything left? */
227 ast_str_truncate(value, lr + length);
228 } else {
230 }
231 } else {
232 /* Nothing to do, but update the buffer length */
234 }
235
236 return ast_str_buffer(value);
237}
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:739

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

989{
990 struct ast_channel *c = NULL;
991 char *fn, *substituted;
992 int ret;
993 char workspace[1024];
994
995 switch (cmd) {
996 case CLI_INIT:
997 e->command = "dialplan eval function";
998 e->usage =
999 "Usage: dialplan eval function <name(args)>\n"
1000 " Evaluate a dialplan function call\n"
1001 " A dummy channel is used to evaluate\n"
1002 " the function call, so only global\n"
1003 " variables should be used.\n";
1004 return NULL;
1005 case CLI_GENERATE:
1006 return NULL;
1007 }
1008
1009 if (a->argc != e->args + 1) {
1010 return CLI_SHOWUSAGE;
1011 }
1012
1014 if (!c) {
1015 ast_cli(a->fd, "Unable to allocate bogus channel for function evaluation.\n");
1016 return CLI_FAILURE;
1017 }
1018
1019 fn = (char *) a->argv[3];
1020 pbx_substitute_variables_helper(c, fn, workspace, sizeof(workspace));
1021 substituted = ast_strdupa(workspace);
1022 workspace[0] = '\0';
1023 ret = ast_func_read(c, substituted, workspace, sizeof(workspace));
1024
1026
1027 ast_cli(a->fd, "Return Value: %s (%d)\n", ret ? "Failure" : "Success", ret);
1028 ast_cli(a->fd, "Result: %s\n", workspace);
1029
1030 return CLI_SUCCESS;
1031}
#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
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
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
static struct test_val a

References a, ast_cli_entry::args, ast_channel_unref, ast_cli(), ast_dummy_channel_alloc, ast_func_read(), ast_strdupa, c, CLI_FAILURE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, pbx_substitute_variables_helper(), 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 1055 of file pbx_variables.c.

1056{
1057 struct ast_channel *chan;
1058 const char *chan_name, *var_name, *var_value;
1059
1060 switch (cmd) {
1061 case CLI_INIT:
1062 e->command = "dialplan set chanvar";
1063 e->usage =
1064 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
1065 " Set channel variable <varname> to <value>\n";
1066 return NULL;
1067 case CLI_GENERATE:
1068 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1069 }
1070
1071 if (a->argc != e->args + 3)
1072 return CLI_SHOWUSAGE;
1073
1074 chan_name = a->argv[e->args];
1075 var_name = a->argv[e->args + 1];
1076 var_value = a->argv[e->args + 2];
1077
1078 if (!(chan = ast_channel_get_by_name(chan_name))) {
1079 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
1080 return CLI_FAILURE;
1081 }
1082
1083 pbx_builtin_setvar_helper(chan, var_name, var_value);
1084
1085 chan = ast_channel_unref(chan);
1086
1087 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
1088
1089 return CLI_SUCCESS;
1090}
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1481
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition: main/cli.c:1872
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 1033 of file pbx_variables.c.

1034{
1035 switch (cmd) {
1036 case CLI_INIT:
1037 e->command = "dialplan set global";
1038 e->usage =
1039 "Usage: dialplan set global <name> <value>\n"
1040 " Set global dialplan variable <name> to <value>\n";
1041 return NULL;
1042 case CLI_GENERATE:
1043 return NULL;
1044 }
1045
1046 if (a->argc != e->args + 2)
1047 return CLI_SHOWUSAGE;
1048
1049 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
1050 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
1051
1052 return CLI_SUCCESS;
1053}

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

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

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

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

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

1410{
1411 int res = 0;
1412
1417 AST_TEST_REGISTER(test_variable_substrings);
1418
1419 return res;
1420}
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 124 of file pbx_variables.c.

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

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

1315{
1316 struct ast_var_t *vardata;
1317
1319 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
1320 ast_var_delete(vardata);
1322}
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471
#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:240

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

1124{
1125 struct ast_var_t *variables;
1126 const char *ret = NULL;
1127 int i;
1128 struct varshead *places[2] = { NULL, &globals };
1129
1130 if (!name)
1131 return NULL;
1132
1133 if (chan) {
1134 ast_channel_lock(chan);
1135 places[0] = ast_channel_varshead(chan);
1136 }
1137
1138 for (i = 0; i < 2; i++) {
1139 if (!places[i])
1140 continue;
1141 if (places[i] == &globals)
1143 AST_LIST_TRAVERSE(places[i], variables, entries) {
1144 if (!strcmp(name, ast_var_name(variables))) {
1145 ret = ast_var_value(variables);
1146 break;
1147 }
1148 }
1149 if (places[i] == &globals)
1151 if (ret)
1152 break;
1153 }
1154
1155 if (chan)
1156 ast_channel_unlock(chan);
1157
1158 return ret;
1159}
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(), array(), 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 1161 of file pbx_variables.c.

1162{
1163 struct ast_var_t *newvariable;
1164 struct varshead *headp;
1165
1166 if (name[strlen(name)-1] == ')') {
1167 char *function = ast_strdupa(name);
1168
1169 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
1170 ast_func_write(chan, function, value);
1171 return;
1172 }
1173
1174 if (chan) {
1175 ast_channel_lock(chan);
1176 headp = ast_channel_varshead(chan);
1177 } else {
1179 headp = &globals;
1180 }
1181
1182 if (value && (newvariable = ast_var_assign(name, value))) {
1183 if (headp == &globals)
1184 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1185 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1186 }
1187
1188 if (chan)
1189 ast_channel_unlock(chan);
1190 else
1192}
#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 1092 of file pbx_variables.c.

1093{
1094 struct ast_var_t *variables;
1095 const char *var, *val;
1096 int total = 0;
1097
1098 if (!chan)
1099 return 0;
1100
1102
1103 ast_channel_lock(chan);
1104
1106 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
1107 /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
1108 ) {
1109 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
1110 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
1111 break;
1112 } else
1113 total++;
1114 } else
1115 break;
1116 }
1117
1118 ast_channel_unlock(chan);
1119
1120 return total;
1121}
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 1252 of file pbx_variables.c.

1253{
1254 char *name, *value, *mydata;
1255
1256 if (ast_strlen_zero(data)) {
1257 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
1258 return 0;
1259 }
1260
1261 mydata = ast_strdupa(data);
1262 name = strsep(&mydata, "=");
1263 value = mydata;
1264 if (!value) {
1265 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
1266 return 0;
1267 }
1268
1269 if (strchr(name, ' ')) {
1270 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
1271 }
1272
1274
1275 return 0;
1276}
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 1194 of file pbx_variables.c.

1195{
1196 struct ast_var_t *newvariable;
1197 struct varshead *headp;
1198 const char *nametail = name;
1199 /*! True if the old value was not an empty string. */
1200 int old_value_existed = 0;
1201
1202 if (name[strlen(name) - 1] == ')') {
1203 char *function = ast_strdupa(name);
1204
1205 return ast_func_write(chan, function, value);
1206 }
1207
1208 if (chan) {
1209 ast_channel_lock(chan);
1210 headp = ast_channel_varshead(chan);
1211 } else {
1213 headp = &globals;
1214 }
1215
1216 /* For comparison purposes, we have to strip leading underscores */
1217 if (*nametail == '_') {
1218 nametail++;
1219 if (*nametail == '_')
1220 nametail++;
1221 }
1222
1223 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
1224 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
1225 /* there is already such a variable, delete it */
1226 AST_LIST_REMOVE_CURRENT(entries);
1227 old_value_existed = !ast_strlen_zero(ast_var_value(newvariable));
1228 ast_var_delete(newvariable);
1229 break;
1230 }
1231 }
1233
1234 if (value && (newvariable = ast_var_assign(name, value))) {
1235 if (headp == &globals) {
1236 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
1237 }
1238 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
1240 } else if (old_value_existed) {
1241 /* We just deleted a non-empty dialplan variable. */
1243 }
1244
1245 if (chan)
1246 ast_channel_unlock(chan);
1247 else
1249 return 0;
1250}
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 1278 of file pbx_variables.c.

1279{
1280 char *data;
1281 int x;
1283 AST_APP_ARG(pair)[99]; /* parse up to 99 variables */
1284 );
1288 );
1289
1290 if (ast_strlen_zero(vdata)) {
1291 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
1292 return 0;
1293 }
1294
1295 data = ast_strdupa(vdata);
1297
1298 for (x = 0; x < args.argc; x++) {
1299 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
1300 if (pair.argc == 2) {
1302 if (strchr(pair.name, ' '))
1303 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
1304 } else if (!chan) {
1305 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
1306 } else {
1307 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, ast_channel_exten(chan), ast_channel_context(chan), ast_channel_priority(chan));
1308 }
1309 }
1310
1311 return 0;
1312}
#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 245 of file pbx_variables.c.

246{
247 struct ast_str *str = ast_str_create(16);
248 const char *cret;
249
250 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
251 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
252 *ret = cret ? workspace : NULL;
253 ast_free(str);
254}
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 912 of file pbx_variables.c.

913{
915}
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 666 of file pbx_variables.c.

667{
668 pbx_substitute_variables_helper_full_location(c, headp, cp1, cp2, count, used, NULL, NULL, 0);
669}
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 676 of file pbx_variables.c.

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

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

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

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

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

1401{
1406 AST_TEST_UNREGISTER(test_variable_substrings);
1407}
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

◆ globals

struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE
static

◆ globalslock

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

◆ vars_cli

struct ast_cli_entry vars_cli[]
static

Definition at line 1392 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 672 of file pbx_variables.c.

Referenced by pbx_substitute_variables_helper_full_location().