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