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