<p>Friendly Automation <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19674">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span></span><br></pre><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, approved
  Friendly Automation: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_if: Adds conditional branch applications<br><br>Adds the If, ElseIf, Else, ExitIf, and EndIf<br>applications for conditional execution<br>of a block of dialplan, similar to the While,<br>EndWhile, and ExitWhile applications. The<br>appropriate branch is executed at most once<br>if available and may be broken out of while<br>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, 405 insertions(+), 0 deletions(-)<br><br></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..b1ff0ad</span><br><span>--- /dev/null</span><br><span>+++ b/apps/app_if.c</span><br><span>@@ -0,0 +1,382 @@</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 2022, 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%);">+                 <note><para>This application (and related applications) set variables</span><br><span style="color: hsl(120, 100%, 40%);">+                     internally during execution.</para></note></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">ElseIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                    <ref type="application">Else</ref></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="ElseIf" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+                <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Start an else 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 optional ElseIf branch. Execution will continue inside the branch</span><br><span style="color: hsl(120, 100%, 40%);">+                        if expr is true and if previous If and ElseIf branches evaluated to false.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                       <para>Please note that execution inside a true If branch will fallthrough into</span><br><span style="color: hsl(120, 100%, 40%);">+                  ElseIf unless the If segment is terminated with an ExitIf call. This is only</span><br><span style="color: hsl(120, 100%, 40%);">+                  necessary with ElseIf but not with Else.</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">Else</ref></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="Else" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+          <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Define an optional else 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 Else branch. Execution will jump here if all previous</span><br><span style="color: hsl(120, 100%, 40%);">+                    If and ElseIf branches evaluated to false.</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">ElseIf</ref></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">ElseIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                    <ref type="application">Else</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">ElseIf</ref></span><br><span style="color: hsl(120, 100%, 40%);">+                    <ref type="application">Else</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 *if_app = "If";</span><br><span style="color: hsl(120, 100%, 40%);">+static char *elseif_app = "ElseIf";</span><br><span style="color: hsl(120, 100%, 40%);">+static char *else_app = "Else";</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%);">+static const char *get_index(struct ast_channel *chan, const char *prefix, int idx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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, const char *otherapp)</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 (!otherapp && 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%);">+                                        } else if (otherapp && level == 1 && !strcasecmp(ast_get_extension_app(e), otherapp)) {</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_helper(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 *label = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     char varname[VAR_SIZE], end_varname[VAR_SIZE + 4];</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%);">+</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%);">+    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 > 1) {</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, sizeof(varname), "%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,sizeof(end_varname),"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 <= 1 && !pbx_checkcondition(ast_strdupa(data))) || (end > 1)) {</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%);">+         int pri, endifpri;</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,sizeof(end_varname),"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%);">+               endifpri = find_matching_endif(chan, NULL);</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 if (end <= 1 && (pri = find_matching_endif(chan, "ElseIf")) > 0 && pri < endifpri) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        pri--; /* back up a priority, since it returned the priority after the ElseIf */</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* If is false, and ElseIf exists, so jump to ElseIf */</span><br><span style="color: hsl(120, 100%, 40%);">+                       ast_verb(3, "Taking conditional false branch, 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 <= 1 && (pri = find_matching_endif(chan, "Else")) > 0 && pri < endifpri) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* don't need to back up a priority, because we don't actually need to execute Else, just jump to the priority after. Directly executing Else will exit the conditional. */</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* If is false, and Else exists, so jump to Else */</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_verb(3, "Taking absolute false branch, 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 {</span><br><span style="color: hsl(120, 100%, 40%);">+                      pri = endifpri;</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (pri > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             ast_verb(3, "Exiting conditional, 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 == 4) { /* Condition added because of end > 0 instead of end == 4 */</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 <= 1 && !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 > 1 && 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, sizeof(end_varname), "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_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+    return if_helper(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 elseif_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+   return if_helper(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 end_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+      return if_helper(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 else_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+     return if_helper(chan, data, 3);</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 exit_exec(struct ast_channel *chan, const char *data) {</span><br><span style="color: hsl(120, 100%, 40%);">+     return if_helper(chan, data, 4);</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(if_app);</span><br><span style="color: hsl(120, 100%, 40%);">+     res |= ast_unregister_application(elseif_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(else_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(if_app, if_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+  res |= ast_register_application_xml(elseif_app, elseif_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+ res |= ast_register_application_xml(stop_app, end_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+      res |= ast_register_application_xml(else_app, else_exec);</span><br><span style="color: hsl(120, 100%, 40%);">+     res |= ast_register_application_xml(exit_app, 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..855f15a</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/app_if.txt</span><br><span>@@ -0,0 +1,4 @@</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, ElseIf, Else, EndIf, and ExitIf applications</span><br><span style="color: hsl(120, 100%, 40%);">+for conditional execution of a block of code.</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/19674">change 19674</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/+/19674"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: I3aa3bd35a5add82465c6ee9bd86b64601f0e1f49 </div>
<div style="display:none"> Gerrit-Change-Number: 19674 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: N A <asterisk@phreaknet.org> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>