DISA -- Direct Inward System Access Application. More...
#include "asterisk.h"
#include <math.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/app.h"
#include "asterisk/indications.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/callerid.h"
#include "asterisk/stringfields.h"
Go to the source code of this file.
Enumerations | |
enum | { NOANSWER_FLAG = (1 << 0), POUND_TO_END_FLAG = (1 << 1) } |
Functions | |
AST_APP_OPTIONS (app_opts,{AST_APP_OPTION('n', NOANSWER_FLAG), AST_APP_OPTION('p', POUND_TO_END_FLAG),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"DISA (Direct Inward System Access) Application") | |
static int | disa_exec (struct ast_channel *chan, const char *data) |
static int | load_module (void) |
static void | play_dialtone (struct ast_channel *chan, char *mailbox) |
static int | unload_module (void) |
Variables | |
static const char | app [] = "DISA" |
DISA -- Direct Inward System Access Application.
Definition in file app_disa.c.
anonymous enum |
Definition at line 119 of file app_disa.c.
00119 { 00120 NOANSWER_FLAG = (1 << 0), 00121 POUND_TO_END_FLAG = (1 << 1), 00122 };
AST_APP_OPTIONS | ( | app_opts | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"DISA (Direct Inward System Access) Application" | ||||
) |
static int disa_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 147 of file app_disa.c.
References ast_channel::_state, accountcode, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_callerid_split(), AST_CDR_FLAG_POSTED, ast_cdr_reset(), ast_clear_flag, AST_CONTROL_CONGESTION, AST_CONTROL_HANGUP, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), ast_explicit_goto(), AST_FLAG_END_DTMF_ONLY, AST_FLAGS_ALL, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_ignore_pattern(), ast_indicate(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_playtones_stop(), ast_read(), ast_safe_sleep(), ast_set_callerid(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_channel::caller, ast_channel::cdr, context, ast_frame::data, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_frame::frametype, ast_channel::hangupcause, ast_party_caller::id, ast_frame_subclass::integer, LOG_WARNING, mailbox, NOANSWER_FLAG, ast_party_id::number, ast_channel::pbx, pbx_builtin_setvar_helper(), play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, S_COR, ast_party_number::str, ast_frame::subclass, ast_frame::uint32, and ast_party_number::valid.
Referenced by load_module().
00148 { 00149 int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0; 00150 int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000); 00151 int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000); 00152 struct ast_flags flags; 00153 char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]=""; 00154 char pwline[256]; 00155 char ourcidname[256],ourcidnum[256]; 00156 struct ast_frame *f; 00157 struct timeval lastdigittime; 00158 int res; 00159 FILE *fp; 00160 AST_DECLARE_APP_ARGS(args, 00161 AST_APP_ARG(passcode); 00162 AST_APP_ARG(context); 00163 AST_APP_ARG(cid); 00164 AST_APP_ARG(mailbox); 00165 AST_APP_ARG(options); 00166 ); 00167 00168 if (ast_strlen_zero(data)) { 00169 ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n"); 00170 return -1; 00171 } 00172 00173 ast_debug(1, "Digittimeout: %d\n", digittimeout); 00174 ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout); 00175 00176 tmp = ast_strdupa(data); 00177 00178 AST_STANDARD_APP_ARGS(args, tmp); 00179 00180 if (ast_strlen_zero(args.context)) 00181 args.context = "disa"; 00182 if (ast_strlen_zero(args.mailbox)) 00183 args.mailbox = ""; 00184 if (!ast_strlen_zero(args.options)) { 00185 ast_app_parse_options(app_opts, &flags, NULL, args.options); 00186 } else { 00187 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 00188 ast_clear_flag(&flags, AST_FLAGS_ALL); 00189 } 00190 00191 00192 ast_debug(1, "Mailbox: %s\n",args.mailbox); 00193 00194 if (!ast_test_flag(&flags, NOANSWER_FLAG)) { 00195 if (chan->_state != AST_STATE_UP) { 00196 /* answer */ 00197 ast_answer(chan); 00198 } 00199 } else special_noanswer = 1; 00200 00201 ast_debug(1, "Context: %s\n",args.context); 00202 00203 if (!strcasecmp(args.passcode, "no-password")) { 00204 k |= 1; /* We have the password */ 00205 ast_debug(1, "DISA no-password login success\n"); 00206 } 00207 00208 lastdigittime = ast_tvnow(); 00209 00210 play_dialtone(chan, args.mailbox); 00211 00212 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00213 00214 for (;;) { 00215 /* if outa time, give em reorder */ 00216 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) { 00217 ast_debug(1,"DISA %s entry timeout on chan %s\n", 00218 ((k&1) ? "extension" : "password"),chan->name); 00219 break; 00220 } 00221 00222 if ((res = ast_waitfor(chan, -1) < 0)) { 00223 ast_debug(1, "Waitfor returned %d\n", res); 00224 continue; 00225 } 00226 00227 if (!(f = ast_read(chan))) { 00228 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00229 return -1; 00230 } 00231 00232 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) { 00233 if (f->data.uint32) 00234 chan->hangupcause = f->data.uint32; 00235 ast_frfree(f); 00236 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00237 return -1; 00238 } 00239 00240 /* If the frame coming in is not DTMF, just drop it and continue */ 00241 if (f->frametype != AST_FRAME_DTMF) { 00242 ast_frfree(f); 00243 continue; 00244 } 00245 00246 j = f->subclass.integer; /* save digit */ 00247 ast_frfree(f); 00248 00249 if (!i) { 00250 k |= 2; /* We have the first digit */ 00251 ast_playtones_stop(chan); 00252 } 00253 00254 lastdigittime = ast_tvnow(); 00255 00256 /* got a DTMF tone */ 00257 if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */ 00258 if (!(k&1)) { /* if in password state */ 00259 if (j == '#') { /* end of password */ 00260 /* see if this is an integer */ 00261 if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */ 00262 fp = fopen(args.passcode,"r"); 00263 if (!fp) { 00264 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name); 00265 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00266 return -1; 00267 } 00268 pwline[0] = 0; 00269 while(fgets(pwline,sizeof(pwline) - 1,fp)) { 00270 if (!pwline[0]) 00271 continue; 00272 if (pwline[strlen(pwline) - 1] == '\n') 00273 pwline[strlen(pwline) - 1] = 0; 00274 if (!pwline[0]) 00275 continue; 00276 /* skip comments */ 00277 if (pwline[0] == '#') 00278 continue; 00279 if (pwline[0] == ';') 00280 continue; 00281 00282 AST_STANDARD_APP_ARGS(args, pwline); 00283 00284 ast_debug(1, "Mailbox: %s\n",args.mailbox); 00285 00286 /* password must be in valid format (numeric) */ 00287 if (sscanf(args.passcode,"%30d", &j) < 1) 00288 continue; 00289 /* if we got it */ 00290 if (!strcmp(exten,args.passcode)) { 00291 if (ast_strlen_zero(args.context)) 00292 args.context = "disa"; 00293 if (ast_strlen_zero(args.mailbox)) 00294 args.mailbox = ""; 00295 break; 00296 } 00297 } 00298 fclose(fp); 00299 } 00300 /* compare the two */ 00301 if (strcmp(exten,args.passcode)) { 00302 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten); 00303 goto reorder; 00304 00305 } 00306 /* password good, set to dial state */ 00307 ast_debug(1,"DISA on chan %s password is good\n",chan->name); 00308 play_dialtone(chan, args.mailbox); 00309 00310 k|=1; /* In number mode */ 00311 i = 0; /* re-set buffer pointer */ 00312 exten[sizeof(acctcode)] = 0; 00313 ast_copy_string(acctcode, exten, sizeof(acctcode)); 00314 exten[0] = 0; 00315 ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name); 00316 continue; 00317 } 00318 } else { 00319 if (j == '#') { /* end of extension .. maybe */ 00320 if (i == 0 00321 && (ast_matchmore_extension(chan, args.context, "#", 1, 00322 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)) 00323 || ast_exists_extension(chan, args.context, "#", 1, 00324 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) ) { 00325 /* Let the # be the part of, or the entire extension */ 00326 } else { 00327 break; 00328 } 00329 } 00330 } 00331 00332 exten[i++] = j; /* save digit */ 00333 exten[i] = 0; 00334 if (!(k&1)) 00335 continue; /* if getting password, continue doing it */ 00336 /* if this exists */ 00337 00338 /* user wants end of number, remove # */ 00339 if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') { 00340 exten[--i] = 0; 00341 break; 00342 } 00343 00344 if (ast_ignore_pattern(args.context, exten)) { 00345 play_dialtone(chan, ""); 00346 did_ignore = 1; 00347 } else 00348 if (did_ignore) { 00349 ast_playtones_stop(chan); 00350 did_ignore = 0; 00351 } 00352 00353 /* if can do some more, do it */ 00354 if (!ast_matchmore_extension(chan, args.context, exten, 1, 00355 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00356 break; 00357 } 00358 } 00359 } 00360 00361 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00362 00363 if (k == 3) { 00364 int recheck = 0; 00365 struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED }; 00366 00367 if (!ast_exists_extension(chan, args.context, exten, 1, 00368 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00369 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten); 00370 exten[0] = 'i'; 00371 exten[1] = '\0'; 00372 recheck = 1; 00373 } 00374 if (!recheck 00375 || ast_exists_extension(chan, args.context, exten, 1, 00376 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00377 ast_playtones_stop(chan); 00378 /* We're authenticated and have a target extension */ 00379 if (!ast_strlen_zero(args.cid)) { 00380 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum)); 00381 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum); 00382 } 00383 00384 if (!ast_strlen_zero(acctcode)) 00385 ast_string_field_set(chan, accountcode, acctcode); 00386 00387 if (special_noanswer) cdr_flags.flags = 0; 00388 ast_cdr_reset(chan->cdr, &cdr_flags); 00389 ast_explicit_goto(chan, args.context, exten, 1); 00390 return 0; 00391 } 00392 } 00393 00394 /* Received invalid, but no "i" extension exists in the given context */ 00395 00396 reorder: 00397 /* Play congestion for a bit */ 00398 ast_indicate(chan, AST_CONTROL_CONGESTION); 00399 ast_safe_sleep(chan, 10*1000); 00400 00401 ast_playtones_stop(chan); 00402 00403 return -1; 00404 }
static int load_module | ( | void | ) | [static] |
Definition at line 411 of file app_disa.c.
References AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, and disa_exec().
00412 { 00413 return ast_register_application_xml(app, disa_exec) ? 00414 AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS; 00415 }
static void play_dialtone | ( | struct ast_channel * | chan, | |
char * | mailbox | |||
) | [static] |
Definition at line 129 of file app_disa.c.
References ast_app_has_voicemail(), ast_get_indication_tone(), ast_playtones_start(), ast_tone_zone_sound_unref(), ast_tonepair_start(), ast_tone_zone_sound::data, and ast_channel::zone.
Referenced by disa_exec().
00130 { 00131 struct ast_tone_zone_sound *ts = NULL; 00132 00133 if (ast_app_has_voicemail(mailbox, NULL)) { 00134 ts = ast_get_indication_tone(chan->zone, "dialrecall"); 00135 } else { 00136 ts = ast_get_indication_tone(chan->zone, "dial"); 00137 } 00138 00139 if (ts) { 00140 ast_playtones_start(chan, 0, ts->data, 0); 00141 ts = ast_tone_zone_sound_unref(ts); 00142 } else { 00143 ast_tonepair_start(chan, 350, 440, 0, 0); 00144 } 00145 }
static int unload_module | ( | void | ) | [static] |
Definition at line 406 of file app_disa.c.
References ast_unregister_application().
00407 { 00408 return ast_unregister_application(app); 00409 }
const char app[] = "DISA" [static] |
Definition at line 117 of file app_disa.c.