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 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 284610 $")
00035
00036 #include <netinet/in.h>
00037 #include <ctype.h>
00038
00039 #include "asterisk/paths.h"
00040 #include "asterisk/file.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/adsi.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/lock.h"
00047
00048 static const char app[] = "ADSIProg";
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 struct adsi_event {
00073 int id;
00074 const char *name;
00075 };
00076
00077 static const struct adsi_event events[] = {
00078 { 1, "CALLERID" },
00079 { 2, "VMWI" },
00080 { 3, "NEARANSWER" },
00081 { 4, "FARANSWER" },
00082 { 5, "ENDOFRING" },
00083 { 6, "IDLE" },
00084 { 7, "OFFHOOK" },
00085 { 8, "CIDCW" },
00086 { 9, "BUSY" },
00087 { 10, "FARRING" },
00088 { 11, "DIALTONE" },
00089 { 12, "RECALL" },
00090 { 13, "MESSAGE" },
00091 { 14, "REORDER" },
00092 { 15, "DISTINCTIVERING" },
00093 { 16, "RING" },
00094 { 17, "REMINDERRING" },
00095 { 18, "SPECIALRING" },
00096 { 19, "CODEDRING" },
00097 { 20, "TIMER" },
00098 { 21, "INUSE" },
00099 { 22, "EVENT22" },
00100 { 23, "EVENT23" },
00101 { 24, "CPEID" },
00102 };
00103
00104 static const struct adsi_event justify[] = {
00105 { 0, "CENTER" },
00106 { 1, "RIGHT" },
00107 { 2, "LEFT" },
00108 { 3, "INDENT" },
00109 };
00110
00111 #define STATE_NORMAL 0
00112 #define STATE_INKEY 1
00113 #define STATE_INSUB 2
00114 #define STATE_INIF 3
00115
00116 #define MAX_RET_CODE 20
00117 #define MAX_SUB_LEN 255
00118 #define MAX_MAIN_LEN 1600
00119
00120 #define ARG_STRING (1 << 0)
00121 #define ARG_NUMBER (1 << 1)
00122
00123 struct adsi_soft_key {
00124 char vname[40];
00125 int retstrlen;
00126 int initlen;
00127 int id;
00128 int defined;
00129 char retstr[80];
00130 };
00131
00132 struct adsi_subscript {
00133 char vname[40];
00134 int id;
00135 int defined;
00136 int datalen;
00137 int inscount;
00138 int ifinscount;
00139 char *ifdata;
00140 char data[2048];
00141 };
00142
00143 struct adsi_state {
00144 char vname[40];
00145 int id;
00146 };
00147
00148 struct adsi_flag {
00149 char vname[40];
00150 int id;
00151 };
00152
00153 struct adsi_display {
00154 char vname[40];
00155 int id;
00156 char data[70];
00157 int datalen;
00158 };
00159
00160 struct adsi_script {
00161 int state;
00162 int numkeys;
00163 int numsubs;
00164 int numstates;
00165 int numdisplays;
00166 int numflags;
00167 struct adsi_soft_key *key;
00168 struct adsi_subscript *sub;
00169
00170 struct adsi_display displays[63];
00171
00172 struct adsi_state states[256];
00173
00174 struct adsi_soft_key keys[62];
00175
00176 struct adsi_subscript subs[128];
00177
00178 struct adsi_flag flags[7];
00179
00180
00181 unsigned char sec[5];
00182 char desc[19];
00183 unsigned char fdn[5];
00184 int ver;
00185 };
00186
00187
00188 static int process_token(void *out, char *src, int maxlen, int argtype)
00189 {
00190 if ((strlen(src) > 1) && src[0] == '\"') {
00191
00192 if (!(argtype & ARG_STRING))
00193 return -1;
00194 src++;
00195
00196 if (maxlen > strlen(src) - 1)
00197 maxlen = strlen(src) - 1;
00198 memcpy(out, src, maxlen);
00199 ((char *)out)[maxlen] = '\0';
00200 } else if (!ast_strlen_zero(src) && (src[0] == '\\')) {
00201 if (!(argtype & ARG_NUMBER))
00202 return -1;
00203
00204 if (sscanf(src, "%30o", (int *)out) != 1)
00205 return -1;
00206 if (argtype & ARG_STRING) {
00207
00208 *((unsigned int *)out) = htonl(*((unsigned int *)out));
00209 }
00210 } else if ((strlen(src) > 2) && (src[0] == '0') && (tolower(src[1]) == 'x')) {
00211 if (!(argtype & ARG_NUMBER))
00212 return -1;
00213
00214 if (sscanf(src + 2, "%30x", (unsigned int *)out) != 1)
00215 return -1;
00216 if (argtype & ARG_STRING) {
00217
00218 *((unsigned int *)out) = htonl(*((unsigned int *)out));
00219 }
00220 } else if ((!ast_strlen_zero(src) && isdigit(src[0]))) {
00221 if (!(argtype & ARG_NUMBER))
00222 return -1;
00223
00224 if (sscanf(src, "%30d", (int *)out) != 1)
00225 return -1;
00226 if (argtype & ARG_STRING) {
00227
00228 *((unsigned int *)out) = htonl(*((unsigned int *)out));
00229 }
00230 } else
00231 return -1;
00232 return 0;
00233 }
00234
00235 static char *get_token(char **buf, const char *script, int lineno)
00236 {
00237 char *tmp = *buf, *keyword;
00238 int quoted = 0;
00239
00240
00241 while(*tmp && (*tmp < 33))
00242 tmp++;
00243 if (!*tmp)
00244 return NULL;
00245 keyword = tmp;
00246 while(*tmp && ((*tmp > 32) || quoted)) {
00247 if (*tmp == '\"') {
00248 quoted = !quoted;
00249 }
00250 tmp++;
00251 }
00252 if (quoted) {
00253 ast_log(LOG_WARNING, "Mismatched quotes at line %d of %s\n", lineno, script);
00254 return NULL;
00255 }
00256 *tmp = '\0';
00257 tmp++;
00258 while(*tmp && (*tmp < 33))
00259 tmp++;
00260
00261 *buf = tmp;
00262 return keyword;
00263 }
00264
00265 static char *validdtmf = "123456789*0#ABCD";
00266
00267 static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00268 {
00269 char dtmfstr[80], *a;
00270 int bytes = 0;
00271
00272 if (!(a = get_token(&args, script, lineno))) {
00273 ast_log(LOG_WARNING, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno, script);
00274 return 0;
00275 }
00276
00277 if (process_token(dtmfstr, a, sizeof(dtmfstr) - 1, ARG_STRING)) {
00278 ast_log(LOG_WARNING, "Invalid token for SENDDTMF at line %d of %s\n", lineno, script);
00279 return 0;
00280 }
00281
00282 a = dtmfstr;
00283
00284 while (*a) {
00285 if (strchr(validdtmf, *a)) {
00286 *buf = *a;
00287 buf++;
00288 bytes++;
00289 } else
00290 ast_log(LOG_WARNING, "'%c' is not a valid DTMF tone at line %d of %s\n", *a, lineno, script);
00291 a++;
00292 }
00293
00294 return bytes;
00295 }
00296
00297 static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00298 {
00299 char *page = get_token(&args, script, lineno);
00300 char *gline = get_token(&args, script, lineno);
00301 int line;
00302 unsigned char cmd;
00303
00304 if (!page || !gline) {
00305 ast_log(LOG_WARNING, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno, script);
00306 return 0;
00307 }
00308
00309 if (!strcasecmp(page, "INFO"))
00310 cmd = 0;
00311 else if (!strcasecmp(page, "COMM"))
00312 cmd = 0x80;
00313 else {
00314 ast_log(LOG_WARNING, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page, lineno, script);
00315 return 0;
00316 }
00317
00318 if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
00319 ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
00320 return 0;
00321 }
00322
00323 cmd |= line;
00324 buf[0] = 0x8b;
00325 buf[1] = cmd;
00326
00327 return 2;
00328 }
00329
00330 static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00331 {
00332 char *dir = get_token(&args, script, lineno);
00333 char *gline = get_token(&args, script, lineno);
00334 int line;
00335 unsigned char cmd;
00336
00337 if (!dir || !gline) {
00338 ast_log(LOG_WARNING, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno, script);
00339 return 0;
00340 }
00341
00342 if (!strcasecmp(dir, "UP"))
00343 cmd = 0;
00344 else if (!strcasecmp(dir, "DOWN"))
00345 cmd = 0x20;
00346 else {
00347 ast_log(LOG_WARNING, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir, lineno, script);
00348 return 0;
00349 }
00350
00351 if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
00352 ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
00353 return 0;
00354 }
00355
00356 cmd |= line;
00357 buf[0] = 0x8c;
00358 buf[1] = cmd;
00359
00360 return 2;
00361 }
00362
00363 static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00364 {
00365 char *gtime = get_token(&args, script, lineno);
00366 int ms;
00367
00368 if (!gtime) {
00369 ast_log(LOG_WARNING, "Expecting number of milliseconds to wait at line %d of %s\n", lineno, script);
00370 return 0;
00371 }
00372
00373 if (process_token(&ms, gtime, sizeof(ms), ARG_NUMBER)) {
00374 ast_log(LOG_WARNING, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime, lineno, script);
00375 return 0;
00376 }
00377
00378 buf[0] = 0x90;
00379
00380 if (id == 11)
00381 buf[1] = ms / 100;
00382 else
00383 buf[1] = ms / 10;
00384
00385 return 2;
00386 }
00387
00388 static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00389 {
00390 char *gstate = get_token(&args, script, lineno);
00391 int state;
00392
00393 if (!gstate) {
00394 ast_log(LOG_WARNING, "Expecting state number at line %d of %s\n", lineno, script);
00395 return 0;
00396 }
00397
00398 if (process_token(&state, gstate, sizeof(state), ARG_NUMBER)) {
00399 ast_log(LOG_WARNING, "Invalid state number '%s' at line %d of %s\n", gstate, lineno, script);
00400 return 0;
00401 }
00402
00403 buf[0] = id;
00404 buf[1] = state;
00405
00406 return 2;
00407 }
00408
00409 static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00410 {
00411 char *tok = get_token(&args, script, lineno);
00412
00413 if (tok)
00414 ast_log(LOG_WARNING, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
00415
00416 buf[0] = id;
00417
00418
00419 if (id == 7)
00420 buf[1] = 0x10;
00421 else
00422 buf[1] = 0x00;
00423
00424 return 2;
00425 }
00426
00427 static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
00428 {
00429 int x;
00430
00431 for (x = 0; x < state->numflags; x++) {
00432 if (!strcasecmp(state->flags[x].vname, name))
00433 return &state->flags[x];
00434 }
00435
00436
00437 if (!create)
00438 return NULL;
00439
00440 if (state->numflags > 6) {
00441 ast_log(LOG_WARNING, "No more flag space at line %d of %s\n", lineno, script);
00442 return NULL;
00443 }
00444
00445 ast_copy_string(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname));
00446 state->flags[state->numflags].id = state->numflags + 1;
00447 state->numflags++;
00448
00449 return &state->flags[state->numflags-1];
00450 }
00451
00452 static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00453 {
00454 char *tok = get_token(&args, script, lineno);
00455 char sname[80];
00456 struct adsi_flag *flag;
00457
00458 if (!tok) {
00459 ast_log(LOG_WARNING, "Setting flag requires a flag number at line %d of %s\n", lineno, script);
00460 return 0;
00461 }
00462
00463 if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
00464 ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
00465 return 0;
00466 }
00467
00468 if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
00469 ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
00470 return 0;
00471 }
00472
00473 buf[0] = id;
00474 buf[1] = ((flag->id & 0x7) << 4) | 1;
00475
00476 return 2;
00477 }
00478
00479 static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00480 {
00481 char *tok = get_token(&args, script, lineno);
00482 struct adsi_flag *flag;
00483 char sname[80];
00484
00485 if (!tok) {
00486 ast_log(LOG_WARNING, "Clearing flag requires a flag number at line %d of %s\n", lineno, script);
00487 return 0;
00488 }
00489
00490 if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
00491 ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
00492 return 0;
00493 }
00494
00495 if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
00496 ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
00497 return 0;
00498 }
00499
00500 buf[0] = id;
00501 buf[1] = ((flag->id & 0x7) << 4);
00502
00503 return 2;
00504 }
00505
00506 static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00507 {
00508 char *tok = get_token(&args, script, lineno);
00509 int secs;
00510
00511 if (!tok) {
00512 ast_log(LOG_WARNING, "Missing number of seconds at line %d of %s\n", lineno, script);
00513 return 0;
00514 }
00515
00516 if (process_token(&secs, tok, sizeof(secs), ARG_NUMBER)) {
00517 ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
00518 return 0;
00519 }
00520
00521 buf[0] = id;
00522 buf[1] = 0x1;
00523 buf[2] = secs;
00524
00525 return 3;
00526 }
00527
00528 static int geteventbyname(char *name)
00529 {
00530 int x;
00531
00532 for (x = 0; x < ARRAY_LEN(events); x++) {
00533 if (!strcasecmp(events[x].name, name))
00534 return events[x].id;
00535 }
00536
00537 return 0;
00538 }
00539
00540 static int getjustifybyname(char *name)
00541 {
00542 int x;
00543
00544 for (x = 0; x < ARRAY_LEN(justify); x++) {
00545 if (!strcasecmp(justify[x].name, name))
00546 return justify[x].id;
00547 }
00548
00549 return -1;
00550 }
00551
00552 static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, const char *script, int lineno)
00553 {
00554 int x;
00555
00556 for (x = 0; x < state->numkeys; x++) {
00557 if (!strcasecmp(state->keys[x].vname, name))
00558 return &state->keys[x];
00559 }
00560
00561 if (state->numkeys > 61) {
00562 ast_log(LOG_WARNING, "No more key space at line %d of %s\n", lineno, script);
00563 return NULL;
00564 }
00565
00566 ast_copy_string(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname));
00567 state->keys[state->numkeys].id = state->numkeys + 2;
00568 state->numkeys++;
00569
00570 return &state->keys[state->numkeys-1];
00571 }
00572
00573 static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, const char *script, int lineno)
00574 {
00575 int x;
00576
00577 for (x = 0; x < state->numsubs; x++) {
00578 if (!strcasecmp(state->subs[x].vname, name))
00579 return &state->subs[x];
00580 }
00581
00582 if (state->numsubs > 127) {
00583 ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
00584 return NULL;
00585 }
00586
00587 ast_copy_string(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname));
00588 state->subs[state->numsubs].id = state->numsubs;
00589 state->numsubs++;
00590
00591 return &state->subs[state->numsubs-1];
00592 }
00593
00594 static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
00595 {
00596 int x;
00597
00598 for (x = 0; x <state->numstates; x++) {
00599 if (!strcasecmp(state->states[x].vname, name))
00600 return &state->states[x];
00601 }
00602
00603
00604 if (!create)
00605 return NULL;
00606
00607 if (state->numstates > 253) {
00608 ast_log(LOG_WARNING, "No more state space at line %d of %s\n", lineno, script);
00609 return NULL;
00610 }
00611
00612 ast_copy_string(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname));
00613 state->states[state->numstates].id = state->numstates + 1;
00614 state->numstates++;
00615
00616 return &state->states[state->numstates-1];
00617 }
00618
00619 static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
00620 {
00621 int x;
00622
00623 for (x = 0; x < state->numdisplays; x++) {
00624 if (!strcasecmp(state->displays[x].vname, name))
00625 return &state->displays[x];
00626 }
00627
00628
00629 if (!create)
00630 return NULL;
00631
00632 if (state->numdisplays > 61) {
00633 ast_log(LOG_WARNING, "No more display space at line %d of %s\n", lineno, script);
00634 return NULL;
00635 }
00636
00637 ast_copy_string(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname));
00638 state->displays[state->numdisplays].id = state->numdisplays + 1;
00639 state->numdisplays++;
00640
00641 return &state->displays[state->numdisplays-1];
00642 }
00643
00644 static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00645 {
00646 char *tok, newkey[80];
00647 int bytes, x, flagid = 0;
00648 unsigned char keyid[6];
00649 struct adsi_soft_key *key;
00650 struct adsi_flag *flag;
00651
00652 for (x = 0; x < 7; x++) {
00653
00654 if (!(tok = get_token(&args, script, lineno)))
00655 break;
00656 if (!strcasecmp(tok, "UNLESS")) {
00657
00658 if (!(tok = get_token(&args, script, lineno)))
00659 ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
00660 else if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING))
00661 ast_log(LOG_WARNING, "Invalid flag name '%s' at line %d of %s\n", tok, lineno, script);
00662 else if (!(flag = getflagbyname(state, newkey, script, lineno, 0)))
00663 ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", newkey, lineno, script);
00664 else
00665 flagid = flag->id;
00666 if ((tok = get_token(&args, script, lineno)))
00667 ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
00668 break;
00669 }
00670 if (x > 5) {
00671 ast_log(LOG_WARNING, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok, lineno, script);
00672 break;
00673 }
00674 if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
00675 ast_log(LOG_WARNING, "Invalid token for key name: %s\n", tok);
00676 continue;
00677 }
00678
00679 if (!(key = getkeybyname(state, newkey, script, lineno)))
00680 break;
00681 keyid[x] = key->id;
00682 }
00683 buf[0] = id;
00684 buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
00685 for (bytes = 0; bytes < x; bytes++)
00686 buf[bytes + 2] = keyid[bytes];
00687
00688 return 2 + x;
00689 }
00690
00691 static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00692 {
00693 char *tok, dispname[80];
00694 int line = 0, flag = 0, cmd = 3;
00695 struct adsi_display *disp;
00696
00697
00698 if (!(tok = get_token(&args, script, lineno)) || process_token(dispname, tok, sizeof(dispname) - 1, ARG_STRING)) {
00699 ast_log(LOG_WARNING, "Invalid display name: %s at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
00700 return 0;
00701 }
00702
00703 if (!(disp = getdisplaybyname(state, dispname, script, lineno, 0))) {
00704 ast_log(LOG_WARNING, "Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
00705 return 0;
00706 }
00707
00708 if (!(tok = get_token(&args, script, lineno)) || strcasecmp(tok, "AT")) {
00709 ast_log(LOG_WARNING, "Missing token 'AT' at line %d of %s\n", lineno, script);
00710 return 0;
00711 }
00712
00713
00714 if (!(tok = get_token(&args, script, lineno)) || process_token(&line, tok, sizeof(line), ARG_NUMBER)) {
00715 ast_log(LOG_WARNING, "Invalid line: '%s' at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
00716 return 0;
00717 }
00718
00719 if ((tok = get_token(&args, script, lineno)) && !strcasecmp(tok, "NOUPDATE")) {
00720 cmd = 1;
00721 tok = get_token(&args, script, lineno);
00722 }
00723
00724 if (tok && !strcasecmp(tok, "UNLESS")) {
00725
00726 if (!(tok = get_token(&args, script, lineno)))
00727 ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
00728 else if (process_token(&flag, tok, sizeof(flag), ARG_NUMBER))
00729 ast_log(LOG_WARNING, "Invalid flag number '%s' at line %d of %s\n", tok, lineno, script);
00730
00731 if ((tok = get_token(&args, script, lineno)))
00732 ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
00733 }
00734
00735 buf[0] = id;
00736 buf[1] = (cmd << 6) | (disp->id & 0x3f);
00737 buf[2] = ((line & 0x1f) << 3) | (flag & 0x7);
00738
00739 return 3;
00740 }
00741
00742 static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00743 {
00744 char *tok = get_token(&args, script, lineno);
00745
00746 if (tok)
00747 ast_log(LOG_WARNING, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
00748
00749 buf[0] = id;
00750 buf[1] = 0x00;
00751 return 2;
00752 }
00753
00754 static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00755 {
00756 char *tok = get_token(&args, script, lineno);
00757
00758 if (tok)
00759 ast_log(LOG_WARNING, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
00760
00761 buf[0] = id;
00762 buf[1] = 0x7;
00763 return 2;
00764 }
00765
00766 static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00767 {
00768 char *tok = get_token(&args, script, lineno);
00769
00770 if (tok)
00771 ast_log(LOG_WARNING, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
00772
00773 buf[0] = id;
00774 buf[1] = 0;
00775 return 2;
00776 }
00777
00778 static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
00779 {
00780 char *tok = get_token(&args, script, lineno);
00781
00782 if (tok)
00783 ast_log(LOG_WARNING, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
00784
00785 buf[0] = id;
00786 buf[1] = 0xf;
00787 return 2;
00788 }
00789
00790 static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00791 {
00792 char *tok = get_token(&args, script, lineno);
00793 char subscr[80];
00794 struct adsi_subscript *sub;
00795
00796 if (!tok) {
00797 ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
00798 return 0;
00799 }
00800
00801 if (process_token(subscr, tok, sizeof(subscr) - 1, ARG_STRING)) {
00802 ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
00803 return 0;
00804 }
00805
00806 if (!(sub = getsubbyname(state, subscr, script, lineno)))
00807 return 0;
00808
00809 buf[0] = 0x9d;
00810 buf[1] = sub->id;
00811
00812 return 2;
00813 }
00814
00815 static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
00816 {
00817 char *tok = get_token(&args, script, lineno);
00818 char subscr[80], sname[80];
00819 int sawin = 0, event, snums[8], scnt = 0, x;
00820 struct adsi_subscript *sub;
00821
00822 if (!tok) {
00823 ast_log(LOG_WARNING, "Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
00824 return 0;
00825 }
00826
00827 if ((event = geteventbyname(tok)) < 1) {
00828 ast_log(LOG_WARNING, "'%s' is not a valid event name, at line %d of %s\n", args, lineno, script);
00829 return 0;
00830 }
00831
00832 tok = get_token(&args, script, lineno);
00833 while ((!sawin && !strcasecmp(tok, "IN")) || (sawin && !strcasecmp(tok, "OR"))) {
00834 sawin = 1;
00835 if (scnt > 7) {
00836 ast_log(LOG_WARNING, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno, script);
00837 return 0;
00838 }
00839
00840 tok = get_token(&args, script, lineno);
00841 if (process_token(sname, tok, sizeof(sname), ARG_STRING)) {
00842 ast_log(LOG_WARNING, "'%s' is not a valid state name at line %d of %s\n", tok, lineno, script);
00843 return 0;
00844 }
00845 if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) == NULL)) {
00846 ast_log(LOG_WARNING, "State '%s' not declared at line %d of %s\n", sname, lineno, script);
00847 return 0;
00848 }
00849 scnt++;
00850 if (!(tok = get_token(&args, script, lineno)))
00851 break;
00852 }
00853 if (!tok || strcasecmp(tok, "GOTO")) {
00854 if (!tok)
00855 tok = "<nothing>";
00856 if (sawin)
00857 ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok, lineno, script);
00858 else
00859 ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok, lineno, script);
00860 }
00861 if (!(tok = get_token(&args, script, lineno))) {
00862 ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
00863 return 0;
00864 }
00865 if (process_token(subscr, tok, sizeof(subscr) - 1, ARG_STRING)) {
00866 ast_log(LOG_WARNING, "Invalid subscript '%s' at line %d of %s\n", tok, lineno, script);
00867 return 0;
00868 }
00869 if (!(sub = getsubbyname(state, subscr, script, lineno)))
00870 return 0;
00871 buf[0] = 8;
00872 buf[1] = event;
00873 buf[2] = sub->id | 0x80;
00874 for (x = 0; x < scnt; x++)
00875 buf[3 + x] = snums[x];
00876 return 3 + scnt;
00877 }
00878
00879 struct adsi_key_cmd {
00880 char *name;
00881 int id;
00882 int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno);
00883 };
00884
00885 static const struct adsi_key_cmd kcmds[] = {
00886 { "SENDDTMF", 0, send_dtmf },
00887
00888 { "ONHOOK", 0x81 },
00889 { "OFFHOOK", 0x82 },
00890 { "FLASH", 0x83 },
00891 { "WAITDIALTONE", 0x84 },
00892
00893 { "BLANK", 0x86 },
00894 { "SENDCHARS", 0x87 },
00895 { "CLEARCHARS", 0x88 },
00896 { "BACKSPACE", 0x89 },
00897
00898 { "GOTOLINE", 0x8b, goto_line },
00899 { "GOTOLINEREL", 0x8c, goto_line_rel },
00900 { "PAGEUP", 0x8d },
00901 { "PAGEDOWN", 0x8e },
00902
00903 { "DELAY", 0x90, send_delay },
00904 { "DIALPULSEONE", 0x91 },
00905 { "DATAMODE", 0x92 },
00906 { "VOICEMODE", 0x93 },
00907
00908
00909 { "CLEARCB1", 0x95, clearcbone },
00910 { "DIGITCOLLECT", 0x96, digitcollect },
00911 { "DIGITDIRECT", 0x96, digitdirect },
00912 { "CLEAR", 0x97 },
00913 { "SHOWDISPLAY", 0x98, showdisplay },
00914 { "CLEARDISPLAY", 0x98, cleardisplay },
00915 { "SHOWKEYS", 0x99, showkeys },
00916 { "SETSTATE", 0x9a, set_state },
00917 { "TIMERSTART", 0x9b, starttimer },
00918 { "TIMERCLEAR", 0x9b, cleartimer },
00919 { "SETFLAG", 0x9c, setflag },
00920 { "CLEARFLAG", 0x9c, clearflag },
00921 { "GOTO", 0x9d, subscript },
00922 { "EVENT22", 0x9e },
00923 { "EVENT23", 0x9f },
00924 { "EXIT", 0xa0 },
00925 };
00926
00927 static const struct adsi_key_cmd opcmds[] = {
00928
00929
00930 { "SHOWKEYS", 2, showkeys },
00931
00932 { "SHOWDISPLAY", 3, showdisplay },
00933 { "CLEARDISPLAY", 3, cleardisplay },
00934 { "CLEAR", 5 },
00935 { "SETSTATE", 6, set_state },
00936 { "TIMERSTART", 7, starttimer },
00937 { "TIMERCLEAR", 7, cleartimer },
00938 { "ONEVENT", 8, onevent },
00939
00940 { "SETFLAG", 10, setflag },
00941 { "CLEARFLAG", 10, clearflag },
00942 { "DELAY", 11, send_delay },
00943 { "EXIT", 12 },
00944 };
00945
00946
00947 static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, const char *script, int lineno)
00948 {
00949 int x, res;
00950 char *unused;
00951
00952 for (x = 0; x < ARRAY_LEN(kcmds); x++) {
00953 if ((kcmds[x].id > -1) && !strcasecmp(kcmds[x].name, code)) {
00954 if (kcmds[x].add_args) {
00955 res = kcmds[x].add_args(key->retstr + key->retstrlen,
00956 code, kcmds[x].id, args, state, script, lineno);
00957 if ((key->retstrlen + res - key->initlen) <= MAX_RET_CODE)
00958 key->retstrlen += res;
00959 else
00960 ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
00961 } else {
00962 if ((unused = get_token(&args, script, lineno)))
00963 ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds[x].name, lineno, script, unused);
00964 if ((key->retstrlen + 1 - key->initlen) <= MAX_RET_CODE) {
00965 key->retstr[key->retstrlen] = kcmds[x].id;
00966 key->retstrlen++;
00967 } else
00968 ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
00969 }
00970 return 0;
00971 }
00972 }
00973 return -1;
00974 }
00975
00976 static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, const char *script, int lineno)
00977 {
00978 int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
00979 char *unused;
00980
00981 for (x = 0; x < ARRAY_LEN(opcmds); x++) {
00982 if ((opcmds[x].id > -1) && !strcasecmp(opcmds[x].name, code)) {
00983 if (opcmds[x].add_args) {
00984 res = opcmds[x].add_args(sub->data + sub->datalen,
00985 code, opcmds[x].id, args, state, script, lineno);
00986 if ((sub->datalen + res + 1) <= max)
00987 sub->datalen += res;
00988 else {
00989 ast_log(LOG_WARNING, "No space for '%s' code in subscript '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
00990 return -1;
00991 }
00992 } else {
00993 if ((unused = get_token(&args, script, lineno)))
00994 ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds[x].name, lineno, script, unused);
00995 if ((sub->datalen + 2) <= max) {
00996 sub->data[sub->datalen] = opcmds[x].id;
00997 sub->datalen++;
00998 } else {
00999 ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
01000 return -1;
01001 }
01002 }
01003
01004 sub->data[sub->datalen] = 0xff;
01005 sub->datalen++;
01006 sub->inscount++;
01007 return 0;
01008 }
01009 }
01010 return -1;
01011 }
01012
01013 static int adsi_process(struct adsi_script *state, char *buf, const char *script, int lineno)
01014 {
01015 char *keyword = get_token(&buf, script, lineno);
01016 char *args, vname[256], tmp[80], tmp2[80];
01017 int lrci, wi, event;
01018 struct adsi_display *disp;
01019 struct adsi_subscript *newsub;
01020
01021 if (!keyword)
01022 return 0;
01023
01024 switch(state->state) {
01025 case STATE_NORMAL:
01026 if (!strcasecmp(keyword, "DESCRIPTION")) {
01027 if ((args = get_token(&buf, script, lineno))) {
01028 if (process_token(state->desc, args, sizeof(state->desc) - 1, ARG_STRING))
01029 ast_log(LOG_WARNING, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args, lineno, script);
01030 } else
01031 ast_log(LOG_WARNING, "Missing argument for DESCRIPTION at line %d of %s\n", lineno, script);
01032 } else if (!strcasecmp(keyword, "VERSION")) {
01033 if ((args = get_token(&buf, script, lineno))) {
01034 if (process_token(&state->ver, args, sizeof(state->ver) - 1, ARG_NUMBER))
01035 ast_log(LOG_WARNING, "'%s' is not a valid token for VERSION at line %d of %s\n", args, lineno, script);
01036 } else
01037 ast_log(LOG_WARNING, "Missing argument for VERSION at line %d of %s\n", lineno, script);
01038 } else if (!strcasecmp(keyword, "SECURITY")) {
01039 if ((args = get_token(&buf, script, lineno))) {
01040 if (process_token(state->sec, args, sizeof(state->sec) - 1, ARG_STRING | ARG_NUMBER))
01041 ast_log(LOG_WARNING, "'%s' is not a valid token for SECURITY at line %d of %s\n", args, lineno, script);
01042 } else
01043 ast_log(LOG_WARNING, "Missing argument for SECURITY at line %d of %s\n", lineno, script);
01044 } else if (!strcasecmp(keyword, "FDN")) {
01045 if ((args = get_token(&buf, script, lineno))) {
01046 if (process_token(state->fdn, args, sizeof(state->fdn) - 1, ARG_STRING | ARG_NUMBER))
01047 ast_log(LOG_WARNING, "'%s' is not a valid token for FDN at line %d of %s\n", args, lineno, script);
01048 } else
01049 ast_log(LOG_WARNING, "Missing argument for FDN at line %d of %s\n", lineno, script);
01050 } else if (!strcasecmp(keyword, "KEY")) {
01051 if (!(args = get_token(&buf, script, lineno))) {
01052 ast_log(LOG_WARNING, "KEY definition missing name at line %d of %s\n", lineno, script);
01053 break;
01054 }
01055 if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
01056 ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
01057 break;
01058 }
01059 if (!(state->key = getkeybyname(state, vname, script, lineno))) {
01060 ast_log(LOG_WARNING, "Out of key space at line %d of %s\n", lineno, script);
01061 break;
01062 }
01063 if (state->key->defined) {
01064 ast_log(LOG_WARNING, "Cannot redefine key '%s' at line %d of %s\n", vname, lineno, script);
01065 break;
01066 }
01067 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
01068 ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
01069 break;
01070 }
01071 if (!(args = get_token(&buf, script, lineno))) {
01072 ast_log(LOG_WARNING, "KEY definition missing short name at line %d of %s\n", lineno, script);
01073 break;
01074 }
01075 if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
01076 ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY short name at line %d of %s\n", args, lineno, script);
01077 break;
01078 }
01079 if ((args = get_token(&buf, script, lineno))) {
01080 if (strcasecmp(args, "OR")) {
01081 ast_log(LOG_WARNING, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args, lineno, script);
01082 break;
01083 }
01084 if (!(args = get_token(&buf, script, lineno))) {
01085 ast_log(LOG_WARNING, "KEY definition missing optional long name at line %d of %s\n", lineno, script);
01086 break;
01087 }
01088 if (process_token(tmp2, args, sizeof(tmp2) - 1, ARG_STRING)) {
01089 ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY long name at line %d of %s\n", args, lineno, script);
01090 break;
01091 }
01092 } else {
01093 ast_copy_string(tmp2, tmp, sizeof(tmp2));
01094 }
01095 if (strlen(tmp2) > 18) {
01096 ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
01097 tmp2[18] = '\0';
01098 }
01099 if (strlen(tmp) > 7) {
01100 ast_log(LOG_WARNING, "Truncating short name to 7 bytes at line %d of %s\n", lineno, script);
01101 tmp[7] = '\0';
01102 }
01103
01104 state->key->retstr[0] = 128;
01105
01106 state->key->retstr[2] = state->key->id;
01107
01108 memcpy(state->key->retstr + 3, tmp2, strlen(tmp2));
01109
01110 state->key->retstrlen = strlen(tmp2) + 3;
01111
01112 state->key->retstr[state->key->retstrlen++] = 0xff;
01113
01114 memcpy(state->key->retstr + state->key->retstrlen, tmp, strlen(tmp));
01115
01116 state->key->retstrlen += strlen(tmp);
01117
01118 state->key->retstr[state->key->retstrlen++] = 0xff;
01119
01120 state->key->initlen = state->key->retstrlen;
01121 state->state = STATE_INKEY;
01122 } else if (!strcasecmp(keyword, "SUB")) {
01123 if (!(args = get_token(&buf, script, lineno))) {
01124 ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
01125 break;
01126 }
01127 if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
01128 ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
01129 break;
01130 }
01131 if (!(state->sub = getsubbyname(state, vname, script, lineno))) {
01132 ast_log(LOG_WARNING, "Out of subroutine space at line %d of %s\n", lineno, script);
01133 break;
01134 }
01135 if (state->sub->defined) {
01136 ast_log(LOG_WARNING, "Cannot redefine subroutine '%s' at line %d of %s\n", vname, lineno, script);
01137 break;
01138 }
01139
01140 state->sub->data[0] = 130;
01141
01142 state->sub->data[2] = 0x0;
01143 state->sub->datalen = 3;
01144 if (state->sub->id) {
01145
01146 state->sub->data[3] = 9;
01147 state->sub->data[4] = state->sub->id;
01148
01149 state->sub->data[6] = 0xff;
01150 state->sub->datalen = 7;
01151 }
01152 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
01153 ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
01154 break;
01155 }
01156 state->state = STATE_INSUB;
01157 } else if (!strcasecmp(keyword, "STATE")) {
01158 if (!(args = get_token(&buf, script, lineno))) {
01159 ast_log(LOG_WARNING, "STATE definition missing name at line %d of %s\n", lineno, script);
01160 break;
01161 }
01162 if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
01163 ast_log(LOG_WARNING, "'%s' is not a valid token for a STATE name at line %d of %s\n", args, lineno, script);
01164 break;
01165 }
01166 if (getstatebyname(state, vname, script, lineno, 0)) {
01167 ast_log(LOG_WARNING, "State '%s' is already defined at line %d of %s\n", vname, lineno, script);
01168 break;
01169 }
01170 getstatebyname(state, vname, script, lineno, 1);
01171 } else if (!strcasecmp(keyword, "FLAG")) {
01172 if (!(args = get_token(&buf, script, lineno))) {
01173 ast_log(LOG_WARNING, "FLAG definition missing name at line %d of %s\n", lineno, script);
01174 break;
01175 }
01176 if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
01177 ast_log(LOG_WARNING, "'%s' is not a valid token for a FLAG name at line %d of %s\n", args, lineno, script);
01178 break;
01179 }
01180 if (getflagbyname(state, vname, script, lineno, 0)) {
01181 ast_log(LOG_WARNING, "Flag '%s' is already defined\n", vname);
01182 break;
01183 }
01184 getflagbyname(state, vname, script, lineno, 1);
01185 } else if (!strcasecmp(keyword, "DISPLAY")) {
01186 lrci = 0;
01187 wi = 0;
01188 if (!(args = get_token(&buf, script, lineno))) {
01189 ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
01190 break;
01191 }
01192 if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
01193 ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
01194 break;
01195 }
01196 if (getdisplaybyname(state, vname, script, lineno, 0)) {
01197 ast_log(LOG_WARNING, "State '%s' is already defined\n", vname);
01198 break;
01199 }
01200 if (!(disp = getdisplaybyname(state, vname, script, lineno, 1)))
01201 break;
01202 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
01203 ast_log(LOG_WARNING, "Missing 'IS' at line %d of %s\n", lineno, script);
01204 break;
01205 }
01206 if (!(args = get_token(&buf, script, lineno))) {
01207 ast_log(LOG_WARNING, "Missing Column 1 text at line %d of %s\n", lineno, script);
01208 break;
01209 }
01210 if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
01211 ast_log(LOG_WARNING, "Token '%s' is not valid column 1 text at line %d of %s\n", args, lineno, script);
01212 break;
01213 }
01214 if (strlen(tmp) > 20) {
01215 ast_log(LOG_WARNING, "Truncating column one to 20 characters at line %d of %s\n", lineno, script);
01216 tmp[20] = '\0';
01217 }
01218 memcpy(disp->data + 5, tmp, strlen(tmp));
01219 disp->datalen = strlen(tmp) + 5;
01220 disp->data[disp->datalen++] = 0xff;
01221
01222 args = get_token(&buf, script, lineno);
01223 if (args && !process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
01224
01225 if (strlen(tmp) > 20) {
01226 ast_log(LOG_WARNING, "Truncating column two to 20 characters at line %d of %s\n", lineno, script);
01227 tmp[20] = '\0';
01228 }
01229 memcpy(disp->data + disp->datalen, tmp, strlen(tmp));
01230 disp->datalen += strlen(tmp);
01231 args = get_token(&buf, script, lineno);
01232 }
01233 while (args) {
01234 if (!strcasecmp(args, "JUSTIFY")) {
01235 args = get_token(&buf, script, lineno);
01236 if (!args) {
01237 ast_log(LOG_WARNING, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno, script);
01238 break;
01239 }
01240 lrci = getjustifybyname(args);
01241 if (lrci < 0) {
01242 ast_log(LOG_WARNING, "'%s' is not a valid justification at line %d of %s\n", args, lineno, script);
01243 break;
01244 }
01245 } else if (!strcasecmp(args, "WRAP")) {
01246 wi = 0x80;
01247 } else {
01248 ast_log(LOG_WARNING, "'%s' is not a known qualifier at line %d of %s\n", args, lineno, script);
01249 break;
01250 }
01251 args = get_token(&buf, script, lineno);
01252 }
01253 if (args) {
01254
01255 break;
01256 }
01257 disp->data[0] = 129;
01258 disp->data[1] = disp->datalen - 2;
01259 disp->data[2] = ((lrci & 0x3) << 6) | disp->id;
01260 disp->data[3] = wi;
01261 disp->data[4] = 0xff;
01262 } else {
01263 ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword);
01264 }
01265 break;
01266 case STATE_INKEY:
01267 if (process_returncode(state->key, keyword, buf, state, script, lineno)) {
01268 if (!strcasecmp(keyword, "ENDKEY")) {
01269
01270 state->state = STATE_NORMAL;
01271 state->key->defined = 1;
01272 state->key->retstr[1] = state->key->retstrlen - 2;
01273 state->key = NULL;
01274 } else {
01275 ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword, lineno, script);
01276 }
01277 }
01278 break;
01279 case STATE_INIF:
01280 if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
01281 if (!strcasecmp(keyword, "ENDIF")) {
01282
01283 state->state = STATE_INSUB;
01284 state->sub->defined = 1;
01285
01286 state->sub->ifdata[2] = state->sub->ifinscount;
01287 } else if (!strcasecmp(keyword, "GOTO")) {
01288 if (!(args = get_token(&buf, script, lineno))) {
01289 ast_log(LOG_WARNING, "GOTO clause missing Subscript name at line %d of %s\n", lineno, script);
01290 break;
01291 }
01292 if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
01293 ast_log(LOG_WARNING, "'%s' is not a valid subscript name token at line %d of %s\n", args, lineno, script);
01294 break;
01295 }
01296 if (!(newsub = getsubbyname(state, tmp, script, lineno)))
01297 break;
01298
01299 state->sub->data[state->sub->datalen++] = 0x8;
01300 state->sub->data[state->sub->datalen++] = state->sub->ifdata[1];
01301 state->sub->data[state->sub->datalen++] = newsub->id;
01302
01303 state->sub->data[state->sub->datalen++] = 0xff;
01304
01305 state->sub->inscount++;
01306 state->sub->ifinscount++;
01307 } else {
01308 ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword, lineno, script);
01309 }
01310 } else
01311 state->sub->ifinscount++;
01312 break;
01313 case STATE_INSUB:
01314 if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
01315 if (!strcasecmp(keyword, "ENDSUB")) {
01316
01317 state->state = STATE_NORMAL;
01318 state->sub->defined = 1;
01319
01320 state->sub->data[1] = state->sub->datalen - 2;
01321 if (state->sub->id) {
01322
01323 state->sub->data[5] = state->sub->inscount;
01324 }
01325 state->sub = NULL;
01326 } else if (!strcasecmp(keyword, "IFEVENT")) {
01327 if (!(args = get_token(&buf, script, lineno))) {
01328 ast_log(LOG_WARNING, "IFEVENT clause missing Event name at line %d of %s\n", lineno, script);
01329 break;
01330 }
01331 if ((event = geteventbyname(args)) < 1) {
01332 ast_log(LOG_WARNING, "'%s' is not a valid event\n", args);
01333 break;
01334 }
01335 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "THEN")) {
01336 ast_log(LOG_WARNING, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno, script);
01337 break;
01338 }
01339 state->sub->ifinscount = 0;
01340 state->sub->ifdata = state->sub->data + state->sub->datalen;
01341
01342 state->sub->ifdata[0] = 0x1;
01343 state->sub->ifdata[1] = event;
01344
01345 state->sub->ifdata[3] = 0xff;
01346 state->sub->datalen += 4;
01347
01348 state->sub->inscount++;
01349 state->state = STATE_INIF;
01350 } else {
01351 ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword, lineno, script);
01352 }
01353 }
01354 break;
01355 default:
01356 ast_log(LOG_WARNING, "Can't process keyword '%s' in weird state %d\n", keyword, state->state);
01357 }
01358 return 0;
01359 }
01360
01361 static struct adsi_script *compile_script(const char *script)
01362 {
01363 FILE *f;
01364 char fn[256], buf[256], *c;
01365 int lineno = 0, x, err;
01366 struct adsi_script *scr;
01367
01368 if (script[0] == '/')
01369 ast_copy_string(fn, script, sizeof(fn));
01370 else
01371 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, script);
01372
01373 if (!(f = fopen(fn, "r"))) {
01374 ast_log(LOG_WARNING, "Can't open file '%s'\n", fn);
01375 return NULL;
01376 }
01377
01378 if (!(scr = ast_calloc(1, sizeof(*scr)))) {
01379 fclose(f);
01380 return NULL;
01381 }
01382
01383
01384 getsubbyname(scr, "main", NULL, 0);
01385 while (!feof(f)) {
01386 if (!fgets(buf, sizeof(buf), f)) {
01387 continue;
01388 }
01389 if (!feof(f)) {
01390 lineno++;
01391
01392 buf[strlen(buf) - 1] = '\0';
01393
01394 if ((c = strchr(buf, ';')))
01395 *c = '\0';
01396 if (!ast_strlen_zero(buf))
01397 adsi_process(scr, buf, script, lineno);
01398 }
01399 }
01400 fclose(f);
01401
01402 switch(scr->state) {
01403 case STATE_NORMAL:
01404 break;
01405 case STATE_INSUB:
01406 ast_log(LOG_WARNING, "Missing ENDSUB at end of file %s\n", script);
01407 ast_free(scr);
01408 return NULL;
01409 case STATE_INKEY:
01410 ast_log(LOG_WARNING, "Missing ENDKEY at end of file %s\n", script);
01411 ast_free(scr);
01412 return NULL;
01413 }
01414 err = 0;
01415
01416
01417 for (x = 0; x < scr->numkeys; x++) {
01418 if (!scr->keys[x].defined) {
01419 ast_log(LOG_WARNING, "Key '%s' referenced but never defined in file %s\n", scr->keys[x].vname, fn);
01420 err++;
01421 }
01422 }
01423
01424
01425 for (x = 0; x < scr->numsubs; x++) {
01426 if (!scr->subs[x].defined) {
01427 ast_log(LOG_WARNING, "Subscript '%s' referenced but never defined in file %s\n", scr->subs[x].vname, fn);
01428 err++;
01429 }
01430 if (x == (scr->numsubs - 1)) {
01431
01432 scr->subs[x].data[2] = 0x80;
01433 }
01434 }
01435
01436 if (err) {
01437 ast_free(scr);
01438 return NULL;
01439 }
01440 return scr;
01441 }
01442
01443 #ifdef DUMP_MESSAGES
01444 static void dump_message(char *type, char *vname, unsigned char *buf, int buflen)
01445 {
01446 int x;
01447 printf("%s %s: [ ", type, vname);
01448 for (x = 0; x < buflen; x++)
01449 printf("%02x ", buf[x]);
01450 printf("]\n");
01451 }
01452 #endif
01453
01454 static int adsi_prog(struct ast_channel *chan, const char *script)
01455 {
01456 struct adsi_script *scr;
01457 int x, bytes;
01458 unsigned char buf[1024];
01459
01460 if (!(scr = compile_script(script)))
01461 return -1;
01462
01463
01464 if (ast_adsi_load_session(chan, NULL, 0, 1) < 1)
01465 return -1;
01466
01467
01468 if (ast_adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
01469
01470 ast_verb(3, "User rejected download attempt\n");
01471 ast_log(LOG_NOTICE, "User rejected download on channel %s\n", chan->name);
01472 ast_free(scr);
01473 return -1;
01474 }
01475
01476 bytes = 0;
01477
01478 for (x = 0; x < scr->numkeys; x++) {
01479 if (bytes + scr->keys[x].retstrlen > 253) {
01480
01481 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01482 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01483 return -1;
01484 }
01485 bytes =0;
01486 }
01487 memcpy(buf + bytes, scr->keys[x].retstr, scr->keys[x].retstrlen);
01488 bytes += scr->keys[x].retstrlen;
01489 #ifdef DUMP_MESSAGES
01490 dump_message("Key", scr->keys[x].vname, scr->keys[x].retstr, scr->keys[x].retstrlen);
01491 #endif
01492 }
01493 if (bytes) {
01494 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01495 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01496 return -1;
01497 }
01498 }
01499
01500 bytes = 0;
01501
01502 for (x = 0; x < scr->numdisplays; x++) {
01503 if (bytes + scr->displays[x].datalen > 253) {
01504
01505 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01506 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01507 return -1;
01508 }
01509 bytes =0;
01510 }
01511 memcpy(buf + bytes, scr->displays[x].data, scr->displays[x].datalen);
01512 bytes += scr->displays[x].datalen;
01513 #ifdef DUMP_MESSAGES
01514 dump_message("Display", scr->displays[x].vname, scr->displays[x].data, scr->displays[x].datalen);
01515 #endif
01516 }
01517 if (bytes) {
01518 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01519 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01520 return -1;
01521 }
01522 }
01523
01524 bytes = 0;
01525
01526 for (x = 0; x < scr->numsubs; x++) {
01527 if (bytes + scr->subs[x].datalen > 253) {
01528
01529 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01530 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01531 return -1;
01532 }
01533 bytes =0;
01534 }
01535 memcpy(buf + bytes, scr->subs[x].data, scr->subs[x].datalen);
01536 bytes += scr->subs[x].datalen;
01537 #ifdef DUMP_MESSAGES
01538 dump_message("Sub", scr->subs[x].vname, scr->subs[x].data, scr->subs[x].datalen);
01539 #endif
01540 }
01541 if (bytes) {
01542 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
01543 ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
01544 return -1;
01545 }
01546 }
01547
01548 bytes = 0;
01549 bytes += ast_adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
01550 bytes += ast_adsi_set_line(buf, ADSI_INFO_PAGE, 1);
01551 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
01552 return -1;
01553 if (ast_adsi_end_download(chan)) {
01554
01555 ast_verb(3, "Download attempt failed\n");
01556 ast_log(LOG_NOTICE, "Download failed on %s\n", chan->name);
01557 ast_free(scr);
01558 return -1;
01559 }
01560 ast_free(scr);
01561 ast_adsi_unload_session(chan);
01562 return 0;
01563 }
01564
01565 static int adsi_exec(struct ast_channel *chan, const char *data)
01566 {
01567 int res = 0;
01568
01569 if (ast_strlen_zero(data))
01570 data = "asterisk.adsi";
01571
01572 if (!ast_adsi_available(chan)) {
01573 ast_verb(3, "ADSI Unavailable on CPE. Not bothering to try.\n");
01574 } else {
01575 ast_verb(3, "ADSI Available on CPE. Attempting Upload.\n");
01576 res = adsi_prog(chan, data);
01577 }
01578
01579 return res;
01580 }
01581
01582 static int unload_module(void)
01583 {
01584 return ast_unregister_application(app);
01585 }
01586
01587 static int load_module(void)
01588 {
01589 if (ast_register_application_xml(app, adsi_exec))
01590 return AST_MODULE_LOAD_FAILURE;
01591 return AST_MODULE_LOAD_SUCCESS;
01592 }
01593
01594 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Asterisk ADSI Programming Application",
01595 .load = load_module,
01596 .unload = unload_module,
01597 .nonoptreq = "res_adsi",
01598 );