core: Add digit filtering to ast_waitfordigit_full
authorCorey Farrell <git@cfware.com>
Wed, 12 Jul 2017 18:24:36 +0000 (14:24 -0400)
committerCorey Farrell <git@cfware.com>
Wed, 12 Jul 2017 23:08:23 +0000 (19:08 -0400)
This adds a parameter to ast_waitfordigit_full which can be used to only
stop waiting when certain expected digits are received.  Any unexpected
DTMF digits are simply ignored.

This also creates a new dialplan application WaitDigit.

ASTERISK-27129 #close

Change-Id: Id233935ea3d13e71c75a0861834c5936c3700ef9

include/asterisk/channel.h
main/channel.c
main/pbx_builtins.c
res/res_agi.c

index 197cc99..cb2e0e6 100644 (file)
@@ -2219,11 +2219,12 @@ int ast_waitfordigit(struct ast_channel *c, int ms);
  * Same as ast_waitfordigit() with audio fd for outputting read audio and ctrlfd to monitor for reading.
  * \param c channel to wait for a digit on
  * \param ms how many milliseconds to wait (<0 for indefinite).
+ * \param breakon string of DTMF digits to break upon or NULL for any.
  * \param audiofd audio file descriptor to write to if audio frames are received
  * \param ctrlfd control file descriptor to monitor for reading
  * \return Returns 1 if ctrlfd becomes available
  */
-int ast_waitfordigit_full(struct ast_channel *c, int ms, int audiofd, int ctrlfd);
+int ast_waitfordigit_full(struct ast_channel *c, int ms, const char *breakon, int audiofd, int ctrlfd);
 
 /*!
  * \brief Reads multiple digits
index 811826f..27efb2e 100644 (file)
@@ -3160,7 +3160,7 @@ int ast_waitfor(struct ast_channel *c, int ms)
 
 int ast_waitfordigit(struct ast_channel *c, int ms)
 {
-       return ast_waitfordigit_full(c, ms, -1, -1);
+       return ast_waitfordigit_full(c, ms, NULL, -1, -1);
 }
 
 int ast_settimeout(struct ast_channel *c, unsigned int rate, int (*func)(const void *data), void *data)
@@ -3222,7 +3222,7 @@ int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int (*func)(co
        return res;
 }
 
-int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, int cmdfd)
+int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, const char *breakon, int audiofd, int cmdfd)
 {
        struct timeval start = ast_tvnow();
        int ms;
@@ -3273,9 +3273,12 @@ int ast_waitfordigit_full(struct ast_channel *c, int timeout_ms, int audiofd, in
                                break;
                        case AST_FRAME_DTMF_END:
                                res = f->subclass.integer;
-                               ast_frfree(f);
-                               ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
-                               return res;
+                               if (!breakon || strchr(breakon, res)) {
+                                       ast_frfree(f);
+                                       ast_channel_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
+                                       return res;
+                               }
+                               break;
                        case AST_FRAME_CONTROL:
                                switch (f->subclass.integer) {
                                case AST_CONTROL_HANGUP:
@@ -6351,11 +6354,11 @@ int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, in
                                silgen = ast_channel_start_silence_generator(c);
                        usleep(1000);
                        if (!d)
-                               d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+                               d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd);
                } else {
                        if (!silgen && ast_opt_transmit_silence)
                                silgen = ast_channel_start_silence_generator(c);
-                       d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+                       d = ast_waitfordigit_full(c, to, NULL, audiofd, ctrlfd);
                }
                if (d < 0) {
                        ast_channel_stop_silence_generator(c, silgen);
index bc27b0d..9d43c10 100644 (file)
                        <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
                </description>
        </application>
+       <application name="WaitDigit" language="en_US">
+               <synopsis>
+                       Waits for a digit to be entered.
+               </synopsis>
+               <syntax>
+                       <parameter name="seconds">
+                               <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
+                               application to wait for 1.5 seconds.</para>
+                       </parameter>
+                       <parameter name="digits">
+                               <para>Digits to accept, all others are ignored.</para>
+                       </parameter>
+               </syntax>
+               <description>
+                       <para>This application waits for the user to press one of the accepted
+                       <replaceable>digits</replaceable> for a specified number of
+                       <replaceable>seconds</replaceable>.</para>
+                       <variablelist>
+                               <variable name="WAITDIGITSTATUS">
+                                       <para>This is the final status of the command</para>
+                                       <value name="ERROR">Parameters are invalid.</value>
+                                       <value name="DTMF">An accepted digit was received.</value>
+                                       <value name="TIMEOUT">The timeout passed before any acceptable digits were received.</value>
+                                       <value name="CANCEL">The channel has hungup or was redirected.</value>
+                               </variable>
+                               <variable name="WAITDIGITRESULT">
+                                       <para>The digit that was received, only set if
+                                       <variable>WAITDIGITSTATUS</variable> is <literal>DTMF</literal>.</para>
+                               </variable>
+                       </variablelist>
+               </description>
+               <see-also>
+                       <ref type="application">Wait</ref>
+                       <ref type="application">WaitExten</ref>
+               </see-also>
+       </application>
        <application name="WaitExten" language="en_US">
                <synopsis>
                        Waits for an extension to be entered.
@@ -957,6 +993,47 @@ static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
 /*!
  * \ingroup applications
  */
+static int pbx_builtin_waitdigit(struct ast_channel *chan, const char *data)
+{
+       int res;
+       int ms;
+       char *parse;
+       AST_DECLARE_APP_ARGS(args,
+               AST_APP_ARG(timeout);
+               AST_APP_ARG(digits);
+       );
+
+       parse = ast_strdupa(data);
+       AST_STANDARD_APP_ARGS(args, parse);
+
+       if (ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) || ms < 0) {
+               pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "ERROR");
+               return 0;
+       }
+
+       /* Wait for "n" seconds */
+       res = ast_waitfordigit_full(chan, ms, S_OR(args.digits, AST_DIGIT_ANY), -1, -1);
+       if (res < 0) {
+               pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "CANCEL");
+               return -1;
+       }
+
+       if (res == 0) {
+               pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "TIMEOUT");
+       } else {
+               char key[2];
+
+               snprintf(key, sizeof(key), "%c", res);
+               pbx_builtin_setvar_helper(chan, "WAITDIGITRESULT", key);
+               pbx_builtin_setvar_helper(chan, "WAITDIGITSTATUS", "DTMF");
+       }
+
+       return 0;
+}
+
+/*!
+ * \ingroup applications
+ */
 static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
 {
        int ms, res;
@@ -1410,6 +1487,7 @@ struct pbx_builtin {
        { "SayPhonetic",    pbx_builtin_sayphonetic },
        { "SetAMAFlags",    pbx_builtin_setamaflags },
        { "Wait",           pbx_builtin_wait },
+       { "WaitDigit",      pbx_builtin_waitdigit },
        { "WaitExten",      pbx_builtin_waitexten }
 };
 
index e8497f7..4660635 100644 (file)
@@ -2393,7 +2393,7 @@ static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, con
                return RESULT_SHOWUSAGE;
        if (sscanf(argv[3], "%30d", &to) != 1)
                return RESULT_SHOWUSAGE;
-       res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
+       res = ast_waitfordigit_full(chan, to, NULL, agi->audio, agi->ctrl);
        ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
        return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
 }
@@ -2673,7 +2673,7 @@ static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const
 
        /* If the user didnt press a key, wait for digitTimeout*/
        if (res == 0 ) {
-               res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
+               res = ast_waitfordigit_full(chan, timeout, NULL, agi->audio, agi->ctrl);
                /* Make sure the new result is in the escape digits of the GET OPTION */
                if ( !strchr(edigits,res) )
                        res=0;