Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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  <support_level>core</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 366048 $")
36 
37 #include <math.h>
38 #include <sys/time.h>
39 
40 #include "asterisk/lock.h"
41 #include "asterisk/file.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/app.h"
44 #include "asterisk/indications.h"
45 #include "asterisk/pbx.h"
46 #include "asterisk/module.h"
47 #include "asterisk/translate.h"
48 #include "asterisk/ulaw.h"
49 #include "asterisk/callerid.h"
50 #include "asterisk/stringfields.h"
51 
52 /*** DOCUMENTATION
53  <application name="DISA" language="en_US">
54  <synopsis>
55  Direct Inward System Access.
56  </synopsis>
57  <syntax>
58  <parameter name="passcode|filename" required="true">
59  <para>If you need to present a DISA dialtone without entering a password,
60  simply set <replaceable>passcode</replaceable> to <literal>no-password</literal></para>
61  <para>You may specified a <replaceable>filename</replaceable> instead of a
62  <replaceable>passcode</replaceable>, this filename must contain individual passcodes</para>
63  </parameter>
64  <parameter name="context">
65  <para>Specifies the dialplan context in which the user-entered extension
66  will be matched. If no context is specified, the DISA application defaults
67  to the <literal>disa</literal> context. Presumably a normal system will have a special
68  context set up for DISA use with some or a lot of restrictions.</para>
69  </parameter>
70  <parameter name="cid">
71  <para>Specifies a new (different) callerid to be used for this call.</para>
72  </parameter>
73  <parameter name="mailbox" argsep="@">
74  <para>Will cause a stutter-dialtone (indication <emphasis>dialrecall</emphasis>)
75  to be used, if the specified mailbox contains any new messages.</para>
76  <argument name="mailbox" required="true" />
77  <argument name="context" required="false" />
78  </parameter>
79  <parameter name="options">
80  <optionlist>
81  <option name="n">
82  <para>The DISA application will not answer initially.</para>
83  </option>
84  <option name="p">
85  <para>The extension entered will be considered complete when a <literal>#</literal>
86  is entered.</para>
87  </option>
88  </optionlist>
89  </parameter>
90  </syntax>
91  <description>
92  <para>The DISA, Direct Inward System Access, application allows someone from
93  outside the telephone switch (PBX) to obtain an <emphasis>internal</emphasis> system
94  dialtone and to place calls from it as if they were placing a call from
95  within the switch.
96  DISA plays a dialtone. The user enters their numeric passcode, followed by
97  the pound sign <literal>#</literal>. If the passcode is correct, the user is then given
98  system dialtone within <replaceable>context</replaceable> on which a call may be placed.
99  If the user enters an invalid extension and extension <literal>i</literal> exists in the specified
100  <replaceable>context</replaceable>, it will be used.
101  </para>
102  <para>Be aware that using this may compromise the security of your PBX.</para>
103  <para>The arguments to this application (in <filename>extensions.conf</filename>) allow either
104  specification of a single global <replaceable>passcode</replaceable> (that everyone uses), or
105  individual passcodes contained in a file (<replaceable>filename</replaceable>).</para>
106  <para>The file that contains the passcodes (if used) allows a complete
107  specification of all of the same arguments available on the command
108  line, with the sole exception of the options. The file may contain blank
109  lines, or comments starting with <literal>#</literal> or <literal>;</literal>.</para>
110  </description>
111  <see-also>
112  <ref type="application">Authenticate</ref>
113  <ref type="application">VMAuthenticate</ref>
114  </see-also>
115  </application>
116  ***/
117 static const char app[] = "DISA";
118 
119 enum {
120  NOANSWER_FLAG = (1 << 0),
121  POUND_TO_END_FLAG = (1 << 1),
122 };
123 
127 });
128 
129 static void play_dialtone(struct ast_channel *chan, char *mailbox)
130 {
131  struct ast_tone_zone_sound *ts = NULL;
132 
133  if (ast_app_has_voicemail(mailbox, NULL)) {
134  ts = ast_get_indication_tone(chan->zone, "dialrecall");
135  } else {
136  ts = ast_get_indication_tone(chan->zone, "dial");
137  }
138 
139  if (ts) {
140  ast_playtones_start(chan, 0, ts->data, 0);
141  ts = ast_tone_zone_sound_unref(ts);
142  } else {
143  ast_tonepair_start(chan, 350, 440, 0, 0);
144  }
145 }
146 
147 static int disa_exec(struct ast_channel *chan, const char *data)
148 {
149  int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
150  int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
151  int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000);
152  struct ast_flags flags;
153  char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
154  char pwline[256];
155  char ourcidname[256],ourcidnum[256];
156  struct ast_frame *f;
157  struct timeval lastdigittime;
158  int res;
159  FILE *fp;
161  AST_APP_ARG(passcode);
163  AST_APP_ARG(cid);
165  AST_APP_ARG(options);
166  );
167 
168  if (ast_strlen_zero(data)) {
169  ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
170  return -1;
171  }
172 
173  ast_debug(1, "Digittimeout: %d\n", digittimeout);
174  ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);
175 
176  tmp = ast_strdupa(data);
177 
179 
180  if (ast_strlen_zero(args.context))
181  args.context = "disa";
182  if (ast_strlen_zero(args.mailbox))
183  args.mailbox = "";
184  if (!ast_strlen_zero(args.options)) {
185  ast_app_parse_options(app_opts, &flags, NULL, args.options);
186  } else {
187  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
188  ast_clear_flag(&flags, AST_FLAGS_ALL);
189  }
190 
191 
192  ast_debug(1, "Mailbox: %s\n",args.mailbox);
193 
194  if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
195  if (chan->_state != AST_STATE_UP) {
196  /* answer */
197  ast_answer(chan);
198  }
199  } else special_noanswer = 1;
200 
201  ast_debug(1, "Context: %s\n",args.context);
202 
203  if (!strcasecmp(args.passcode, "no-password")) {
204  k |= 1; /* We have the password */
205  ast_debug(1, "DISA no-password login success\n");
206  }
207 
208  lastdigittime = ast_tvnow();
209 
210  play_dialtone(chan, args.mailbox);
211 
213 
214  for (;;) {
215  /* if outa time, give em reorder */
216  if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
217  ast_debug(1,"DISA %s entry timeout on chan %s\n",
218  ((k&1) ? "extension" : "password"),chan->name);
219  break;
220  }
221 
222  if ((res = ast_waitfor(chan, -1) < 0)) {
223  ast_debug(1, "Waitfor returned %d\n", res);
224  continue;
225  }
226 
227  if (!(f = ast_read(chan))) {
229  return -1;
230  }
231 
233  if (f->data.uint32)
234  chan->hangupcause = f->data.uint32;
235  ast_frfree(f);
237  return -1;
238  }
239 
240  /* If the frame coming in is not DTMF, just drop it and continue */
241  if (f->frametype != AST_FRAME_DTMF) {
242  ast_frfree(f);
243  continue;
244  }
245 
246  j = f->subclass.integer; /* save digit */
247  ast_frfree(f);
248 
249  if (!i) {
250  k |= 2; /* We have the first digit */
251  ast_playtones_stop(chan);
252  }
253 
254  lastdigittime = ast_tvnow();
255 
256  /* got a DTMF tone */
257  if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
258  if (!(k&1)) { /* if in password state */
259  if (j == '#') { /* end of password */
260  /* see if this is an integer */
261  if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
262  fp = fopen(args.passcode,"r");
263  if (!fp) {
264  ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
266  return -1;
267  }
268  pwline[0] = 0;
269  while(fgets(pwline,sizeof(pwline) - 1,fp)) {
270  if (!pwline[0])
271  continue;
272  if (pwline[strlen(pwline) - 1] == '\n')
273  pwline[strlen(pwline) - 1] = 0;
274  if (!pwline[0])
275  continue;
276  /* skip comments */
277  if (pwline[0] == '#')
278  continue;
279  if (pwline[0] == ';')
280  continue;
281 
282  AST_STANDARD_APP_ARGS(args, pwline);
283 
284  ast_debug(1, "Mailbox: %s\n",args.mailbox);
285 
286  /* password must be in valid format (numeric) */
287  if (sscanf(args.passcode,"%30d", &j) < 1)
288  continue;
289  /* if we got it */
290  if (!strcmp(exten,args.passcode)) {
291  if (ast_strlen_zero(args.context))
292  args.context = "disa";
293  if (ast_strlen_zero(args.mailbox))
294  args.mailbox = "";
295  break;
296  }
297  }
298  fclose(fp);
299  }
300  /* compare the two */
301  if (strcmp(exten,args.passcode)) {
302  ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
303  goto reorder;
304 
305  }
306  /* password good, set to dial state */
307  ast_debug(1,"DISA on chan %s password is good\n",chan->name);
308  play_dialtone(chan, args.mailbox);
309 
310  k|=1; /* In number mode */
311  i = 0; /* re-set buffer pointer */
312  exten[sizeof(acctcode)] = 0;
313  ast_copy_string(acctcode, exten, sizeof(acctcode));
314  exten[0] = 0;
315  ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name);
316  continue;
317  }
318  } else {
319  if (j == '#') { /* end of extension .. maybe */
320  if (i == 0
321  && (ast_matchmore_extension(chan, args.context, "#", 1,
322  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
323  || ast_exists_extension(chan, args.context, "#", 1,
324  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) ) {
325  /* Let the # be the part of, or the entire extension */
326  } else {
327  break;
328  }
329  }
330  }
331 
332  exten[i++] = j; /* save digit */
333  exten[i] = 0;
334  if (!(k&1))
335  continue; /* if getting password, continue doing it */
336  /* if this exists */
337 
338  /* user wants end of number, remove # */
339  if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
340  exten[--i] = 0;
341  break;
342  }
343 
344  if (ast_ignore_pattern(args.context, exten)) {
345  play_dialtone(chan, "");
346  did_ignore = 1;
347  } else
348  if (did_ignore) {
349  ast_playtones_stop(chan);
350  did_ignore = 0;
351  }
352 
353  /* if can do some more, do it */
354  if (!ast_matchmore_extension(chan, args.context, exten, 1,
355  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
356  break;
357  }
358  }
359  }
360 
362 
363  if (k == 3) {
364  int recheck = 0;
365  struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };
366 
367  if (!ast_exists_extension(chan, args.context, exten, 1,
368  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
369  pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
370  exten[0] = 'i';
371  exten[1] = '\0';
372  recheck = 1;
373  }
374  if (!recheck
375  || ast_exists_extension(chan, args.context, exten, 1,
376  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
377  ast_playtones_stop(chan);
378  /* We're authenticated and have a target extension */
379  if (!ast_strlen_zero(args.cid)) {
380  ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
381  ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
382  }
383 
384  if (!ast_strlen_zero(acctcode))
385  ast_string_field_set(chan, accountcode, acctcode);
386 
387  if (special_noanswer) cdr_flags.flags = 0;
388  ast_cdr_reset(chan->cdr, &cdr_flags);
389  ast_explicit_goto(chan, args.context, exten, 1);
390  return 0;
391  }
392  }
393 
394  /* Received invalid, but no "i" extension exists in the given context */
395 
396 reorder:
397  /* Play congestion for a bit */
399  ast_safe_sleep(chan, 10*1000);
400 
401  ast_playtones_stop(chan);
402 
403  return -1;
404 }
405 
406 static int unload_module(void)
407 {
408  return ast_unregister_application(app);
409 }
410 
411 static int load_module(void)
412 {
415 }
416 
417 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");
static int load_module(void)
Definition: app_disa.c:411
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
union ast_frame_subclass subclass
Definition: frame.h:146
Tone Indication Support.
static char accountcode[AST_MAX_ACCOUNT_CODE]
Definition: chan_iax2.c:383
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:7051
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:5420
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
Definition: app.h:712
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
struct ast_tone_zone * zone
Definition: channel.h:767
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
Definition: callerid.c:1093
static void play_dialtone(struct ast_channel *chan, char *mailbox)
Definition: app_disa.c:129
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_cdr_reset(struct ast_cdr *cdr, struct ast_flags *flags)
Reset the detail record, optionally posting it first.
Definition: cdr.c:1149
#define ast_test_flag(p, flag)
Definition: utils.h:63
Support for translation of data formats. translate.c.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4393
int ast_app_has_voicemail(const char *mailbox, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to &quot;INBOX&quot;. If folder is &quot;INBOX&quot;, includes the number of messages in the &quot;Urgent&quot; folder.
Definition: app.c:421
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
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: app.c:2101
#define AST_FRAME_DTMF
Definition: frame.h:128
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
unsigned int flags
Definition: utils.h:201
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
int ast_ignore_pattern(const char *context, const char *pattern)
Checks to see if a number should be ignored.
Definition: pbx.c:8650
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8708
struct ast_cdr * cdr
Definition: channel.h:766
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
void ast_playtones_stop(struct ast_channel *chan)
Stop playing tones on a channel.
Definition: indications.c:411
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
String fields in structures.
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
u-Law to Signed linear conversion
General Asterisk PBX channel definitions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define AST_MAX_EXTENSION
Definition: channel.h:135
#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:83
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:226
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:5400
static int firstdigittimeout
Wait up to 16 seconds for first digit (FXO logic)
Definition: chan_dahdi.c:449
Core PBX routines and definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static struct @350 args
enum ast_channel_state _state
Definition: channel.h:839
Description of a tone.
Definition: indications.h:36
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:473
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int unload_module(void)
Definition: app_disa.c:406
static struct ast_app_option app_opts[128]
Definition: app_disa.c:127
#define AST_FLAGS_ALL
Definition: utils.h:196
static struct ast_format f[]
Definition: format_g726.c:181
static const char app[]
Definition: app_disa.c:117
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_clear_flag(p, flag)
Definition: utils.h:77
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...
Definition: pbx.c:10546
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
int dtimeoutms
Definition: pbx.h:180
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
Definition: frame.h:142
int hangupcause
Definition: channel.h:849
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:319
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
Definition: channel.c:7951
const char * data
Description of a tone.
Definition: indications.h:53
uint32_t uint32
Definition: frame.h:160
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
enum ast_frame_type frametype
Definition: frame.h:144
static int disa_exec(struct ast_channel *chan, const char *data)
Definition: app_disa.c:147
#define ast_frfree(fr)
Definition: frame.h:583
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
union ast_frame::@172 data
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
Definition: app.h:721
struct ast_pbx * pbx
Definition: channel.h:761
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
int rtimeoutms
Definition: pbx.h:181
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292