Merge anthm's app_read addition, somewhat modified (bug #3013)
[asterisk/asterisk.git] / apps / app_read.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Trivial application to read a variable
5  * 
6  * Copyright (C) 2003, Digium
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13  
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/app.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <asterisk/options.h>
23 #include <asterisk/utils.h>
24 #include <string.h>
25 #include <stdlib.h>
26
27 static char *tdesc = "Read Variable Application";
28
29 static char *app = "Read";
30
31 static char *synopsis = "Read a variable";
32
33 static char *descrip = 
34 "  Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n"
35 "Reads a #-terminated string of digits a certian number of times from the\n"
36 "user in to the given variable, optionally playing a given filename first.\n"
37 "  maxdigits  -- maximum acceptable number of digits. Stops reading after\n"
38 "                maxdigits have been entered (without requiring the user to\n"
39 "                press the '#' key).\n"
40 "                Defaults to 0 - no limit - wait for the user press the '#' key.\n"
41 "                Any value below 0 means the same. Max accepted value is 255.\n"
42 "  option     -- may be 'skip' to return immediately if the line is not up,\n"
43 "                or 'noanswer' to read digits even if the line is not up.\n\n"
44 "If attempts is greater than 1, that many attempts will be made in the event no data is entered.\n"
45 "If timeout is greater than 0, that value will override the default timeout.\n\n"
46 "Returns -1 on hangup or error and 0 otherwise.\n";
47
48 STANDARD_LOCAL_USER;
49
50 LOCAL_USER_DECL;
51
52 #define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
53
54 static int read_exec(struct ast_channel *chan, void *data)
55 {
56         int res = 0;
57         struct localuser *u;
58         char tmp[256];
59         char *timeout = NULL;
60         char *varname = NULL;
61         char *filename = NULL;
62         char *loops;
63         char *maxdigitstr=NULL;
64         char *options=NULL;
65         int option_skip = 0;
66         int option_noanswer = 0;
67         int maxdigits=255;
68         int tries = 1;
69         int to = 0;
70         int defined = 0, x = 0;
71         char *argcopy;
72         char *args[8];
73
74         if (data)
75                 argcopy = ast_strdupa((char *)data);
76
77         if (ast_seperate_app_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) {
78                 ast_log(LOG_WARNING, "Cannot Parse Arguements.\n");
79                 return -1;
80         }
81
82         varname = args[x++];
83         filename = args[x++];
84         maxdigitstr = args[x++];
85         options = args[x++];
86         loops = args[x++];
87         
88         if (options) { 
89                 if (!strcasecmp(options, "skip"))
90                         option_skip = 1;
91                 else if (!strcasecmp(options, "noanswer"))
92                         option_noanswer = 1;
93                 else {
94                         if (strchr(options, 's'))
95                                 option_skip = 1;
96                         if (strchr(options, 'n'))
97                                 option_noanswer = 1;
98                 }
99         }
100
101         if(loops) {
102                 tries = atoi(loops);
103                 if(tries <= 0)
104                         tries = 1;
105         }
106
107         if(timeout) {
108                 to = atoi(timeout);
109                 if(to <= 0)
110                         to = 0;
111         }
112
113         if (!(filename) || ast_strlen_zero(filename)) 
114                 filename = NULL;
115         if (maxdigitstr) {
116             maxdigits = atoi(maxdigitstr);
117             if ((maxdigits<1) || (maxdigits>255)) {
118                 maxdigits = 255;
119             } else
120                         ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %i digits.\n", maxdigits);
121         }
122         if (!(varname) || ast_strlen_zero(varname)) {
123                 ast_log(LOG_WARNING, "Read requires an variable name\n");
124                 return -1;
125         }
126         LOCAL_USER_ADD(u);
127         if (chan->_state != AST_STATE_UP) {
128                 if (option_skip) {
129                         /* At the user's option, skip if the line is not up */
130                         pbx_builtin_setvar_helper(chan, varname, "\0");
131                         LOCAL_USER_REMOVE(u);
132                         return 0;
133                 } else if (!option_noanswer) {
134                         /* Otherwise answer unless we're supposed to read while on-hook */
135                         res = ast_answer(chan);
136                 }
137         }
138         if (!res) {
139                 while(tries && !res) {
140                         ast_stopstream(chan);
141                         res = ast_app_getdata(chan, filename, tmp, maxdigits, 0);
142                         if (res > -1) {
143                                 pbx_builtin_setvar_helper(chan, varname, tmp);
144                                 if (!ast_strlen_zero(tmp)) {
145                                         ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
146                                         tries = 0;
147                                 } else {
148                                         tries--;
149                                         if (tries)
150                                                 ast_verbose(VERBOSE_PREFIX_3 "User entered nothing, %d chance(s) left\n", tries);
151                                         else
152                                                 ast_verbose(VERBOSE_PREFIX_3 "User entered nothing.\n");
153                                 }
154                                 res = 0;
155                         } else {
156                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
157                         }
158                 }
159         }
160         LOCAL_USER_REMOVE(u);
161         return res;
162 }
163
164 int unload_module(void)
165 {
166         STANDARD_HANGUP_LOCALUSERS;
167         return ast_unregister_application(app);
168 }
169
170 int load_module(void)
171 {
172         return ast_register_application(app, read_exec, synopsis, descrip);
173 }
174
175 char *description(void)
176 {
177         return tdesc;
178 }
179
180 int usecount(void)
181 {
182         int res;
183         STANDARD_USECOUNT(res);
184         return res;
185 }
186
187 char *key()
188 {
189         return ASTERISK_GPL_KEY;
190 }