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