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: 211528 $")
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, "%30o", (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, "%30x", (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, "%30d", (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 if (!fgets(buf, sizeof(buf), f)) {
01368 continue;
01369 }
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 (ast_adsi_load_session(chan, NULL, 0, 1) < 1)
01448 return -1;
01449
01450
01451 if (ast_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 (ast_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 (ast_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 (ast_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 (ast_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 (ast_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 (ast_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 += ast_adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
01535 bytes += ast_adsi_set_line(buf, ADSI_INFO_PAGE, 1);
01536 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
01537 return -1;
01538 if (ast_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 ast_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 ast_module_user *u;
01555
01556 u = ast_module_user_add(chan);
01557
01558 if (ast_strlen_zero(data))
01559 data = "asterisk.adsi";
01560
01561 if (!ast_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 ast_module_user_remove(u);
01571
01572 return res;
01573 }
01574
01575 static int unload_module(void)
01576 {
01577 int res;
01578
01579 ast_module_user_hangup_all();
01580
01581 res = ast_unregister_application(app);
01582
01583
01584 return res;
01585 }
01586
01587 static int load_module(void)
01588 {
01589 return ast_register_application(app, adsi_exec, synopsis, descrip);
01590 }
01591
01592 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk ADSI Programming Application");