000c9ef2ae97af3913d6530e71a476f462f11a14
[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 "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
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 *app = "PrivacyManager";
53
54 static char *synopsis = "Require phone number to be entered, if no CallerID sent";
55
56 static char *descrip =
57   "  PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
58   "is sent, PrivacyManager answers the channel and asks the caller to\n"
59   "enter their phone number. The caller is given 3 attempts to do so.\n"
60   "The application does nothing if Caller*ID was received on the channel.\n"
61   "  Configuration file privacy.conf contains two variables:\n"
62   "   maxretries  default 3  -maximum number of attempts the caller is allowed \n"
63   "               to input a callerid.\n"
64   "   minlength   default 10 -minimum allowable digits in the input callerid number.\n"
65   "If you don't want to use the config file and have an i/o operation with\n"
66   "every call, you can also specify maxretries and minlength as application\n"
67   "parameters. Doing so supercedes any values set in privacy.conf.\n"
68   "The application sets the following channel variable upon completion: \n"
69   "PRIVACYMGRSTATUS  The status of the privacy manager's attempt to collect \n"
70   "                  a phone number from the user. A text string that is either:\n" 
71   "          SUCCESS | FAILED \n"
72 ;
73
74
75 static int privacy_exec (struct ast_channel *chan, void *data)
76 {
77         int res=0;
78         int retries;
79         int maxretries = 3;
80         int minlength = 10;
81         int x = 0;
82         const char *s;
83         char phone[30];
84         struct ast_module_user *u;
85         struct ast_config *cfg = NULL;
86         char *parse = NULL;
87         AST_DECLARE_APP_ARGS(args,
88                 AST_APP_ARG(maxretries);
89                 AST_APP_ARG(minlength);
90                 AST_APP_ARG(options);
91         );
92
93         u = ast_module_user_add(chan);
94
95         if (!ast_strlen_zero(chan->cid.cid_num)) {
96                 if (option_verbose > 2)
97                         ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
98         } else {
99                 /*Answer the channel if it is not already*/
100                 if (chan->_state != AST_STATE_UP) {
101                         res = ast_answer(chan);
102                         if (res) {
103                                 ast_module_user_remove(u);
104                                 return -1;
105                         }
106                 }
107
108                 if (!ast_strlen_zero(data)) {
109                         parse = ast_strdupa(data);
110                         
111                         AST_STANDARD_APP_ARGS(args, parse);
112
113                         if (args.maxretries) {
114                                 if (sscanf(args.maxretries, "%d", &x) == 1)
115                                         maxretries = x;
116                                 else
117                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
118                         }
119                         if (args.minlength) {
120                                 if (sscanf(args.minlength, "%d", &x) == 1)
121                                         minlength = x;
122                                 else
123                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
124                         }
125
126                 }               
127
128                 if (!x)
129                 {
130                         /*Read in the config file*/
131                         cfg = ast_config_load(PRIV_CONFIG);
132                 
133                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
134                                 if (sscanf(s, "%d", &x) == 1) 
135                                         maxretries = x;
136                                 else
137                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
138                         }
139
140                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
141                                 if (sscanf(s, "%d", &x) == 1) 
142                                         minlength = x;
143                                 else
144                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
145                         }
146                 }       
147                 
148                 /*Play unidentified call*/
149                 res = ast_safe_sleep(chan, 1000);
150                 if (!res)
151                         res = ast_streamfile(chan, "privacy-unident", chan->language);
152                 if (!res)
153                         res = ast_waitstream(chan, "");
154
155                 /*Ask for 10 digit number, give 3 attempts*/
156                 for (retries = 0; retries < maxretries; retries++) {
157                         if (!res)
158                                 res = ast_streamfile(chan, "privacy-prompt", chan->language);
159                         if (!res)
160                                 res = ast_waitstream(chan, "");
161
162                         if (!res ) 
163                                 res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
164
165                         if (res < 0)
166                                 break;
167
168                         /*Make sure we get at least digits*/
169                         if (strlen(phone) >= minlength ) 
170                                 break;
171                         else {
172                                 res = ast_streamfile(chan, "privacy-incorrect", chan->language);
173                                 if (!res)
174                                         res = ast_waitstream(chan, "");
175                         }
176                 }
177                 
178                 /*Got a number, play sounds and send them on their way*/
179                 if ((retries < maxretries) && res >= 0 ) {
180                         res = ast_streamfile(chan, "privacy-thankyou", chan->language);
181                         if (!res)
182                                 res = ast_waitstream(chan, "");
183
184                         ast_set_callerid (chan, phone, "Privacy Manager", NULL); 
185
186                         /* Clear the unavailable presence bit so if it came in on PRI
187                          * the caller id will now be passed out to other channels
188                          */
189                         chan->cid.cid_pres &= (AST_PRES_UNAVAILABLE ^ 0xFF);
190
191                         if (option_verbose > 2) {
192                                 ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s, callerpres to %d\n",phone,chan->cid.cid_pres);
193                         }
194                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
195                 } else {
196                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
197                 }
198                 if (cfg) 
199                         ast_config_destroy(cfg);
200         }
201
202         ast_module_user_remove(u);
203
204         return 0;
205 }
206
207 static int unload_module(void)
208 {
209         return ast_unregister_application (app);
210 }
211
212 static int load_module(void)
213 {
214         return ast_register_application(app, privacy_exec, synopsis, descrip);
215 }
216
217 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");