Don't reload a configuration file if nothing has changed.
[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_config *cfg = NULL;
85         char *parse = NULL;
86         struct ast_flags config_flags = { 0 };
87         AST_DECLARE_APP_ARGS(args,
88                 AST_APP_ARG(maxretries);
89                 AST_APP_ARG(minlength);
90                 AST_APP_ARG(options);
91         );
92
93         if (!ast_strlen_zero(chan->cid.cid_num)) {
94                 if (option_verbose > 2)
95                         ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
96         } else {
97                 /*Answer the channel if it is not already*/
98                 if (chan->_state != AST_STATE_UP) {
99                         if ((res = ast_answer(chan)))
100                                 return -1;
101                 }
102
103                 if (!ast_strlen_zero(data)) {
104                         parse = ast_strdupa(data);
105                         
106                         AST_STANDARD_APP_ARGS(args, parse);
107
108                         if (args.maxretries) {
109                                 if (sscanf(args.maxretries, "%d", &x) == 1)
110                                         maxretries = x;
111                                 else
112                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
113                         }
114                         if (args.minlength) {
115                                 if (sscanf(args.minlength, "%d", &x) == 1)
116                                         minlength = x;
117                                 else
118                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
119                         }
120
121                 }               
122
123                 if (!x)
124                 {
125                         /*Read in the config file*/
126                         cfg = ast_config_load(PRIV_CONFIG, config_flags);
127                 
128                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
129                                 if (sscanf(s, "%d", &x) == 1) 
130                                         maxretries = x;
131                                 else
132                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
133                         }
134
135                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
136                                 if (sscanf(s, "%d", &x) == 1) 
137                                         minlength = x;
138                                 else
139                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
140                         }
141                 }       
142                 
143                 /*Play unidentified call*/
144                 res = ast_safe_sleep(chan, 1000);
145                 if (!res)
146                         res = ast_streamfile(chan, "privacy-unident", chan->language);
147                 if (!res)
148                         res = ast_waitstream(chan, "");
149
150                 /*Ask for 10 digit number, give 3 attempts*/
151                 for (retries = 0; retries < maxretries; retries++) {
152                         if (!res)
153                                 res = ast_streamfile(chan, "privacy-prompt", chan->language);
154                         if (!res)
155                                 res = ast_waitstream(chan, "");
156
157                         if (!res ) 
158                                 res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
159
160                         if (res < 0)
161                                 break;
162
163                         /*Make sure we get at least digits*/
164                         if (strlen(phone) >= minlength ) 
165                                 break;
166                         else {
167                                 res = ast_streamfile(chan, "privacy-incorrect", chan->language);
168                                 if (!res)
169                                         res = ast_waitstream(chan, "");
170                         }
171                 }
172                 
173                 /*Got a number, play sounds and send them on their way*/
174                 if ((retries < maxretries) && res >= 0 ) {
175                         res = ast_streamfile(chan, "privacy-thankyou", chan->language);
176                         if (!res)
177                                 res = ast_waitstream(chan, "");
178
179                         ast_set_callerid (chan, phone, "Privacy Manager", NULL); 
180
181                         /* Clear the unavailable presence bit so if it came in on PRI
182                          * the caller id will now be passed out to other channels
183                          */
184                         chan->cid.cid_pres &= (AST_PRES_UNAVAILABLE ^ 0xFF);
185
186                         if (option_verbose > 2) {
187                                 ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s, callerpres to %d\n",phone,chan->cid.cid_pres);
188                         }
189                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
190                 } else {
191                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
192                 }
193                 if (cfg) 
194                         ast_config_destroy(cfg);
195         }
196
197         return 0;
198 }
199
200 static int unload_module(void)
201 {
202         return ast_unregister_application (app);
203 }
204
205 static int load_module(void)
206 {
207         return ast_register_application(app, privacy_exec, synopsis, descrip);
208 }
209
210 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");