<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/17792">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pbx_variables: Add variable registration and validation<br><br>Adds a mechanism for modules to register the special<br>variables they use with the PBX core. This allows us<br>to do a few things:<br><br>First, a CLI command is added to allow the user to see<br>all special Asterisk variables, along with a description<br>of what each variable is for. This includes core Asterisk<br>variables and those registered by modules.<br><br>Secondly, at runtime the variable setter now is aware<br>of what variables names are reserved and in use by<br>Asterisk, and it can throw a warning if a user tries to<br>set one of these variables. This operation would currently<br>fail, but would do so silently since the variable would<br>be saved to the channel; however, it can never be retrieved<br>as the variable substituter will match a built-in first,<br>and thus the stored value is not usable.<br><br>Consequently, more robust variable validation is now<br>possible and users are warned about confirmed or possible<br>conflicts with variable set operations.<br><br>ASTERISK-29849 #close<br><br>Change-Id: Iad3b8d9833c7d9debe04aca59260d7316c3ad28c<br>---<br>M apps/app_morsecode.c<br>M include/asterisk/chanvars.h<br>M include/asterisk/pbx.h<br>M main/pbx_variables.c<br>4 files changed, 335 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/92/17792/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_morsecode.c b/apps/app_morsecode.c</span><br><span>index f9b2119..166c646 100644</span><br><span>--- a/apps/app_morsecode.c</span><br><span>+++ b/apps/app_morsecode.c</span><br><span>@@ -281,6 +281,17 @@</span><br><span> return res;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ char name[20];</span><br><span style="color: hsl(120, 100%, 40%);">+ char description[64];</span><br><span style="color: hsl(120, 100%, 40%);">+} morsevars[] =</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ { "MORSEDITLEN", "Value in ms for length of dit" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "MORSETONE", "Pitch (in Hz) of tone, default is 800" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "MORSESPACETONE", "Pitch (in Hz) of spaces, default is 0" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "MORSETYPE", "Code type to use (AMERICAN or INTERNATIONAL (default))" },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int unload_module(void)</span><br><span> {</span><br><span> return ast_unregister_application(app_morsecode);</span><br><span>@@ -288,6 +299,7 @@</span><br><span> </span><br><span> static int load_module(void)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_REGISTER_VARIABLES(AST_VAR_MODULE_WRITE, morsevars);</span><br><span> return ast_register_application_xml(app_morsecode, morsecode_exec);</span><br><span> }</span><br><span> </span><br><span>diff --git a/include/asterisk/chanvars.h b/include/asterisk/chanvars.h</span><br><span>index 1a303c5..932a3d2 100644</span><br><span>--- a/include/asterisk/chanvars.h</span><br><span>+++ b/include/asterisk/chanvars.h</span><br><span>@@ -25,12 +25,78 @@</span><br><span> </span><br><span> #include "asterisk/linkedlists.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief special variable types</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note These only apply to special Asterisk variables (i.e. all caps)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_variable_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VAR_SYSTEM, /*!< Special variables that pertain to the entire Asterisk system (R/O) */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VAR_CHANNEL_BUILTIN, /*!< Special variables that pertain to a specific channel (R/O) */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VAR_MODULE, /*!< Special variables used by individual modules (R/O) */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VAR_MODULE_WRITE, /*!< Special variables used by individual modules, that a user may write */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_var_t {</span><br><span> AST_LIST_ENTRY(ast_var_t) entries;</span><br><span> char *value;</span><br><span> char name[0];</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determines whether a variable name is reserved by Asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Name of variable</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 not reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_varname_reserved(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determines whether a variable may be edited by users</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Name of variable</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 user editable</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 not user editable (read only)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_variable_editable(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Determines whether a user variable assignment should be made</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Name of variable</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This function is for user variable assignments only, not internal Asterisk assignments.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This variable will log any warnings as necessary and return whether or not assignment</span><br><span style="color: hsl(120, 100%, 40%);">+ * should proceed.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 Do not set variable</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Okay to set variable</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_bad_variable_assignment(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Register a special variable</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param vartype The type of special variable</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param name Name of variable</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param description Description of variable</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This only applies to special Asterisk variables. No applicability to user globals or chan vars.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 Failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_register_variable(int vartype, const char *name, char *description);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_REGISTER_VARIABLES(typ, array) { \</span><br><span style="color: hsl(120, 100%, 40%);">+ int x; \</span><br><span style="color: hsl(120, 100%, 40%);">+ for (x = 0; x < ARRAY_LEN(array); x++) { \</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_register_variable(typ, array[x].name, array[x].description); \</span><br><span style="color: hsl(120, 100%, 40%);">+ } \</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AST_LIST_HEAD_NOLOCK(varshead, ast_var_t);</span><br><span> </span><br><span> struct varshead *ast_var_list_create(void);</span><br><span>diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h</span><br><span>index f5f0691..4ada3e1 100644</span><br><span>--- a/include/asterisk/pbx.h</span><br><span>+++ b/include/asterisk/pbx.h</span><br><span>@@ -1386,6 +1386,18 @@</span><br><span> int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Same as pbx_builtin_setvar_helper, but accepts a restricted flag</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param restricted 0 for (unrestricted) variable assignments made by Asterisk internally and 1 for (restricted)</span><br><span style="color: hsl(120, 100%, 40%);">+ * variable assignments made by applications, functions, etc. processing user variable assignments.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note Will lock the channel. May also be used to set a channel dialplan function to a particular value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \see ast_func_write</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return -1 if the dialplan function fails to be set</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int pbx_builtin_setvar_helper_restricted(struct ast_channel *chan, const char *name, const char *value, int restricted);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Retrieve the value of a builtin variable or variable from the channel variable stack.</span><br><span> * \note Will lock the channel.</span><br><span> */</span><br><span>diff --git a/main/pbx_variables.c b/main/pbx_variables.c</span><br><span>index 7a85989..d3bf8d0 100644</span><br><span>--- a/main/pbx_variables.c</span><br><span>+++ b/main/pbx_variables.c</span><br><span>@@ -109,6 +109,190 @@</span><br><span> AST_RWLOCK_DEFINE_STATIC(globalslock);</span><br><span> static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AST_RWLOCK_DEFINE_STATIC(systemvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+AST_RWLOCK_DEFINE_STATIC(specialchanvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+AST_RWLOCK_DEFINE_STATIC(modvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+AST_RWLOCK_DEFINE_STATIC(modeditvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+static struct varshead systemvars = AST_LIST_HEAD_NOLOCK_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct varshead specialchanvars = AST_LIST_HEAD_NOLOCK_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct varshead modvars = AST_LIST_HEAD_NOLOCK_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+static struct varshead modeditvars = AST_LIST_HEAD_NOLOCK_INIT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_variable_register_helper(struct varshead *headp, int add, const char *name, char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_var_t *newvariable;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *nametail = name;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strcmp(ast_var_name(newvariable), nametail)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* there is already such a variable */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!value) { /* we're not adding a variable at the moment */</span><br><span style="color: hsl(120, 100%, 40%);">+ res = 1; /* var exists */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!add && value) { /* delete an existing var */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Deregistering special variable '%s'\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_REMOVE_CURRENT(entries);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_var_delete(newvariable);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res && value) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Failed to catch duplicate registration of '%s'\n", name); /* should never happen */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (value && (newvariable = ast_var_assign(name, value))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Registering special variable '%s'\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_INSERT_HEAD(headp, newvariable, entries);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_varname_reserved(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tmp = (char*) name;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Asterisk broadly reserves all uppercase + underscore var names for use by Asterisk */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (*tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (tmp[0] != '_' && !isupper(tmp[0])) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_variable_editable(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_varname_reserved(name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1; /* if not a special reserved format (all uppercase/underscore), okay */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* okay, if it's reserved, then it has to be registered as editable */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&modeditvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_variable_register_helper(&modeditvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&modeditvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_bad_variable_assignment(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_variable_editable(name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0; /* if not a special reserved format (all uppercase/underscore), okay */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* variable name is reserved, but is it actually in use? */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&systemvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&specialchanvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&modvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&systemvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&specialchanvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&modvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&systemvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&specialchanvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&modvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Read-only variable name '%s' is reserved by Asterisk and cannot be set\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1; /* user cannot set this variable, reject */</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Variable name '%s' is reserved by Asterisk (all uppercase) and may pose a conflict\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0; /* warn the user, but don't outright reject setting the variable */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_register_variable(int vartype, const char *name, char *description)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&systemvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&specialchanvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&modvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(&modeditvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* is the variable already registered? */</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&systemvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&specialchanvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&modvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_variable_register_helper(&modeditvars, 1, name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) { /* yeah, it is */</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Special variable '%s' is already registered.\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_strlen_zero(description)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Registration of variable '%s' failed: missing description\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ } if (vartype == AST_VAR_SYSTEM) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_variable_register_helper(&systemvars, 1, name, description);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (vartype == AST_VAR_CHANNEL_BUILTIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_variable_register_helper(&specialchanvars, 1, name, description);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (vartype == AST_VAR_MODULE) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_variable_register_helper(&modvars, 1, name, description);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (vartype == AST_VAR_MODULE_WRITE) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_variable_register_helper(&modeditvars, 1, name, description);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Registration of variable '%s' failed: invalid type\n", name);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&systemvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&specialchanvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&modvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(&modeditvarslock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int print_specialvars(int fd, ast_rwlock_t *lock, struct varshead *headp, char *catname, char *edit)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int c = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_var_t *newvariable;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_wrlock(lock);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(fd, "%-12s %-20s %-8s %s\n", catname, ast_var_name(newvariable), edit, ast_var_value(newvariable));</span><br><span style="color: hsl(120, 100%, 40%);">+ c++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rwlock_unlock(lock);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return c;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief CLI support for listing special variables in a parseable way */</span><br><span style="color: hsl(120, 100%, 40%);">+static char *handle_show_specialvars(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "dialplan show specialvars";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: dialplan show specialvars\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " List available special variables\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "%-12s %-20s %-8s %s\n", "Type", "Variable Name", "Editable", "Description");</span><br><span style="color: hsl(120, 100%, 40%);">+ i += print_specialvars(a->fd, &systemvarslock, &systemvars, "System", "No");</span><br><span style="color: hsl(120, 100%, 40%);">+ i += print_specialvars(a->fd, &specialchanvarslock, &specialchanvars, "Channel", "No");</span><br><span style="color: hsl(120, 100%, 40%);">+ i += print_specialvars(a->fd, &modvarslock, &modvars, "Module", "No");</span><br><span style="color: hsl(120, 100%, 40%);">+ i += print_specialvars(a->fd, &modeditvarslock, &modeditvars, "Module", "Yes");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "\n -- %d special variable(s) registered\n", i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span> * \brief extract offset:length from variable name.</span><br><span> * \return 1 if there is a offset:length part, which is</span><br><span>@@ -938,7 +1122,7 @@</span><br><span> if (a->argc != e->args + 2)</span><br><span> return CLI_SHOWUSAGE;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper_restricted(NULL, a->argv[3], a->argv[4], 1);</span><br><span> ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);</span><br><span> </span><br><span> return CLI_SUCCESS;</span><br><span>@@ -972,7 +1156,7 @@</span><br><span> return CLI_FAILURE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- pbx_builtin_setvar_helper(chan, var_name, var_value);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper_restricted(chan, var_name, var_value, 1);</span><br><span> </span><br><span> chan = ast_channel_unref(chan);</span><br><span> </span><br><span>@@ -1063,6 +1247,11 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* this function is only called by userland functions, so always check */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_bad_variable_assignment(name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (chan) {</span><br><span> ast_channel_lock(chan);</span><br><span> headp = ast_channel_varshead(chan);</span><br><span>@@ -1085,6 +1274,11 @@</span><br><span> </span><br><span> int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ return pbx_builtin_setvar_helper_restricted(chan, name, value, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int pbx_builtin_setvar_helper_restricted(struct ast_channel *chan, const char *name, const char *value, int restricted)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span> struct ast_var_t *newvariable;</span><br><span> struct varshead *headp;</span><br><span> const char *nametail = name;</span><br><span>@@ -1097,6 +1291,10 @@</span><br><span> return ast_func_write(chan, function, value);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (restricted && ast_bad_variable_assignment(name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (chan) {</span><br><span> ast_channel_lock(chan);</span><br><span> headp = ast_channel_varshead(chan);</span><br><span>@@ -1162,7 +1360,7 @@</span><br><span> ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- pbx_builtin_setvar_helper(chan, name, value);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper_restricted(chan, name, value, 1);</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>@@ -1190,7 +1388,7 @@</span><br><span> for (x = 0; x < args.argc; x++) {</span><br><span> AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');</span><br><span> if (pair.argc == 2) {</span><br><span style="color: hsl(0, 100%, 40%);">- pbx_builtin_setvar_helper(chan, pair.name, pair.value);</span><br><span style="color: hsl(120, 100%, 40%);">+ pbx_builtin_setvar_helper_restricted(chan, pair.name, pair.value, 1);</span><br><span> if (strchr(pair.name, ' '))</span><br><span> 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);</span><br><span> } else if (!chan) {</span><br><span>@@ -1213,9 +1411,49 @@</span><br><span> ast_rwlock_unlock(&globalslock);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct pbx_builtin_system_vars {</span><br><span style="color: hsl(120, 100%, 40%);">+ char name[20];</span><br><span style="color: hsl(120, 100%, 40%);">+ char description[64];</span><br><span style="color: hsl(120, 100%, 40%);">+} builtinsystemvars[] =</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ { "EPOCH", "Current unix style epoch" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "SYSTEMNAME", "value of systemname option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTCACHEDIR", "value of astcachedir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTETCDIR", "value of astetcdir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTMODDIR", "value of astmoddir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTVARLIBDIR", "value of astvarlib option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTDBDIR", "value of astdbdir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTKEYDIR", "value of astkeydir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTDATADIR", "value of astdatadir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTAGIDIR", "value of astagidir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTSPOOLDIR", "value of astspooldir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTRUNDIR", "value of astrundir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTLOGDIR", "value of astlogdir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ASTSBINDIR", "value of astsbindir option from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "ENTITYID", "Global Entity ID set automatically, or from asterisk.conf" },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ char name[20];</span><br><span style="color: hsl(120, 100%, 40%);">+ char description[64];</span><br><span style="color: hsl(120, 100%, 40%);">+} builtinchannelvars[] =</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CALLINGPRES", "Caller ID presentation for incoming calls (PRI channels)" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CALLINGANI2", "Caller ANI2 (PRI channels)" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CALLINGTON", "Caller Type of Number (PRI channels)" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CALLINGTNS", "Transit Network Selector (PRI channels)" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "EXTEN", "Current extension" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CONTEXT", "Current context" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "PRIORITY", "Current priority" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "CHANNEL", "Current channel name" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "UNIQUEID", "Current call unique identifier" },</span><br><span style="color: hsl(120, 100%, 40%);">+ { "HANGUPCAUSE", "Asterisk cause of hangup (inbound/outbound)" },</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct ast_cli_entry vars_cli[] = {</span><br><span> AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),</span><br><span> AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(handle_show_specialvars, "Show special Asterisk variables"),</span><br><span> AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),</span><br><span> AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),</span><br><span> };</span><br><span>@@ -1232,6 +1470,9 @@</span><br><span> {</span><br><span> int res = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ AST_REGISTER_VARIABLES(AST_VAR_SYSTEM, builtinsystemvars);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_REGISTER_VARIABLES(AST_VAR_CHANNEL_BUILTIN, builtinchannelvars);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> res |= ast_cli_register_multiple(vars_cli, ARRAY_LEN(vars_cli));</span><br><span> res |= ast_register_application2("Set", pbx_builtin_setvar, NULL, NULL, NULL);</span><br><span> res |= ast_register_application2("MSet", pbx_builtin_setvar_multiple, NULL, NULL, NULL);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/17792">change 17792</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/17792"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iad3b8d9833c7d9debe04aca59260d7316c3ad28c </div>
<div style="display:none"> Gerrit-Change-Number: 17792 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>