don't use '%i' at all, since we have no current use cases that need non base-10 parsi...
[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 certain number of times from the\n"
36 "user in to the given variable.\n"
37 "  filename   -- file to play before reading digits.\n"
38 "  maxdigits  -- maximum acceptable number of digits. Stops reading after\n"
39 "                maxdigits have been entered (without requiring the user to\n"
40 "                press the '#' key).\n"
41 "                Defaults to 0 - no limit - wait for the user press the '#' key.\n"
42 "                Any value below 0 means the same. Max accepted value is 255.\n"
43 "  option     -- may be 'skip' to return immediately if the line is not up,\n"
44 "                or 'noanswer' to read digits even if the line is not up.\n"
45 "  attempts   -- if greater than 1, that many attempts will be made in the \n"
46 "                event no data is entered.\n"
47 "  timeout    -- if greater than 0, that value will override the default timeout.\n\n"
48 "Returns -1 on hangup or error and 0 otherwise.\n";
49
50 STANDARD_LOCAL_USER;
51
52 LOCAL_USER_DECL;
53
54 #define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
55
56 static int read_exec(struct ast_channel *chan, void *data)
57 {
58         int res = 0;
59         struct localuser *u;
60         char tmp[256];
61         char *timeout = NULL;
62         char *varname = NULL;
63         char *filename = NULL;
64         char *loops;
65         char *maxdigitstr=NULL;
66         char *options=NULL;
67         int option_skip = 0;
68         int option_noanswer = 0;
69         int maxdigits=255;
70         int tries = 1;
71         int to = 0;
72         int x = 0;
73         char *argcopy = NULL;
74         char *args[8];
75
76         if (data)
77                 argcopy = ast_strdupa((char *)data);
78
79         if (ast_separate_app_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) {
80                 ast_log(LOG_WARNING, "Cannot Parse Arguements.\n");
81                 return -1;
82         }
83
84         varname = args[x++];
85         filename = args[x++];
86         maxdigitstr = args[x++];
87         options = args[x++];
88         loops = args[x++];
89         
90         if (options) { 
91                 if (!strcasecmp(options, "skip"))
92                         option_skip = 1;
93                 else if (!strcasecmp(options, "noanswer"))
94                         option_noanswer = 1;
95                 else {
96                         if (strchr(options, 's'))
97                                 option_skip = 1;
98                         if (strchr(options, 'n'))
99                                 option_noanswer = 1;
100                 }
101         }
102
103         if(loops) {
104                 tries = atoi(loops);
105                 if(tries <= 0)
106                         tries = 1;
107         }
108
109         if(timeout) {
110                 to = atoi(timeout);
111                 if(to <= 0)
112                         to = 0;
113         }
114
115         if (!(filename) || ast_strlen_zero(filename)) 
116                 filename = NULL;
117         if (maxdigitstr) {
118                 maxdigits = atoi(maxdigitstr);
119                 if ((maxdigits<1) || (maxdigits>255)) {
120                         maxdigits = 255;
121                 } else if (option_verbose > 2)
122                         ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %d digits.\n", maxdigits);
123         }
124         if (!(varname) || ast_strlen_zero(varname)) {
125                 ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n");
126                 return -1;
127         }
128         LOCAL_USER_ADD(u);
129         if (chan->_state != AST_STATE_UP) {
130                 if (option_skip) {
131                         /* At the user's option, skip if the line is not up */
132                         pbx_builtin_setvar_helper(chan, varname, "\0");
133                         LOCAL_USER_REMOVE(u);
134                         return 0;
135                 } else if (!option_noanswer) {
136                         /* Otherwise answer unless we're supposed to read while on-hook */
137                         res = ast_answer(chan);
138                 }
139         }
140         if (!res) {
141                 while(tries && !res) {
142                         ast_stopstream(chan);
143                         res = ast_app_getdata(chan, filename, tmp, maxdigits, 0);
144                         if (res > -1) {
145                                 pbx_builtin_setvar_helper(chan, varname, tmp);
146                                 if (!ast_strlen_zero(tmp)) {
147                                         if (option_verbose > 2)
148                                                 ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
149                                         tries = 0;
150                                 } else {
151                                         tries--;
152                                         if (option_verbose > 2) {
153                                                 if (tries)
154                                                         ast_verbose(VERBOSE_PREFIX_3 "User entered nothing, %d chance(s) left\n", tries);
155                                                 else
156                                                         ast_verbose(VERBOSE_PREFIX_3 "User entered nothing.\n");
157                                         }
158                                 }
159                                 res = 0;
160                         } else {
161                                 if (option_verbose > 2)
162                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
163                         }
164                 }
165         }
166         LOCAL_USER_REMOVE(u);
167         return res;
168 }
169
170 int unload_module(void)
171 {
172         STANDARD_HANGUP_LOCALUSERS;
173         return ast_unregister_application(app);
174 }
175
176 int load_module(void)
177 {
178         return ast_register_application(app, read_exec, synopsis, descrip);
179 }
180
181 char *description(void)
182 {
183         return tdesc;
184 }
185
186 int usecount(void)
187 {
188         int res;
189         STANDARD_USECOUNT(res);
190         return res;
191 }
192
193 char *key()
194 {
195         return ASTERISK_GPL_KEY;
196 }