<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/16426">View Change</a></p><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_read: Allow reading # as a digit<br><br>Allows for the digit # to be read as a digit,<br>just like any other DTMF digit, as opposed to<br>forcing it to be used as an end of input<br>indicator. The default behavior remains<br>unchanged.<br><br>ASTERISK-18454 #close<br><br>Change-Id: I3033432adb9d296ad227e76b540b8b4a2417665b<br>---<br>M apps/app_read.c<br>A doc/CHANGES-staging/app_read.txt<br>M include/asterisk/app.h<br>M main/app.c<br>4 files changed, 71 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/apps/app_read.c b/apps/app_read.c</span><br><span>index 6398281..dd48f05 100644</span><br><span>--- a/apps/app_read.c</span><br><span>+++ b/apps/app_read.c</span><br><span>@@ -75,6 +75,16 @@</span><br><span>                                   <option name="n"></span><br><span>                                            <para>to read digits even if the line is not up.</para></span><br><span>                                  </option></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <option name="t"></span><br><span style="color: hsl(120, 100%, 40%);">+                                             <para>Terminator digit(s) to use for ending input.</span><br><span style="color: hsl(120, 100%, 40%);">+                                              Default is <literal>#</literal>. If you need to read</span><br><span style="color: hsl(120, 100%, 40%);">+                                              the digit <literal>#</literal> literally, you should</span><br><span style="color: hsl(120, 100%, 40%);">+                                              remove or change the terminator character. Multiple</span><br><span style="color: hsl(120, 100%, 40%);">+                                           terminator characters may be specified. If no terminator</span><br><span style="color: hsl(120, 100%, 40%);">+                                              digit is present, input cannot be ended using digits</span><br><span style="color: hsl(120, 100%, 40%);">+                                          and you will need to rely on duration and max digits</span><br><span style="color: hsl(120, 100%, 40%);">+                                          for ending input.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                        </option></span><br><span>                              </optionlist></span><br><span>                  </parameter></span><br><span>                   <parameter name="attempts"></span><br><span>@@ -114,12 +124,20 @@</span><br><span>  OPT_SKIP = (1 << 0),</span><br><span>   OPT_INDICATION = (1 << 1),</span><br><span>     OPT_NOANSWER = (1 << 2),</span><br><span style="color: hsl(120, 100%, 40%);">+        OPT_TERMINATOR = (1 << 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%);">+enum {</span><br><span style="color: hsl(120, 100%, 40%);">+        OPT_ARG_TERMINATOR,</span><br><span style="color: hsl(120, 100%, 40%);">+   /* note: this entry _MUST_ be the last one in the enum */</span><br><span style="color: hsl(120, 100%, 40%);">+     OPT_ARG_ARRAY_SIZE,</span><br><span> };</span><br><span> </span><br><span> AST_APP_OPTIONS(read_app_options, {</span><br><span>         AST_APP_OPTION('s', OPT_SKIP),</span><br><span>       AST_APP_OPTION('i', OPT_INDICATION),</span><br><span>         AST_APP_OPTION('n', OPT_NOANSWER),</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_APP_OPTION_ARG('t', OPT_TERMINATOR, OPT_ARG_TERMINATOR),</span><br><span> });</span><br><span> </span><br><span> static char *app = "Read";</span><br><span>@@ -132,9 +150,11 @@</span><br><span>       int tries = 1, to = 0, x = 0;</span><br><span>        double tosec;</span><br><span>        char *argcopy = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *opt_args[OPT_ARG_ARRAY_SIZE];</span><br><span>  struct ast_tone_zone_sound *ts = NULL;</span><br><span>       struct ast_flags flags = {0};</span><br><span>        const char *status = "ERROR";</span><br><span style="color: hsl(120, 100%, 40%);">+       char *terminator = NULL; /* use default terminator # by default */</span><br><span> </span><br><span>       AST_DECLARE_APP_ARGS(arglist,</span><br><span>                AST_APP_ARG(variable);</span><br><span>@@ -156,7 +176,7 @@</span><br><span>         AST_STANDARD_APP_ARGS(arglist, argcopy);</span><br><span> </span><br><span>         if (!ast_strlen_zero(arglist.options)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);</span><br><span>      }</span><br><span> </span><br><span>        if (!ast_strlen_zero(arglist.attempts)) {</span><br><span>@@ -192,6 +212,13 @@</span><br><span>                     ts = ast_get_indication_tone(ast_channel_zone(chan), arglist.filename);</span><br><span>              }</span><br><span>    }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_test_flag(&flags, OPT_TERMINATOR)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!ast_strlen_zero(arglist.filename)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     terminator = opt_args[OPT_ARG_TERMINATOR];</span><br><span style="color: hsl(120, 100%, 40%);">+            } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      terminator = ""; /* no digit inherently will terminate input */</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span>    if (ast_channel_state(chan) != AST_STATE_UP) {</span><br><span>               if (ast_test_flag(&flags, OPT_SKIP)) {</span><br><span>                   /* At the user's option, skip if the line is not up */</span><br><span>@@ -223,7 +250,7 @@</span><br><span>                                             break;</span><br><span>                                       }</span><br><span>                                    tmp[x++] = res;</span><br><span style="color: hsl(0, 100%, 40%);">-                                 if (tmp[x-1] == '#') {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        if (strchr(terminator, tmp[x-1])) {</span><br><span>                                          tmp[x-1] = '\0';</span><br><span>                                             status = "OK";</span><br><span>                                             break;</span><br><span>@@ -233,7 +260,7 @@</span><br><span>                                         }</span><br><span>                            }</span><br><span>                    } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                res = ast_app_getdata(chan, arglist.filename, tmp, maxdigits, to);</span><br><span style="color: hsl(120, 100%, 40%);">+                            res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);</span><br><span>                            if (res == AST_GETDATA_COMPLETE || res == AST_GETDATA_EMPTY_END_TERMINATED)</span><br><span>                                  status = "OK";</span><br><span>                             else if (res == AST_GETDATA_TIMEOUT)</span><br><span>diff --git a/doc/CHANGES-staging/app_read.txt b/doc/CHANGES-staging/app_read.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..df3247c</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/app_read.txt</span><br><span>@@ -0,0 +1,5 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: app_read</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+A new option allows the digit '#' to be read literally,</span><br><span style="color: hsl(120, 100%, 40%);">+rather than used exclusively as the input terminator</span><br><span style="color: hsl(120, 100%, 40%);">+character.</span><br><span>diff --git a/include/asterisk/app.h b/include/asterisk/app.h</span><br><span>index 7690364..ab246c8 100644</span><br><span>--- a/include/asterisk/app.h</span><br><span>+++ b/include/asterisk/app.h</span><br><span>@@ -137,6 +137,23 @@</span><br><span>  */</span><br><span> int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Plays a stream and gets DTMF data from a channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param c Which channel one is interacting with</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prompt File to pass to ast_streamfile (the one that you wish to play).</span><br><span style="color: hsl(120, 100%, 40%);">+ *        It is also valid for this to be multiple files concatenated by "&".</span><br><span style="color: hsl(120, 100%, 40%);">+ *        For example, "file1&file2&file3".</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param s The location where the DTMF data will be stored</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param maxlen Max Length of the data</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param timeout Timeout length waiting for data(in milliseconds).  Set to 0 for standard timeout(six seconds), or -1 for no time out.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param terminator A string of characters that may be used as terminators to end input. If NULL, "#" will be used.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This function was designed for application programmers for situations where they need</span><br><span style="color: hsl(120, 100%, 40%);">+ *  to play a message and then get some DTMF data in response to the message.  If a digit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  is pressed during playback, it will immediately break out of the message and continue</span><br><span style="color: hsl(120, 100%, 40%);">+ *  execution of your code.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, char *terminator);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Full version with audiofd and controlfd.  NOTE: returns '2' on ctrlfd available, not '1' like other full functions */</span><br><span> int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);</span><br><span> </span><br><span>diff --git a/main/app.c b/main/app.c</span><br><span>index 09c0123..f5fbffd 100644</span><br><span>--- a/main/app.c</span><br><span>+++ b/main/app.c</span><br><span>@@ -193,9 +193,26 @@</span><br><span>  * \param s The string to read in to.  Must be at least the size of your length</span><br><span>  * \param maxlen How many digits to read (maximum)</span><br><span>  * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for</span><br><span style="color: hsl(0, 100%, 40%);">- *      "ludicrous time" (essentially never times out) */</span><br><span style="color: hsl(120, 100%, 40%);">+ *      "ludicrous time" (essentially never times out)</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span> enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+    return ast_app_getdata_terminator(c, prompt, s, maxlen, timeout, 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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief ast_app_getdata</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param c The channel to read from</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param prompt The file to stream to the channel</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param s The string to read in to.  Must be at least the size of your length</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param maxlen How many digits to read (maximum)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for</span><br><span style="color: hsl(120, 100%, 40%);">+ *      "ludicrous time" (essentially never times out)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param terminator A string of characters that may be used as terminators to end input. Default if NULL is "#"</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s,</span><br><span style="color: hsl(120, 100%, 40%);">+   int maxlen, int timeout, char *terminator)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>        int res = 0, to, fto;</span><br><span>        char *front, *filename;</span><br><span> </span><br><span>@@ -232,7 +249,7 @@</span><br><span>                    fto = 50;</span><br><span>                    to = ast_channel_pbx(c) ? ast_channel_pbx(c)->dtimeoutms : 2000;</span><br><span>          }</span><br><span style="color: hsl(0, 100%, 40%);">-               res = ast_readstring(c, s, maxlen, to, fto, "#");</span><br><span style="color: hsl(120, 100%, 40%);">+           res = ast_readstring(c, s, maxlen, to, fto, S_OR(terminator, "#"));</span><br><span>                if (res == AST_GETDATA_EMPTY_END_TERMINATED) {</span><br><span>                       return res;</span><br><span>          }</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/+/16426">change 16426</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/+/16426"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 19 </div>
<div style="display:none"> Gerrit-Change-Id: I3033432adb9d296ad227e76b540b8b4a2417665b </div>
<div style="display:none"> Gerrit-Change-Number: 16426 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </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-MessageType: merged </div>