Asterisk - The Open Source Telephony Project GIT-master-a358458
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 <synopsis>
44 Read a variable.
45 </synopsis>
46 <syntax>
47 <parameter name="variable" required="true">
48 <para>The input digits will be stored in the given <replaceable>variable</replaceable>
49 name.</para>
50 </parameter>
51 <parameter name="filenames" argsep="&amp;">
52 <para>Ampersand separated list of filenames to play before
53 reading digits or tone with option <literal>i</literal>. If
54 the filename is a relative filename (it does not begin with a
55 slash), it will be searched for in the Asterisk sounds
56 directory. If the filename is able to be parsed as a URL,
57 Asterisk will download the file and then begin playback on
58 it. To include a literal <literal>&amp;</literal> in the URL
59 you can enclose the URL in single quotes.</para>
60 <argument name="filename" required="true" />
61 <argument name="filename2" multiple="true" />
62 </parameter>
63 <parameter name="maxdigits">
64 <para>Maximum acceptable number of digits. Stops reading after
65 <replaceable>maxdigits</replaceable> have been entered (without
66 requiring the user to press the <literal>#</literal> key).</para>
67 <para>Defaults to <literal>0</literal> - no limit - wait for the
68 user press the <literal>#</literal> key. Any value below
69 <literal>0</literal> means the same. Max accepted value is
70 <literal>255</literal>.</para>
71 </parameter>
72 <parameter name="options">
73 <optionlist>
74 <option name="s">
75 <para>to return immediately if the line is not up.</para>
76 </option>
77 <option name="i">
78 <para>to play filename as an indication tone from your
79 <filename>indications.conf</filename>.</para>
80 </option>
81 <option name="n">
82 <para>to read digits even if the line is not up.</para>
83 </option>
84 <option name="t">
85 <para>Terminator digit(s) to use for ending input.
86 Default is <literal>#</literal>. If you need to read
87 the digit <literal>#</literal> literally, you should
88 remove or change the terminator character. Multiple
89 terminator characters may be specified. If no terminator
90 digit is present, input cannot be ended using digits
91 and you will need to rely on duration and max digits
92 for ending input.</para>
93 </option>
94 <option name="e">
95 <para>to read the terminator as the digit string if the
96 only digit read is the terminator. This is for cases
97 where the terminator is a valid digit, but only by itself.
98 ie; <literal>1234</literal> and <literal>#</literal> are
99 valid, but <literal>1234#</literal> is not.</para>
100 </option>
101 </optionlist>
102 </parameter>
103 <parameter name="attempts">
104 <para>If greater than <literal>1</literal>, that many
105 <replaceable>attempts</replaceable> will be made in the
106 event no data is entered.</para>
107 </parameter>
108 <parameter name="timeout">
109 <para>The number of seconds to wait for a digit response. If greater
110 than <literal>0</literal>, that value will override the default timeout.
111 Can be floating point.</para>
112 </parameter>
113 </syntax>
114 <description>
115 <para>Reads a #-terminated string of digits a certain number of times from the
116 user in to the given <replaceable>variable</replaceable>.</para>
117 <para>This application sets the following channel variable upon completion:</para>
118 <variablelist>
119 <variable name="READSTATUS">
120 <para>This is the status of the read operation.</para>
121 <value name="OK" />
122 <value name="ERROR" />
123 <value name="HANGUP" />
124 <value name="INTERRUPTED" />
125 <value name="SKIPPED" />
126 <value name="TIMEOUT" />
127 </variable>
128 </variablelist>
129 </description>
130 <see-also>
131 <ref type="application">SendDTMF</ref>
132 </see-also>
133 </application>
134 ***/
135
137 OPT_SKIP = (1 << 0),
138 OPT_INDICATION = (1 << 1),
139 OPT_NOANSWER = (1 << 2),
140 OPT_TERMINATOR = (1 << 3),
142};
143
144enum {
146 /* note: this entry _MUST_ be the last one in the enum */
148};
149
156});
157
158static char *app = "Read";
159
160static int read_exec(struct ast_channel *chan, const char *data)
161{
162 int res = 0;
163 char tmp[256] = "";
164 int maxdigits = 255;
165 int tries = 1, to = 0, x = 0;
166 double tosec;
167 char *argcopy = NULL;
168 char *opt_args[OPT_ARG_ARRAY_SIZE];
169 struct ast_tone_zone_sound *ts = NULL;
170 struct ast_flags flags = {0};
171 const char *status = "ERROR";
172 char *terminator = "#"; /* use default terminator # by default */
173
174 AST_DECLARE_APP_ARGS(arglist,
175 AST_APP_ARG(variable);
176 AST_APP_ARG(filename);
177 AST_APP_ARG(maxdigits);
179 AST_APP_ARG(attempts);
180 AST_APP_ARG(timeout);
181 );
182
183 pbx_builtin_setvar_helper(chan, "READSTATUS", status);
184 if (ast_strlen_zero(data)) {
185 ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
186 return 0;
187 }
188
189 argcopy = ast_strdupa(data);
190
191 AST_STANDARD_APP_ARGS(arglist, argcopy);
192
193 if (!ast_strlen_zero(arglist.options)) {
194 ast_app_parse_options(read_app_options, &flags, opt_args, arglist.options);
195 }
196
197 if (!ast_strlen_zero(arglist.attempts)) {
198 tries = atoi(arglist.attempts);
199 if (tries <= 0)
200 tries = 1;
201 }
202
203 if (!ast_strlen_zero(arglist.timeout)) {
204 tosec = atof(arglist.timeout);
205 if (tosec <= 0)
206 to = 0;
207 else
208 to = tosec * 1000.0;
209 }
210
211 if (ast_strlen_zero(arglist.filename)) {
212 arglist.filename = NULL;
213 }
214 if (!ast_strlen_zero(arglist.maxdigits)) {
215 maxdigits = atoi(arglist.maxdigits);
216 if ((maxdigits < 1) || (maxdigits > 255)) {
217 maxdigits = 255;
218 } else
219 ast_verb(3, "Accepting a maximum of %d digits.\n", maxdigits);
220 }
221 if (ast_strlen_zero(arglist.variable)) {
222 ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[,filename][,maxdigits][,option][,attempts][,timeout])\n\n");
223 return 0;
224 }
226 if (!ast_strlen_zero(arglist.filename)) {
227 ts = ast_get_indication_tone(ast_channel_zone(chan), arglist.filename);
228 }
229 }
231 if (!ast_strlen_zero(opt_args[OPT_ARG_TERMINATOR])) {
232 terminator = opt_args[OPT_ARG_TERMINATOR];
233 } else {
234 terminator = ""; /* no digit inherently will terminate input */
235 }
236 }
237 if (ast_channel_state(chan) != AST_STATE_UP) {
239 /* At the user's option, skip if the line is not up */
240 if (ts) {
242 }
243 pbx_builtin_setvar_helper(chan, arglist.variable, "");
244 pbx_builtin_setvar_helper(chan, "READSTATUS", "SKIPPED");
245 return 0;
246 } else if (!ast_test_flag(&flags, OPT_NOANSWER)) {
247 /* Otherwise answer unless we're supposed to read while on-hook */
248 res = ast_answer(chan);
249 }
250 }
251 if (!res) {
252 while (tries && !res) {
253 ast_stopstream(chan);
254 if (ts && ts->data[0]) {
255 if (!to)
256 to = ast_channel_pbx(chan) ? ast_channel_pbx(chan)->rtimeoutms : 6000;
257 res = ast_playtones_start(chan, 0, ts->data, 0);
258 for (x = 0; x < maxdigits; ) {
259 res = ast_waitfordigit(chan, to);
260 ast_playtones_stop(chan);
261 if (res < 1) {
262 if (res == 0)
263 status = "TIMEOUT";
264 tmp[x]='\0';
265 break;
266 }
267 tmp[x++] = res;
268 if (terminator && strchr(terminator, tmp[x-1])) {
269 tmp[x-1] = '\0';
270 status = "OK";
271 break;
272 }
273 if (x >= maxdigits) {
274 status = "OK";
275 }
276 }
277 } else {
278 res = ast_app_getdata_terminator(chan, arglist.filename, tmp, maxdigits, to, terminator);
279 if (res == AST_GETDATA_COMPLETE) {
280 status = "OK";
281 } else if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
283 /* if the option is set to do so, read the
284 returned string as the terminator string */
285 ast_copy_string(tmp, terminator, sizeof(tmp));
286 }
287 status = "OK";
288 } else if (res == AST_GETDATA_TIMEOUT) {
289 status = "TIMEOUT";
290 } else if (res == AST_GETDATA_INTERRUPTED) {
291 status = "INTERRUPTED";
292 }
293 }
294 if (res > -1) {
295 pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
296 if (!ast_strlen_zero(tmp)) {
297 ast_verb(3, "User entered '%s'\n", tmp);
298 tries = 0;
299 } else {
300 tries--;
301 if (tries)
302 ast_verb(3, "User entered nothing, %d chance%s left\n", tries, (tries != 1) ? "s" : "");
303 else
304 ast_verb(3, "User entered nothing.\n");
305 }
306 res = 0;
307 } else {
308 pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
309 ast_verb(3, "User disconnected\n");
310 }
311 }
312 }
313
314 if (ts) {
316 }
317
318 if (ast_check_hangup(chan))
319 status = "HANGUP";
320 pbx_builtin_setvar_helper(chan, "READSTATUS", status);
321 return 0;
322}
323
324static int unload_module(void)
325{
327}
328
329static int load_module(void)
330{
332}
333
334AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application");
jack_status_t status
Definition: app_jack.c:146
read_option_flags
Definition: app_mf.c:190
static int read_exec(struct ast_channel *chan, const char *data)
Definition: app_read.c:160
static char * app
Definition: app_read.c:158
static int load_module(void)
Definition: app_read.c:329
static int unload_module(void)
Definition: app_read.c:324
@ OPT_TERMINATOR
Definition: app_read.c:140
@ OPT_NOANSWER
Definition: app_read.c:139
@ OPT_INDICATION
Definition: app_read.c:138
@ OPT_SKIP
Definition: app_read.c:137
@ OPT_KEEP_TERMINATOR
Definition: app_read.c:141
static const struct ast_app_option read_app_options[128]
Definition: app_read.c:156
@ OPT_ARG_TERMINATOR
Definition: app_read.c:145
@ OPT_ARG_ARRAY_SIZE
Definition: app_read.c:147
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
static int tmp()
Definition: bt_open.c:389
General Asterisk PBX channel definitions.
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3175
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:2805
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:3056
#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:567
#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:626
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:216
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