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