00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "asterisk.h"
00034
00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00036
00037 #include <math.h>
00038 #include <sys/time.h>
00039
00040 #include "asterisk/lock.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/indications.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/translate.h"
00048 #include "asterisk/ulaw.h"
00049 #include "asterisk/callerid.h"
00050 #include "asterisk/stringfields.h"
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 static const char app[] = "DISA";
00118
00119 enum {
00120 NOANSWER_FLAG = (1 << 0),
00121 POUND_TO_END_FLAG = (1 << 1),
00122 };
00123
00124 AST_APP_OPTIONS(app_opts, {
00125 AST_APP_OPTION('n', NOANSWER_FLAG),
00126 AST_APP_OPTION('p', POUND_TO_END_FLAG),
00127 });
00128
00129 static void play_dialtone(struct ast_channel *chan, char *mailbox)
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 }
00146
00147 static int disa_exec(struct ast_channel *chan, const char *data)
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
00187 ast_debug(1, "Mailbox: %s\n",args.mailbox);
00188
00189 if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
00190 if (chan->_state != AST_STATE_UP) {
00191
00192 ast_answer(chan);
00193 }
00194 } else special_noanswer = 1;
00195
00196 ast_debug(1, "Context: %s\n",args.context);
00197
00198 if (!strcasecmp(args.passcode, "no-password")) {
00199 k |= 1;
00200 ast_debug(1, "DISA no-password login success\n");
00201 }
00202
00203 lastdigittime = ast_tvnow();
00204
00205 play_dialtone(chan, args.mailbox);
00206
00207 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00208
00209 for (;;) {
00210
00211 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
00212 ast_debug(1,"DISA %s entry timeout on chan %s\n",
00213 ((k&1) ? "extension" : "password"),chan->name);
00214 break;
00215 }
00216
00217 if ((res = ast_waitfor(chan, -1) < 0)) {
00218 ast_debug(1, "Waitfor returned %d\n", res);
00219 continue;
00220 }
00221
00222 if (!(f = ast_read(chan))) {
00223 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00224 return -1;
00225 }
00226
00227 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
00228 if (f->data.uint32)
00229 chan->hangupcause = f->data.uint32;
00230 ast_frfree(f);
00231 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00232 return -1;
00233 }
00234
00235
00236 if (f->frametype != AST_FRAME_DTMF) {
00237 ast_frfree(f);
00238 continue;
00239 }
00240
00241 j = f->subclass.integer;
00242 ast_frfree(f);
00243
00244 if (!i) {
00245 k |= 2;
00246 ast_playtones_stop(chan);
00247 }
00248
00249 lastdigittime = ast_tvnow();
00250
00251
00252 if (i < AST_MAX_EXTENSION) {
00253 if (!(k&1)) {
00254 if (j == '#') {
00255
00256 if (sscanf(args.passcode,"%30d",&j) < 1) {
00257 fp = fopen(args.passcode,"r");
00258 if (!fp) {
00259 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
00260 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00261 return -1;
00262 }
00263 pwline[0] = 0;
00264 while(fgets(pwline,sizeof(pwline) - 1,fp)) {
00265 if (!pwline[0])
00266 continue;
00267 if (pwline[strlen(pwline) - 1] == '\n')
00268 pwline[strlen(pwline) - 1] = 0;
00269 if (!pwline[0])
00270 continue;
00271
00272 if (pwline[0] == '#')
00273 continue;
00274 if (pwline[0] == ';')
00275 continue;
00276
00277 AST_STANDARD_APP_ARGS(args, pwline);
00278
00279 ast_debug(1, "Mailbox: %s\n",args.mailbox);
00280
00281
00282 if (sscanf(args.passcode,"%30d", &j) < 1)
00283 continue;
00284
00285 if (!strcmp(exten,args.passcode)) {
00286 if (ast_strlen_zero(args.context))
00287 args.context = "disa";
00288 if (ast_strlen_zero(args.mailbox))
00289 args.mailbox = "";
00290 break;
00291 }
00292 }
00293 fclose(fp);
00294 }
00295
00296 if (strcmp(exten,args.passcode)) {
00297 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
00298 goto reorder;
00299
00300 }
00301
00302 ast_debug(1,"DISA on chan %s password is good\n",chan->name);
00303 play_dialtone(chan, args.mailbox);
00304
00305 k|=1;
00306 i = 0;
00307 exten[sizeof(acctcode)] = 0;
00308 ast_copy_string(acctcode, exten, sizeof(acctcode));
00309 exten[0] = 0;
00310 ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name);
00311 continue;
00312 }
00313 } else {
00314 if (j == '#') {
00315 if (i == 0
00316 && (ast_matchmore_extension(chan, args.context, "#", 1,
00317 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
00318 || ast_exists_extension(chan, args.context, "#", 1,
00319 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) ) {
00320
00321 } else {
00322 break;
00323 }
00324 }
00325 }
00326
00327 exten[i++] = j;
00328 exten[i] = 0;
00329 if (!(k&1))
00330 continue;
00331
00332
00333
00334 if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
00335 exten[--i] = 0;
00336 break;
00337 }
00338
00339 if (ast_ignore_pattern(args.context, exten)) {
00340 play_dialtone(chan, "");
00341 did_ignore = 1;
00342 } else
00343 if (did_ignore) {
00344 ast_playtones_stop(chan);
00345 did_ignore = 0;
00346 }
00347
00348
00349 if (!ast_matchmore_extension(chan, args.context, exten, 1,
00350 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00351 break;
00352 }
00353 }
00354 }
00355
00356 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00357
00358 if (k == 3) {
00359 int recheck = 0;
00360 struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };
00361
00362 if (!ast_exists_extension(chan, args.context, exten, 1,
00363 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00364 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
00365 exten[0] = 'i';
00366 exten[1] = '\0';
00367 recheck = 1;
00368 }
00369 if (!recheck
00370 || ast_exists_extension(chan, args.context, exten, 1,
00371 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00372 ast_playtones_stop(chan);
00373
00374 if (!ast_strlen_zero(args.cid)) {
00375 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
00376 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
00377 }
00378
00379 if (!ast_strlen_zero(acctcode))
00380 ast_string_field_set(chan, accountcode, acctcode);
00381
00382 if (special_noanswer) cdr_flags.flags = 0;
00383 ast_cdr_reset(chan->cdr, &cdr_flags);
00384 ast_explicit_goto(chan, args.context, exten, 1);
00385 return 0;
00386 }
00387 }
00388
00389
00390
00391 reorder:
00392
00393 ast_indicate(chan, AST_CONTROL_CONGESTION);
00394 ast_safe_sleep(chan, 10*1000);
00395
00396 ast_playtones_stop(chan);
00397
00398 return -1;
00399 }
00400
00401 static int unload_module(void)
00402 {
00403 return ast_unregister_application(app);
00404 }
00405
00406 static int load_module(void)
00407 {
00408 return ast_register_application_xml(app, disa_exec) ?
00409 AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00410 }
00411
00412 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");