Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
54 <version>0.1.9</version>
55 </since>
56 <synopsis>
57 Direct Inward System Access.
58 </synopsis>
59 <syntax>
60 <parameter name="passcode|filename" required="true">
61 <para>If you need to present a DISA dialtone without entering a password,
62 simply set <replaceable>passcode</replaceable> to <literal>no-password</literal></para>
63 <para>You may specified a <replaceable>filename</replaceable> instead of a
64 <replaceable>passcode</replaceable>, this filename must contain individual passcodes</para>
65 </parameter>
66 <parameter name="context">
67 <para>Specifies the dialplan context in which the user-entered extension
68 will be matched. If no context is specified, the DISA application defaults
69 to the <literal>disa</literal> context. Presumably a normal system will have a special
70 context set up for DISA use with some or a lot of restrictions.</para>
71 </parameter>
72 <parameter name="cid">
73 <para>Specifies a new (different) callerid to be used for this call.</para>
74 </parameter>
75 <parameter name="mailbox" argsep="@">
76 <para>Will cause a stutter-dialtone (indication <emphasis>dialrecall</emphasis>)
77 to be used, if the specified mailbox contains any new messages.</para>
78 <argument name="mailbox" required="true" />
79 <argument name="context" required="false" />
80 </parameter>
81 <parameter name="options">
82 <optionlist>
83 <option name="n">
84 <para>The DISA application will not answer initially.</para>
85 </option>
86 <option name="p">
87 <para>The extension entered will be considered complete when a <literal>#</literal>
88 is entered.</para>
89 </option>
90 </optionlist>
91 </parameter>
92 </syntax>
93 <description>
94 <para>The DISA, Direct Inward System Access, application allows someone from
95 outside the telephone switch (PBX) to obtain an <emphasis>internal</emphasis> system
96 dialtone and to place calls from it as if they were placing a call from
97 within the switch.
98 DISA plays a dialtone. The user enters their numeric passcode, followed by
99 the pound sign <literal>#</literal>. If the passcode is correct, the user is then given
100 system dialtone within <replaceable>context</replaceable> on which a call may be placed.
101 If the user enters an invalid extension and extension <literal>i</literal> exists in the specified
102 <replaceable>context</replaceable>, it will be used.
103 </para>
104 <para>Be aware that using this may compromise the security of your PBX.</para>
105 <para>The arguments to this application (in <filename>extensions.conf</filename>) allow either
106 specification of a single global <replaceable>passcode</replaceable> (that everyone uses), or
107 individual passcodes contained in a file (<replaceable>filename</replaceable>).</para>
108 <para>The file that contains the passcodes (if used) allows a complete
109 specification of all of the same arguments available on the command
110 line, with the sole exception of the options. The file may contain blank
111 lines, or comments starting with <literal>#</literal> or <literal>;</literal>.</para>
112 </description>
113 <see-also>
114 <ref type="application">Authenticate</ref>
115 <ref type="application">VMAuthenticate</ref>
116 </see-also>
117 </application>
118 ***/
119static const char app[] = "DISA";
120
121enum {
122 NOANSWER_FLAG = (1 << 0),
124};
125
129});
130
131static void play_dialtone(struct ast_channel *chan, char *mailbox)
132{
133 struct ast_tone_zone_sound *ts = NULL;
134
136 ts = ast_get_indication_tone(ast_channel_zone(chan), "dialrecall");
137 } else {
138 ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
139 }
140
141 if (ts) {
142 ast_playtones_start(chan, 0, ts->data, 0);
144 } else {
145 ast_tonepair_start(chan, 350, 440, 0, 0);
146 }
147}
148
149static int disa_exec(struct ast_channel *chan, const char *data)
150{
151 int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
152 int firstdigittimeout = (ast_channel_pbx(chan) ? ast_channel_pbx(chan)->rtimeoutms : 20000);
153 int digittimeout = (ast_channel_pbx(chan) ? ast_channel_pbx(chan)->dtimeoutms : 10000);
154 struct ast_flags flags;
155 char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
156 char pwline[256];
157 char ourcidname[256],ourcidnum[256];
158 struct ast_frame *f;
159 struct timeval lastdigittime;
160 int res;
161 FILE *fp;
163 AST_APP_ARG(passcode);
165 AST_APP_ARG(cid);
168 );
169
170 if (ast_strlen_zero(data)) {
171 ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
172 return -1;
173 }
174
175 ast_debug(1, "Digittimeout: %d\n", digittimeout);
176 ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);
177
178 tmp = ast_strdupa(data);
179
181
182 if (ast_strlen_zero(args.context))
183 args.context = "disa";
184 if (ast_strlen_zero(args.mailbox))
185 args.mailbox = "";
186 if (!ast_strlen_zero(args.options)) {
187 ast_app_parse_options(app_opts, &flags, NULL, args.options);
188 } else {
189 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
191 }
192
193
194 ast_debug(1, "Mailbox: %s\n",args.mailbox);
195
196 if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
197 if (ast_channel_state(chan) != AST_STATE_UP) {
198 /* answer */
199 ast_answer(chan);
200 }
201 } else special_noanswer = 1;
202
203 ast_debug(1, "Context: %s\n",args.context);
204
205 if (!strcasecmp(args.passcode, "no-password")) {
206 k |= 1; /* We have the password */
207 ast_debug(1, "DISA no-password login success\n");
208 }
209
210 lastdigittime = ast_tvnow();
211
212 play_dialtone(chan, args.mailbox);
213
215
216 for (;;) {
217 /* if outa time, give em reorder */
218 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
219 ast_debug(1,"DISA %s entry timeout on chan %s\n",
220 ((k&1) ? "extension" : "password"),ast_channel_name(chan));
221 break;
222 }
223
224 if ((res = ast_waitfor(chan, -1)) < 0) {
225 ast_debug(1, "Waitfor returned %d\n", res);
226 continue;
227 }
228
229 if (!(f = ast_read(chan))) {
231 return -1;
232 }
233
235 if (f->data.uint32)
237 ast_frfree(f);
239 return -1;
240 }
241
242 /* If the frame coming in is not DTMF, just drop it and continue */
243 if (f->frametype != AST_FRAME_DTMF) {
244 ast_frfree(f);
245 continue;
246 }
247
248 j = f->subclass.integer; /* save digit */
249 ast_frfree(f);
250
251 if (!i) {
252 k |= 2; /* We have the first digit */
253 ast_playtones_stop(chan);
254 }
255
256 lastdigittime = ast_tvnow();
257
258 /* got a DTMF tone */
259 if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
260 if (!(k&1)) { /* if in password state */
261 if (j == '#') { /* end of password */
262 /* see if this is an integer */
263 if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
264 fp = fopen(args.passcode,"r");
265 if (!fp) {
266 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,ast_channel_name(chan));
268 return -1;
269 }
270 pwline[0] = 0;
271 while(fgets(pwline,sizeof(pwline) - 1,fp)) {
272 if (!pwline[0])
273 continue;
274 if (pwline[strlen(pwline) - 1] == '\n')
275 pwline[strlen(pwline) - 1] = 0;
276 if (!pwline[0])
277 continue;
278 /* skip comments */
279 if (pwline[0] == '#')
280 continue;
281 if (pwline[0] == ';')
282 continue;
283
285
286 ast_debug(1, "Mailbox: %s\n",args.mailbox);
287
288 /* password must be in valid format (numeric) */
289 if (sscanf(args.passcode,"%30d", &j) < 1)
290 continue;
291 /* if we got it */
292 if (!strcmp(exten,args.passcode)) {
293 if (ast_strlen_zero(args.context))
294 args.context = "disa";
295 if (ast_strlen_zero(args.mailbox))
296 args.mailbox = "";
297 break;
298 }
299 }
300 fclose(fp);
301 }
302 /* compare the two */
303 if (strcmp(exten,args.passcode)) {
304 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",ast_channel_name(chan),exten);
305 goto reorder;
306
307 }
308 /* password good, set to dial state */
309 ast_debug(1,"DISA on chan %s password is good\n",ast_channel_name(chan));
310 play_dialtone(chan, args.mailbox);
311
312 k|=1; /* In number mode */
313 i = 0; /* re-set buffer pointer */
314 exten[sizeof(acctcode)] = 0;
315 ast_copy_string(acctcode, exten, sizeof(acctcode));
316 exten[0] = 0;
317 ast_debug(1,"Successful DISA log-in on chan %s\n", ast_channel_name(chan));
318 continue;
319 }
320 } else {
321 if (j == '#') { /* end of extension .. maybe */
322 if (i == 0
323 && (ast_matchmore_extension(chan, args.context, "#", 1,
324 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
325 || ast_exists_extension(chan, args.context, "#", 1,
326 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) ) {
327 /* Let the # be the part of, or the entire extension */
328 } else {
329 break;
330 }
331 }
332 }
333
334 exten[i++] = j; /* save digit */
335 exten[i] = 0;
336 if (!(k&1))
337 continue; /* if getting password, continue doing it */
338 /* if this exists */
339
340 /* user wants end of number, remove # */
341 if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
342 exten[--i] = 0;
343 break;
344 }
345
346 if (ast_ignore_pattern(args.context, exten)) {
347 play_dialtone(chan, "");
348 did_ignore = 1;
349 } else
350 if (did_ignore) {
351 ast_playtones_stop(chan);
352 did_ignore = 0;
353 }
354
355 /* if can do some more, do it */
356 if (!ast_matchmore_extension(chan, args.context, exten, 1,
357 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
358 break;
359 }
360 }
361 }
362
364
365 if (k == 3) {
366 int recheck = 0;
367
368 if (!ast_exists_extension(chan, args.context, exten, 1,
369 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
370 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
371 exten[0] = 'i';
372 exten[1] = '\0';
373 recheck = 1;
374 }
375 if (!recheck
376 || ast_exists_extension(chan, args.context, exten, 1,
377 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
378 ast_playtones_stop(chan);
379 /* We're authenticated and have a target extension */
380 if (!ast_strlen_zero(args.cid)) {
381 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
382 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
383 }
384
385 if (!ast_strlen_zero(acctcode)) {
386 ast_channel_lock(chan);
387 ast_channel_accountcode_set(chan, acctcode);
388 ast_channel_unlock(chan);
389 }
390
391 if (ast_pbx_exec_application(chan, "ResetCDR", special_noanswer ? "" : "e")) {
392 ast_log(AST_LOG_NOTICE, "ResetCDR application not found; CDR will not be reset\n");
393 }
394 ast_explicit_goto(chan, args.context, exten, 1);
395 return 0;
396 }
397 }
398
399 /* Received invalid, but no "i" extension exists in the given context */
400
401reorder:
402 /* Play congestion for a bit */
404 ast_safe_sleep(chan, 10*1000);
405
406 ast_playtones_stop(chan);
407
408 return -1;
409}
410
411static int unload_module(void)
412{
414}
415
416static int load_module(void)
417{
420}
421
422AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");
static const char app[]
Definition: app_disa.c:119
static int disa_exec(struct ast_channel *chan, const char *data)
Definition: app_disa.c:149
static const struct ast_app_option app_opts[128]
Definition: app_disa.c:129
static void play_dialtone(struct ast_channel *chan, char *mailbox)
Definition: app_disa.c:131
static int load_module(void)
Definition: app_disa.c:416
static int unload_module(void)
Definition: app_disa.c:411
@ NOANSWER_FLAG
Definition: app_disa.c:122
@ POUND_TO_END_FLAG
Definition: app_disa.c:123
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
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:1292
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:11060
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
Definition: channel.c:7603
#define ast_channel_lock(chan)
Definition: channel.h:2970
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3190
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4274
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:7355
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:11053
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1027
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:2834
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4294
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1601
#define ast_channel_unlock(chan)
Definition: channel.h:2971
#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:3066
#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:581
#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:640
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:4190
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:6960
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:6894
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:4210
#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.
union ast_frame::@228 data
struct ast_frame_subclass subclass
enum ast_frame_type frametype
int rtimeoutms
Definition: pbx.h:217
int dtimeoutms
Definition: pbx.h:216
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:157
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