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