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: 366048 $")
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 } else {
00187
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
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;
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
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
00241 if (f->frametype != AST_FRAME_DTMF) {
00242 ast_frfree(f);
00243 continue;
00244 }
00245
00246 j = f->subclass.integer;
00247 ast_frfree(f);
00248
00249 if (!i) {
00250 k |= 2;
00251 ast_playtones_stop(chan);
00252 }
00253
00254 lastdigittime = ast_tvnow();
00255
00256
00257 if (i < AST_MAX_EXTENSION) {
00258 if (!(k&1)) {
00259 if (j == '#') {
00260
00261 if (sscanf(args.passcode,"%30d",&j) < 1) {
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
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
00287 if (sscanf(args.passcode,"%30d", &j) < 1)
00288 continue;
00289
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
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
00307 ast_debug(1,"DISA on chan %s password is good\n",chan->name);
00308 play_dialtone(chan, args.mailbox);
00309
00310 k|=1;
00311 i = 0;
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 == '#') {
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
00326 } else {
00327 break;
00328 }
00329 }
00330 }
00331
00332 exten[i++] = j;
00333 exten[i] = 0;
00334 if (!(k&1))
00335 continue;
00336
00337
00338
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
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
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
00395
00396 reorder:
00397
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 }
00405
00406 static int unload_module(void)
00407 {
00408 return ast_unregister_application(app);
00409 }
00410
00411 static int load_module(void)
00412 {
00413 return ast_register_application_xml(app, disa_exec) ?
00414 AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00415 }
00416
00417 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");