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