<p>N A has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19675">View Change</a></p><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;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/75/19675/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..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/+/19675">change 19675</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/+/19675"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 20 </div>
<div style="display:none"> Gerrit-Change-Id: I3aa3bd35a5add82465c6ee9bd86b64601f0e1f49 </div>
<div style="display:none"> Gerrit-Change-Number: 19675 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: N A <asterisk@phreaknet.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>