Merged revisions 24097 via svnmerge from
[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 LOCAL_USER_DECL;
80
81 static int privacy_exec (struct ast_channel *chan, void *data)
82 {
83         int res=0;
84         int retries;
85         int maxretries = 3;
86         int minlength = 10;
87         int x = 0;
88         char *s;
89         char phone[30];
90         struct localuser *u;
91         struct ast_config *cfg = NULL;
92         char *parse = NULL;
93         int priority_jump = 0;
94         AST_DECLARE_APP_ARGS(args,
95                 AST_APP_ARG(maxretries);
96                 AST_APP_ARG(minlength);
97                 AST_APP_ARG(options);
98         );
99
100         LOCAL_USER_ADD (u);
101         if (!ast_strlen_zero(chan->cid.cid_num)) {
102                 if (option_verbose > 2)
103                         ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
104         } else {
105                 /*Answer the channel if it is not already*/
106                 if (chan->_state != AST_STATE_UP) {
107                         res = ast_answer(chan);
108                         if (res) {
109                                 LOCAL_USER_REMOVE(u);
110                                 return -1;
111                         }
112                 }
113
114                 if (!ast_strlen_zero((char *)data))
115                 {
116                         if (!(parse = ast_strdupa(data))) {
117                                 LOCAL_USER_REMOVE(u);
118                                 return -1;
119                         }
120                         
121                         AST_STANDARD_APP_ARGS(args, parse);
122
123                         if (args.maxretries) {
124                                 if (sscanf(args.maxretries, "%d", &x) == 1)
125                                         maxretries = x;
126                                 else
127                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
128                         }
129                         if (args.minlength) {
130                                 if (sscanf(args.minlength, "%d", &x) == 1)
131                                         minlength = x;
132                                 else
133                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
134                         }
135                         if (args.options)
136                                 if (strchr(args.options, 'j'))
137                                         priority_jump = 1;
138
139                 }               
140
141                 if (!x)
142                 {
143                         /*Read in the config file*/
144                         cfg = ast_config_load(PRIV_CONFIG);
145                 
146                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
147                                 if (sscanf(s, "%d", &x) == 1) 
148                                         maxretries = x;
149                                 else
150                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
151                         }
152
153                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
154                                 if (sscanf(s, "%d", &x) == 1) 
155                                         minlength = x;
156                                 else
157                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
158                         }
159                 }       
160                 
161                 /*Play unidentified call*/
162                 res = ast_safe_sleep(chan, 1000);
163                 if (!res)
164                         res = ast_streamfile(chan, "privacy-unident", chan->language);
165                 if (!res)
166                         res = ast_waitstream(chan, "");
167
168                 /*Ask for 10 digit number, give 3 attempts*/
169                 for (retries = 0; retries < maxretries; retries++) {
170                         if (!res)
171                                 res = ast_streamfile(chan, "privacy-prompt", chan->language);
172                         if (!res)
173                                 res = ast_waitstream(chan, "");
174
175                         if (!res ) 
176                                 res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
177
178                         if (res < 0)
179                                 break;
180
181                         /*Make sure we get at least digits*/
182                         if (strlen(phone) >= minlength ) 
183                                 break;
184                         else {
185                                 res = ast_streamfile(chan, "privacy-incorrect", chan->language);
186                                 if (!res)
187                                         res = ast_waitstream(chan, "");
188                         }
189                 }
190                 
191                 /*Got a number, play sounds and send them on their way*/
192                 if ((retries < maxretries) && res >= 0 ) {
193                         res = ast_streamfile(chan, "privacy-thankyou", chan->language);
194                         if (!res)
195                                 res = ast_waitstream(chan, "");
196
197                         ast_set_callerid (chan, phone, "Privacy Manager", NULL); 
198
199                         /* Clear the unavailable presence bit so if it came in on PRI
200                          * the caller id will now be passed out to other channels
201                          */
202                         chan->cid.cid_pres &= (AST_PRES_UNAVAILABLE ^ 0xFF);
203
204                         if (option_verbose > 2) {
205                                 ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s, callerpres to %d\n",phone,chan->cid.cid_pres);
206                         }
207                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
208                 } else {
209                         if (priority_jump || ast_opt_priority_jumping)  
210                                 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
211                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
212                 }
213                 if (cfg) 
214                         ast_config_destroy(cfg);
215         }
216
217   LOCAL_USER_REMOVE (u);
218   return 0;
219 }
220
221 static int unload_module(void *mod)
222 {
223         int res;
224
225         res = ast_unregister_application (app);
226
227         STANDARD_HANGUP_LOCALUSERS;
228
229         return res;
230 }
231
232 static int load_module(void *mod)
233 {
234         return ast_register_application (app, privacy_exec, synopsis, descrip);
235 }
236
237 static const char *description(void)
238 {
239         return tdesc;
240 }
241
242 static const char *key(void)
243 {
244         return ASTERISK_GPL_KEY;
245 }
246
247 STD_MOD1;