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 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 276347 $")
00032
00033 #include <math.h>
00034 #include <sys/time.h>
00035
00036 #include "asterisk/lock.h"
00037 #include "asterisk/file.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/app.h"
00040 #include "asterisk/indications.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/translate.h"
00044 #include "asterisk/ulaw.h"
00045 #include "asterisk/callerid.h"
00046 #include "asterisk/stringfields.h"
00047
00048
00049
00050
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 static const char app[] = "DISA";
00114
00115 enum {
00116 NOANSWER_FLAG = (1 << 0),
00117 POUND_TO_END_FLAG = (1 << 1),
00118 };
00119
00120 AST_APP_OPTIONS(app_opts, {
00121 AST_APP_OPTION('n', NOANSWER_FLAG),
00122 AST_APP_OPTION('p', POUND_TO_END_FLAG),
00123 });
00124
00125 static void play_dialtone(struct ast_channel *chan, char *mailbox)
00126 {
00127 struct ast_tone_zone_sound *ts = NULL;
00128
00129 if (ast_app_has_voicemail(mailbox, NULL)) {
00130 ts = ast_get_indication_tone(chan->zone, "dialrecall");
00131 } else {
00132 ts = ast_get_indication_tone(chan->zone, "dial");
00133 }
00134
00135 if (ts) {
00136 ast_playtones_start(chan, 0, ts->data, 0);
00137 ts = ast_tone_zone_sound_unref(ts);
00138 } else {
00139 ast_tonepair_start(chan, 350, 440, 0, 0);
00140 }
00141 }
00142
00143 static int disa_exec(struct ast_channel *chan, const char *data)
00144 {
00145 int i = 0, j, k = 0, did_ignore = 0, special_noanswer = 0;
00146 int firstdigittimeout = (chan->pbx ? chan->pbx->rtimeoutms : 20000);
00147 int digittimeout = (chan->pbx ? chan->pbx->dtimeoutms : 10000);
00148 struct ast_flags flags;
00149 char *tmp, exten[AST_MAX_EXTENSION] = "", acctcode[20]="";
00150 char pwline[256];
00151 char ourcidname[256],ourcidnum[256];
00152 struct ast_frame *f;
00153 struct timeval lastdigittime;
00154 int res;
00155 FILE *fp;
00156 AST_DECLARE_APP_ARGS(args,
00157 AST_APP_ARG(passcode);
00158 AST_APP_ARG(context);
00159 AST_APP_ARG(cid);
00160 AST_APP_ARG(mailbox);
00161 AST_APP_ARG(options);
00162 );
00163
00164 if (ast_strlen_zero(data)) {
00165 ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
00166 return -1;
00167 }
00168
00169 ast_debug(1, "Digittimeout: %d\n", digittimeout);
00170 ast_debug(1, "Responsetimeout: %d\n", firstdigittimeout);
00171
00172 tmp = ast_strdupa(data);
00173
00174 AST_STANDARD_APP_ARGS(args, tmp);
00175
00176 if (ast_strlen_zero(args.context))
00177 args.context = "disa";
00178 if (ast_strlen_zero(args.mailbox))
00179 args.mailbox = "";
00180 if (!ast_strlen_zero(args.options))
00181 ast_app_parse_options(app_opts, &flags, NULL, args.options);
00182
00183 ast_debug(1, "Mailbox: %s\n",args.mailbox);
00184
00185 if (!ast_test_flag(&flags, NOANSWER_FLAG)) {
00186 if (chan->_state != AST_STATE_UP) {
00187
00188 ast_answer(chan);
00189 }
00190 } else special_noanswer = 1;
00191
00192 ast_debug(1, "Context: %s\n",args.context);
00193
00194 if (!strcasecmp(args.passcode, "no-password")) {
00195 k |= 1;
00196 ast_debug(1, "DISA no-password login success\n");
00197 }
00198
00199 lastdigittime = ast_tvnow();
00200
00201 play_dialtone(chan, args.mailbox);
00202
00203 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00204
00205 for (;;) {
00206
00207 if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) > ((k&2) ? digittimeout : firstdigittimeout)) {
00208 ast_debug(1,"DISA %s entry timeout on chan %s\n",
00209 ((k&1) ? "extension" : "password"),chan->name);
00210 break;
00211 }
00212
00213 if ((res = ast_waitfor(chan, -1) < 0)) {
00214 ast_debug(1, "Waitfor returned %d\n", res);
00215 continue;
00216 }
00217
00218 if (!(f = ast_read(chan))) {
00219 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00220 return -1;
00221 }
00222
00223 if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
00224 if (f->data.uint32)
00225 chan->hangupcause = f->data.uint32;
00226 ast_frfree(f);
00227 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00228 return -1;
00229 }
00230
00231
00232 if (f->frametype != AST_FRAME_DTMF) {
00233 ast_frfree(f);
00234 continue;
00235 }
00236
00237 j = f->subclass.integer;
00238 ast_frfree(f);
00239
00240 if (!i) {
00241 k |= 2;
00242 ast_playtones_stop(chan);
00243 }
00244
00245 lastdigittime = ast_tvnow();
00246
00247
00248 if (i < AST_MAX_EXTENSION) {
00249 if (!(k&1)) {
00250 if (j == '#') {
00251
00252 if (sscanf(args.passcode,"%30d",&j) < 1) {
00253 fp = fopen(args.passcode,"r");
00254 if (!fp) {
00255 ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
00256 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00257 return -1;
00258 }
00259 pwline[0] = 0;
00260 while(fgets(pwline,sizeof(pwline) - 1,fp)) {
00261 if (!pwline[0])
00262 continue;
00263 if (pwline[strlen(pwline) - 1] == '\n')
00264 pwline[strlen(pwline) - 1] = 0;
00265 if (!pwline[0])
00266 continue;
00267
00268 if (pwline[0] == '#')
00269 continue;
00270 if (pwline[0] == ';')
00271 continue;
00272
00273 AST_STANDARD_APP_ARGS(args, pwline);
00274
00275 ast_debug(1, "Mailbox: %s\n",args.mailbox);
00276
00277
00278 if (sscanf(args.passcode,"%30d", &j) < 1)
00279 continue;
00280
00281 if (!strcmp(exten,args.passcode)) {
00282 if (ast_strlen_zero(args.context))
00283 args.context = "disa";
00284 if (ast_strlen_zero(args.mailbox))
00285 args.mailbox = "";
00286 break;
00287 }
00288 }
00289 fclose(fp);
00290 }
00291
00292 if (strcmp(exten,args.passcode)) {
00293 ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
00294 goto reorder;
00295
00296 }
00297
00298 ast_debug(1,"DISA on chan %s password is good\n",chan->name);
00299 play_dialtone(chan, args.mailbox);
00300
00301 k|=1;
00302 i = 0;
00303 exten[sizeof(acctcode)] = 0;
00304 ast_copy_string(acctcode, exten, sizeof(acctcode));
00305 exten[0] = 0;
00306 ast_debug(1,"Successful DISA log-in on chan %s\n", chan->name);
00307 continue;
00308 }
00309 } else {
00310 if (j == '#') {
00311 if (i == 0
00312 && (ast_matchmore_extension(chan, args.context, "#", 1,
00313 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
00314 || ast_exists_extension(chan, args.context, "#", 1,
00315 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) ) {
00316
00317 } else {
00318 break;
00319 }
00320 }
00321 }
00322
00323 exten[i++] = j;
00324 exten[i] = 0;
00325 if (!(k&1))
00326 continue;
00327
00328
00329
00330 if (ast_test_flag(&flags, POUND_TO_END_FLAG) && j == '#') {
00331 exten[--i] = 0;
00332 break;
00333 }
00334
00335 if (ast_ignore_pattern(args.context, exten)) {
00336 play_dialtone(chan, "");
00337 did_ignore = 1;
00338 } else
00339 if (did_ignore) {
00340 ast_playtones_stop(chan);
00341 did_ignore = 0;
00342 }
00343
00344
00345 if (!ast_matchmore_extension(chan, args.context, exten, 1,
00346 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00347 break;
00348 }
00349 }
00350 }
00351
00352 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00353
00354 if (k == 3) {
00355 int recheck = 0;
00356 struct ast_flags cdr_flags = { AST_CDR_FLAG_POSTED };
00357
00358 if (!ast_exists_extension(chan, args.context, exten, 1,
00359 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00360 pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
00361 exten[0] = 'i';
00362 exten[1] = '\0';
00363 recheck = 1;
00364 }
00365 if (!recheck
00366 || ast_exists_extension(chan, args.context, exten, 1,
00367 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00368 ast_playtones_stop(chan);
00369
00370 if (!ast_strlen_zero(args.cid)) {
00371 ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
00372 ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
00373 }
00374
00375 if (!ast_strlen_zero(acctcode))
00376 ast_string_field_set(chan, accountcode, acctcode);
00377
00378 if (special_noanswer) cdr_flags.flags = 0;
00379 ast_cdr_reset(chan->cdr, &cdr_flags);
00380 ast_explicit_goto(chan, args.context, exten, 1);
00381 return 0;
00382 }
00383 }
00384
00385
00386
00387 reorder:
00388
00389 ast_indicate(chan, AST_CONTROL_CONGESTION);
00390 ast_safe_sleep(chan, 10*1000);
00391
00392 ast_playtones_stop(chan);
00393
00394 return -1;
00395 }
00396
00397 static int unload_module(void)
00398 {
00399 return ast_unregister_application(app);
00400 }
00401
00402 static int load_module(void)
00403 {
00404 return ast_register_application_xml(app, disa_exec) ?
00405 AST_MODULE_LOAD_DECLINE : AST_MODULE_LOAD_SUCCESS;
00406 }
00407
00408 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");