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