<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16121">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_if: Adds If, EndIf, and ExitIf applications<br><br>Adds applications for conditional execution<br>of a block of dialplan, similar to the While,<br>EndWhile, and ExitWhile applications. The branch<br>if executed once if the condition is true and<br>may be broken out of while inside.<br><br>ASTERISK-29497<br><br>Change-Id: I3aa3bd35a5add82465c6ee9bd86b64601f0e1f49<br>---<br>A apps/app_if.c<br>A doc/CHANGES-staging/app_if.txt<br>2 files changed, 313 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/21/16121/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_if.c b/apps/app_if.c</span><br><span>new file mode 100644</span><br><span>index 0000000..302338e</span><br><span>--- /dev/null</span><br><span>+++ b/apps/app_if.c</span><br><span>@@ -0,0 +1,308 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright 2021, Naveen Albert <asterisk@phreaknet.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Naveen Albert <asterisk@phreaknet.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</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%);">+/*! \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief If Branch Implementation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Naveen Albert <asterisk@phreaknet.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \ingroup applications</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%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+    <support_level>extended</support_level></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%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** DOCUMENTATION</span><br><span style="color: hsl(120, 100%, 40%);">+   <application name="If" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+            <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Start an if branch.</span><br><span style="color: hsl(120, 100%, 40%);">+           </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax></span><br><span style="color: hsl(120, 100%, 40%);">+                        <parameter name="expr" required="true" /></span><br><span style="color: hsl(120, 100%, 40%);">+           </syntax></span><br><span style="color: hsl(120, 100%, 40%);">+               <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>Start an If branch.  Execution will continue inside the branch</span><br><span style="color: hsl(120, 100%, 40%);">+                    if expr is true.</para></span><br><span style="color: hsl(120, 100%, 40%);">+         </description></span><br><span style="color: hsl(120, 100%, 40%);">+          <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">EndIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                     <ref type="application">ExitIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+            </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+     </application></span><br><span style="color: hsl(120, 100%, 40%);">+  <application name="EndIf" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+         <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      End an if branch.</span><br><span style="color: hsl(120, 100%, 40%);">+             </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax /></span><br><span style="color: hsl(120, 100%, 40%);">+              <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>Ends the branch begun by the preceding <literal>If()</literal> application.</para></span><br><span style="color: hsl(120, 100%, 40%);">+              </description></span><br><span style="color: hsl(120, 100%, 40%);">+          <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">If</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                        <ref type="application">ExitIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+            </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+     </application></span><br><span style="color: hsl(120, 100%, 40%);">+  <application name="ExitIf" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+                <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      End an If branch.</span><br><span style="color: hsl(120, 100%, 40%);">+             </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+             <syntax /></span><br><span style="color: hsl(120, 100%, 40%);">+              <description></span><br><span style="color: hsl(120, 100%, 40%);">+                   <para>Exits an <literal>If()</literal> branch, whether or not it has completed.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                </description></span><br><span style="color: hsl(120, 100%, 40%);">+          <see-also></span><br><span style="color: hsl(120, 100%, 40%);">+                      <ref type="application">If</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                        <ref type="application">EndIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+             </see-also></span><br><span style="color: hsl(120, 100%, 40%);">+     </application></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 char *start_app = "If";</span><br><span style="color: hsl(120, 100%, 40%);">+static char *stop_app = "EndIf";</span><br><span style="color: hsl(120, 100%, 40%);">+static char *exit_app = "ExitIf";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define VAR_SIZE 64</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 const char *get_index(struct ast_channel *chan, const char *prefix, int idx) {</span><br><span style="color: hsl(120, 100%, 40%);">+    char varname[VAR_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(varname, VAR_SIZE, "%s_%d", prefix, idx);</span><br><span style="color: hsl(120, 100%, 40%);">+  return pbx_builtin_getvar_helper(chan, varname);</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 struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)</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 ast_context *c2;</span><br><span style="color: hsl(120, 100%, 40%);">+       int idx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ast_extension_match(ast_get_extension_name(e), exten)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  int needmatch = ast_get_extension_matchcid(e);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||</span><br><span style="color: hsl(120, 100%, 40%);">+                            (!needmatch)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               /* This is the matching extension we want */</span><br><span style="color: hsl(120, 100%, 40%);">+                          struct ast_exten *p;</span><br><span style="color: hsl(120, 100%, 40%);">+                          for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                    if (priority != ast_get_extension_priority(p))</span><br><span style="color: hsl(120, 100%, 40%);">+                                                continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                                     return p;</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%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* No match; run through includes */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (idx = 0; idx < ast_context_includes_count(c); idx++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                const struct ast_include *i = ast_context_includes_get(c, idx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             e = find_matching_priority(c2, exten, priority, callerid);</span><br><span style="color: hsl(120, 100%, 40%);">+                            if (e)</span><br><span style="color: hsl(120, 100%, 40%);">+                                        return 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%);">+     }</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%);">+static int find_matching_endif(struct ast_channel *chan)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_context *c;</span><br><span style="color: hsl(120, 100%, 40%);">+        int res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ast_rdlock_contexts()) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Failed to lock contexts list\n");</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%);">+   for (c=ast_walk_contexts(NULL); c; c=ast_walk_contexts(c)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_exten *e;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!ast_rdlock_context(c)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            /* This is the matching context we want */</span><br><span style="color: hsl(120, 100%, 40%);">+                            int cur_priority = ast_channel_priority(chan) + 1, level=1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                         for (e = find_matching_priority(c, ast_channel_exten(chan), cur_priority,</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%);">+                                       e;</span><br><span style="color: hsl(120, 100%, 40%);">+                                    e = find_matching_priority(c, ast_channel_exten(chan), ++cur_priority,</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 (!strcasecmp(ast_get_extension_app(e), "IF")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                          level++;</span><br><span style="color: hsl(120, 100%, 40%);">+                                      } else if (!strcasecmp(ast_get_extension_app(e), "ENDIF")) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                                level--;</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 (level == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                             res = cur_priority;</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_unlock_context(c);</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (res > 0) {</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_unlock_contexts();</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 _if_exec(struct ast_channel *chan, const char *data, int end)</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%);">+    const char *if_pri = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *my_name = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *condition = NULL, *label = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  char varname[VAR_SIZE], end_varname[VAR_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *prefix = "IF";</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t size=0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int used_index_i = -1, x=0;</span><br><span style="color: hsl(120, 100%, 40%);">+   char used_index[VAR_SIZE] = "0", new_index[VAR_SIZE] = "0";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!chan) {</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%);">+   for (x=0;;x++) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (get_index(chan, prefix, x)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     used_index_i = x;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else</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%);">+   snprintf(used_index, VAR_SIZE, "%d", used_index_i);</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(new_index, VAR_SIZE, "%d", used_index_i + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!end)</span><br><span style="color: hsl(120, 100%, 40%);">+             condition = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;</span><br><span style="color: hsl(120, 100%, 40%);">+      my_name = ast_alloca(size);</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(my_name, 0, size);</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(my_name, size, "%s_%s_%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (end) {</span><br><span style="color: hsl(120, 100%, 40%);">+            label = used_index;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (!(label = pbx_builtin_getvar_helper(chan, my_name))) {</span><br><span style="color: hsl(120, 100%, 40%);">+             label = new_index;</span><br><span style="color: hsl(120, 100%, 40%);">+            pbx_builtin_setvar_helper(chan, my_name, label);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     snprintf(varname, VAR_SIZE, "%s_%s", prefix, label);</span><br><span style="color: hsl(120, 100%, 40%);">+        if ((if_pri = pbx_builtin_getvar_helper(chan, varname)) && !end) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if_pri = ast_strdupa(if_pri);</span><br><span style="color: hsl(120, 100%, 40%);">+         snprintf(end_varname,VAR_SIZE,"END_%s",varname);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_channel_unlock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((!end && !pbx_checkcondition(condition)) || (end > 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Condition Met (clean up helper vars) */</span><br><span style="color: hsl(120, 100%, 40%);">+            const char *goto_str;</span><br><span style="color: hsl(120, 100%, 40%);">+         pbx_builtin_setvar_helper(chan, varname, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               pbx_builtin_setvar_helper(chan, my_name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+               snprintf(end_varname,VAR_SIZE,"END_%s",varname);</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_channel_lock(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+               if ((goto_str = pbx_builtin_getvar_helper(chan, end_varname))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_parseable_goto(chan, goto_str);</span><br><span style="color: hsl(120, 100%, 40%);">+                   pbx_builtin_setvar_helper(chan, end_varname, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      int pri = find_matching_endif(chan);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (pri > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_verb(3, "Jumping to priority %d\n", pri);</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_channel_priority_set(chan, pri);</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else if (end == 2) { /* Condition added because of end > 0 instead of end == 2 */</span><br><span style="color: hsl(120, 100%, 40%);">+                                ast_log(LOG_WARNING, "Couldn't find matching EndIf? (If at %s@%s priority %d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));</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_channel_unlock(chan);</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%);">+   if (!end && !if_pri) {</span><br><span style="color: hsl(120, 100%, 40%);">+                char *goto_str;</span><br><span style="color: hsl(120, 100%, 40%);">+               size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto_str = ast_alloca(size);</span><br><span style="color: hsl(120, 100%, 40%);">+          memset(goto_str, 0, size);</span><br><span style="color: hsl(120, 100%, 40%);">+            snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan));</span><br><span style="color: hsl(120, 100%, 40%);">+               pbx_builtin_setvar_helper(chan, varname, goto_str);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (end && if_pri) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* END of branch */</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(end_varname, VAR_SIZE, "END_%s", varname);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (! pbx_builtin_getvar_helper(chan, end_varname)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 char *goto_str;</span><br><span style="color: hsl(120, 100%, 40%);">+                       size = strlen(ast_channel_context(chan)) + strlen(ast_channel_exten(chan)) + 32;</span><br><span style="color: hsl(120, 100%, 40%);">+                      goto_str = ast_alloca(size);</span><br><span style="color: hsl(120, 100%, 40%);">+                  memset(goto_str, 0, size);</span><br><span style="color: hsl(120, 100%, 40%);">+                    snprintf(goto_str, size, "%s,%s,%d", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan)+1);</span><br><span style="color: hsl(120, 100%, 40%);">+                     pbx_builtin_setvar_helper(chan, end_varname, goto_str);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_parseable_goto(chan, if_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%);">+   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 if_start_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+      return _if_exec(chan, data, 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%);">+static int if_end_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+    return _if_exec(chan, data, 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%);">+static int if_exit_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+   return _if_exec(chan, data, 2);</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 unload_module(void)</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%);">+    res = ast_unregister_application(start_app);</span><br><span style="color: hsl(120, 100%, 40%);">+  res |= ast_unregister_application(stop_app);</span><br><span style="color: hsl(120, 100%, 40%);">+  res |= ast_unregister_application(exit_app);</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 load_module(void)</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%);">+    res = ast_register_application_xml(start_app, if_start_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_register_application_xml(stop_app, if_end_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+   res |= ast_register_application_xml(exit_app, if_exit_exec);</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%);">+AST_MODULE_INFO_STANDARD_EXTENDED(ASTERISK_GPL_KEY, "If Branch and Conditional Execution");</span><br><span>diff --git a/doc/CHANGES-staging/app_if.txt b/doc/CHANGES-staging/app_if.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..1dc6f29</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/app_if.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: app_if</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Adds the If, EndIf, and ExitIf applications</span><br><span style="color: hsl(120, 100%, 40%);">+for conditional execution of a block of code.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/16121">change 16121</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/+/16121"/><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: I3aa3bd35a5add82465c6ee9bd86b64601f0e1f49 </div>
<div style="display:none"> Gerrit-Change-Number: 16121 </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>