Asterisk - The Open Source Telephony Project GIT-master-a358458
app_disa.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2005, Digium, Inc.
5 *
6 *
7 * Made only slightly more sane by Mark Spencer <markster@digium.com>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20/*! \file
21 *
22 * \brief DISA -- Direct Inward System Access Application
23 *
24 * \author Jim Dixon <jim@lambdatel.com>
25 *
26 * \ingroup applications
27 */
28
29/*** MODULEINFO
30 <use type="module">app_cdr</use>
31 <support_level>core</support_level>
32 ***/
33
34#include "asterisk.h"
35
36#include <math.h>
37#include <sys/time.h>
38
39#include "asterisk/lock.h"
40#include "asterisk/file.h"
41#include "asterisk/channel.h"
42#include "asterisk/app.h"
44#include "asterisk/pbx.h"
45#include "asterisk/module.h"
46#include "asterisk/translate.h"
47#include "asterisk/ulaw.h"
48#include "asterisk/callerid.h"
50
51/*** DOCUMENTATION
52 <application name="DISA" language="en_US">
53 <synopsis>
54 Direct Inward System Access.
55 </synopsis>
56 <syntax>
57 <parameter name="passcode|filename" required="true">
58 <para>If you need to present a DISA dialtone without entering a password,
59 simply set <replaceable>passcode</replaceable> to <literal>no-password</literal></para>
60 <para>You may specified a <replaceable>filename</replaceable> instead of a
61 <replaceable>passcode</replaceable>, this filename must contain individual passcodes</para>
62 </parameter>
63 <parameter name="context">
64 <para>Specifies the dialplan context in which the user-entered extension
65 will be matched. If no context is specified, the DISA application defaults
66 to the <literal>disa</literal> context. Presumably a normal system will have a special
67 context set up for DISA use with some or a lot of restrictions.</para>
68 </parameter>
69 <parameter name="cid">
70 <para>Specifies a new (different) callerid to be used for this call.</para>
71 </parameter>
72 <parameter name="mailbox" argsep="@">
73 <para>Will cause a stutter-dialtone (indication <emphasis>dialrecall</emphasis>)
74 to be used, if the specified mailbox contains any new messages.</para>
75 <argument name="mailbox" required="true" />
76 <argument name="context" required="false" />
77 </parameter>
78 <parameter name="options">
79 <optionlist>
80 <option name="n">
81 <para>The DISA application will not answer initially.</para>
82 </option>
83 <option name="p">
84 <para>The extension entered will be considered complete when a <literal>#</literal>
85 is entered.</para>
86 </option>
87 </optionlist>
88 </parameter>
89 </syntax>
90 <description>
91 <para>The DISA, Direct Inward System Access, application allows someone from
92 outside the telephone switch (PBX) to obtain an <emphasis>internal</emphasis> system
93 dialtone and to place calls from it as if they were placing a call from
94 within the switch.
95 DISA plays a dialtone. The user enters their numeric passcode, followed by
96 the pound sign <literal>#</literal>. If the passcode is correct, the user is then given
97 system dialtone within <replaceable>context</replaceable> on which a call may be placed.
98 If the user enters an invalid extension and extension <literal>i</literal> exists in the specified
99 <replaceable>context</replaceable>, it will be used.
100 </para>
101 <para>Be aware that using this may compromise the security of your PBX.</para>
102 <para>The arguments to this application (in <filename>extensions.conf</filename>) allow either
103 specification of a single global <replaceable>passcode</replaceable> (that everyone uses), or
104 individual passcodes contained in a file (<replaceable>filename</replaceable>).</para>
105 <para>The file that contains the passcodes (if used) allows a complete
106 specification of all of the same arguments available on the command
107 line, with the sole exception of the options. The file may contain blank
108 lines, or comments starting with <literal>#</literal> or <literal>;</literal>.</para>
109 </description>
110 <see-also>
111 <ref type="application">Authenticate</ref>
112 <ref type="application">VMAuthenticate</ref>
113 </see-also>
114 </application>
115 ***/
116static const char app[] = "DISA";
117
118enum {
119 NOANSWER_FLAG = (1 << 0),
121};
122
126});
127
128static void play_dialtone(struct ast_channel *chan, char *mailbox)
129{
130 struct ast_tone_zone_sound *ts = NULL;
131
133 ts = ast_get_indication_tone(ast_channel_zone(chan), "dialrecall");
134 } else {
135 ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
136 }
137
138 if (ts) {
139 ast_playtones_start(chan, 0, ts->data, 0);
141 } else {
142 ast_tonepair_start(chan, 350, 440, 0, 0);
143 }
144}
145
146static int disa_exec(struct ast_channel *chan, const char *data)
147{
148 int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
149 int firstdigittimeout = (ast_channel_pbx(chan) ? ast_channel_pbx(chan)->rtimeoutms : 20000);
150 int digittimeout = (ast_channel_pbx(chan) ? ast_channel_pbx(chan)->dtimeoutms : 10000);
151 struct ast_flags flags;
152 char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
153 char pwline[256];
154 char ourcidname[256],ourcidnum[256];
155 struct ast_frame *f;
156 struct timeval lastdigittime;
157 int res;
158 FILE *fp;
160 AST_APP_ARG(passcode);
162 AST_APP_ARG(cid);
165 );
166
167 if (ast_strlen_zero(data)) {
168 ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
169 return -1;
170 }
171
172 ast_debug(1, "Digittimeout: %d\n", digittimeout);
173 ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);
174
175 tmp = ast_strdupa(data);
176
178
179 if (ast_strlen_zero(args.context))
180 args.context = "disa";
181 if (ast_strlen_zero(args.mailbox))
182 args.mailbox = "";
183 if (!ast_strlen_zero(args.options)) {
184 ast_app_parse_options(app_opts, &flags, NULL, args.options);
185 } else {
186 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
188 }
189
190
191 ast_debug(1, "Mailbox: %s\n",args.mailbox);
192
193 if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
194 if (ast_channel_state(chan) != AST_STATE_UP) {
195 /* answer */
196 ast_answer(chan);
197 }
198 } else special_noanswer = 1;
199
200 ast_debug(1, "Context: %s\n",args.context);
201
202 if (!strcasecmp(args.passcode, "no-password")) {
203 k |= 1; /* We have the password */
204 ast_debug(1, "DISA no-password login success\n");
205 }
206
207 lastdigittime = ast_tvnow();
208
209 play_dialtone(chan, args.mailbox);
210
212
213 for (;;) {
214 /* if outa time, give em reorder */
215 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
216 ast_debug(1,"DISA %s entry timeout on chan %s\n",
217 ((k&1) ? "extension" : "password"),ast_channel_name(chan));
218 break;
219 }
220
221 if ((res = ast_waitfor(chan, -1)) < 0) {
222 ast_debug(1, "Waitfor returned %d\n", res);
223 continue;
224 }
225
226 if (!(f = ast_read(chan))) {
228 return -1;
229 }
230
232 if (f->data.uint32)
234 ast_frfree(f);
236 return -1;
237 }
238
239 /* If the frame coming in is not DTMF, just drop it and continue */
240 if (f->frametype != AST_FRAME_DTMF) {
241 ast_frfree(f);
242 continue;
243 }
244
245 j = f->subclass.integer; /* save digit */
246 ast_frfree(f);
247
248 if (!i) {
249 k |= 2; /* We have the first digit */
250 ast_playtones_stop(chan);
251 }
252
253 lastdigittime = ast_tvnow();
254
255 /* got a DTMF tone */
256 if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
257 if (!(k&1)) { /* if in password state */
258 if (j == '#') { /* end of password */
259 /* see if this is an integer */
260 if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
261 fp = fopen(args.passcode,"r");
262 if (!fp) {
263 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,ast_channel_name(chan));
265 return -1;
266 }
267 pwline[0] = 0;
268 while(fgets(pwline,sizeof(pwline) - 1,fp)) {
269 if (!pwline[0])
270 continue;
271 if (pwline[strlen(pwline) - 1] == '\n')
272 pwline[strlen(pwline) - 1] = 0;
273 if (!pwline[0])
274 continue;
275 /* skip comments */
276 if (pwline[0] == '#')
277 continue;
278 if (pwline[0] == ';')
279 continue;
280
282
283 ast_debug(1, "Mailbox: %s\n",args.mailbox);
284
285 /* password must be in valid format (numeric) */
286 if (sscanf(args.passcode,"%30d", &j) < 1)
287 continue;
288 /* if we got it */
289 if (!strcmp(exten,args.passcode)) {
290 if (ast_strlen_zero(args.context))
291 args.context = "disa";
292 if (ast_strlen_zero(args.mailbox))
293 args.mailbox = "";
294 break;
295 }
296 }
297 fclose(fp);
298 }
299 /* compare the two */
300 if (strcmp(exten,args.passcode)) {
301 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",ast_channel_name(chan),exten);
302 goto reorder;
303
304 }
305 /* password good, set to dial state */
306 ast_debug(1,"DISA on chan %s password is good\n",ast_channel_name(chan));
307 play_dialtone(chan, args.mailbox);
308
309 k|=1; /* In number mode */
310 i = 0; /* re-set buffer pointer */
311 exten[sizeof(acctcode)] = 0;
312 ast_copy_string(acctcode, exten, sizeof(acctcode));
313 exten[0] = 0;
314 ast_debug(1,"Successful DISA log-in on chan %s\n", ast_channel_name(chan));
315 continue;
316 }
317 } else {
318 if (j == '#') { /* end of extension .. maybe */
319 if (i == 0
320 && (ast_matchmore_extension(chan, args.context, "#", 1,
321 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
322 || ast_exists_extension(chan, args.context, "#", 1,
323 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) ) {
324 /* Let the # be the part of, or the entire extension */
325 } else {
326 break;
327 }
328 }
329 }
330
331 exten[i++] = j; /* save digit */
332 exten[i] = 0;
333 if (!(k&1))
334 continue; /* if getting password, continue doing it */
335 /* if this exists */
336
337 /* user wants end of number, remove # */
338 if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
339 exten[--i] = 0;
340 break;
341 }
342
343 if (ast_ignore_pattern(args.context, exten)) {
344 play_dialtone(chan, "");
345 did_ignore = 1;
346 } else
347 if (did_ignore) {
348 ast_playtones_stop(chan);
349 did_ignore = 0;
350 }
351
352 /* if can do some more, do it */
353 if (!ast_matchmore_extension(chan, args.context, exten, 1,
354 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
355 break;
356 }
357 }
358 }
359
361
362 if (k == 3) {
363 int recheck = 0;
364
365 if (!ast_exists_extension(chan, args.context, exten, 1,
366 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
367 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
368 exten[0] = 'i';
369 exten[1] = '\0';
370 recheck = 1;
371 }
372 if (!recheck
373 || ast_exists_extension(chan, args.context, exten, 1,
374 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
375 ast_playtones_stop(chan);
376 /* We're authenticated and have a target extension */
377 if (!ast_strlen_zero(args.cid)) {
378 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
379 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
380 }
381
382 if (!ast_strlen_zero(acctcode)) {
383 ast_channel_lock(chan);
384 ast_channel_accountcode_set(chan, acctcode);
385 ast_channel_unlock(chan);
386 }
387
388 if (ast_pbx_exec_application(chan, "ResetCDR", special_noanswer ? "" : "e")) {
389 ast_log(AST_LOG_NOTICE, "ResetCDR application not found; CDR will not be reset\n");
390 }
391 ast_explicit_goto(chan, args.context, exten, 1);
392 return 0;
393 }
394 }
395
396 /* Received invalid, but no "i" extension exists in the given context */
397
398reorder:
399 /* Play congestion for a bit */
401 ast_safe_sleep(chan, 10*1000);
402
403 ast_playtones_stop(chan);
404
405 return -1;
406}
407
408static int unload_module(void)
409{
411}
412
413static int load_module(void)
414{
417}
418
419AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");
static const char app[]
Definition: app_disa.c:116
static int disa_exec(struct ast_channel *chan, const char *data)
Definition: app_disa.c:146
static const struct ast_app_option app_opts[128]
Definition: app_disa.c:126
static void play_dialtone(struct ast_channel *chan, char *mailbox)
Definition: app_disa.c:128
static int load_module(void)
Definition: app_disa.c:413
static int unload_module(void)
Definition: app_disa.c:408
@ NOANSWER_FLAG
Definition: app_disa.c:119
@ POUND_TO_END_FLAG
Definition: app_disa.c:120
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1193
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11034
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
Definition: channel.c:7582
#define ast_channel_lock(chan)
Definition: channel.h:2922
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3162
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4257
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7334
struct ast_tone_zone * ast_channel_zone(const struct ast_channel *chan)
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11027
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1007
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2805
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4277
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1574
#define ast_channel_unlock(chan)
Definition: channel.h:2923
#define AST_MAX_EXTENSION
Definition: channel.h:134
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
Generic File Format Support. Should be included by clients of the file handling routines....
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
Definition: main/app.c:582
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3056
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_HANGUP
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LOG_NOTICE
#define LOG_WARNING
Tone Indication Support.
static struct ast_tone_zone_sound * ast_tone_zone_sound_unref(struct ast_tone_zone_sound *ts)
Release a reference to an ast_tone_zone_sound.
Definition: indications.h:227
int ast_playtones_start(struct ast_channel *chan, int vol, const char *tonelist, int interruptible)
Start playing a list of tones on a channel.
Definition: indications.c:302
void ast_playtones_stop(struct ast_channel *chan)
Stop playing tones on a channel.
Definition: indications.c:393
struct ast_tone_zone_sound * ast_get_indication_tone(const struct ast_tone_zone *zone, const char *indication)
Locate a tone zone sound.
Definition: indications.c:461
Asterisk locking-related definitions:
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
Core PBX routines and definitions.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
int ast_pbx_exec_application(struct ast_channel *chan, const char *app_name, const char *app_args)
Execute an application.
Definition: pbx_app.c:501
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:6945
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:6879
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks to see if adding anything to this extension might match something. (exists ^ canmatch)
Definition: pbx.c:4195
#define NULL
Definition: resample.c:96
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Main Channel structure associated with a channel.
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
union ast_frame::@226 data
enum ast_frame_type frametype
int rtimeoutms
Definition: pbx.h:216
int dtimeoutms
Definition: pbx.h:215
Description of a tone.
Definition: indications.h:35
const char * data
Description of a tone.
Definition: indications.h:52
Number structure.
Definition: app_followme.c:154
const char * args
static struct test_options options
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Support for translation of data formats. translate.c.
u-Law to Signed linear conversion
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define AST_FLAGS_ALL
Definition: utils.h:196