2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Program Asterisk ADSI Scripts into phone
23 * \author Mark Spencer <markster@digium.com>
25 * \ingroup applications
29 <depend>res_adsi</depend>
34 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include <netinet/in.h>
39 #include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
40 #include "asterisk/file.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/module.h"
44 #include "asterisk/adsi.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/lock.h"
48 static char *app
= "ADSIProg";
50 static char *synopsis
= "Load Asterisk ADSI Scripts into phone";
52 /* #define DUMP_MESSAGES */
54 static char *descrip
=
55 " ADSIProg(script): This application programs an ADSI Phone with the given\n"
56 "script. If nothing is specified, the default script (asterisk.adsi) is used.\n";
63 static struct adsi_event events
[] = {
78 { 15, "DISTINCTIVERING" },
80 { 17, "REMINDERRING" },
81 { 18, "SPECIALRING" },
90 static struct adsi_event justify
[] = {
97 #define STATE_NORMAL 0
102 #define MAX_RET_CODE 20
103 #define MAX_SUB_LEN 255
104 #define MAX_MAIN_LEN 1600
106 #define ARG_STRING (1 << 0)
107 #define ARG_NUMBER (1 << 1)
109 struct adsi_soft_key
{
110 char vname
[40]; /* Which "variable" is associated with it */
111 int retstrlen
; /* Length of return string */
112 int initlen
; /* initial length */
115 char retstr
[80]; /* Return string data */
118 struct adsi_subscript
{
139 struct adsi_display
{
153 struct adsi_soft_key
*key
;
154 struct adsi_subscript
*sub
;
155 /* Pre-defined displays */
156 struct adsi_display displays
[63];
157 /* ADSI States 1 (initial) - 254 */
158 struct adsi_state states
[256];
160 struct adsi_soft_key keys
[62];
161 /* Subscripts 0 (main) to 127 */
162 struct adsi_subscript subs
[128];
164 struct adsi_flag flags
[7];
166 /* Stuff from adsi script */
167 unsigned char sec
[5];
169 unsigned char fdn
[5];
174 static int process_token(void *out
, char *src
, int maxlen
, int argtype
)
176 if ((strlen(src
) > 1) && src
[0] == '\"') {
177 /* This is a quoted string */
178 if (!(argtype
& ARG_STRING
))
181 /* Don't take more than what's there */
182 if (maxlen
> strlen(src
) - 1)
183 maxlen
= strlen(src
) - 1;
184 memcpy(out
, src
, maxlen
);
185 ((char *)out
)[maxlen
] = '\0';
186 } else if (!ast_strlen_zero(src
) && (src
[0] == '\\')) {
187 if (!(argtype
& ARG_NUMBER
))
190 if (sscanf(src
, "%o", (int *)out
) != 1)
192 if (argtype
& ARG_STRING
) {
194 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
196 } else if ((strlen(src
) > 2) && (src
[0] == '0') && (tolower(src
[1]) == 'x')) {
197 if (!(argtype
& ARG_NUMBER
))
200 if (sscanf(src
+ 2, "%x", (unsigned int *)out
) != 1)
202 if (argtype
& ARG_STRING
) {
204 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
206 } else if ((!ast_strlen_zero(src
) && isdigit(src
[0]))) {
207 if (!(argtype
& ARG_NUMBER
))
210 if (sscanf(src
, "%d", (int *)out
) != 1)
212 if (argtype
& ARG_STRING
) {
214 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
221 static char *get_token(char **buf
, char *script
, int lineno
)
223 char *tmp
= *buf
, *keyword
;
226 /* Advance past any white space */
227 while(*tmp
&& (*tmp
< 33))
232 while(*tmp
&& ((*tmp
> 32) || quoted
)) {
239 ast_log(LOG_WARNING
, "Mismatched quotes at line %d of %s\n", lineno
, script
);
244 while(*tmp
&& (*tmp
< 33))
246 /* Note where we left off */
251 static char *validdtmf
= "123456789*0#ABCD";
253 static int send_dtmf(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
255 char dtmfstr
[80], *a
;
258 if (!(a
= get_token(&args
, script
, lineno
))) {
259 ast_log(LOG_WARNING
, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno
, script
);
263 if (process_token(dtmfstr
, a
, sizeof(dtmfstr
) - 1, ARG_STRING
)) {
264 ast_log(LOG_WARNING
, "Invalid token for SENDDTMF at line %d of %s\n", lineno
, script
);
271 if (strchr(validdtmf
, *a
)) {
276 ast_log(LOG_WARNING
, "'%c' is not a valid DTMF tone at line %d of %s\n", *a
, lineno
, script
);
283 static int goto_line(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
285 char *page
= get_token(&args
, script
, lineno
);
286 char *gline
= get_token(&args
, script
, lineno
);
290 if (!page
|| !gline
) {
291 ast_log(LOG_WARNING
, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno
, script
);
295 if (!strcasecmp(page
, "INFO"))
297 else if (!strcasecmp(page
, "COMM"))
300 ast_log(LOG_WARNING
, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page
, lineno
, script
);
304 if (process_token(&line
, gline
, sizeof(line
), ARG_NUMBER
)) {
305 ast_log(LOG_WARNING
, "Invalid line number '%s' at line %d of %s\n", gline
, lineno
, script
);
316 static int goto_line_rel(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
318 char *dir
= get_token(&args
, script
, lineno
);
319 char *gline
= get_token(&args
, script
, lineno
);
323 if (!dir
|| !gline
) {
324 ast_log(LOG_WARNING
, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno
, script
);
328 if (!strcasecmp(dir
, "UP"))
330 else if (!strcasecmp(dir
, "DOWN"))
333 ast_log(LOG_WARNING
, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir
, lineno
, script
);
337 if (process_token(&line
, gline
, sizeof(line
), ARG_NUMBER
)) {
338 ast_log(LOG_WARNING
, "Invalid line number '%s' at line %d of %s\n", gline
, lineno
, script
);
349 static int send_delay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
351 char *gtime
= get_token(&args
, script
, lineno
);
355 ast_log(LOG_WARNING
, "Expecting number of milliseconds to wait at line %d of %s\n", lineno
, script
);
359 if (process_token(&ms
, gtime
, sizeof(ms
), ARG_NUMBER
)) {
360 ast_log(LOG_WARNING
, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime
, lineno
, script
);
374 static int set_state(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
376 char *gstate
= get_token(&args
, script
, lineno
);
380 ast_log(LOG_WARNING
, "Expecting state number at line %d of %s\n", lineno
, script
);
384 if (process_token(&state
, gstate
, sizeof(state
), ARG_NUMBER
)) {
385 ast_log(LOG_WARNING
, "Invalid state number '%s' at line %d of %s\n", gstate
, lineno
, script
);
395 static int cleartimer(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
397 char *tok
= get_token(&args
, script
, lineno
);
400 ast_log(LOG_WARNING
, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
404 /* For some reason the clear code is different slightly */
413 static struct adsi_flag
*getflagbyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
417 for (x
= 0; x
< state
->numflags
; x
++) {
418 if (!strcasecmp(state
->flags
[x
].vname
, name
))
419 return &state
->flags
[x
];
422 /* Return now if we're not allowed to create */
426 if (state
->numflags
> 6) {
427 ast_log(LOG_WARNING
, "No more flag space at line %d of %s\n", lineno
, script
);
431 ast_copy_string(state
->flags
[state
->numflags
].vname
, name
, sizeof(state
->flags
[state
->numflags
].vname
));
432 state
->flags
[state
->numflags
].id
= state
->numflags
+ 1;
435 return &state
->flags
[state
->numflags
-1];
438 static int setflag(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
440 char *tok
= get_token(&args
, script
, lineno
);
442 struct adsi_flag
*flag
;
445 ast_log(LOG_WARNING
, "Setting flag requires a flag number at line %d of %s\n", lineno
, script
);
449 if (process_token(sname
, tok
, sizeof(sname
) - 1, ARG_STRING
)) {
450 ast_log(LOG_WARNING
, "Invalid flag '%s' at line %d of %s\n", tok
, lineno
, script
);
454 if (!(flag
= getflagbyname(state
, sname
, script
, lineno
, 0))) {
455 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", sname
, lineno
, script
);
460 buf
[1] = ((flag
->id
& 0x7) << 4) | 1;
465 static int clearflag(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
467 char *tok
= get_token(&args
, script
, lineno
);
468 struct adsi_flag
*flag
;
472 ast_log(LOG_WARNING
, "Clearing flag requires a flag number at line %d of %s\n", lineno
, script
);
476 if (process_token(sname
, tok
, sizeof(sname
) - 1, ARG_STRING
)) {
477 ast_log(LOG_WARNING
, "Invalid flag '%s' at line %d of %s\n", tok
, lineno
, script
);
481 if (!(flag
= getflagbyname(state
, sname
, script
, lineno
, 0))) {
482 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", sname
, lineno
, script
);
487 buf
[1] = ((flag
->id
& 0x7) << 4);
492 static int starttimer(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
494 char *tok
= get_token(&args
, script
, lineno
);
498 ast_log(LOG_WARNING
, "Missing number of seconds at line %d of %s\n", lineno
, script
);
502 if (process_token(&secs
, tok
, sizeof(secs
), ARG_NUMBER
)) {
503 ast_log(LOG_WARNING
, "Invalid number of seconds '%s' at line %d of %s\n", tok
, lineno
, script
);
514 static int geteventbyname(char *name
)
518 for (x
= 0; x
< ARRAY_LEN(events
); x
++) {
519 if (!strcasecmp(events
[x
].name
, name
))
526 static int getjustifybyname(char *name
)
530 for (x
= 0; x
< ARRAY_LEN(justify
); x
++) {
531 if (!strcasecmp(justify
[x
].name
, name
))
532 return justify
[x
].id
;
538 static struct adsi_soft_key
*getkeybyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
)
542 for (x
= 0; x
< state
->numkeys
; x
++) {
543 if (!strcasecmp(state
->keys
[x
].vname
, name
))
544 return &state
->keys
[x
];
547 if (state
->numkeys
> 61) {
548 ast_log(LOG_WARNING
, "No more key space at line %d of %s\n", lineno
, script
);
552 ast_copy_string(state
->keys
[state
->numkeys
].vname
, name
, sizeof(state
->keys
[state
->numkeys
].vname
));
553 state
->keys
[state
->numkeys
].id
= state
->numkeys
+ 2;
556 return &state
->keys
[state
->numkeys
-1];
559 static struct adsi_subscript
*getsubbyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
)
563 for (x
= 0; x
< state
->numsubs
; x
++) {
564 if (!strcasecmp(state
->subs
[x
].vname
, name
))
565 return &state
->subs
[x
];
568 if (state
->numsubs
> 127) {
569 ast_log(LOG_WARNING
, "No more subscript space at line %d of %s\n", lineno
, script
);
573 ast_copy_string(state
->subs
[state
->numsubs
].vname
, name
, sizeof(state
->subs
[state
->numsubs
].vname
));
574 state
->subs
[state
->numsubs
].id
= state
->numsubs
;
577 return &state
->subs
[state
->numsubs
-1];
580 static struct adsi_state
*getstatebyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
584 for (x
= 0; x
<state
->numstates
; x
++) {
585 if (!strcasecmp(state
->states
[x
].vname
, name
))
586 return &state
->states
[x
];
589 /* Return now if we're not allowed to create */
593 if (state
->numstates
> 253) {
594 ast_log(LOG_WARNING
, "No more state space at line %d of %s\n", lineno
, script
);
598 ast_copy_string(state
->states
[state
->numstates
].vname
, name
, sizeof(state
->states
[state
->numstates
].vname
));
599 state
->states
[state
->numstates
].id
= state
->numstates
+ 1;
602 return &state
->states
[state
->numstates
-1];
605 static struct adsi_display
*getdisplaybyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
609 for (x
= 0; x
< state
->numdisplays
; x
++) {
610 if (!strcasecmp(state
->displays
[x
].vname
, name
))
611 return &state
->displays
[x
];
614 /* Return now if we're not allowed to create */
618 if (state
->numdisplays
> 61) {
619 ast_log(LOG_WARNING
, "No more display space at line %d of %s\n", lineno
, script
);
623 ast_copy_string(state
->displays
[state
->numdisplays
].vname
, name
, sizeof(state
->displays
[state
->numdisplays
].vname
));
624 state
->displays
[state
->numdisplays
].id
= state
->numdisplays
+ 1;
625 state
->numdisplays
++;
627 return &state
->displays
[state
->numdisplays
-1];
630 static int showkeys(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
632 char *tok
, newkey
[80];
633 int bytes
, x
, flagid
= 0;
634 unsigned char keyid
[6];
635 struct adsi_soft_key
*key
;
636 struct adsi_flag
*flag
;
638 for (x
= 0; x
< 7; x
++) {
639 /* Up to 6 key arguments */
640 if (!(tok
= get_token(&args
, script
, lineno
)))
642 if (!strcasecmp(tok
, "UNLESS")) {
643 /* Check for trailing UNLESS flag */
644 if (!(tok
= get_token(&args
, script
, lineno
)))
645 ast_log(LOG_WARNING
, "Missing argument for UNLESS clause at line %d of %s\n", lineno
, script
);
646 else if (process_token(newkey
, tok
, sizeof(newkey
) - 1, ARG_STRING
))
647 ast_log(LOG_WARNING
, "Invalid flag name '%s' at line %d of %s\n", tok
, lineno
, script
);
648 else if (!(flag
= getflagbyname(state
, newkey
, script
, lineno
, 0)))
649 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", newkey
, lineno
, script
);
652 if ((tok
= get_token(&args
, script
, lineno
)))
653 ast_log(LOG_WARNING
, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok
, lineno
, script
);
657 ast_log(LOG_WARNING
, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok
, lineno
, script
);
660 if (process_token(newkey
, tok
, sizeof(newkey
) - 1, ARG_STRING
)) {
661 ast_log(LOG_WARNING
, "Invalid token for key name: %s\n", tok
);
665 if (!(key
= getkeybyname(state
, newkey
, script
, lineno
)))
670 buf
[1] = (flagid
& 0x7) << 3 | (x
& 0x7);
671 for (bytes
= 0; bytes
< x
; bytes
++)
672 buf
[bytes
+ 2] = keyid
[bytes
];
677 static int showdisplay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
679 char *tok
, dispname
[80];
680 int line
= 0, flag
= 0, cmd
= 3;
681 struct adsi_display
*disp
;
684 if (!(tok
= get_token(&args
, script
, lineno
)) || process_token(dispname
, tok
, sizeof(dispname
) - 1, ARG_STRING
)) {
685 ast_log(LOG_WARNING
, "Invalid display name: %s at line %d of %s\n", tok
? tok
: "<nothing>", lineno
, script
);
689 if (!(disp
= getdisplaybyname(state
, dispname
, script
, lineno
, 0))) {
690 ast_log(LOG_WARNING
, "Display '%s' is undefined at line %d of %s\n", dispname
, lineno
, script
);
694 if (!(tok
= get_token(&args
, script
, lineno
)) || strcasecmp(tok
, "AT")) {
695 ast_log(LOG_WARNING
, "Missing token 'AT' at line %d of %s\n", lineno
, script
);
699 /* Get line number */
700 if (!(tok
= get_token(&args
, script
, lineno
)) || process_token(&line
, tok
, sizeof(line
), ARG_NUMBER
)) {
701 ast_log(LOG_WARNING
, "Invalid line: '%s' at line %d of %s\n", tok
? tok
: "<nothing>", lineno
, script
);
705 if ((tok
= get_token(&args
, script
, lineno
)) && !strcasecmp(tok
, "NOUPDATE")) {
707 tok
= get_token(&args
, script
, lineno
);
710 if (tok
&& !strcasecmp(tok
, "UNLESS")) {
711 /* Check for trailing UNLESS flag */
712 if (!(tok
= get_token(&args
, script
, lineno
)))
713 ast_log(LOG_WARNING
, "Missing argument for UNLESS clause at line %d of %s\n", lineno
, script
);
714 else if (process_token(&flag
, tok
, sizeof(flag
), ARG_NUMBER
))
715 ast_log(LOG_WARNING
, "Invalid flag number '%s' at line %d of %s\n", tok
, lineno
, script
);
717 if ((tok
= get_token(&args
, script
, lineno
)))
718 ast_log(LOG_WARNING
, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok
, lineno
, script
);
722 buf
[1] = (cmd
<< 6) | (disp
->id
& 0x3f);
723 buf
[2] = ((line
& 0x1f) << 3) | (flag
& 0x7);
728 static int cleardisplay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
730 char *tok
= get_token(&args
, script
, lineno
);
733 ast_log(LOG_WARNING
, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
740 static int digitdirect(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
742 char *tok
= get_token(&args
, script
, lineno
);
745 ast_log(LOG_WARNING
, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
752 static int clearcbone(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
754 char *tok
= get_token(&args
, script
, lineno
);
757 ast_log(LOG_WARNING
, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
764 static int digitcollect(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
766 char *tok
= get_token(&args
, script
, lineno
);
769 ast_log(LOG_WARNING
, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
776 static int subscript(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
778 char *tok
= get_token(&args
, script
, lineno
);
780 struct adsi_subscript
*sub
;
783 ast_log(LOG_WARNING
, "Missing subscript to call at line %d of %s\n", lineno
, script
);
787 if (process_token(subscr
, tok
, sizeof(subscr
) - 1, ARG_STRING
)) {
788 ast_log(LOG_WARNING
, "Invalid number of seconds '%s' at line %d of %s\n", tok
, lineno
, script
);
792 if (!(sub
= getsubbyname(state
, subscr
, script
, lineno
)))
801 static int onevent(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
803 char *tok
= get_token(&args
, script
, lineno
);
804 char subscr
[80], sname
[80];
805 int sawin
= 0, event
, snums
[8], scnt
= 0, x
;
806 struct adsi_subscript
*sub
;
809 ast_log(LOG_WARNING
, "Missing event for 'ONEVENT' at line %d of %s\n", lineno
, script
);
813 if ((event
= geteventbyname(tok
)) < 1) {
814 ast_log(LOG_WARNING
, "'%s' is not a valid event name, at line %d of %s\n", args
, lineno
, script
);
818 tok
= get_token(&args
, script
, lineno
);
819 while ((!sawin
&& !strcasecmp(tok
, "IN")) || (sawin
&& !strcasecmp(tok
, "OR"))) {
822 ast_log(LOG_WARNING
, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno
, script
);
825 /* Process 'in' things */
826 tok
= get_token(&args
, script
, lineno
);
827 if (process_token(sname
, tok
, sizeof(sname
), ARG_STRING
)) {
828 ast_log(LOG_WARNING
, "'%s' is not a valid state name at line %d of %s\n", tok
, lineno
, script
);
831 if ((snums
[scnt
] = getstatebyname(state
, sname
, script
, lineno
, 0) < 0)) {
832 ast_log(LOG_WARNING
, "State '%s' not declared at line %d of %s\n", sname
, lineno
, script
);
836 if (!(tok
= get_token(&args
, script
, lineno
)))
839 if (!tok
|| strcasecmp(tok
, "GOTO")) {
843 ast_log(LOG_WARNING
, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok
, lineno
, script
);
845 ast_log(LOG_WARNING
, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok
, lineno
, script
);
847 if (!(tok
= get_token(&args
, script
, lineno
))) {
848 ast_log(LOG_WARNING
, "Missing subscript to call at line %d of %s\n", lineno
, script
);
851 if (process_token(subscr
, tok
, sizeof(subscr
) - 1, ARG_STRING
)) {
852 ast_log(LOG_WARNING
, "Invalid subscript '%s' at line %d of %s\n", tok
, lineno
, script
);
855 if (!(sub
= getsubbyname(state
, subscr
, script
, lineno
)))
859 buf
[2] = sub
->id
| 0x80;
860 for (x
= 0; x
< scnt
; x
++)
861 buf
[3 + x
] = snums
[x
];
865 struct adsi_key_cmd
{
868 int (*add_args
)(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
);
871 static struct adsi_key_cmd kcmds
[] = {
872 { "SENDDTMF", 0, send_dtmf
},
873 /* Encoded DTMF would go here */
877 { "WAITDIALTONE", 0x84 },
878 /* Send line number */
880 { "SENDCHARS", 0x87 },
881 { "CLEARCHARS", 0x88 },
882 { "BACKSPACE", 0x89 },
884 { "GOTOLINE", 0x8b, goto_line
},
885 { "GOTOLINEREL", 0x8c, goto_line_rel
},
887 { "PAGEDOWN", 0x8e },
889 { "DELAY", 0x90, send_delay
},
890 { "DIALPULSEONE", 0x91 },
891 { "DATAMODE", 0x92 },
892 { "VOICEMODE", 0x93 },
893 /* Display call buffer 'n' */
894 /* Clear call buffer 'n' */
895 { "CLEARCB1", 0x95, clearcbone
},
896 { "DIGITCOLLECT", 0x96, digitcollect
},
897 { "DIGITDIRECT", 0x96, digitdirect
},
899 { "SHOWDISPLAY", 0x98, showdisplay
},
900 { "CLEARDISPLAY", 0x98, cleardisplay
},
901 { "SHOWKEYS", 0x99, showkeys
},
902 { "SETSTATE", 0x9a, set_state
},
903 { "TIMERSTART", 0x9b, starttimer
},
904 { "TIMERCLEAR", 0x9b, cleartimer
},
905 { "SETFLAG", 0x9c, setflag
},
906 { "CLEARFLAG", 0x9c, clearflag
},
907 { "GOTO", 0x9d, subscript
},
913 static struct adsi_key_cmd opcmds
[] = {
915 /* 1 - Branch on event -- handled specially */
916 { "SHOWKEYS", 2, showkeys
},
917 /* Display Control */
918 { "SHOWDISPLAY", 3, showdisplay
},
919 { "CLEARDISPLAY", 3, cleardisplay
},
921 { "SETSTATE", 6, set_state
},
922 { "TIMERSTART", 7, starttimer
},
923 { "TIMERCLEAR", 7, cleartimer
},
924 { "ONEVENT", 8, onevent
},
925 /* 9 - Subroutine label, treated specially */
926 { "SETFLAG", 10, setflag
},
927 { "CLEARFLAG", 10, clearflag
},
928 { "DELAY", 11, send_delay
},
933 static int process_returncode(struct adsi_soft_key
*key
, char *code
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
938 for (x
= 0; x
< ARRAY_LEN(kcmds
); x
++) {
939 if ((kcmds
[x
].id
> -1) && !strcasecmp(kcmds
[x
].name
, code
)) {
940 if (kcmds
[x
].add_args
) {
941 res
= kcmds
[x
].add_args(key
->retstr
+ key
->retstrlen
,
942 code
, kcmds
[x
].id
, args
, state
, script
, lineno
);
943 if ((key
->retstrlen
+ res
- key
->initlen
) <= MAX_RET_CODE
)
944 key
->retstrlen
+= res
;
946 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
);
948 if ((unused
= get_token(&args
, script
, lineno
)))
949 ast_log(LOG_WARNING
, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds
[x
].name
, lineno
, script
, unused
);
950 if ((key
->retstrlen
+ 1 - key
->initlen
) <= MAX_RET_CODE
) {
951 key
->retstr
[key
->retstrlen
] = kcmds
[x
].id
;
954 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
);
962 static int process_opcode(struct adsi_subscript
*sub
, char *code
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
964 int x
, res
, max
= sub
->id
? MAX_SUB_LEN
: MAX_MAIN_LEN
;
967 for (x
= 0; x
< ARRAY_LEN(opcmds
); x
++) {
968 if ((opcmds
[x
].id
> -1) && !strcasecmp(opcmds
[x
].name
, code
)) {
969 if (opcmds
[x
].add_args
) {
970 res
= opcmds
[x
].add_args(sub
->data
+ sub
->datalen
,
971 code
, opcmds
[x
].id
, args
, state
, script
, lineno
);
972 if ((sub
->datalen
+ res
+ 1) <= max
)
975 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
);
979 if ((unused
= get_token(&args
, script
, lineno
)))
980 ast_log(LOG_WARNING
, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds
[x
].name
, lineno
, script
, unused
);
981 if ((sub
->datalen
+ 2) <= max
) {
982 sub
->data
[sub
->datalen
] = opcmds
[x
].id
;
985 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
);
989 /* Separate commands with 0xff */
990 sub
->data
[sub
->datalen
] = 0xff;
999 static int adsi_process(struct adsi_script
*state
, char *buf
, char *script
, int lineno
)
1001 char *keyword
= get_token(&buf
, script
, lineno
);
1002 char *args
, vname
[256], tmp
[80], tmp2
[80];
1003 int lrci
, wi
, event
;
1004 struct adsi_display
*disp
;
1005 struct adsi_subscript
*newsub
;
1010 switch(state
->state
) {
1012 if (!strcasecmp(keyword
, "DESCRIPTION")) {
1013 if ((args
= get_token(&buf
, script
, lineno
))) {
1014 if (process_token(state
->desc
, args
, sizeof(state
->desc
) - 1, ARG_STRING
))
1015 ast_log(LOG_WARNING
, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args
, lineno
, script
);
1017 ast_log(LOG_WARNING
, "Missing argument for DESCRIPTION at line %d of %s\n", lineno
, script
);
1018 } else if (!strcasecmp(keyword
, "VERSION")) {
1019 if ((args
= get_token(&buf
, script
, lineno
))) {
1020 if (process_token(&state
->ver
, args
, sizeof(state
->ver
) - 1, ARG_NUMBER
))
1021 ast_log(LOG_WARNING
, "'%s' is not a valid token for VERSION at line %d of %s\n", args
, lineno
, script
);
1023 ast_log(LOG_WARNING
, "Missing argument for VERSION at line %d of %s\n", lineno
, script
);
1024 } else if (!strcasecmp(keyword
, "SECURITY")) {
1025 if ((args
= get_token(&buf
, script
, lineno
))) {
1026 if (process_token(state
->sec
, args
, sizeof(state
->sec
) - 1, ARG_STRING
| ARG_NUMBER
))
1027 ast_log(LOG_WARNING
, "'%s' is not a valid token for SECURITY at line %d of %s\n", args
, lineno
, script
);
1029 ast_log(LOG_WARNING
, "Missing argument for SECURITY at line %d of %s\n", lineno
, script
);
1030 } else if (!strcasecmp(keyword
, "FDN")) {
1031 if ((args
= get_token(&buf
, script
, lineno
))) {
1032 if (process_token(state
->fdn
, args
, sizeof(state
->fdn
) - 1, ARG_STRING
| ARG_NUMBER
))
1033 ast_log(LOG_WARNING
, "'%s' is not a valid token for FDN at line %d of %s\n", args
, lineno
, script
);
1035 ast_log(LOG_WARNING
, "Missing argument for FDN at line %d of %s\n", lineno
, script
);
1036 } else if (!strcasecmp(keyword
, "KEY")) {
1037 if (!(args
= get_token(&buf
, script
, lineno
))) {
1038 ast_log(LOG_WARNING
, "KEY definition missing name at line %d of %s\n", lineno
, script
);
1041 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1042 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1045 if (!(state
->key
= getkeybyname(state
, vname
, script
, lineno
))) {
1046 ast_log(LOG_WARNING
, "Out of key space at line %d of %s\n", lineno
, script
);
1049 if (state
->key
->defined
) {
1050 ast_log(LOG_WARNING
, "Cannot redefine key '%s' at line %d of %s\n", vname
, lineno
, script
);
1053 if (!(args
= get_token(&buf
, script
, lineno
)) || strcasecmp(args
, "IS")) {
1054 ast_log(LOG_WARNING
, "Expecting 'IS', but got '%s' at line %d of %s\n", args
? args
: "<nothing>", lineno
, script
);
1057 if (!(args
= get_token(&buf
, script
, lineno
))) {
1058 ast_log(LOG_WARNING
, "KEY definition missing short name at line %d of %s\n", lineno
, script
);
1061 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1062 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY short name at line %d of %s\n", args
, lineno
, script
);
1065 if ((args
= get_token(&buf
, script
, lineno
))) {
1066 if (strcasecmp(args
, "OR")) {
1067 ast_log(LOG_WARNING
, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args
, lineno
, script
);
1070 if (!(args
= get_token(&buf
, script
, lineno
))) {
1071 ast_log(LOG_WARNING
, "KEY definition missing optional long name at line %d of %s\n", lineno
, script
);
1074 if (process_token(tmp2
, args
, sizeof(tmp2
) - 1, ARG_STRING
)) {
1075 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY long name at line %d of %s\n", args
, lineno
, script
);
1079 ast_copy_string(tmp2
, tmp
, sizeof(tmp2
));
1081 if (strlen(tmp2
) > 18) {
1082 ast_log(LOG_WARNING
, "Truncating full name to 18 characters at line %d of %s\n", lineno
, script
);
1085 if (strlen(tmp
) > 7) {
1086 ast_log(LOG_WARNING
, "Truncating short name to 7 bytes at line %d of %s\n", lineno
, script
);
1089 /* Setup initial stuff */
1090 state
->key
->retstr
[0] = 128;
1091 /* 1 has the length */
1092 state
->key
->retstr
[2] = state
->key
->id
;
1093 /* Put the Full name in */
1094 memcpy(state
->key
->retstr
+ 3, tmp2
, strlen(tmp2
));
1096 state
->key
->retstrlen
= strlen(tmp2
) + 3;
1097 /* Put trailing 0xff */
1098 state
->key
->retstr
[state
->key
->retstrlen
++] = 0xff;
1099 /* Put the short name */
1100 memcpy(state
->key
->retstr
+ state
->key
->retstrlen
, tmp
, strlen(tmp
));
1102 state
->key
->retstrlen
+= strlen(tmp
);
1103 /* Put trailing 0xff */
1104 state
->key
->retstr
[state
->key
->retstrlen
++] = 0xff;
1105 /* Record initial length */
1106 state
->key
->initlen
= state
->key
->retstrlen
;
1107 state
->state
= STATE_INKEY
;
1108 } else if (!strcasecmp(keyword
, "SUB")) {
1109 if (!(args
= get_token(&buf
, script
, lineno
))) {
1110 ast_log(LOG_WARNING
, "SUB definition missing name at line %d of %s\n", lineno
, script
);
1113 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1114 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1117 if (!(state
->sub
= getsubbyname(state
, vname
, script
, lineno
))) {
1118 ast_log(LOG_WARNING
, "Out of subroutine space at line %d of %s\n", lineno
, script
);
1121 if (state
->sub
->defined
) {
1122 ast_log(LOG_WARNING
, "Cannot redefine subroutine '%s' at line %d of %s\n", vname
, lineno
, script
);
1126 state
->sub
->data
[0] = 130;
1127 /* 1 is the length */
1128 state
->sub
->data
[2] = 0x0; /* Clear extensibility bit */
1129 state
->sub
->datalen
= 3;
1130 if (state
->sub
->id
) {
1131 /* If this isn't the main subroutine, make a subroutine label for it */
1132 state
->sub
->data
[3] = 9;
1133 state
->sub
->data
[4] = state
->sub
->id
;
1135 state
->sub
->data
[6] = 0xff;
1136 state
->sub
->datalen
= 7;
1138 if (!(args
= get_token(&buf
, script
, lineno
)) || strcasecmp(args
, "IS")) {
1139 ast_log(LOG_WARNING
, "Expecting 'IS', but got '%s' at line %d of %s\n", args
? args
: "<nothing>", lineno
, script
);
1142 state
->state
= STATE_INSUB
;
1143 } else if (!strcasecmp(keyword
, "STATE")) {
1144 if (!(args
= get_token(&buf
, script
, lineno
))) {
1145 ast_log(LOG_WARNING
, "STATE definition missing name at line %d of %s\n", lineno
, script
);
1148 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1149 ast_log(LOG_WARNING
, "'%s' is not a valid token for a STATE name at line %d of %s\n", args
, lineno
, script
);
1152 if (getstatebyname(state
, vname
, script
, lineno
, 0)) {
1153 ast_log(LOG_WARNING
, "State '%s' is already defined at line %d of %s\n", vname
, lineno
, script
);
1156 getstatebyname(state
, vname
, script
, lineno
, 1);
1157 } else if (!strcasecmp(keyword
, "FLAG")) {
1158 if (!(args
= get_token(&buf
, script
, lineno
))) {
1159 ast_log(LOG_WARNING
, "FLAG definition missing name at line %d of %s\n", lineno
, script
);
1162 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1163 ast_log(LOG_WARNING
, "'%s' is not a valid token for a FLAG name at line %d of %s\n", args
, lineno
, script
);
1166 if (getflagbyname(state
, vname
, script
, lineno
, 0)) {
1167 ast_log(LOG_WARNING
, "Flag '%s' is already defined\n", vname
);
1170 getflagbyname(state
, vname
, script
, lineno
, 1);
1171 } else if (!strcasecmp(keyword
, "DISPLAY")) {
1174 if (!(args
= get_token(&buf
, script
, lineno
))) {
1175 ast_log(LOG_WARNING
, "SUB definition missing name at line %d of %s\n", lineno
, script
);
1178 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1179 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1182 if (getdisplaybyname(state
, vname
, script
, lineno
, 0)) {
1183 ast_log(LOG_WARNING
, "State '%s' is already defined\n", vname
);
1186 if (!(disp
= getdisplaybyname(state
, vname
, script
, lineno
, 1)))
1188 if (!(args
= get_token(&buf
, script
, lineno
)) || strcasecmp(args
, "IS")) {
1189 ast_log(LOG_WARNING
, "Missing 'IS' at line %d of %s\n", lineno
, script
);
1192 if (!(args
= get_token(&buf
, script
, lineno
))) {
1193 ast_log(LOG_WARNING
, "Missing Column 1 text at line %d of %s\n", lineno
, script
);
1196 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1197 ast_log(LOG_WARNING
, "Token '%s' is not valid column 1 text at line %d of %s\n", args
, lineno
, script
);
1200 if (strlen(tmp
) > 20) {
1201 ast_log(LOG_WARNING
, "Truncating column one to 20 characters at line %d of %s\n", lineno
, script
);
1204 memcpy(disp
->data
+ 5, tmp
, strlen(tmp
));
1205 disp
->datalen
= strlen(tmp
) + 5;
1206 disp
->data
[disp
->datalen
++] = 0xff;
1208 args
= get_token(&buf
, script
, lineno
);
1209 if (args
&& !process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1210 /* Got a column two */
1211 if (strlen(tmp
) > 20) {
1212 ast_log(LOG_WARNING
, "Truncating column two to 20 characters at line %d of %s\n", lineno
, script
);
1215 memcpy(disp
->data
+ disp
->datalen
, tmp
, strlen(tmp
));
1216 disp
->datalen
+= strlen(tmp
);
1217 args
= get_token(&buf
, script
, lineno
);
1220 if (!strcasecmp(args
, "JUSTIFY")) {
1221 args
= get_token(&buf
, script
, lineno
);
1223 ast_log(LOG_WARNING
, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno
, script
);
1226 lrci
= getjustifybyname(args
);
1228 ast_log(LOG_WARNING
, "'%s' is not a valid justification at line %d of %s\n", args
, lineno
, script
);
1231 } else if (!strcasecmp(args
, "WRAP")) {
1234 ast_log(LOG_WARNING
, "'%s' is not a known qualifier at line %d of %s\n", args
, lineno
, script
);
1237 args
= get_token(&buf
, script
, lineno
);
1240 /* Something bad happened */
1243 disp
->data
[0] = 129;
1244 disp
->data
[1] = disp
->datalen
- 2;
1245 disp
->data
[2] = ((lrci
& 0x3) << 6) | disp
->id
;
1247 disp
->data
[4] = 0xff;
1249 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword
);
1253 if (process_returncode(state
->key
, keyword
, buf
, state
, script
, lineno
)) {
1254 if (!strcasecmp(keyword
, "ENDKEY")) {
1255 /* Return to normal operation and increment current key */
1256 state
->state
= STATE_NORMAL
;
1257 state
->key
->defined
= 1;
1258 state
->key
->retstr
[1] = state
->key
->retstrlen
- 2;
1261 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword
, lineno
, script
);
1266 if (process_opcode(state
->sub
, keyword
, buf
, state
, script
, lineno
)) {
1267 if (!strcasecmp(keyword
, "ENDIF")) {
1268 /* Return to normal SUB operation and increment current key */
1269 state
->state
= STATE_INSUB
;
1270 state
->sub
->defined
= 1;
1271 /* Store the proper number of instructions */
1272 state
->sub
->ifdata
[2] = state
->sub
->ifinscount
;
1273 } else if (!strcasecmp(keyword
, "GOTO")) {
1274 if (!(args
= get_token(&buf
, script
, lineno
))) {
1275 ast_log(LOG_WARNING
, "GOTO clause missing Subscript name at line %d of %s\n", lineno
, script
);
1278 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1279 ast_log(LOG_WARNING
, "'%s' is not a valid subscript name token at line %d of %s\n", args
, lineno
, script
);
1282 if (!(newsub
= getsubbyname(state
, tmp
, script
, lineno
)))
1284 /* Somehow you use GOTO to go to another place */
1285 state
->sub
->data
[state
->sub
->datalen
++] = 0x8;
1286 state
->sub
->data
[state
->sub
->datalen
++] = state
->sub
->ifdata
[1];
1287 state
->sub
->data
[state
->sub
->datalen
++] = newsub
->id
;
1289 state
->sub
->data
[state
->sub
->datalen
++] = 0xff;
1290 /* Increment counters */
1291 state
->sub
->inscount
++;
1292 state
->sub
->ifinscount
++;
1294 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword
, lineno
, script
);
1297 state
->sub
->ifinscount
++;
1300 if (process_opcode(state
->sub
, keyword
, buf
, state
, script
, lineno
)) {
1301 if (!strcasecmp(keyword
, "ENDSUB")) {
1302 /* Return to normal operation and increment current key */
1303 state
->state
= STATE_NORMAL
;
1304 state
->sub
->defined
= 1;
1305 /* Store the proper length */
1306 state
->sub
->data
[1] = state
->sub
->datalen
- 2;
1307 if (state
->sub
->id
) {
1308 /* if this isn't main, store number of instructions, too */
1309 state
->sub
->data
[5] = state
->sub
->inscount
;
1312 } else if (!strcasecmp(keyword
, "IFEVENT")) {
1313 if (!(args
= get_token(&buf
, script
, lineno
))) {
1314 ast_log(LOG_WARNING
, "IFEVENT clause missing Event name at line %d of %s\n", lineno
, script
);
1317 if ((event
= geteventbyname(args
)) < 1) {
1318 ast_log(LOG_WARNING
, "'%s' is not a valid event\n", args
);
1321 if (!(args
= get_token(&buf
, script
, lineno
)) || strcasecmp(args
, "THEN")) {
1322 ast_log(LOG_WARNING
, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno
, script
);
1325 state
->sub
->ifinscount
= 0;
1326 state
->sub
->ifdata
= state
->sub
->data
+ state
->sub
->datalen
;
1327 /* Reserve header and insert op codes */
1328 state
->sub
->ifdata
[0] = 0x1;
1329 state
->sub
->ifdata
[1] = event
;
1330 /* 2 is for the number of instructions */
1331 state
->sub
->ifdata
[3] = 0xff;
1332 state
->sub
->datalen
+= 4;
1333 /* Update Subscript instruction count */
1334 state
->sub
->inscount
++;
1335 state
->state
= STATE_INIF
;
1337 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword
, lineno
, script
);
1342 ast_log(LOG_WARNING
, "Can't process keyword '%s' in weird state %d\n", keyword
, state
->state
);
1347 static struct adsi_script
*compile_script(char *script
)
1350 char fn
[256], buf
[256], *c
;
1351 int lineno
= 0, x
, err
;
1352 struct adsi_script
*scr
;
1354 if (script
[0] == '/')
1355 ast_copy_string(fn
, script
, sizeof(fn
));
1357 snprintf(fn
, sizeof(fn
), "%s/%s", ast_config_AST_CONFIG_DIR
, script
);
1359 if (!(f
= fopen(fn
, "r"))) {
1360 ast_log(LOG_WARNING
, "Can't open file '%s'\n", fn
);
1364 if (!(scr
= ast_calloc(1, sizeof(*scr
)))) {
1369 /* Create "main" as first subroutine */
1370 getsubbyname(scr
, "main", NULL
, 0);
1372 fgets(buf
, sizeof(buf
), f
);
1375 /* Trim off trailing return */
1376 buf
[strlen(buf
) - 1] = '\0';
1377 /* Strip comments */
1378 if ((c
= strchr(buf
, ';')))
1380 if (!ast_strlen_zero(buf
))
1381 adsi_process(scr
, buf
, script
, lineno
);
1385 /* Make sure we're in the main routine again */
1386 switch(scr
->state
) {
1390 ast_log(LOG_WARNING
, "Missing ENDSUB at end of file %s\n", script
);
1394 ast_log(LOG_WARNING
, "Missing ENDKEY at end of file %s\n", script
);
1400 /* Resolve all keys and record their lengths */
1401 for (x
= 0; x
< scr
->numkeys
; x
++) {
1402 if (!scr
->keys
[x
].defined
) {
1403 ast_log(LOG_WARNING
, "Key '%s' referenced but never defined in file %s\n", scr
->keys
[x
].vname
, fn
);
1408 /* Resolve all subs */
1409 for (x
= 0; x
< scr
->numsubs
; x
++) {
1410 if (!scr
->subs
[x
].defined
) {
1411 ast_log(LOG_WARNING
, "Subscript '%s' referenced but never defined in file %s\n", scr
->subs
[x
].vname
, fn
);
1414 if (x
== (scr
->numsubs
- 1)) {
1415 /* Clear out extension bit on last message */
1416 scr
->subs
[x
].data
[2] = 0x80;
1427 #ifdef DUMP_MESSAGES
1428 static void dump_message(char *type
, char *vname
, unsigned char *buf
, int buflen
)
1431 printf("%s %s: [ ", type
, vname
);
1432 for (x
= 0; x
< buflen
; x
++)
1433 printf("%02x ", buf
[x
]);
1438 static int adsi_prog(struct ast_channel
*chan
, char *script
)
1440 struct adsi_script
*scr
;
1442 unsigned char buf
[1024];
1444 if (!(scr
= compile_script(script
)))
1447 /* Start an empty ADSI Session */
1448 if (ast_adsi_load_session(chan
, NULL
, 0, 1) < 1)
1451 /* Now begin the download attempt */
1452 if (ast_adsi_begin_download(chan
, scr
->desc
, scr
->fdn
, scr
->sec
, scr
->ver
)) {
1453 /* User rejected us for some reason */
1454 ast_verb(3, "User rejected download attempt\n");
1455 ast_log(LOG_NOTICE
, "User rejected download on channel %s\n", chan
->name
);
1461 /* Start with key definitions */
1462 for (x
= 0; x
< scr
->numkeys
; x
++) {
1463 if (bytes
+ scr
->keys
[x
].retstrlen
> 253) {
1464 /* Send what we've collected so far */
1465 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1466 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1471 memcpy(buf
+ bytes
, scr
->keys
[x
].retstr
, scr
->keys
[x
].retstrlen
);
1472 bytes
+= scr
->keys
[x
].retstrlen
;
1473 #ifdef DUMP_MESSAGES
1474 dump_message("Key", scr
->keys
[x
].vname
, scr
->keys
[x
].retstr
, scr
->keys
[x
].retstrlen
);
1478 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1479 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1485 /* Continue with the display messages */
1486 for (x
= 0; x
< scr
->numdisplays
; x
++) {
1487 if (bytes
+ scr
->displays
[x
].datalen
> 253) {
1488 /* Send what we've collected so far */
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
->displays
[x
].data
, scr
->displays
[x
].datalen
);
1496 bytes
+= scr
->displays
[x
].datalen
;
1497 #ifdef DUMP_MESSAGES
1498 dump_message("Display", scr
->displays
[x
].vname
, scr
->displays
[x
].data
, scr
->displays
[x
].datalen
);
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
);
1509 /* Send subroutines */
1510 for (x
= 0; x
< scr
->numsubs
; x
++) {
1511 if (bytes
+ scr
->subs
[x
].datalen
> 253) {
1512 /* Send what we've collected so far */
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
->subs
[x
].data
, scr
->subs
[x
].datalen
);
1520 bytes
+= scr
->subs
[x
].datalen
;
1521 #ifdef DUMP_MESSAGES
1522 dump_message("Sub", scr
->subs
[x
].vname
, scr
->subs
[x
].data
, scr
->subs
[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
);
1533 bytes
+= ast_adsi_display(buf
, ADSI_INFO_PAGE
, 1, ADSI_JUST_LEFT
, 0, "Download complete.", "");
1534 bytes
+= ast_adsi_set_line(buf
, ADSI_INFO_PAGE
, 1);
1535 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
) < 0)
1537 if (ast_adsi_end_download(chan
)) {
1538 /* Download failed for some reason */
1539 ast_verb(3, "Download attempt failed\n");
1540 ast_log(LOG_NOTICE
, "Download failed on %s\n", chan
->name
);
1545 ast_adsi_unload_session(chan
);
1549 static int adsi_exec(struct ast_channel
*chan
, void *data
)
1553 if (ast_strlen_zero(data
))
1554 data
= "asterisk.adsi";
1556 if (!ast_adsi_available(chan
)) {
1557 ast_verb(3, "ADSI Unavailable on CPE. Not bothering to try.\n");
1559 ast_verb(3, "ADSI Available on CPE. Attempting Upload.\n");
1560 res
= adsi_prog(chan
, data
);
1566 static int unload_module(void)
1568 return ast_unregister_application(app
);
1571 static int load_module(void)
1573 if (ast_register_application(app
, adsi_exec
, synopsis
, descrip
))
1574 return AST_MODULE_LOAD_FAILURE
;
1575 return AST_MODULE_LOAD_SUCCESS
;
1578 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Asterisk ADSI Programming Application");