Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
app_read.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Trivial application to read a variable
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * \ingroup applications
26 */
27
28/*** MODULEINFO
29 <support_level>core</support_level>
30 ***/
31
32#include "asterisk.h"
33
34#include "asterisk/file.h"
35#include "asterisk/pbx.h"
36#include "asterisk/channel.h"
37#include "asterisk/app.h"
38#include "asterisk/module.h"
40
41/*** DOCUMENTATION
42 <application name="Read" language="en_US">
43 <since>
44 <version>1.6.1.0</version>
45 </since>
46 <synopsis>
47 Read a variable.
48 </synopsis>
49 <syntax>
50 <parameter name="variable" required="true">
51 <para>The input digits will be stored in the given <replaceable>variable</replaceable>
52 name.</para>
53 </parameter>
54 <parameter name="filenames" argsep="&amp;">
55 <para>Ampersand separated list of filenames to play before
56 reading digits or tone with option <literal>i</literal>. If
57 the filename is a relative filename (it does not begin with a
58 slash), it will be searched for in the Asterisk sounds
59 directory. If the filename is able to be parsed as a URL,
60 Asterisk will download the file and then begin playback on
61 it. To include a literal <literal>&amp;</literal> in the URL
62 you can enclose the URL in single quotes.</para>
63 <argument name="filename" required="true" />
64 <argument name="filename2" multiple="true" />
65 </parameter>
66 <parameter name="maxdigits">
67 <para>Maximum acceptable number of digits. Stops reading after
68 <replaceable>maxdigits</replaceable> have been entered (without
69 requiring the user to press the <literal>#</literal> key).</para>
70 <para>Defaults to <literal>0</literal> - no limit - wait for the
71 user press the <literal>#</literal> key. Any value below
72 <literal>0</literal> means the same. Max accepted value is
73 <literal>255</literal>.</para>
74 </parameter>
75 <parameter name="options">
76 <optionlist>
77 <option name="s">
78 <para>to return immediately if the line is not up.</para>
79 </option>
80 <option name="i">
81 <para>to play filename as an indication tone from your
82 <filename>indications.conf</filename>.</para>
83 </option>
84 <option name="n">
85 <para>to read digits even if the line is not up.</para>
86 </option>
87 <option name="t">
88 <para>Terminator digit(s) to use for ending input.
89 Default is <literal>#</literal>. If you need to read
90 the digit <literal>#</literal> literally, you should
91 remove or change the terminator character. Multiple
92 terminator characters may be specified. If no terminator
93 digit is present, input cannot be ended using digits
94 and you will need to rely on duration and max digits
95 for ending input.</para>
96 </option>
97 <option name="e">
98 <para>to read the terminator as the digit string if the
99 only digit read is the terminator. This is for cases
100 where the terminator is a valid digit, but only by itself.
101 ie; <literal>1234</literal> and <literal>#</literal> are
102 valid, but <literal>1234#</literal> is not.</para>
103 </option>
104 </optionlist>
105 </parameter>
106 <parameter name="attempts">
107 <para>If greater than <literal>1</literal>, that many
108 <replaceable>attempts</replaceable> will be made in the
109 event no data is entered.</para>
110 </parameter>
111 <parameter name="timeout">
112 <para>The number of seconds to wait for a digit response. If greater
113 than <literal>0</literal>, that value will override the default timeout.
114 Can be floating point.</para>
115 </parameter>
116 </syntax>
117 <description>
118 <para>Reads a #-terminated string of digits a certain number of times from the
119 user in to the given <replaceable>variable</replaceable>.</para>
120 <para>This application sets the following channel variable upon completion:</para>
121 <variablelist>
122 <variable name="READSTATUS">
123 <para>This is the status of the read operation.</para>
124 <value name="OK" />
125 <value name="ERROR" />
126 <value name="HANGUP" />
127 <value name="INTERRUPTED" />
128 <value name="SKIPPED" />
129 <value name="TIMEOUT" />
130 </variable>
131 </variablelist>
132 </description>
133 <see-also>
134 <ref type="application">SendDTMF</ref>
135 </see-also>
136 </application>
137 ***/
138
140 OPT_SKIP = (1 << 0),
141 OPT_INDICATION = (1 << 1),
142 OPT_NOANSWER = (1 << 2),
143 OPT_TERMINATOR = (1 << 3),
145};
146
147enum {
149 /* note: this entry _MUST_ be the last one in the enum */
151};
152
159});
160
161static char *app = "Read";
162
163static int read_exec(struct ast_channel *chan, const char *data)
164{
165 int res = 0;
166 char tmp[256] = "";
167 int maxdigits = 255;
168 int tries = 1, to = 0, x = 0;
169 double tosec;
170 char *argcopy = NULL;
171 char *opt_args[OPT_ARG_ARRAY_SIZE];
172 struct ast_tone_zone_sound *ts = NULL;
173 struct ast_flags flags = {0};
174 const char *status = "ERROR";
175 char *terminator = "#"; /* use default terminator # by default */
176
177 AST_DECLARE_APP_ARGS(arglist,
178 AST_APP_ARG(variable);
179 AST_APP_ARG(filename);
180 AST_APP_ARG(maxdigits);
182 AST_APP_ARG(attempts);
183 AST_APP_ARG(timeout);
184 );
185
186 pbx_builtin_setvar_helper(chan, "READSTATUS", status);
187 if (ast_strlen_zero(data)) {
188 ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
189 return 0;
190 }
191
192 argcopy = ast_strdupa(data);
193
194 AST_STANDARD_APP_ARGS(arglist, argcopy);
195
196 if (!ast_strlen_zero(arglist.options)) {
197 ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);
198 }
199
200 if (!ast_strlen_zero(arglist.attempts)) {
201 tries = atoi(arglist.attempts);
202 if (tries <= 0)
203 tries = 1;
204 }
205
206 if (!ast_strlen_zero(arglist.timeout)) {
207 tosec = atof(arglist.timeout);
208 if (tosec <= 0)
209 to = 0;
210 else
211 to = tosec * 1000.0;
212 }
213
214 if (ast_strlen_zero(arglist.filename)) {
215 arglist.filename = NULL;
216 }
217 if (!ast_strlen_zero(arglist.maxdigits)) {
218 maxdigits = atoi(arglist.maxdigits);
219 if ((maxdigits < 1) || (maxdigits > 255)) {
220 maxdigits = 255;
221 } else
222 ast_verb(3, "Accepting a maximum of %d digits.\n", maxdigits);
223 }
224 if (ast_strlen_zero(arglist.variable)) {
225 ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[,filename][,maxdigits][,option][,attempts][,timeout])\n\n");
226 return 0;
227 }
229 if (!ast_strlen_zero(arglist.filename)) {
230 ts = ast_get_indication_tone(ast_channel_zone(chan), arglist.filename);
231 }
232 }
234 if (!ast_strlen_zero(opt_args[OPT_ARG_TERMINATOR])) {
235 terminator = opt_args[OPT_ARG_TERMINATOR];
236 } else {
237 terminator = ""; /* no digit inherently will terminate input */
238 }
239 }
240 if (ast_channel_state(chan) != AST_STATE_UP) {
242 /* At the user's option, skip if the line is not up */
243 if (ts) {
245 }
246 pbx_builtin_setvar_helper(chan, arglist.variable, "");
247 pbx_builtin_setvar_helper(chan, "READSTATUS", "SKIPPED");
248 return 0;
249 } else if (!ast_test_flag(&flags, OPT_NOANSWER)) {
250 /* Otherwise answer unless we're supposed to read while on-hook */
251 res = ast_answer(chan);
252 }
253 }
254 if (!res) {
255 while (tries && !res) {
256 ast_stopstream(chan);
257 if (ts && ts->data[0]) {
258 if (!to)
259 to = ast_channel_pbx(chan) ? ast_channel_pbx(chan)->rtimeoutms : 6000;
260 res = ast_playtones_start(chan, 0, ts->data, 0);
261 for (x = 0; x < maxdigits; ) {
262 res = ast_waitfordigit(chan, to);
263 ast_playtones_stop(chan);
264 if (res < 1) {
265 if (res == 0)
266 status = "TIMEOUT";
267 tmp[x]='\0';
268 break;
269 }
270 tmp[x++] = res;
271 if (terminator && strchr(terminator, tmp[x-1])) {
272 tmp[x-1] = '\0';
273 status = "OK";
274 break;
275 }
276 if (x >= maxdigits) {
277 status = "OK";
278 }
279 }
280 } else {
281 res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);
282 if (res == AST_GETDATA_COMPLETE) {
283 status = "OK";
284 } else if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
286 /* if the option is set to do so, read the
287 returned string as the terminator string */
288 ast_copy_string(tmp, terminator, sizeof(tmp));
289 }
290 status = "OK";
291 } else if (res == AST_GETDATA_TIMEOUT) {
292 status = "TIMEOUT";
293 } else if (res == AST_GETDATA_INTERRUPTED) {
294 status = "INTERRUPTED";
295 }
296 }
297 if (res > -1) {
298 pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
299 if (!ast_strlen_zero(tmp)) {
300 ast_verb(3, "User entered '%s'\n", tmp);
301 tries = 0;
302 } else {
303 tries--;
304 if (tries)
305 ast_verb(3, "User entered nothing, %d chance%s left\n", tries, (tries != 1) ? "s" : "");
306 else
307 ast_verb(3, "User entered nothing.\n");
308 }
309 res = 0;
310 } else {
311 pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
312 ast_verb(3, "User disconnected\n");
313 }
314 }
315 }
316
317 if (ts) {
319 }
320
321 if (ast_check_hangup(chan))
322 status = "HANGUP";
323 pbx_builtin_setvar_helper(chan, "READSTATUS", status);
324 return 0;
325}
326
327static int unload_module(void)
328{
330}
331
332static int load_module(void)
333{
335}
336
337AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application");
jack_status_t status
Definition: app_jack.c:149
read_option_flags
Definition: app_mf.c:188
static int read_exec(struct ast_channel *chan, const char *data)
Definition: app_read.c:163
static char * app
Definition: app_read.c:161
static int load_module(void)
Definition: app_read.c:332
static int unload_module(void)
Definition: app_read.c:327
@ OPT_TERMINATOR
Definition: app_read.c:143
@ OPT_NOANSWER
Definition: app_read.c:142
@ OPT_INDICATION
Definition: app_read.c:141
@ OPT_SKIP
Definition: app_read.c:140
@ OPT_KEEP_TERMINATOR
Definition: app_read.c:144
static const struct ast_app_option read_app_options[128]
Definition: app_read.c:159
@ OPT_ARG_TERMINATOR
Definition: app_read.c:148
@ OPT_ARG_ARRAY_SIZE
Definition: app_read.c:150
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
General Asterisk PBX channel definitions.
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3203
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
struct ast_tone_zone * ast_channel_zone(const struct ast_channel *chan)
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2834
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
@ AST_GETDATA_INTERRUPTED
@ AST_GETDATA_COMPLETE
@ AST_GETDATA_TIMEOUT
@ AST_GETDATA_EMPTY_END_TERMINATED
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
enum ast_getdata_result ast_app_getdata_terminator(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout, char *terminator)
Plays a stream and gets DTMF data from a channel.
Definition: main/app.c:193
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
#define ast_verb(level,...)
#define LOG_WARNING
Tone Indication Support.
static struct ast_tone_zone_sound * ast_tone_zone_sound_unref(struct ast_tone_zone_sound *ts)
Release a reference to an ast_tone_zone_sound.
Definition: indications.h:227
int ast_playtones_start(struct ast_channel *chan, int vol, const char *tonelist, int interruptible)
Start playing a list of tones on a channel.
Definition: indications.c:302
void ast_playtones_stop(struct ast_channel *chan)
Stop playing tones on a channel.
Definition: indications.c:393
struct ast_tone_zone_sound * ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication)
Locate a tone zone sound.
Definition: indications.c:461
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:581
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Core PBX routines and definitions.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
#define NULL
Definition: resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
int rtimeoutms
Definition: pbx.h:217
Description of a tone.
Definition: indications.h:35
const char * data
Description of a tone.
Definition: indications.h:52
static struct test_options options
#define ast_test_flag(p, flag)
Definition: utils.h:63