44 #include <netinet/in.h>
56 static const char app[] =
"ADSIProg";
100 { 15,
"DISTINCTIVERING" },
102 { 17,
"REMINDERRING" },
103 { 18,
"SPECIALRING" },
119 #define STATE_NORMAL 0
120 #define STATE_INKEY 1
121 #define STATE_INSUB 2
124 #define MAX_RET_CODE 20
125 #define MAX_SUB_LEN 255
126 #define MAX_MAIN_LEN 1600
128 #define ARG_STRING (1 << 0)
129 #define ARG_NUMBER (1 << 1)
189 unsigned char sec[5];
191 unsigned char fdn[5];
196 static int process_token(
void *out,
char *src,
int maxlen,
int argtype)
198 if ((strlen(src) > 1) && src[0] ==
'\"') {
200 if (!(argtype & ARG_STRING))
204 if (maxlen > strlen(src) - 1)
205 maxlen = strlen(src) - 1;
206 memcpy(out, src, maxlen);
207 ((
char *)out)[maxlen] =
'\0';
208 }
else if (!ast_strlen_zero(src) && (src[0] ==
'\\')) {
209 if (!(argtype & ARG_NUMBER))
212 if (sscanf(src,
"%30o", (
unsigned *)out) != 1)
214 if (argtype & ARG_STRING) {
216 *((
unsigned int *)out) = htonl(*((
unsigned int *)out));
218 }
else if ((strlen(src) > 2) && (src[0] ==
'0') && (tolower(src[1]) ==
'x')) {
219 if (!(argtype & ARG_NUMBER))
222 if (sscanf(src + 2,
"%30x", (
unsigned int *)out) != 1)
224 if (argtype & ARG_STRING) {
226 *((
unsigned int *)out) = htonl(*((
unsigned int *)out));
228 }
else if ((!ast_strlen_zero(src) && isdigit(src[0]))) {
229 if (!(argtype & ARG_NUMBER))
232 if (sscanf(src,
"%30d", (
int *)out) != 1)
234 if (argtype & ARG_STRING) {
236 *((
unsigned int *)out) = htonl(*((
unsigned int *)out));
243 static char *get_token(
char **buf,
const char *script,
int lineno)
245 char *tmp = *buf, *keyword;
249 while(*tmp && (*tmp < 33))
254 while(*tmp && ((*tmp > 32) || quoted)) {
261 ast_log(LOG_WARNING,
"Mismatched quotes at line %d of %s\n", lineno, script);
266 while(*tmp && (*tmp < 33))
273 static char *validdtmf =
"123456789*0#ABCD";
275 static int send_dtmf(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *
state,
const char *script,
int lineno)
277 char dtmfstr[80], *a;
280 if (!(a = get_token(&args, script, lineno))) {
281 ast_log(LOG_WARNING,
"Expecting something to send for SENDDTMF at line %d of %s\n", lineno, script);
285 if (process_token(dtmfstr, a,
sizeof(dtmfstr) - 1, ARG_STRING)) {
286 ast_log(LOG_WARNING,
"Invalid token for SENDDTMF at line %d of %s\n", lineno, script);
293 if (strchr(validdtmf, *a)) {
298 ast_log(LOG_WARNING,
"'%c' is not a valid DTMF tone at line %d of %s\n", *a, lineno, script);
305 static int goto_line(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
307 char *page = get_token(&args, script, lineno);
308 char *gline = get_token(&args, script, lineno);
312 if (!page || !gline) {
313 ast_log(LOG_WARNING,
"Expecting page and line number for GOTOLINE at line %d of %s\n", lineno, script);
317 if (!strcasecmp(page,
"INFO"))
319 else if (!strcasecmp(page,
"COMM"))
322 ast_log(LOG_WARNING,
"Expecting either 'INFO' or 'COMM' page, got '%s' at line %d of %s\n", page, lineno, script);
326 if (process_token(&line, gline,
sizeof(line), ARG_NUMBER)) {
327 ast_log(LOG_WARNING,
"Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
338 static int goto_line_rel(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
340 char *dir = get_token(&args, script, lineno);
341 char *gline = get_token(&args, script, lineno);
345 if (!dir || !gline) {
346 ast_log(LOG_WARNING,
"Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno, script);
350 if (!strcasecmp(dir,
"UP"))
352 else if (!strcasecmp(dir,
"DOWN"))
355 ast_log(LOG_WARNING,
"Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir, lineno, script);
359 if (process_token(&line, gline,
sizeof(line), ARG_NUMBER)) {
360 ast_log(LOG_WARNING,
"Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
371 static int send_delay(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
373 char *gtime = get_token(&args, script, lineno);
377 ast_log(LOG_WARNING,
"Expecting number of milliseconds to wait at line %d of %s\n", lineno, script);
381 if (process_token(&ms, gtime,
sizeof(ms), ARG_NUMBER)) {
382 ast_log(LOG_WARNING,
"Invalid delay milliseconds '%s' at line %d of %s\n", gtime, lineno, script);
396 static int set_state(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
398 char *gstate = get_token(&args, script, lineno);
402 ast_log(LOG_WARNING,
"Expecting state number at line %d of %s\n", lineno, script);
406 if (process_token(&state, gstate,
sizeof(state), ARG_NUMBER)) {
407 ast_log(LOG_WARNING,
"Invalid state number '%s' at line %d of %s\n", gstate, lineno, script);
417 static int cleartimer(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
419 char *tok = get_token(&args, script, lineno);
422 ast_log(LOG_WARNING,
"Clearing timer requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
435 static struct adsi_flag *getflagbyname(
struct adsi_script *state,
char *name,
const char *script,
int lineno,
int create)
439 for (x = 0; x < state->numflags; x++) {
440 if (!strcasecmp(state->flags[x].vname, name))
441 return &state->flags[x];
448 if (state->numflags > 6) {
449 ast_log(LOG_WARNING,
"No more flag space at line %d of %s\n", lineno, script);
453 ast_copy_string(state->flags[state->numflags].vname, name,
sizeof(state->flags[state->numflags].vname));
454 state->flags[state->numflags].id = state->numflags + 1;
457 return &state->flags[state->numflags-1];
460 static int setflag(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
462 char *tok = get_token(&args, script, lineno);
467 ast_log(LOG_WARNING,
"Setting flag requires a flag number at line %d of %s\n", lineno, script);
471 if (process_token(sname, tok,
sizeof(sname) - 1, ARG_STRING)) {
472 ast_log(LOG_WARNING,
"Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
476 if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
477 ast_log(LOG_WARNING,
"Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
482 buf[1] = ((flag->id & 0x7) << 4) | 1;
487 static int clearflag(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
489 char *tok = get_token(&args, script, lineno);
494 ast_log(LOG_WARNING,
"Clearing flag requires a flag number at line %d of %s\n", lineno, script);
498 if (process_token(sname, tok,
sizeof(sname) - 1, ARG_STRING)) {
499 ast_log(LOG_WARNING,
"Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
503 if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
504 ast_log(LOG_WARNING,
"Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
509 buf[1] = ((flag->id & 0x7) << 4);
514 static int starttimer(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
516 char *tok = get_token(&args, script, lineno);
520 ast_log(LOG_WARNING,
"Missing number of seconds at line %d of %s\n", lineno, script);
524 if (process_token(&secs, tok,
sizeof(secs), ARG_NUMBER)) {
525 ast_log(LOG_WARNING,
"Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
536 static int geteventbyname(
char *name)
540 for (x = 0; x < ARRAY_LEN(events); x++) {
541 if (!strcasecmp(events[x].name, name))
548 static int getjustifybyname(
char *name)
552 for (x = 0; x < ARRAY_LEN(justify); x++) {
553 if (!strcasecmp(justify[x].name, name))
554 return justify[x].
id;
564 for (x = 0; x < state->numkeys; x++) {
565 if (!strcasecmp(state->keys[x].vname, name))
566 return &state->keys[x];
569 if (state->numkeys > 61) {
570 ast_log(LOG_WARNING,
"No more key space at line %d of %s\n", lineno, script);
574 ast_copy_string(state->keys[state->numkeys].vname, name,
sizeof(state->keys[state->numkeys].vname));
575 state->keys[state->numkeys].id = state->numkeys + 2;
578 return &state->keys[state->numkeys-1];
585 for (x = 0; x < state->numsubs; x++) {
586 if (!strcasecmp(state->subs[x].vname, name))
587 return &state->subs[x];
590 if (state->numsubs > 127) {
591 ast_log(LOG_WARNING,
"No more subscript space at line %d of %s\n", lineno,
S_OR(script,
"unknown"));
595 ast_copy_string(state->subs[state->numsubs].vname, name,
sizeof(state->subs[state->numsubs].vname));
596 state->subs[state->numsubs].id = state->numsubs;
599 return &state->subs[state->numsubs-1];
602 static struct adsi_state *getstatebyname(
struct adsi_script *state,
char *name,
const char *script,
int lineno,
int create)
606 for (x = 0; x <state->numstates; x++) {
607 if (!strcasecmp(state->states[x].vname, name))
608 return &state->states[x];
615 if (state->numstates > 253) {
616 ast_log(LOG_WARNING,
"No more state space at line %d of %s\n", lineno, script);
620 ast_copy_string(state->states[state->numstates].vname, name,
sizeof(state->states[state->numstates].vname));
621 state->states[state->numstates].id = state->numstates + 1;
624 return &state->states[state->numstates-1];
627 static struct adsi_display *getdisplaybyname(
struct adsi_script *state,
char *name,
const char *script,
int lineno,
int create)
631 for (x = 0; x < state->numdisplays; x++) {
632 if (!strcasecmp(state->displays[x].vname, name))
633 return &state->displays[x];
640 if (state->numdisplays > 61) {
641 ast_log(LOG_WARNING,
"No more display space at line %d of %s\n", lineno, script);
645 ast_copy_string(state->displays[state->numdisplays].vname, name,
sizeof(state->displays[state->numdisplays].vname));
646 state->displays[state->numdisplays].id = state->numdisplays + 1;
647 state->numdisplays++;
649 return &state->displays[state->numdisplays-1];
652 static int showkeys(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
654 char *tok, newkey[80];
655 int bytes, x, flagid = 0;
656 unsigned char keyid[6];
660 for (x = 0; x < 7; x++) {
662 if (!(tok = get_token(&args, script, lineno)))
664 if (!strcasecmp(tok,
"UNLESS")) {
666 if (!(tok = get_token(&args, script, lineno)))
667 ast_log(LOG_WARNING,
"Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
668 else if (process_token(newkey, tok,
sizeof(newkey) - 1, ARG_STRING))
669 ast_log(LOG_WARNING,
"Invalid flag name '%s' at line %d of %s\n", tok, lineno, script);
670 else if (!(flag = getflagbyname(state, newkey, script, lineno, 0)))
671 ast_log(LOG_WARNING,
"Flag '%s' is undeclared at line %d of %s\n", newkey, lineno, script);
674 if ((tok = get_token(&args, script, lineno)))
675 ast_log(LOG_WARNING,
"Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
679 ast_log(LOG_WARNING,
"Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok, lineno, script);
682 if (process_token(newkey, tok,
sizeof(newkey) - 1, ARG_STRING)) {
683 ast_log(LOG_WARNING,
"Invalid token for key name: %s\n", tok);
687 if (!(key = getkeybyname(state, newkey, script, lineno)))
692 buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
693 for (bytes = 0; bytes < x; bytes++)
694 buf[bytes + 2] = keyid[bytes];
699 static int showdisplay(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
701 char *tok, dispname[80];
702 int line = 0, flag = 0, cmd = 3;
706 if (!(tok = get_token(&args, script, lineno)) || process_token(dispname, tok,
sizeof(dispname) - 1, ARG_STRING)) {
707 ast_log(LOG_WARNING,
"Invalid display name: %s at line %d of %s\n", tok ? tok :
"<nothing>", lineno, script);
711 if (!(disp = getdisplaybyname(state, dispname, script, lineno, 0))) {
712 ast_log(LOG_WARNING,
"Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
716 if (!(tok = get_token(&args, script, lineno)) || strcasecmp(tok,
"AT")) {
717 ast_log(LOG_WARNING,
"Missing token 'AT' at line %d of %s\n", lineno, script);
722 if (!(tok = get_token(&args, script, lineno)) || process_token(&line, tok,
sizeof(line), ARG_NUMBER)) {
723 ast_log(LOG_WARNING,
"Invalid line: '%s' at line %d of %s\n", tok ? tok :
"<nothing>", lineno, script);
727 if ((tok = get_token(&args, script, lineno)) && !strcasecmp(tok,
"NOUPDATE")) {
729 tok = get_token(&args, script, lineno);
732 if (tok && !strcasecmp(tok,
"UNLESS")) {
734 if (!(tok = get_token(&args, script, lineno)))
735 ast_log(LOG_WARNING,
"Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
736 else if (process_token(&flag, tok,
sizeof(flag), ARG_NUMBER))
737 ast_log(LOG_WARNING,
"Invalid flag number '%s' at line %d of %s\n", tok, lineno, script);
739 if ((tok = get_token(&args, script, lineno)))
740 ast_log(LOG_WARNING,
"Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
744 buf[1] = (cmd << 6) | (disp->id & 0x3f);
745 buf[2] = ((line & 0x1f) << 3) | (flag & 0x7);
750 static int cleardisplay(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
752 char *tok = get_token(&args, script, lineno);
755 ast_log(LOG_WARNING,
"Clearing display requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
762 static int digitdirect(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
764 char *tok = get_token(&args, script, lineno);
767 ast_log(LOG_WARNING,
"Digitdirect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
774 static int clearcbone(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
776 char *tok = get_token(&args, script, lineno);
779 ast_log(LOG_WARNING,
"CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
786 static int digitcollect(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *istate,
const char *script,
int lineno)
788 char *tok = get_token(&args, script, lineno);
791 ast_log(LOG_WARNING,
"Digitcollect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
798 static int subscript(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
800 char *tok = get_token(&args, script, lineno);
805 ast_log(LOG_WARNING,
"Missing subscript to call at line %d of %s\n", lineno, script);
809 if (process_token(subscr, tok,
sizeof(subscr) - 1, ARG_STRING)) {
810 ast_log(LOG_WARNING,
"Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
814 if (!(sub = getsubbyname(state, subscr, script, lineno)))
823 static int onevent(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
825 char *tok = get_token(&args, script, lineno);
826 char subscr[80], sname[80];
827 int sawin = 0,
event, snums[8], scnt = 0, x;
831 ast_log(LOG_WARNING,
"Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
835 if ((
event = geteventbyname(tok)) < 1) {
836 ast_log(LOG_WARNING,
"'%s' is not a valid event name, at line %d of %s\n", args, lineno, script);
840 tok = get_token(&args, script, lineno);
841 while ((!sawin && !strcasecmp(tok,
"IN")) || (sawin && !strcasecmp(tok,
"OR"))) {
844 ast_log(LOG_WARNING,
"No more than 8 states may be specified for inclusion at line %d of %s\n", lineno, script);
848 tok = get_token(&args, script, lineno);
849 if (process_token(sname, tok,
sizeof(sname), ARG_STRING)) {
850 ast_log(LOG_WARNING,
"'%s' is not a valid state name at line %d of %s\n", tok, lineno, script);
853 if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) == NULL)) {
854 ast_log(LOG_WARNING,
"State '%s' not declared at line %d of %s\n", sname, lineno, script);
858 if (!(tok = get_token(&args, script, lineno)))
861 if (!tok || strcasecmp(tok,
"GOTO")) {
865 ast_log(LOG_WARNING,
"Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok, lineno, script);
867 ast_log(LOG_WARNING,
"Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok, lineno, script);
869 if (!(tok = get_token(&args, script, lineno))) {
870 ast_log(LOG_WARNING,
"Missing subscript to call at line %d of %s\n", lineno, script);
873 if (process_token(subscr, tok,
sizeof(subscr) - 1, ARG_STRING)) {
874 ast_log(LOG_WARNING,
"Invalid subscript '%s' at line %d of %s\n", tok, lineno, script);
877 if (!(sub = getsubbyname(state, subscr, script, lineno)))
881 buf[2] = sub->id | 0x80;
882 for (x = 0; x < scnt; x++)
883 buf[3 + x] = snums[x];
890 int (*add_args)(
char *buf,
char *name,
int id,
char *args,
struct adsi_script *state,
const char *script,
int lineno);
894 {
"SENDDTMF", 0, send_dtmf },
899 {
"WAITDIALTONE", 0x84 },
902 {
"SENDCHARS", 0x87 },
903 {
"CLEARCHARS", 0x88 },
904 {
"BACKSPACE", 0x89 },
906 {
"GOTOLINE", 0x8b, goto_line },
907 {
"GOTOLINEREL", 0x8c, goto_line_rel },
909 {
"PAGEDOWN", 0x8e },
911 {
"DELAY", 0x90, send_delay },
912 {
"DIALPULSEONE", 0x91 },
913 {
"DATAMODE", 0x92 },
914 {
"VOICEMODE", 0x93 },
917 {
"CLEARCB1", 0x95, clearcbone },
918 {
"DIGITCOLLECT", 0x96, digitcollect },
919 {
"DIGITDIRECT", 0x96, digitdirect },
921 {
"SHOWDISPLAY", 0x98, showdisplay },
922 {
"CLEARDISPLAY", 0x98, cleardisplay },
923 {
"SHOWKEYS", 0x99, showkeys },
924 {
"SETSTATE", 0x9a, set_state },
925 {
"TIMERSTART", 0x9b, starttimer },
926 {
"TIMERCLEAR", 0x9b, cleartimer },
927 {
"SETFLAG", 0x9c, setflag },
928 {
"CLEARFLAG", 0x9c, clearflag },
929 {
"GOTO", 0x9d, subscript },
938 {
"SHOWKEYS", 2, showkeys },
940 {
"SHOWDISPLAY", 3, showdisplay },
941 {
"CLEARDISPLAY", 3, cleardisplay },
943 {
"SETSTATE", 6, set_state },
944 {
"TIMERSTART", 7, starttimer },
945 {
"TIMERCLEAR", 7, cleartimer },
946 {
"ONEVENT", 8, onevent },
948 {
"SETFLAG", 10, setflag },
949 {
"CLEARFLAG", 10, clearflag },
950 {
"DELAY", 11, send_delay },
955 static int process_returncode(
struct adsi_soft_key *key,
char *code,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
960 for (x = 0; x < ARRAY_LEN(kcmds); x++) {
961 if ((kcmds[x].
id > -1) && !strcasecmp(kcmds[x].name, code)) {
962 if (kcmds[x].add_args) {
963 res = kcmds[x].add_args(key->retstr + key->retstrlen,
964 code, kcmds[x].id, args, state, script, lineno);
965 if ((key->retstrlen + res - key->initlen) <= MAX_RET_CODE)
966 key->retstrlen += res;
968 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);
970 if ((unused = get_token(&args, script, lineno)))
971 ast_log(LOG_WARNING,
"'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds[x].name, lineno, script, unused);
972 if ((key->retstrlen + 1 - key->initlen) <= MAX_RET_CODE) {
973 key->retstr[key->retstrlen] = kcmds[x].id;
976 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);
984 static int process_opcode(
struct adsi_subscript *sub,
char *code,
char *args,
struct adsi_script *state,
const char *script,
int lineno)
986 int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
989 for (x = 0; x < ARRAY_LEN(opcmds); x++) {
990 if ((opcmds[x].
id > -1) && !strcasecmp(opcmds[x].name, code)) {
991 if (opcmds[x].add_args) {
992 res = opcmds[x].add_args(sub->data + sub->datalen,
993 code, opcmds[x].id, args, state, script, lineno);
994 if ((sub->datalen + res + 1) <= max)
997 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);
1001 if ((unused = get_token(&args, script, lineno)))
1002 ast_log(LOG_WARNING,
"'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds[x].name, lineno, script, unused);
1003 if ((sub->datalen + 2) <= max) {
1004 sub->data[sub->datalen] = opcmds[x].id;
1007 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);
1012 sub->data[sub->datalen] = 0xff;
1021 static int adsi_process(
struct adsi_script *state,
char *buf,
const char *script,
int lineno)
1023 char *keyword = get_token(&buf, script, lineno);
1024 char *args, vname[256], tmp[80], tmp2[80];
1025 int lrci, wi,
event;
1032 switch(state->state) {
1034 if (!strcasecmp(keyword,
"DESCRIPTION")) {
1035 if ((args = get_token(&buf, script, lineno))) {
1036 if (process_token(state->desc, args,
sizeof(state->desc) - 1, ARG_STRING))
1037 ast_log(LOG_WARNING,
"'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args, lineno, script);
1039 ast_log(LOG_WARNING,
"Missing argument for DESCRIPTION at line %d of %s\n", lineno, script);
1040 }
else if (!strcasecmp(keyword,
"VERSION")) {
1041 if ((args = get_token(&buf, script, lineno))) {
1042 if (process_token(&state->ver, args,
sizeof(state->ver) - 1, ARG_NUMBER))
1043 ast_log(LOG_WARNING,
"'%s' is not a valid token for VERSION at line %d of %s\n", args, lineno, script);
1045 ast_log(LOG_WARNING,
"Missing argument for VERSION at line %d of %s\n", lineno, script);
1046 }
else if (!strcasecmp(keyword,
"SECURITY")) {
1047 if ((args = get_token(&buf, script, lineno))) {
1048 if (process_token(state->sec, args,
sizeof(state->sec) - 1, ARG_STRING | ARG_NUMBER))
1049 ast_log(LOG_WARNING,
"'%s' is not a valid token for SECURITY at line %d of %s\n", args, lineno, script);
1051 ast_log(LOG_WARNING,
"Missing argument for SECURITY at line %d of %s\n", lineno, script);
1052 }
else if (!strcasecmp(keyword,
"FDN")) {
1053 if ((args = get_token(&buf, script, lineno))) {
1054 if (process_token(state->fdn, args,
sizeof(state->fdn) - 1, ARG_STRING | ARG_NUMBER))
1055 ast_log(LOG_WARNING,
"'%s' is not a valid token for FDN at line %d of %s\n", args, lineno, script);
1057 ast_log(LOG_WARNING,
"Missing argument for FDN at line %d of %s\n", lineno, script);
1058 }
else if (!strcasecmp(keyword,
"KEY")) {
1059 if (!(args = get_token(&buf, script, lineno))) {
1060 ast_log(LOG_WARNING,
"KEY definition missing name at line %d of %s\n", lineno, script);
1063 if (process_token(vname, args,
sizeof(vname) - 1, ARG_STRING)) {
1064 ast_log(LOG_WARNING,
"'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
1067 if (!(state->key = getkeybyname(state, vname, script, lineno))) {
1068 ast_log(LOG_WARNING,
"Out of key space at line %d of %s\n", lineno, script);
1071 if (state->key->defined) {
1072 ast_log(LOG_WARNING,
"Cannot redefine key '%s' at line %d of %s\n", vname, lineno, script);
1075 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args,
"IS")) {
1076 ast_log(LOG_WARNING,
"Expecting 'IS', but got '%s' at line %d of %s\n", args ? args :
"<nothing>", lineno, script);
1079 if (!(args = get_token(&buf, script, lineno))) {
1080 ast_log(LOG_WARNING,
"KEY definition missing short name at line %d of %s\n", lineno, script);
1083 if (process_token(tmp, args,
sizeof(tmp) - 1, ARG_STRING)) {
1084 ast_log(LOG_WARNING,
"'%s' is not a valid token for a KEY short name at line %d of %s\n", args, lineno, script);
1087 if ((args = get_token(&buf, script, lineno))) {
1088 if (strcasecmp(args,
"OR")) {
1089 ast_log(LOG_WARNING,
"Expecting 'OR' but got '%s' instead at line %d of %s\n", args, lineno, script);
1092 if (!(args = get_token(&buf, script, lineno))) {
1093 ast_log(LOG_WARNING,
"KEY definition missing optional long name at line %d of %s\n", lineno, script);
1096 if (process_token(tmp2, args,
sizeof(tmp2) - 1, ARG_STRING)) {
1097 ast_log(LOG_WARNING,
"'%s' is not a valid token for a KEY long name at line %d of %s\n", args, lineno, script);
1103 if (strlen(tmp2) > 18) {
1104 ast_log(LOG_WARNING,
"Truncating full name to 18 characters at line %d of %s\n", lineno, script);
1107 if (strlen(tmp) > 7) {
1108 ast_log(LOG_WARNING,
"Truncating short name to 7 bytes at line %d of %s\n", lineno, script);
1112 state->key->retstr[0] = 0x80;
1114 state->key->retstr[2] = state->key->id;
1116 memcpy(state->key->retstr + 3, tmp2, strlen(tmp2));
1118 state->key->retstrlen = strlen(tmp2) + 3;
1120 state->key->retstr[state->key->retstrlen++] = 0xff;
1122 memcpy(state->key->retstr + state->key->retstrlen, tmp, strlen(tmp));
1124 state->key->retstrlen += strlen(tmp);
1126 state->key->retstr[state->key->retstrlen++] = 0xff;
1128 state->key->initlen = state->key->retstrlen;
1129 state->state = STATE_INKEY;
1130 }
else if (!strcasecmp(keyword,
"SUB")) {
1131 if (!(args = get_token(&buf, script, lineno))) {
1132 ast_log(LOG_WARNING,
"SUB definition missing name at line %d of %s\n", lineno, script);
1135 if (process_token(vname, args,
sizeof(vname) - 1, ARG_STRING)) {
1136 ast_log(LOG_WARNING,
"'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
1139 if (!(state->sub = getsubbyname(state, vname, script, lineno))) {
1140 ast_log(LOG_WARNING,
"Out of subroutine space at line %d of %s\n", lineno, script);
1143 if (state->sub->defined) {
1144 ast_log(LOG_WARNING,
"Cannot redefine subroutine '%s' at line %d of %s\n", vname, lineno, script);
1148 state->sub->data[0] = 0x82;
1150 state->sub->data[2] = 0x0;
1151 state->sub->datalen = 3;
1152 if (state->sub->id) {
1154 state->sub->data[3] = 9;
1155 state->sub->data[4] = state->sub->id;
1157 state->sub->data[6] = 0xff;
1158 state->sub->datalen = 7;
1160 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args,
"IS")) {
1161 ast_log(LOG_WARNING,
"Expecting 'IS', but got '%s' at line %d of %s\n", args ? args :
"<nothing>", lineno, script);
1164 state->state = STATE_INSUB;
1165 }
else if (!strcasecmp(keyword,
"STATE")) {
1166 if (!(args = get_token(&buf, script, lineno))) {
1167 ast_log(LOG_WARNING,
"STATE definition missing name at line %d of %s\n", lineno, script);
1170 if (process_token(vname, args,
sizeof(vname) - 1, ARG_STRING)) {
1171 ast_log(LOG_WARNING,
"'%s' is not a valid token for a STATE name at line %d of %s\n", args, lineno, script);
1174 if (getstatebyname(state, vname, script, lineno, 0)) {
1175 ast_log(LOG_WARNING,
"State '%s' is already defined at line %d of %s\n", vname, lineno, script);
1178 getstatebyname(state, vname, script, lineno, 1);
1179 }
else if (!strcasecmp(keyword,
"FLAG")) {
1180 if (!(args = get_token(&buf, script, lineno))) {
1181 ast_log(LOG_WARNING,
"FLAG definition missing name at line %d of %s\n", lineno, script);
1184 if (process_token(vname, args,
sizeof(vname) - 1, ARG_STRING)) {
1185 ast_log(LOG_WARNING,
"'%s' is not a valid token for a FLAG name at line %d of %s\n", args, lineno, script);
1188 if (getflagbyname(state, vname, script, lineno, 0)) {
1189 ast_log(LOG_WARNING,
"Flag '%s' is already defined\n", vname);
1192 getflagbyname(state, vname, script, lineno, 1);
1193 }
else if (!strcasecmp(keyword,
"DISPLAY")) {
1196 if (!(args = get_token(&buf, script, lineno))) {
1197 ast_log(LOG_WARNING,
"SUB definition missing name at line %d of %s\n", lineno, script);
1200 if (process_token(vname, args,
sizeof(vname) - 1, ARG_STRING)) {
1201 ast_log(LOG_WARNING,
"'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
1204 if (getdisplaybyname(state, vname, script, lineno, 0)) {
1205 ast_log(LOG_WARNING,
"State '%s' is already defined\n", vname);
1208 if (!(disp = getdisplaybyname(state, vname, script, lineno, 1)))
1210 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args,
"IS")) {
1211 ast_log(LOG_WARNING,
"Missing 'IS' at line %d of %s\n", lineno, script);
1214 if (!(args = get_token(&buf, script, lineno))) {
1215 ast_log(LOG_WARNING,
"Missing Column 1 text at line %d of %s\n", lineno, script);
1218 if (process_token(tmp, args,
sizeof(tmp) - 1, ARG_STRING)) {
1219 ast_log(LOG_WARNING,
"Token '%s' is not valid column 1 text at line %d of %s\n", args, lineno, script);
1222 if (strlen(tmp) > 20) {
1223 ast_log(LOG_WARNING,
"Truncating column one to 20 characters at line %d of %s\n", lineno, script);
1226 memcpy(disp->data + 5, tmp, strlen(tmp));
1227 disp->datalen = strlen(tmp) + 5;
1228 disp->data[disp->datalen++] = 0xff;
1230 args = get_token(&buf, script, lineno);
1231 if (args && !process_token(tmp, args,
sizeof(tmp) - 1, ARG_STRING)) {
1233 if (strlen(tmp) > 20) {
1234 ast_log(LOG_WARNING,
"Truncating column two to 20 characters at line %d of %s\n", lineno, script);
1237 memcpy(disp->data + disp->datalen, tmp, strlen(tmp));
1238 disp->datalen += strlen(tmp);
1239 args = get_token(&buf, script, lineno);
1242 if (!strcasecmp(args,
"JUSTIFY")) {
1243 args = get_token(&buf, script, lineno);
1245 ast_log(LOG_WARNING,
"Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno, script);
1248 lrci = getjustifybyname(args);
1250 ast_log(LOG_WARNING,
"'%s' is not a valid justification at line %d of %s\n", args, lineno, script);
1253 }
else if (!strcasecmp(args,
"WRAP")) {
1256 ast_log(LOG_WARNING,
"'%s' is not a known qualifier at line %d of %s\n", args, lineno, script);
1259 args = get_token(&buf, script, lineno);
1265 disp->data[0] = 0x81;
1266 disp->data[1] = disp->datalen - 2;
1267 disp->data[2] = ((lrci & 0x3) << 6) | disp->id;
1269 disp->data[4] = 0xff;
1271 ast_log(LOG_WARNING,
"Invalid or Unknown keyword '%s' in PROGRAM\n", keyword);
1275 if (process_returncode(state->key, keyword, buf, state, script, lineno)) {
1276 if (!strcasecmp(keyword,
"ENDKEY")) {
1278 state->state = STATE_NORMAL;
1279 state->key->defined = 1;
1280 state->key->retstr[1] = state->key->retstrlen - 2;
1283 ast_log(LOG_WARNING,
"Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword, lineno, script);
1288 if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
1289 if (!strcasecmp(keyword,
"ENDIF")) {
1291 state->state = STATE_INSUB;
1292 state->sub->defined = 1;
1294 state->sub->ifdata[2] = state->sub->ifinscount;
1295 }
else if (!strcasecmp(keyword,
"GOTO")) {
1296 if (!(args = get_token(&buf, script, lineno))) {
1297 ast_log(LOG_WARNING,
"GOTO clause missing Subscript name at line %d of %s\n", lineno, script);
1300 if (process_token(tmp, args,
sizeof(tmp) - 1, ARG_STRING)) {
1301 ast_log(LOG_WARNING,
"'%s' is not a valid subscript name token at line %d of %s\n", args, lineno, script);
1304 if (!(newsub = getsubbyname(state, tmp, script, lineno)))
1307 state->sub->data[state->sub->datalen++] = 0x8;
1308 state->sub->data[state->sub->datalen++] = state->sub->ifdata[1];
1309 state->sub->data[state->sub->datalen++] = newsub->id;
1311 state->sub->data[state->sub->datalen++] = 0xff;
1313 state->sub->inscount++;
1314 state->sub->ifinscount++;
1316 ast_log(LOG_WARNING,
"Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword, lineno, script);
1319 state->sub->ifinscount++;
1322 if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
1323 if (!strcasecmp(keyword,
"ENDSUB")) {
1325 state->state = STATE_NORMAL;
1326 state->sub->defined = 1;
1328 state->sub->data[1] = state->sub->datalen - 2;
1329 if (state->sub->id) {
1331 state->sub->data[5] = state->sub->inscount;
1334 }
else if (!strcasecmp(keyword,
"IFEVENT")) {
1335 if (!(args = get_token(&buf, script, lineno))) {
1336 ast_log(LOG_WARNING,
"IFEVENT clause missing Event name at line %d of %s\n", lineno, script);
1339 if ((event = geteventbyname(args)) < 1) {
1340 ast_log(LOG_WARNING,
"'%s' is not a valid event\n", args);
1343 if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args,
"THEN")) {
1344 ast_log(LOG_WARNING,
"IFEVENT clause missing 'THEN' at line %d of %s\n", lineno, script);
1347 state->sub->ifinscount = 0;
1348 state->sub->ifdata = state->sub->data + state->sub->datalen;
1350 state->sub->ifdata[0] = 0x1;
1351 state->sub->ifdata[1] = event;
1353 state->sub->ifdata[3] = 0xff;
1354 state->sub->datalen += 4;
1356 state->sub->inscount++;
1357 state->state = STATE_INIF;
1359 ast_log(LOG_WARNING,
"Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword, lineno, script);
1364 ast_log(LOG_WARNING,
"Can't process keyword '%s' in weird state %d\n", keyword, state->state);
1369 static struct adsi_script *compile_script(
const char *script)
1372 char fn[256], buf[256], *c;
1373 int lineno = 0, x, err;
1376 if (script[0] ==
'/')
1379 snprintf(fn,
sizeof(fn),
"%s/%s", ast_config_AST_CONFIG_DIR, script);
1381 if (!(f = fopen(fn,
"r"))) {
1382 ast_log(LOG_WARNING,
"Can't open file '%s'\n", fn);
1392 getsubbyname(scr,
"main", NULL, 0);
1394 if (!fgets(buf,
sizeof(buf), f)) {
1400 buf[strlen(buf) - 1] =
'\0';
1402 if ((c = strchr(buf,
';')))
1404 if (!ast_strlen_zero(buf))
1405 adsi_process(scr, buf, script, lineno);
1410 switch(scr->state) {
1414 ast_log(LOG_WARNING,
"Missing ENDSUB at end of file %s\n", script);
1418 ast_log(LOG_WARNING,
"Missing ENDKEY at end of file %s\n", script);
1425 for (x = 0; x < scr->numkeys; x++) {
1426 if (!scr->keys[x].defined) {
1427 ast_log(LOG_WARNING,
"Key '%s' referenced but never defined in file %s\n", scr->keys[x].vname, fn);
1433 for (x = 0; x < scr->numsubs; x++) {
1434 if (!scr->subs[x].defined) {
1435 ast_log(LOG_WARNING,
"Subscript '%s' referenced but never defined in file %s\n", scr->subs[x].vname, fn);
1438 if (x == (scr->numsubs - 1)) {
1440 scr->subs[x].data[2] = 0x80;
1451 #ifdef DUMP_MESSAGES
1452 static void dump_message(
char *type,
char *vname,
unsigned char *buf,
int buflen)
1455 printf(
"%s %s: [ ", type, vname);
1456 for (x = 0; x < buflen; x++)
1457 printf(
"%02hhx ", buf[x]);
1462 static int adsi_prog(
struct ast_channel *chan,
const char *script)
1466 unsigned char buf[1024];
1468 if (!(scr = compile_script(script)))
1476 if (ast_adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
1478 ast_verb(3,
"User rejected download attempt\n");
1479 ast_log(LOG_NOTICE,
"User rejected download on channel %s\n", ast_channel_name(chan));
1486 for (x = 0; x < scr->numkeys; x++) {
1487 if (bytes + scr->keys[x].retstrlen > 253) {
1489 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1490 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1495 memcpy(buf + bytes, scr->keys[x].retstr, scr->keys[x].retstrlen);
1496 bytes += scr->keys[x].retstrlen;
1497 #ifdef DUMP_MESSAGES
1498 dump_message(
"Key", scr->keys[x].vname, scr->keys[x].retstr, scr->keys[x].retstrlen);
1502 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1503 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1510 for (x = 0; x < scr->numdisplays; x++) {
1511 if (bytes + scr->displays[x].datalen > 253) {
1513 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1514 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1519 memcpy(buf + bytes, scr->displays[x].data, scr->displays[x].datalen);
1520 bytes += scr->displays[x].datalen;
1521 #ifdef DUMP_MESSAGES
1522 dump_message(
"Display", scr->displays[x].vname, scr->displays[x].data, scr->displays[x].datalen);
1526 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1527 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1534 for (x = 0; x < scr->numsubs; x++) {
1535 if (bytes + scr->subs[x].datalen > 253) {
1537 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1538 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1543 memcpy(buf + bytes, scr->subs[x].data, scr->subs[x].datalen);
1544 bytes += scr->subs[x].datalen;
1545 #ifdef DUMP_MESSAGES
1546 dump_message(
"Sub", scr->subs[x].vname, scr->subs[x].data, scr->subs[x].datalen);
1550 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
1551 ast_log(LOG_WARNING,
"Unable to send chunk ending at %d\n", x);
1557 bytes +=
ast_adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0,
"Download complete.",
"");
1559 if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
1561 if (ast_adsi_end_download(chan)) {
1563 ast_verb(3,
"Download attempt failed\n");
1564 ast_log(LOG_NOTICE,
"Download failed on %s\n", ast_channel_name(chan));
1569 ast_adsi_unload_session(chan);
1573 static int adsi_exec(
struct ast_channel *chan,
const char *data)
1577 if (ast_strlen_zero(data))
1578 data =
"asterisk.adsi";
1581 ast_verb(3,
"ADSI Unavailable on CPE. Not bothering to try.\n");
1583 ast_verb(3,
"ADSI Available on CPE. Attempting Upload.\n");
1584 res = adsi_prog(chan, data);
1590 static int unload_module(
void)
1612 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,
"Asterisk ADSI Programming Application",
1613 .support_level = AST_MODULE_SUPPORT_DEPRECATED,
1615 .unload = unload_module,
1616 .requires =
"res_adsi",
Main Channel structure associated with a channel.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
int ast_adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
Check if scripts for a given app are already loaded. Version may be -1, if any version is okay...
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
ADSI Support (built upon Caller*ID)
int ast_unregister_application(const char *app)
Unregister an application.
static int load_module(void)
Load the module.
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
static struct stasis_rest_handlers events
REST handler for /api-docs/events.json.
int ast_adsi_display(unsigned char *buf, int page, int line, int just, int wrap, char *col1, char *col2)
Loads a line of info into the display.
Core PBX routines and definitions.
#define ast_calloc(num, len)
A wrapper for calloc()
Module has failed to load, may be in an inconsistent state.
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.