make app_queue 1.2 jump compliant (issue #5580)
[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 <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/lock.h"
35 #include "asterisk/file.h"
36 #include "asterisk/utils.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/options.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/module.h"
42 #include "asterisk/translate.h"
43 #include "asterisk/image.h"
44 #include "asterisk/callerid.h"
45 #include "asterisk/app.h"
46 #include "asterisk/config.h"
47
48 #define PRIV_CONFIG "privacy.conf"
49
50 static char *tdesc = "Require phone number to be entered, if no CallerID sent";
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 STANDARD_LOCAL_USER;
78
79 LOCAL_USER_DECL;
80
81
82
83 static int privacy_exec (struct ast_channel *chan, void *data)
84 {
85         int res=0;
86         int retries;
87         int maxretries = 3;
88         int minlength = 10;
89         int x = 0;
90         char *s;
91         char phone[30];
92         struct localuser *u;
93         struct ast_config *cfg = NULL;
94         char *parse = NULL;
95         int priority_jump = 0;
96         AST_DECLARE_APP_ARGS(args,
97                 AST_APP_ARG(maxretries);
98                 AST_APP_ARG(minlength);
99                 AST_APP_ARG(options);
100         );
101
102         LOCAL_USER_ADD (u);
103         if (!ast_strlen_zero(chan->cid.cid_num)) {
104                 if (option_verbose > 2)
105                         ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
106         } else {
107                 /*Answer the channel if it is not already*/
108                 if (chan->_state != AST_STATE_UP) {
109                         res = ast_answer(chan);
110                         if (res) {
111                                 LOCAL_USER_REMOVE(u);
112                                 return -1;
113                         }
114                 }
115
116                 if (!ast_strlen_zero((char *)data))
117                 {
118                         parse = ast_strdupa(data);
119                         if (!parse) {
120                                 ast_log(LOG_ERROR, "Out of memory!\n");
121                                 LOCAL_USER_REMOVE(u);
122                                 return -1;
123                         }
124                         
125                         AST_STANDARD_APP_ARGS(args, parse);
126
127                         if (args.maxretries) {
128                                 if (sscanf(args.maxretries, "%d", &x) == 1)
129                                         maxretries = x;
130                                 else
131                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
132                         }
133                         if (args.minlength) {
134                                 if (sscanf(args.minlength, "%d", &x) == 1)
135                                         minlength = x;
136                                 else
137                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
138                         }
139                         if (args.options)
140                                 if (strchr(args.options, 'j'))
141                                         priority_jump = 1;
142
143                 }               
144
145                 if (!x)
146                 {
147                         /*Read in the config file*/
148                         cfg = ast_config_load(PRIV_CONFIG);
149                 
150                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
151                                 if (sscanf(s, "%d", &x) == 1) 
152                                         maxretries = x;
153                                 else
154                                         ast_log(LOG_WARNING, "Invalid max retries argument\n");
155                         }
156
157                         if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
158                                 if (sscanf(s, "%d", &x) == 1) 
159                                         minlength = x;
160                                 else
161                                         ast_log(LOG_WARNING, "Invalid min length argument\n");
162                         }
163                 }       
164                 
165                 /*Play unidentified call*/
166                 res = ast_safe_sleep(chan, 1000);
167                 if (!res)
168                         res = ast_streamfile(chan, "privacy-unident", chan->language);
169                 if (!res)
170                         res = ast_waitstream(chan, "");
171
172                 /*Ask for 10 digit number, give 3 attempts*/
173                 for (retries = 0; retries < maxretries; retries++) {
174                         if (!res)
175                                 res = ast_streamfile(chan, "privacy-prompt", chan->language);
176                         if (!res)
177                                 res = ast_waitstream(chan, "");
178
179                         if (!res ) 
180                                 res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
181
182                         if (res < 0)
183                                 break;
184
185                         /*Make sure we get at least digits*/
186                         if (strlen(phone) >= minlength ) 
187                                 break;
188                         else {
189                                 res = ast_streamfile(chan, "privacy-incorrect", chan->language);
190                                 if (!res)
191                                         res = ast_waitstream(chan, "");
192                         }
193                 }
194                 
195                 /*Got a number, play sounds and send them on their way*/
196                 if ((retries < maxretries) && res == 1 ) {
197                         res = ast_streamfile(chan, "privacy-thankyou", chan->language);
198                         if (!res)
199                                 res = ast_waitstream(chan, "");
200                         ast_set_callerid (chan, phone, "Privacy Manager", NULL);
201                         if (option_verbose > 2)
202                                 ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",phone);
203                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
204                 } else {
205                         if (priority_jump || option_priority_jumping)   
206                                 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
207                         pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
208                 }
209                 if (cfg) 
210                         ast_config_destroy(cfg);
211         }
212
213   LOCAL_USER_REMOVE (u);
214   return 0;
215 }
216
217 int
218 unload_module (void)
219 {
220         int res;
221
222         res = ast_unregister_application (app);
223
224         STANDARD_HANGUP_LOCALUSERS;
225
226         return res;
227 }
228
229 int
230 load_module (void)
231 {
232   return ast_register_application (app, privacy_exec, synopsis,
233                                    descrip);
234 }
235
236 char *
237 description (void)
238 {
239   return tdesc;
240 }
241
242 int
243 usecount (void)
244 {
245   int res;
246   STANDARD_USECOUNT (res);
247   return res;
248 }
249
250 char *
251 key ()
252 {
253   return ASTERISK_GPL_KEY;
254 }