revert my pass through the tree to remove checks of the result of ast_strdupa
[asterisk/asterisk.git] / apps / app_privacy.c
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 Block all calls without Caller*ID, require phone # to be entered
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * 
25  * \ingroup applications
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include "asterisk.h"
33
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35
36 #include "asterisk/lock.h"
37 #include "asterisk/file.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/options.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/module.h"
44 #include "asterisk/translate.h"
45 #include "asterisk/image.h"
46 #include "asterisk/callerid.h"
47 #include "asterisk/app.h"
48 #include "asterisk/config.h"
49
50 #define PRIV_CONFIG "privacy.conf"
51
52 static char *tdesc = "Require phone number to be entered, if no CallerID sent";
53
54 static char *app = "PrivacyManager";
55
56 static char *synopsis = "Require phone number to be entered, if no CallerID sent";
57
58 static char *descrip =
59   "  PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
60   "is sent, PrivacyManager answers the channel and asks the caller to\n"
61   "enter their phone number. The caller is given 3 attempts to do so.\n"
62   "The application does nothing if Caller*ID was received on the channel.\n"
63   "  Configuration file privacy.conf contains two variables:\n"
64   "   maxretries  default 3  -maximum number of attempts the caller is allowed \n"
65   "               to input a callerid.\n"
66   "   minlength   default 10 -minimum allowable digits in the input callerid number.\n"
67   "If you don't want to use the config file and have an i/o operation with\n"
68   "every call, you can also specify maxretries and minlength as application\n"
69   "parameters. Doing so supercedes any values set in privacy.conf.\n"
70   "The option string may contain the following character: \n"
71   "  'j' -- jump to n+101 priority after <maxretries> failed attempts to collect\n"
72   "         the minlength number of digits.\n"
73   "The application sets the following channel variable upon completion: \n"
74   "PRIVACYMGRSTATUS  The status of the privacy manager's attempt to collect \n"
75   "                  a phone number from the user. A text string that is either:\n" 
76   "          SUCCESS | FAILED \n"
77 ;
78
79 STANDARD_LOCAL_USER;
80
81 LOCAL_USER_DECL;
82
83
84
85 static int privacy_exec (struct ast_channel *chan, void *data)
86 {
87         int res=0;
88         int retries;
89         int maxretries = 3;
90         int minlength = 10;
91         int x = 0;
92         char *s;
93         char phone[30];
94         struct localuser *u;
95         struct ast_config *cfg = NULL;
96         char *parse = NULL;
97         int priority_jump = 0;
98         AST_DECLARE_APP_ARGS(args,
99                 AST_APP_ARG(maxretries);
100                 AST_APP_ARG(minlength);
101                 AST_APP_ARG(options);
102         );
103
104         LOCAL_USER_ADD (u);
105         if (!ast_strlen_zero(chan->cid.cid_num)) {
106                 if (option_verbose > 2)
107                         ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
108         } else {
109                 /*Answer the channel if it is not already*/
110                 if (chan->_state != AST_STATE_UP) {
111                         res = ast_answer(chan);
112                         if (res) {
113                                 LOCAL_USER_REMOVE(u);
114                                 return -1;
115                         }
116                 }
117
118                 if (!ast_strlen_zero((char *)data))
119                 {
120                         parse = ast_strdupa(data);
121                         if (!parse) {
122                                 ast_log(LOG_ERROR, "Out of memory!\n");
123                                 LOCAL_USER_REMOVE(u);
124                                 return -1;
125                         }
126                         
127                         AST_STANDARD_APP_ARGS(args, parse);
128
129                         if (args.maxretries) {
130                                 if (sscanf(args.maxretries, "%d", &x) == 1)
131                                         maxretries = x;
132                                 else
133                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
134                         }
135                         if (args.minlength) {
136                                 if (sscanf(args.minlength, "%d", &x) == 1)
137                                         minlength = x;
138                                 else
139                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
140                         }
141                         if (args.options)
142                                 if (strchr(args.options, 'j'))
143                                         priority_jump = 1;
144
145                 }               
146
147                 if (!x)
148                 {
149                         /*Read in the config file*/
150                         cfg = ast_config_load(PRIV_CONFIG);
151                 
152                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
153                                 if (sscanf(s, "%d", &x) == 1) 
154                                         maxretries = x;
155                                 else
156                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
157                         }
158
159                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
160                                 if (sscanf(s, "%d", &x) == 1) 
161                                         minlength = x;
162                                 else
163                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
164                         }
165                 }       
166                 
167                 /*Play unidentified call*/
168                 res = ast_safe_sleep(chan, 1000);
169                 if (!res)
170                         res = ast_streamfile(chan, "privacy-unident", chan->language);
171                 if (!res)
172                         res = ast_waitstream(chan, "");
173
174                 /*Ask for 10 digit number, give 3 attempts*/
175                 for (retries = 0; retries < maxretries; retries++) {
176                         if (!res)
177                                 res = ast_streamfile(chan, "privacy-prompt", chan->language);
178                         if (!res)
179                                 res = ast_waitstream(chan, "");
180
181                         if (!res ) 
182                                 res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
183
184                         if (res < 0)
185                                 break;
186
187                         /*Make sure we get at least digits*/
188                         if (strlen(phone) >= minlength ) 
189                                 break;
190                         else {
191                                 res = ast_streamfile(chan, "privacy-incorrect", chan->language);
192                                 if (!res)
193                                         res = ast_waitstream(chan, "");
194                         }
195                 }
196                 
197                 /*Got a number, play sounds and send them on their way*/
198                 if ((retries < maxretries) && !res ) {
199                         res = ast_streamfile(chan, "privacy-thankyou", chan->language);
200                         if (!res)
201                                 res = ast_waitstream(chan, "");
202                         ast_set_callerid (chan, phone, "Privacy Manager", NULL);
203                         if (option_verbose > 2)
204                                 ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",phone);
205                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
206                 } else {
207                         if (priority_jump || ast_opt_priority_jumping)  
208                                 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
209                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
210                 }
211                 if (cfg) 
212                         ast_config_destroy(cfg);
213         }
214
215   LOCAL_USER_REMOVE (u);
216   return 0;
217 }
218
219 int
220 unload_module (void)
221 {
222         int res;
223
224         res = ast_unregister_application (app);
225
226         STANDARD_HANGUP_LOCALUSERS;
227
228         return res;
229 }
230
231 int
232 load_module (void)
233 {
234   return ast_register_application (app, privacy_exec, synopsis,
235                                    descrip);
236 }
237
238 char *
239 description (void)
240 {
241   return tdesc;
242 }
243
244 int
245 usecount (void)
246 {
247   int res;
248   STANDARD_USECOUNT (res);
249   return res;
250 }
251
252 char *
253 key ()
254 {
255   return ASTERISK_GPL_KEY;
256 }