<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>