mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-11-04 05:15:22 +00:00 
			
		
		
		
	app_read: Allow reading # as a digit
Allows for the digit # to be read as a digit, just like any other DTMF digit, as opposed to forcing it to be used as an end of input indicator. The default behavior remains unchanged. ASTERISK-18454 #close Change-Id: I3033432adb9d296ad227e76b540b8b4a2417665b
This commit is contained in:
		
				
					committed by
					
						
						George Joseph
					
				
			
			
				
	
			
			
			
						parent
						
							6fbf55ac11
						
					
				
				
					commit
					6cc004dc5a
				
			@@ -75,6 +75,16 @@
 | 
			
		||||
					<option name="n">
 | 
			
		||||
						<para>to read digits even if the line is not up.</para>
 | 
			
		||||
					</option>
 | 
			
		||||
					<option name="t">
 | 
			
		||||
						<para>Terminator digit(s) to use for ending input.
 | 
			
		||||
						Default is <literal>#</literal>. If you need to read
 | 
			
		||||
						the digit <literal>#</literal> literally, you should
 | 
			
		||||
						remove or change the terminator character. Multiple
 | 
			
		||||
						terminator characters may be specified. If no terminator
 | 
			
		||||
						digit is present, input cannot be ended using digits
 | 
			
		||||
						and you will need to rely on duration and max digits
 | 
			
		||||
						for ending input.</para>
 | 
			
		||||
					</option>
 | 
			
		||||
				</optionlist>
 | 
			
		||||
			</parameter>
 | 
			
		||||
			<parameter name="attempts">
 | 
			
		||||
@@ -114,12 +124,20 @@ enum read_option_flags {
 | 
			
		||||
	OPT_SKIP = (1 << 0),
 | 
			
		||||
	OPT_INDICATION = (1 << 1),
 | 
			
		||||
	OPT_NOANSWER = (1 << 2),
 | 
			
		||||
	OPT_TERMINATOR = (1 << 3),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	OPT_ARG_TERMINATOR,
 | 
			
		||||
	/* note: this entry _MUST_ be the last one in the enum */
 | 
			
		||||
	OPT_ARG_ARRAY_SIZE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
AST_APP_OPTIONS(read_app_options, {
 | 
			
		||||
	AST_APP_OPTION('s', OPT_SKIP),
 | 
			
		||||
	AST_APP_OPTION('i', OPT_INDICATION),
 | 
			
		||||
	AST_APP_OPTION('n', OPT_NOANSWER),
 | 
			
		||||
	AST_APP_OPTION_ARG('t', OPT_TERMINATOR, OPT_ARG_TERMINATOR),
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
static char *app = "Read";
 | 
			
		||||
@@ -132,9 +150,11 @@ static int read_exec(struct ast_channel *chan, const char *data)
 | 
			
		||||
	int tries = 1, to = 0, x = 0;
 | 
			
		||||
	double tosec;
 | 
			
		||||
	char *argcopy = NULL;
 | 
			
		||||
	char *opt_args[OPT_ARG_ARRAY_SIZE];
 | 
			
		||||
	struct ast_tone_zone_sound *ts = NULL;
 | 
			
		||||
	struct ast_flags flags = {0};
 | 
			
		||||
	const char *status = "ERROR";
 | 
			
		||||
	char *terminator = NULL; /* use default terminator # by default */
 | 
			
		||||
 | 
			
		||||
	AST_DECLARE_APP_ARGS(arglist,
 | 
			
		||||
		AST_APP_ARG(variable);
 | 
			
		||||
@@ -156,7 +176,7 @@ static int read_exec(struct ast_channel *chan, const char *data)
 | 
			
		||||
	AST_STANDARD_APP_ARGS(arglist, argcopy);
 | 
			
		||||
 | 
			
		||||
	if (!ast_strlen_zero(arglist.options)) {
 | 
			
		||||
		ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
 | 
			
		||||
		ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!ast_strlen_zero(arglist.attempts)) {
 | 
			
		||||
@@ -192,6 +212,13 @@ static int read_exec(struct ast_channel *chan, const char *data)
 | 
			
		||||
			ts = ast_get_indication_tone(ast_channel_zone(chan), arglist.filename);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (ast_test_flag(&flags, OPT_TERMINATOR)) {
 | 
			
		||||
		if (!ast_strlen_zero(arglist.filename)) {
 | 
			
		||||
			terminator = opt_args[OPT_ARG_TERMINATOR];
 | 
			
		||||
		} else {
 | 
			
		||||
			terminator = ""; /* no digit inherently will terminate input */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (ast_channel_state(chan) != AST_STATE_UP) {
 | 
			
		||||
		if (ast_test_flag(&flags, OPT_SKIP)) {
 | 
			
		||||
			/* At the user's option, skip if the line is not up */
 | 
			
		||||
@@ -223,7 +250,7 @@ static int read_exec(struct ast_channel *chan, const char *data)
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
					tmp[x++] = res;
 | 
			
		||||
					if (tmp[x-1] == '#') {
 | 
			
		||||
					if (strchr(terminator, tmp[x-1])) {
 | 
			
		||||
						tmp[x-1] = '\0';
 | 
			
		||||
						status = "OK";
 | 
			
		||||
						break;
 | 
			
		||||
@@ -233,7 +260,7 @@ static int read_exec(struct ast_channel *chan, const char *data)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				res = ast_app_getdata(chan, arglist.filename, tmp, maxdigits, to);
 | 
			
		||||
				res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);
 | 
			
		||||
				if (res == AST_GETDATA_COMPLETE || res == AST_GETDATA_EMPTY_END_TERMINATED)
 | 
			
		||||
					status = "OK";
 | 
			
		||||
				else if (res == AST_GETDATA_TIMEOUT)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								doc/CHANGES-staging/app_read.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								doc/CHANGES-staging/app_read.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
Subject: app_read
 | 
			
		||||
 | 
			
		||||
A new option allows the digit '#' to be read literally,
 | 
			
		||||
rather than used exclusively as the input terminator
 | 
			
		||||
character.
 | 
			
		||||
@@ -137,6 +137,23 @@ int ast_ivr_menu_run(struct ast_channel *c, struct ast_ivr_menu *menu, void *cbd
 | 
			
		||||
 */
 | 
			
		||||
int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout);
 | 
			
		||||
 | 
			
		||||
/*! \brief Plays a stream and gets DTMF data from a channel
 | 
			
		||||
 * \param c Which channel one is interacting with
 | 
			
		||||
 * \param prompt File to pass to ast_streamfile (the one that you wish to play).
 | 
			
		||||
 *        It is also valid for this to be multiple files concatenated by "&".
 | 
			
		||||
 *        For example, "file1&file2&file3".
 | 
			
		||||
 * \param s The location where the DTMF data will be stored
 | 
			
		||||
 * \param maxlen Max Length of the data
 | 
			
		||||
 * \param timeout Timeout length waiting for data(in milliseconds).  Set to 0 for standard timeout(six seconds), or -1 for no time out.
 | 
			
		||||
 * \param terminator A string of characters that may be used as terminators to end input. If NULL, "#" will be used.
 | 
			
		||||
 *
 | 
			
		||||
 *  This function was designed for application programmers for situations where they need
 | 
			
		||||
 *  to play a message and then get some DTMF data in response to the message.  If a digit
 | 
			
		||||
 *  is pressed during playback, it will immediately break out of the message and continue
 | 
			
		||||
 *  execution of your code.
 | 
			
		||||
 */
 | 
			
		||||
int ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, char *terminator);
 | 
			
		||||
 | 
			
		||||
/*! \brief Full version with audiofd and controlfd.  NOTE: returns '2' on ctrlfd available, not '1' like other full functions */
 | 
			
		||||
int ast_app_getdata_full(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								main/app.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								main/app.c
									
									
									
									
									
								
							@@ -193,8 +193,25 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
 | 
			
		||||
 * \param s The string to read in to.  Must be at least the size of your length
 | 
			
		||||
 * \param maxlen How many digits to read (maximum)
 | 
			
		||||
 * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
 | 
			
		||||
 *      "ludicrous time" (essentially never times out) */
 | 
			
		||||
 *      "ludicrous time" (essentially never times out)
 | 
			
		||||
 */
 | 
			
		||||
enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
 | 
			
		||||
{
 | 
			
		||||
	return ast_app_getdata_terminator(c, prompt, s, maxlen, timeout, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \brief ast_app_getdata
 | 
			
		||||
 * \param c The channel to read from
 | 
			
		||||
 * \param prompt The file to stream to the channel
 | 
			
		||||
 * \param s The string to read in to.  Must be at least the size of your length
 | 
			
		||||
 * \param maxlen How many digits to read (maximum)
 | 
			
		||||
 * \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
 | 
			
		||||
 *      "ludicrous time" (essentially never times out)
 | 
			
		||||
 * \param terminator A string of characters that may be used as terminators to end input. Default if NULL is "#"
 | 
			
		||||
 */
 | 
			
		||||
enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s,
 | 
			
		||||
	int maxlen, int timeout, char *terminator)
 | 
			
		||||
{
 | 
			
		||||
	int res = 0, to, fto;
 | 
			
		||||
	char *front, *filename;
 | 
			
		||||
@@ -232,7 +249,7 @@ enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *promp
 | 
			
		||||
			fto = 50;
 | 
			
		||||
			to = ast_channel_pbx(c) ? ast_channel_pbx(c)->dtimeoutms : 2000;
 | 
			
		||||
		}
 | 
			
		||||
		res = ast_readstring(c, s, maxlen, to, fto, "#");
 | 
			
		||||
		res = ast_readstring(c, s, maxlen, to, fto, S_OR(terminator, "#"));
 | 
			
		||||
		if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
 | 
			
		||||
			return res;
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user