diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 55126b472f..f0fe5b212f 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -2239,11 +2239,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 diff --git a/main/channel.c b/main/channel.c index 23bb74f082..66825559c2 100644 --- a/main/channel.c +++ b/main/channel.c @@ -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: @@ -6356,11 +6359,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); diff --git a/main/pbx_builtins.c b/main/pbx_builtins.c index bc27b0d58a..9d43c10ffc 100644 --- a/main/pbx_builtins.c +++ b/main/pbx_builtins.c @@ -580,6 +580,42 @@ This application waits for a specified number of seconds. + + + Waits for a digit to be entered. + + + + Can be passed with fractions of a second. For example, 1.5 will ask the + application to wait for 1.5 seconds. + + + Digits to accept, all others are ignored. + + + + This application waits for the user to press one of the accepted + digits for a specified number of + seconds. + + + This is the final status of the command + Parameters are invalid. + An accepted digit was received. + The timeout passed before any acceptable digits were received. + The channel has hungup or was redirected. + + + The digit that was received, only set if + WAITDIGITSTATUS is DTMF. + + + + + Wait + WaitExten + + Waits for an extension to be entered. @@ -954,6 +990,47 @@ static int pbx_builtin_wait(struct ast_channel *chan, const char *data) return 0; } +/*! + * \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 */ @@ -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 } }; diff --git a/res/res_agi.c b/res/res_agi.c index e8497f7cae..466063557b 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -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;