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