<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/15928">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">app_waitforcond: New application<br><br>While several applications exist to wait for<br>a certain event to occur, none allow waiting<br>for any generic expression to become true.<br>This application allows for waiting for a condition<br>to become true, with configurable timeout and<br>checking interval.<br><br>ASTERISK-29444<br><br>Change-Id: I08adf2824b8bc63405778cf355963b5005612f41<br>---<br>A apps/app_waitforcond.c<br>A doc/CHANGES-staging/app_waitforcond.txt<br>2 files changed, 239 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_waitforcond.c b/apps/app_waitforcond.c</span><br><span>new file mode 100644</span><br><span>index 0000000..7bc254c</span><br><span>--- /dev/null</span><br><span>+++ b/apps/app_waitforcond.c</span><br><span>@@ -0,0 +1,234 @@</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 (C) 2021, Naveen Albert</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 Sleep until a condition is true</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/logger.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/channel.h"</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/app.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="WaitForCondition" language="en_US"></span><br><span style="color: hsl(120, 100%, 40%);">+              <synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                      Wait (sleep) until the given condition is true.</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="replacementchar" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                          <para>Specifies the character in the expression used to replace the <literal>$</literal></span><br><span style="color: hsl(120, 100%, 40%);">+                            character. This character should not be used anywhere in the expression itself.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                  </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="expression" required="true"></span><br><span style="color: hsl(120, 100%, 40%);">+                               <para>A modified logical expression with the <literal>$</literal> characters replaced by</span><br><span style="color: hsl(120, 100%, 40%);">+                            <replaceable>replacementchar</replaceable>. This is necessary to pass the expression itself</span><br><span style="color: hsl(120, 100%, 40%);">+                               into the application, rather than its initial evaluation.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                        </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="timeout"></span><br><span style="color: hsl(120, 100%, 40%);">+                            <para>The maximum amount of time, in seconds, this application should wait for a condition</span><br><span style="color: hsl(120, 100%, 40%);">+                              to become true before dialplan execution continues automatically to the next priority.</span><br><span style="color: hsl(120, 100%, 40%);">+                                By default, there is no timeout.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                 </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+                    <parameter name="interval"></span><br><span style="color: hsl(120, 100%, 40%);">+                           <para>The frequency, in seconds, of polling the condition, which can be adjusted depending</span><br><span style="color: hsl(120, 100%, 40%);">+                              on how time-sensitive execution needs to be. By default, this is 0.05.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                   </parameter></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>Waits until <replaceable>expression</replaceable> evaluates to true, checking every</span><br><span style="color: hsl(120, 100%, 40%);">+                   <replaceable>interval</replaceable> seconds for up to <replaceable>timeout</replaceable>. Default</span><br><span style="color: hsl(120, 100%, 40%);">+                     is evaluate <replaceable>expression</replaceable> every 50 milliseconds with no timeout.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                     <example title="Wait for ${condition} to become 1 for up to 40 seconds, checking every 500ms"></span><br><span style="color: hsl(120, 100%, 40%);">+                         same => n,WaitForCondition(#,#["#{condition}"="1"],40,0.5)</span><br><span style="color: hsl(120, 100%, 40%);">+                    </example></span><br><span style="color: hsl(120, 100%, 40%);">+                      <para>Sets <variable>WAITFORCONDITIONSTATUS</variable> to one of the following values:</para></span><br><span style="color: hsl(120, 100%, 40%);">+                 <variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+                          <variable name="WAITFORCONDITIONSTATUS"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <value name="TRUE"></span><br><span style="color: hsl(120, 100%, 40%);">+                                           Condition evaluated to true before timeout expired.</span><br><span style="color: hsl(120, 100%, 40%);">+                                   </value></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <value name="FAILURE"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                Invalid argument.</span><br><span style="color: hsl(120, 100%, 40%);">+                                     </value></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <value name="TIMEOUT"></span><br><span style="color: hsl(120, 100%, 40%);">+                                                Timeout elapsed without condition evaluating to true.</span><br><span style="color: hsl(120, 100%, 40%);">+                                 </value></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <value name="HANGUP"></span><br><span style="color: hsl(120, 100%, 40%);">+                                         Channel hung up before condition became true.</span><br><span style="color: hsl(120, 100%, 40%);">+                                 </value></span><br><span style="color: hsl(120, 100%, 40%);">+                                </variable></span><br><span style="color: hsl(120, 100%, 40%);">+                     </variablelist></span><br><span style="color: hsl(120, 100%, 40%);">+         </description></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 *app = "WaitForCondition";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int waitforcond_exec(struct ast_channel *chan, const char *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int ms, i;</span><br><span style="color: hsl(120, 100%, 40%);">+    double timeout = 0, poll = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int timeout_ms = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int poll_ms = 50; /* default is evaluate the condition every 50ms */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct timeval start = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+   char dollarsignrep;</span><br><span style="color: hsl(120, 100%, 40%);">+   int brackets = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     char *pos, *open_bracket, *expression, *optargs = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       char condition[512];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        AST_DECLARE_APP_ARGS(args,</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_APP_ARG(timeout);</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_APP_ARG(interval);</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%);">+  pos = ast_strdupa(data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ast_strlen_zero(pos)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "WaitForCondition requires a condition\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* is there at least a [ followed by a ] somewhere ? */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!(open_bracket = strchr(pos, '[')) || !strchr(open_bracket, ']')) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "No expression detected. Did you forget to replace the $ signs?\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   dollarsignrep = pos[0];</span><br><span style="color: hsl(120, 100%, 40%);">+       if (dollarsignrep == '$' || dollarsignrep == '[' || dollarsignrep == ']'</span><br><span style="color: hsl(120, 100%, 40%);">+              || dollarsignrep == '{' || dollarsignrep == '}') {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Dollar sign replacement cannot be %c.\n", dollarsignrep);</span><br><span style="color: hsl(120, 100%, 40%);">+               pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     ++pos;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (pos[0] != ',') {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Invalid separator: %c\n", pos[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+              pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     ++pos;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (pos[0] != dollarsignrep) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Expression start does not match provided replacement: %c\n", pos[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+           pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   expression = pos; /* we're at the start of the expression */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* commas may appear within the expression, so go until we've encountered as many closing brackets as opening */</span><br><span style="color: hsl(120, 100%, 40%);">+  while (++pos) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (pos[0] == '\0') {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_log(LOG_ERROR, "Could not parse end of expression.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "FAILURE");</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (pos[0] == '[') {</span><br><span style="color: hsl(120, 100%, 40%);">+                  brackets++;</span><br><span style="color: hsl(120, 100%, 40%);">+           } else if (pos[0] == ']') {</span><br><span style="color: hsl(120, 100%, 40%);">+                   brackets--;</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (brackets == 0) { /* reached end of expression */</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%);">+     ++pos;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (pos[0] != '\0') {</span><br><span style="color: hsl(120, 100%, 40%);">+         ++pos; /* eat comma separator */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (pos[0] != '\0') {</span><br><span style="color: hsl(120, 100%, 40%);">+                 optargs = ast_strdupa(pos);</span><br><span style="color: hsl(120, 100%, 40%);">+                   AST_STANDARD_APP_ARGS(args, optargs);</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (!ast_strlen_zero(args.timeout)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         if (sscanf(args.timeout, "%30lg", &timeout) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                     ast_log(LOG_WARNING, "Invalid timeout provided: %s. No timeout set.\n", args.timeout);</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%);">+                             timeout_ms = timeout * 1000.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%);">+                   if (!ast_strlen_zero(args.interval)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (sscanf(args.interval, "%30lg", &poll) != 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                       ast_log(LOG_WARNING, "Invalid polling interval provided: %s. Default unchanged.\n", args.interval);</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%);">+                             if (poll < 0.001) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        ast_log(LOG_WARNING, "Polling interval cannot be less than 1ms. Default unchanged.\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%);">+                             poll_ms = poll * 1000.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%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (i = 0; expression[i] != '\0'; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (expression[i] == dollarsignrep) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 expression[i] = '$'; /* replace $s back into expression for variable parsing */</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%);">+   if (timeout_ms > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_debug(1, "Waiting for condition for %f seconds: %s (checking every %d ms)", timeout, expression, poll_ms);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_debug(1, "Waiting for condition, forever: %s (checking every %d ms)", expression, poll_ms);</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%);">+   while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Substitute variables now */</span><br><span style="color: hsl(120, 100%, 40%);">+                pbx_substitute_variables_helper(chan, expression, condition, sizeof(condition) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (pbx_checkcondition(condition)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "TRUE");</span><br><span style="color: hsl(120, 100%, 40%);">+                        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If a timeout was specified, check that it hasn't expired */</span><br><span style="color: hsl(120, 100%, 40%);">+            if ((timeout_ms > 0) && !(ms = ast_remaining_ms(start, timeout_ms))) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "TIMEOUT");</span><br><span style="color: hsl(120, 100%, 40%);">+                     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ast_safe_sleep(chan, poll_ms)) { /* don't waste CPU, we don't need a super tight loop */</span><br><span style="color: hsl(120, 100%, 40%);">+                  pbx_builtin_setvar_helper(chan, "WAITFORCONDITIONSTATUS", "HANGUP");</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -1; /* channel hung up */</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%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return ast_unregister_application(app);</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%);">+ return ast_register_application_xml(app, waitforcond_exec);</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, "Wait until condition is true");</span><br><span>diff --git a/doc/CHANGES-staging/app_waitforcond.txt b/doc/CHANGES-staging/app_waitforcond.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..a7ab600</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/app_waitforcond.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: WaitForCondition application</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+This application provides a way to halt</span><br><span style="color: hsl(120, 100%, 40%);">+dialplan execution until a provided</span><br><span style="color: hsl(120, 100%, 40%);">+condition evaluates to true.</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/15928">change 15928</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/+/15928"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: I08adf2824b8bc63405778cf355963b5005612f41 </div>
<div style="display:none"> Gerrit-Change-Number: 15928 </div>
<div style="display:none"> Gerrit-PatchSet: 9 </div>
<div style="display:none"> Gerrit-Owner: N A <mail@interlinked.x10host.com> </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-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Richard Mudgett <rmudgett@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>