#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 | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
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 struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "DISA (Direct Inward System Access) Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static const char | app [] = "DISA" |
static struct ast_app_option | app_opts [128] = { [ 'n' ] = { .flag = NOANSWER_FLAG }, [ 'p' ] = { .flag = POUND_TO_END_FLAG },} |
static struct ast_module_info * | ast_module_info = &__mod_info |
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 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 417 of file app_disa.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 417 of file app_disa.c.
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, app_opts, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, AST_CONTROL_HANGUP, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_END_DTMF_ONLY, AST_FLAGS_ALL, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree, ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), AST_MAX_EXTENSION, ast_playtones_stop(), ast_read(), ast_set_flag, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), ast_channel::caller, context, ast_pbx::dtimeoutms, exten, f, firstdigittimeout, ast_flags::flags, ast_channel::hangupcause, ast_party_caller::id, LOG_WARNING, mailbox, ast_channel::name, NOANSWER_FLAG, ast_party_id::number, ast_channel::pbx, play_dialtone(), POUND_TO_END_FLAG, ast_pbx::rtimeoutms, S_COR, ast_party_number::str, 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 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "DISA (Direct Inward System Access) Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 417 of file app_disa.c.
const char app[] = "DISA" [static] |
Definition at line 117 of file app_disa.c.
struct ast_app_option app_opts[128] = { [ 'n' ] = { .flag = NOANSWER_FLAG }, [ 'p' ] = { .flag = POUND_TO_END_FLAG },} [static] |
Definition at line 127 of file app_disa.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 417 of file app_disa.c.