<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/17470">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">pbx: Add variable substitution API for extensions<br><br>Currently, variable substitution involving dialplan<br>extensions is quite clunky since it entails obtaining<br>the current dialplan location, backing it up, storing<br>the desired variables for substitution on the channel,<br>performing substitution, then restoring the original<br>location.<br><br>In addition to being clunky, things could also go wrong<br>if an async goto were to occur and change the dialplan<br>location during a substitution.<br><br>Fundamentally, there's no reason it needs to be done this<br>way, so new API is added to allow for directly passing in<br>the dialplan location for the purposes of variable<br>substitution so we don't need to mess with the channel<br>information anymore. Existing API is not changed.<br><br>ASTERISK-29745 #close<br><br>Change-Id: I23273bf27fa0efb64a606eebf9aa8e2f41a065e4<br>---<br>M include/asterisk/pbx.h<br>M main/pbx.c<br>M main/pbx_variables.c<br>3 files changed, 112 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/70/17470/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h</span><br><span>index c75e50a..6fe0e2d 100644</span><br><span>--- a/include/asterisk/pbx.h</span><br><span>+++ b/include/asterisk/pbx.h</span><br><span>@@ -1277,6 +1277,22 @@</span><br><span> const char *ast_get_extension_app(struct ast_exten *e);</span><br><span> const char *ast_get_extension_label(struct ast_exten *e);</span><br><span> void *ast_get_extension_app_data(struct ast_exten *e);</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 Fill a string buffer with the data at a dialplan extension</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buf String buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param bufsize Size of buf</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param c Channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param context Dialplan context</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param exten Dialplan extension</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param priority Dialplan priority</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 Failed to obtain extension data</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Successfully obtained extension data</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *context, const char *exten, int priority);</span><br><span> /*! @} */</span><br><span> </span><br><span> /*! @name Registrar info functions ... */</span><br><span>@@ -1400,6 +1416,11 @@</span><br><span> void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count);</span><br><span> void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);</span><br><span> void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);</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 Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the context, extension, and priority in.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used, char *context, char *exten, int pri);</span><br><span> /*! @} */</span><br><span> /*! @} */</span><br><span> </span><br><span>@@ -1485,6 +1506,25 @@</span><br><span>  */</span><br><span> int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Parses a dialplan location into context, extension, priority</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param chan Channel to execute on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param context Pointer to initial value for context.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param exten Pointer to initial value for exten.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pri Pointer to initial value for pri</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ipri Pointer to integer value of priority</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param mode Pointer to mode (or NULL if mode is not used)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param rest Pointer to buffer to capture rest of parsing (or NULL if not used)</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * strsep should be used to initially populate context, exten, and pri prior</span><br><span style="color: hsl(120, 100%, 40%);">+ * to calling this function. All arguments are modified in place.</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 non-zero failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int pbx_parse_location(struct ast_channel *chan, char *context, char *exten, char *pri, int *ipri, int *mode, char *rest);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_custom_function* ast_custom_function_find(const char *name);</span><br><span> </span><br><span> /*!</span><br><span>diff --git a/main/pbx.c b/main/pbx.c</span><br><span>index 0cae9b8..09f6804 100644</span><br><span>--- a/main/pbx.c</span><br><span>+++ b/main/pbx.c</span><br><span>@@ -8610,6 +8610,26 @@</span><br><span>     return e ? e->data : NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *context, const char *exten, int priority)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_exten *e;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_rdlock_contexts();</span><br><span style="color: hsl(120, 100%, 40%);">+        e = pbx_find_extension(c, NULL, &q, context, exten, priority, NULL, "", E_MATCH);</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_unlock_contexts();</span><br><span style="color: hsl(120, 100%, 40%);">+        if (e) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    const char *tmp = ast_get_extension_app_data(e);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (tmp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_copy_string(buf, tmp, bufsize);</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 0;</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> /*</span><br><span>  * Walking functions ...</span><br><span>  */</span><br><span>@@ -8807,6 +8827,43 @@</span><br><span>    return __ast_goto_if_exists(chan, context, exten, priority, 1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+int pbx_parse_location(struct ast_channel *chan, char *context, char *exten, char *pri, int *ipri, int *mode, char *rest)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* do the strsep before here, so we don't have to alloc and free */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!exten) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* Only a priority in this one */</span><br><span style="color: hsl(120, 100%, 40%);">+             pri = context;</span><br><span style="color: hsl(120, 100%, 40%);">+                exten = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         context = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (!pri) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* Only an extension and priority in this one */</span><br><span style="color: hsl(120, 100%, 40%);">+              pri = exten;</span><br><span style="color: hsl(120, 100%, 40%);">+          exten = context;</span><br><span style="color: hsl(120, 100%, 40%);">+              context = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (*pri == '+') {</span><br><span style="color: hsl(120, 100%, 40%);">+                    *mode = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    pri++;</span><br><span style="color: hsl(120, 100%, 40%);">+                } else if (*pri == '-') {</span><br><span style="color: hsl(120, 100%, 40%);">+                     *mode = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                   pri++;</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%);">+     if ((rest && sscanf(pri, "%30d%1s", ipri, rest) != 1) || sscanf(pri, "%30d", ipri) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                *ipri = ast_findlabel_extension(chan, context ? context : ast_channel_context(chan),</span><br><span style="color: hsl(120, 100%, 40%);">+                  exten ? exten : ast_channel_exten(chan), pri,</span><br><span style="color: hsl(120, 100%, 40%);">+                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));</span><br><span style="color: hsl(120, 100%, 40%);">+               if (*ipri < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            } else if (mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    *mode = 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%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)</span><br><span> {</span><br><span>   char *exten, *pri, *context;</span><br><span>diff --git a/main/pbx_variables.c b/main/pbx_variables.c</span><br><span>index 91b5bbb..bd3cbcb 100644</span><br><span>--- a/main/pbx_variables.c</span><br><span>+++ b/main/pbx_variables.c</span><br><span>@@ -625,6 +625,11 @@</span><br><span> </span><br><span> void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+    pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, NULL, NULL, 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%);">+void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used, char *context, char *exten, int pri)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>        /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */</span><br><span>         const char *whereweare;</span><br><span>      const char *orig_cp2 = cp2;</span><br><span>@@ -759,7 +764,16 @@</span><br><span>                           ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");</span><br><span>                        } else {</span><br><span>                             /* Retrieve variable value */</span><br><span style="color: hsl(0, 100%, 40%);">-                           pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);</span><br><span style="color: hsl(120, 100%, 40%);">+                             /* For dialplan location, if we were told what to substitute explicitly, use that instead */</span><br><span style="color: hsl(120, 100%, 40%);">+                          if (exten && !strcmp(vars, "EXTEN")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ast_copy_string(workspace, context, VAR_BUF_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+                            } else if (context && !strcmp(vars, "CONTEXT")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_copy_string(workspace, context, VAR_BUF_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+                            } else if (pri && !strcmp(vars, "PRIORITY")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      snprintf(workspace, VAR_BUF_SIZE, "%d", pri);</span><br><span style="color: hsl(120, 100%, 40%);">+                               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);</span><br><span style="color: hsl(120, 100%, 40%);">+                             }</span><br><span>                    }</span><br><span>                    if (cp4) {</span><br><span>                           cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/17470">change 17470</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/+/17470"/><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: I23273bf27fa0efb64a606eebf9aa8e2f41a065e4 </div>
<div style="display:none"> Gerrit-Change-Number: 17470 </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>