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 <sys/types.h>
37 #include <netinet/in.h>
46 #include "asterisk/file.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/module.h"
51 #include "asterisk/adsi.h"
52 #include "asterisk/options.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/lock.h"
56 static char *app
= "ADSIProg";
58 static char *synopsis
= "Load Asterisk ADSI Scripts into phone";
60 /* #define DUMP_MESSAGES */
62 static char *descrip
=
63 " ADSIProg(script): This application programs an ADSI Phone with the given\n"
64 "script. If nothing is specified, the default script (asterisk.adsi) is used.\n";
71 static struct adsi_event events
[] = {
86 { 15, "DISTINCTIVERING" },
88 { 17, "REMINDERRING" },
89 { 18, "SPECIALRING" },
98 static struct adsi_event justify
[] = {
105 #define STATE_NORMAL 0
106 #define STATE_INKEY 1
107 #define STATE_INSUB 2
110 #define MAX_RET_CODE 20
111 #define MAX_SUB_LEN 255
112 #define MAX_MAIN_LEN 1600
114 #define ARG_STRING (1 << 0)
115 #define ARG_NUMBER (1 << 1)
117 struct adsi_soft_key
{
118 char vname
[40]; /* Which "variable" is associated with it */
119 int retstrlen
; /* Length of return string */
120 int initlen
; /* initial length */
123 char retstr
[80]; /* Return string data */
126 struct adsi_subscript
{
147 struct adsi_display
{
161 struct adsi_soft_key
*key
;
162 struct adsi_subscript
*sub
;
163 /* Pre-defined displays */
164 struct adsi_display displays
[63];
165 /* ADSI States 1 (initial) - 254 */
166 struct adsi_state states
[256];
168 struct adsi_soft_key keys
[62];
169 /* Subscripts 0 (main) to 127 */
170 struct adsi_subscript subs
[128];
172 struct adsi_flag flags
[7];
174 /* Stuff from adsi script */
175 unsigned char sec
[5];
177 unsigned char fdn
[5];
182 static int process_token(void *out
, char *src
, int maxlen
, int argtype
)
184 if ((strlen(src
) > 1) && src
[0] == '\"') {
185 /* This is a quoted string */
186 if (!(argtype
& ARG_STRING
))
189 /* Don't take more than what's there */
190 if (maxlen
> strlen(src
) - 1)
191 maxlen
= strlen(src
) - 1;
192 memcpy(out
, src
, maxlen
);
193 ((char *)out
)[maxlen
] = '\0';
194 } else if (!ast_strlen_zero(src
) && (src
[0] == '\\')) {
195 if (!(argtype
& ARG_NUMBER
))
198 if (sscanf(src
, "%o", (int *)out
) != 1)
200 if (argtype
& ARG_STRING
) {
202 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
204 } else if ((strlen(src
) > 2) && (src
[0] == '0') && (tolower(src
[1]) == 'x')) {
205 if (!(argtype
& ARG_NUMBER
))
208 if (sscanf(src
+ 2, "%x", (unsigned int *)out
) != 1)
210 if (argtype
& ARG_STRING
) {
212 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
214 } else if ((!ast_strlen_zero(src
) && isdigit(src
[0]))) {
215 if (!(argtype
& ARG_NUMBER
))
218 if (sscanf(src
, "%d", (int *)out
) != 1)
220 if (argtype
& ARG_STRING
) {
222 *((unsigned int *)out
) = htonl(*((unsigned int *)out
));
229 static char *get_token(char **buf
, char *script
, int lineno
)
234 /* Advance past any white space */
235 while(*tmp
&& (*tmp
< 33))
240 while(*tmp
&& ((*tmp
> 32) || quoted
)) {
247 ast_log(LOG_WARNING
, "Mismatched quotes at line %d of %s\n", lineno
, script
);
252 while(*tmp
&& (*tmp
< 33))
254 /* Note where we left off */
259 static char *validdtmf
= "123456789*0#ABCD";
261 static int send_dtmf(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
266 a
= get_token(&args
, script
, lineno
);
268 ast_log(LOG_WARNING
, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno
, script
);
271 if (process_token(dtmfstr
, a
, sizeof(dtmfstr
) - 1, ARG_STRING
)) {
272 ast_log(LOG_WARNING
, "Invalid token for SENDDTMF at line %d of %s\n", lineno
, script
);
277 if (strchr(validdtmf
, *a
)) {
282 ast_log(LOG_WARNING
, "'%c' is not a valid DTMF tone at line %d of %s\n", *a
, lineno
, script
);
288 static int goto_line(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
294 page
= get_token(&args
, script
, lineno
);
295 gline
= get_token(&args
, script
, lineno
);
296 if (!page
|| !gline
) {
297 ast_log(LOG_WARNING
, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno
, script
);
300 if (!strcasecmp(page
, "INFO")) {
302 } else if (!strcasecmp(page
, "COMM")) {
305 ast_log(LOG_WARNING
, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page
, lineno
, script
);
308 if (process_token(&line
, gline
, sizeof(line
), ARG_NUMBER
)) {
309 ast_log(LOG_WARNING
, "Invalid line number '%s' at line %d of %s\n", gline
, lineno
, script
);
318 static int goto_line_rel(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
324 dir
= get_token(&args
, script
, lineno
);
325 gline
= get_token(&args
, script
, lineno
);
326 if (!dir
|| !gline
) {
327 ast_log(LOG_WARNING
, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno
, script
);
330 if (!strcasecmp(dir
, "UP")) {
332 } else if (!strcasecmp(dir
, "DOWN")) {
335 ast_log(LOG_WARNING
, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir
, lineno
, script
);
338 if (process_token(&line
, gline
, sizeof(line
), ARG_NUMBER
)) {
339 ast_log(LOG_WARNING
, "Invalid line number '%s' at line %d of %s\n", gline
, lineno
, script
);
348 static int send_delay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
352 gtime
= get_token(&args
, script
, lineno
);
354 ast_log(LOG_WARNING
, "Expecting number of milliseconds to wait at line %d of %s\n", lineno
, script
);
357 if (process_token(&ms
, gtime
, sizeof(ms
), ARG_NUMBER
)) {
358 ast_log(LOG_WARNING
, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime
, lineno
, script
);
369 static int set_state(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
373 gstate
= get_token(&args
, script
, lineno
);
375 ast_log(LOG_WARNING
, "Expecting state number at line %d of %s\n", lineno
, script
);
378 if (process_token(&state
, gstate
, sizeof(state
), ARG_NUMBER
)) {
379 ast_log(LOG_WARNING
, "Invalid state number '%s' at line %d of %s\n", gstate
, lineno
, script
);
387 static int cleartimer(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
390 tok
= get_token(&args
, script
, lineno
);
392 ast_log(LOG_WARNING
, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
395 /* For some reason the clear code is different slightly */
403 static struct adsi_flag
*getflagbyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
406 for (x
=0;x
<state
->numflags
;x
++)
407 if (!strcasecmp(state
->flags
[x
].vname
, name
))
408 return &state
->flags
[x
];
409 /* Return now if we're not allowed to create */
412 if (state
->numflags
> 6) {
413 ast_log(LOG_WARNING
, "No more flag space at line %d of %s\n", lineno
, script
);
416 ast_copy_string(state
->flags
[state
->numflags
].vname
, name
, sizeof(state
->flags
[state
->numflags
].vname
));
417 state
->flags
[state
->numflags
].id
= state
->numflags
+ 1;
419 return &state
->flags
[state
->numflags
-1];
422 static int setflag(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
426 struct adsi_flag
*flag
;
427 tok
= get_token(&args
, script
, lineno
);
429 ast_log(LOG_WARNING
, "Setting flag requires a flag number at line %d of %s\n", lineno
, script
);
432 if (process_token(sname
, tok
, sizeof(sname
) - 1, ARG_STRING
)) {
433 ast_log(LOG_WARNING
, "Invalid flag '%s' at line %d of %s\n", tok
, lineno
, script
);
436 flag
= getflagbyname(state
, sname
, script
, lineno
, 0);
438 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", sname
, lineno
, script
);
442 buf
[1] = ((flag
->id
& 0x7) << 4) | 1;
446 static int clearflag(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
449 struct adsi_flag
*flag
;
451 tok
= get_token(&args
, script
, lineno
);
453 ast_log(LOG_WARNING
, "Clearing flag requires a flag number at line %d of %s\n", lineno
, script
);
456 if (process_token(sname
, tok
, sizeof(sname
) - 1, ARG_STRING
)) {
457 ast_log(LOG_WARNING
, "Invalid flag '%s' at line %d of %s\n", tok
, lineno
, script
);
460 flag
= getflagbyname(state
, sname
, script
, lineno
, 0);
462 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", sname
, lineno
, script
);
466 buf
[1] = ((flag
->id
& 0x7) << 4);
470 static int starttimer(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
474 tok
= get_token(&args
, script
, lineno
);
476 ast_log(LOG_WARNING
, "Missing number of seconds at line %d of %s\n", lineno
, script
);
479 if (process_token(&secs
, tok
, sizeof(secs
), ARG_NUMBER
)) {
480 ast_log(LOG_WARNING
, "Invalid number of seconds '%s' at line %d of %s\n", tok
, lineno
, script
);
489 static int geteventbyname(char *name
)
492 for (x
=0;x
<sizeof(events
) / sizeof(events
[0]); x
++) {
493 if (!strcasecmp(events
[x
].name
, name
))
499 static int getjustifybyname(char *name
)
502 for (x
=0;x
<sizeof(justify
) / sizeof(justify
[0]); x
++) {
503 if (!strcasecmp(justify
[x
].name
, name
))
504 return justify
[x
].id
;
509 static struct adsi_soft_key
*getkeybyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
)
512 for (x
=0;x
<state
->numkeys
;x
++)
513 if (!strcasecmp(state
->keys
[x
].vname
, name
))
514 return &state
->keys
[x
];
515 if (state
->numkeys
> 61) {
516 ast_log(LOG_WARNING
, "No more key space at line %d of %s\n", lineno
, script
);
519 ast_copy_string(state
->keys
[state
->numkeys
].vname
, name
, sizeof(state
->keys
[state
->numkeys
].vname
));
520 state
->keys
[state
->numkeys
].id
= state
->numkeys
+ 2;
522 return &state
->keys
[state
->numkeys
-1];
525 static struct adsi_subscript
*getsubbyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
)
528 for (x
=0;x
<state
->numsubs
;x
++)
529 if (!strcasecmp(state
->subs
[x
].vname
, name
))
530 return &state
->subs
[x
];
531 if (state
->numsubs
> 127) {
532 ast_log(LOG_WARNING
, "No more subscript space at line %d of %s\n", lineno
, script
);
535 ast_copy_string(state
->subs
[state
->numsubs
].vname
, name
, sizeof(state
->subs
[state
->numsubs
].vname
));
536 state
->subs
[state
->numsubs
].id
= state
->numsubs
;
538 return &state
->subs
[state
->numsubs
-1];
541 static struct adsi_state
*getstatebyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
544 for (x
=0;x
<state
->numstates
;x
++)
545 if (!strcasecmp(state
->states
[x
].vname
, name
))
546 return &state
->states
[x
];
547 /* Return now if we're not allowed to create */
550 if (state
->numstates
> 253) {
551 ast_log(LOG_WARNING
, "No more state space at line %d of %s\n", lineno
, script
);
554 ast_copy_string(state
->states
[state
->numstates
].vname
, name
, sizeof(state
->states
[state
->numstates
].vname
));
555 state
->states
[state
->numstates
].id
= state
->numstates
+ 1;
557 return &state
->states
[state
->numstates
-1];
560 static struct adsi_display
*getdisplaybyname(struct adsi_script
*state
, char *name
, char *script
, int lineno
, int create
)
563 for (x
=0;x
<state
->numdisplays
;x
++)
564 if (!strcasecmp(state
->displays
[x
].vname
, name
))
565 return &state
->displays
[x
];
566 /* Return now if we're not allowed to create */
569 if (state
->numdisplays
> 61) {
570 ast_log(LOG_WARNING
, "No more display space at line %d of %s\n", lineno
, script
);
573 ast_copy_string(state
->displays
[state
->numdisplays
].vname
, name
, sizeof(state
->displays
[state
->numdisplays
].vname
));
574 state
->displays
[state
->numdisplays
].id
= state
->numdisplays
+ 1;
575 state
->numdisplays
++;
576 return &state
->displays
[state
->numdisplays
-1];
579 static int showkeys(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
584 unsigned char keyid
[6];
587 struct adsi_soft_key
*key
;
588 struct adsi_flag
*flag
;
591 /* Up to 6 key arguments */
592 tok
= get_token(&args
, script
, lineno
);
595 if (!strcasecmp(tok
, "UNLESS")) {
596 /* Check for trailing UNLESS flag */
597 tok
= get_token(&args
, script
, lineno
);
599 ast_log(LOG_WARNING
, "Missing argument for UNLESS clause at line %d of %s\n", lineno
, script
);
600 } else if (process_token(newkey
, tok
, sizeof(newkey
) - 1, ARG_STRING
)) {
601 ast_log(LOG_WARNING
, "Invalid flag name '%s' at line %d of %s\n", tok
, lineno
, script
);
602 } else if (!(flag
= getflagbyname(state
, newkey
, script
, lineno
, 0))) {
603 ast_log(LOG_WARNING
, "Flag '%s' is undeclared at line %d of %s\n", newkey
, lineno
, script
);
606 if ((tok
= get_token(&args
, script
, lineno
)))
607 ast_log(LOG_WARNING
, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok
, lineno
, script
);
611 ast_log(LOG_WARNING
, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok
, lineno
, script
);
614 if (process_token(newkey
, tok
, sizeof(newkey
) - 1, ARG_STRING
)) {
615 ast_log(LOG_WARNING
, "Invalid token for key name: %s\n", tok
);
619 key
= getkeybyname(state
, newkey
, script
, lineno
);
625 buf
[1] = (flagid
& 0x7) << 3 | (x
& 0x7);
626 for (bytes
=0;bytes
<x
;bytes
++) {
627 buf
[bytes
+ 2] = keyid
[bytes
];
632 static int showdisplay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
639 struct adsi_display
*disp
;
642 tok
= get_token(&args
, script
, lineno
);
643 if (!tok
|| process_token(dispname
, tok
, sizeof(dispname
) - 1, ARG_STRING
)) {
644 ast_log(LOG_WARNING
, "Invalid display name: %s at line %d of %s\n", tok
? tok
: "<nothing>", lineno
, script
);
647 disp
= getdisplaybyname(state
, dispname
, script
, lineno
, 0);
649 ast_log(LOG_WARNING
, "Display '%s' is undefined at line %d of %s\n", dispname
, lineno
, script
);
653 tok
= get_token(&args
, script
, lineno
);
654 if (!tok
|| strcasecmp(tok
, "AT")) {
655 ast_log(LOG_WARNING
, "Missing token 'AT' at line %d of %s\n", lineno
, script
);
658 /* Get line number */
659 tok
= get_token(&args
, script
, lineno
);
660 if (!tok
|| process_token(&line
, tok
, sizeof(line
), ARG_NUMBER
)) {
661 ast_log(LOG_WARNING
, "Invalid line: '%s' at line %d of %s\n", tok
? tok
: "<nothing>", lineno
, script
);
664 tok
= get_token(&args
, script
, lineno
);
665 if (tok
&& !strcasecmp(tok
, "NOUPDATE")) {
667 tok
= get_token(&args
, script
, lineno
);
669 if (tok
&& !strcasecmp(tok
, "UNLESS")) {
670 /* Check for trailing UNLESS flag */
671 tok
= get_token(&args
, script
, lineno
);
673 ast_log(LOG_WARNING
, "Missing argument for UNLESS clause at line %d of %s\n", lineno
, script
);
674 } else if (process_token(&flag
, tok
, sizeof(flag
), ARG_NUMBER
)) {
675 ast_log(LOG_WARNING
, "Invalid flag number '%s' at line %d of %s\n", tok
, lineno
, script
);
677 if ((tok
= get_token(&args
, script
, lineno
)))
678 ast_log(LOG_WARNING
, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok
, lineno
, script
);
682 buf
[1] = (cmd
<< 6) | (disp
->id
& 0x3f);
683 buf
[2] = ((line
& 0x1f) << 3) | (flag
& 0x7);
687 static int cleardisplay(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
690 tok
= get_token(&args
, script
, lineno
);
692 ast_log(LOG_WARNING
, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
699 static int digitdirect(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
702 tok
= get_token(&args
, script
, lineno
);
704 ast_log(LOG_WARNING
, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
711 static int clearcbone(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
714 tok
= get_token(&args
, script
, lineno
);
716 ast_log(LOG_WARNING
, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
723 static int digitcollect(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*istate
, char *script
, int lineno
)
726 tok
= get_token(&args
, script
, lineno
);
728 ast_log(LOG_WARNING
, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok
, lineno
, script
);
735 static int subscript(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
739 struct adsi_subscript
*sub
;
740 tok
= get_token(&args
, script
, lineno
);
742 ast_log(LOG_WARNING
, "Missing subscript to call at line %d of %s\n", lineno
, script
);
745 if (process_token(subscript
, tok
, sizeof(subscript
) - 1, ARG_STRING
)) {
746 ast_log(LOG_WARNING
, "Invalid number of seconds '%s' at line %d of %s\n", tok
, lineno
, script
);
749 sub
= getsubbyname(state
, subscript
, script
, lineno
);
757 static int onevent(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
767 struct adsi_subscript
*sub
;
768 tok
= get_token(&args
, script
, lineno
);
770 ast_log(LOG_WARNING
, "Missing event for 'ONEVENT' at line %d of %s\n", lineno
, script
);
773 event
= geteventbyname(tok
);
775 ast_log(LOG_WARNING
, "'%s' is not a valid event name, at line %d of %s\n", args
, lineno
, script
);
778 tok
= get_token(&args
, script
, lineno
);
779 while ((!sawin
&& !strcasecmp(tok
, "IN")) ||
780 (sawin
&& !strcasecmp(tok
, "OR"))) {
783 ast_log(LOG_WARNING
, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno
, script
);
786 /* Process 'in' things */
787 tok
= get_token(&args
, script
, lineno
);
788 if (process_token(sname
, tok
, sizeof(sname
), ARG_STRING
)) {
789 ast_log(LOG_WARNING
, "'%s' is not a valid state name at line %d of %s\n", tok
, lineno
, script
);
792 if ((snums
[scnt
] = getstatebyname(state
, sname
, script
, lineno
, 0) < 0)) {
793 ast_log(LOG_WARNING
, "State '%s' not declared at line %d of %s\n", sname
, lineno
, script
);
797 tok
= get_token(&args
, script
, lineno
);
801 if (!tok
|| strcasecmp(tok
, "GOTO")) {
805 ast_log(LOG_WARNING
, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok
, lineno
, script
);
807 ast_log(LOG_WARNING
, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok
, lineno
, script
);
809 tok
= get_token(&args
, script
, lineno
);
811 ast_log(LOG_WARNING
, "Missing subscript to call at line %d of %s\n", lineno
, script
);
814 if (process_token(subscript
, tok
, sizeof(subscript
) - 1, ARG_STRING
)) {
815 ast_log(LOG_WARNING
, "Invalid subscript '%s' at line %d of %s\n", tok
, lineno
, script
);
818 sub
= getsubbyname(state
, subscript
, script
, lineno
);
823 buf
[2] = sub
->id
| 0x80;
825 buf
[3 + x
] = snums
[x
];
829 struct adsi_key_cmd
{
832 int (*add_args
)(char *buf
, char *name
, int id
, char *args
, struct adsi_script
*state
, char *script
, int lineno
);
835 static struct adsi_key_cmd kcmds
[] = {
836 { "SENDDTMF", 0, send_dtmf
},
837 /* Encoded DTMF would go here */
841 { "WAITDIALTONE", 0x84 },
842 /* Send line number */
844 { "SENDCHARS", 0x87 },
845 { "CLEARCHARS", 0x88 },
846 { "BACKSPACE", 0x89 },
848 { "GOTOLINE", 0x8b, goto_line
},
849 { "GOTOLINEREL", 0x8c, goto_line_rel
},
851 { "PAGEDOWN", 0x8e },
853 { "DELAY", 0x90, send_delay
},
854 { "DIALPULSEONE", 0x91 },
855 { "DATAMODE", 0x92 },
856 { "VOICEMODE", 0x93 },
857 /* Display call buffer 'n' */
858 /* Clear call buffer 'n' */
859 { "CLEARCB1", 0x95, clearcbone
},
860 { "DIGITCOLLECT", 0x96, digitcollect
},
861 { "DIGITDIRECT", 0x96, digitdirect
},
863 { "SHOWDISPLAY", 0x98, showdisplay
},
864 { "CLEARDISPLAY", 0x98, cleardisplay
},
865 { "SHOWKEYS", 0x99, showkeys
},
866 { "SETSTATE", 0x9a, set_state
},
867 { "TIMERSTART", 0x9b, starttimer
},
868 { "TIMERCLEAR", 0x9b, cleartimer
},
869 { "SETFLAG", 0x9c, setflag
},
870 { "CLEARFLAG", 0x9c, clearflag
},
871 { "GOTO", 0x9d, subscript
},
877 static struct adsi_key_cmd opcmds
[] = {
879 /* 1 - Branch on event -- handled specially */
880 { "SHOWKEYS", 2, showkeys
},
881 /* Display Control */
882 { "SHOWDISPLAY", 3, showdisplay
},
883 { "CLEARDISPLAY", 3, cleardisplay
},
885 { "SETSTATE", 6, set_state
},
886 { "TIMERSTART", 7, starttimer
},
887 { "TIMERCLEAR", 7, cleartimer
},
888 { "ONEVENT", 8, onevent
},
889 /* 9 - Subroutine label, treated specially */
890 { "SETFLAG", 10, setflag
},
891 { "CLEARFLAG", 10, clearflag
},
892 { "DELAY", 11, send_delay
},
897 static int process_returncode(struct adsi_soft_key
*key
, char *code
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
902 for (x
=0;x
<sizeof(kcmds
) / sizeof(kcmds
[0]);x
++) {
903 if ((kcmds
[x
].id
> -1) && !strcasecmp(kcmds
[x
].name
, code
)) {
904 if (kcmds
[x
].add_args
) {
905 res
= kcmds
[x
].add_args(key
->retstr
+ key
->retstrlen
,
906 code
, kcmds
[x
].id
, args
, state
, script
, lineno
);
907 if ((key
->retstrlen
+ res
- key
->initlen
) <= MAX_RET_CODE
)
908 key
->retstrlen
+= res
;
910 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
);
912 if ((unused
= get_token(&args
, script
, lineno
)))
913 ast_log(LOG_WARNING
, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds
[x
].name
, lineno
, script
, unused
);
914 if ((key
->retstrlen
+ 1 - key
->initlen
) <= MAX_RET_CODE
) {
915 key
->retstr
[key
->retstrlen
] = kcmds
[x
].id
;
918 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
);
926 static int process_opcode(struct adsi_subscript
*sub
, char *code
, char *args
, struct adsi_script
*state
, char *script
, int lineno
)
931 int max
= sub
->id
? MAX_SUB_LEN
: MAX_MAIN_LEN
;
932 for (x
=0;x
<sizeof(opcmds
) / sizeof(opcmds
[0]);x
++) {
933 if ((opcmds
[x
].id
> -1) && !strcasecmp(opcmds
[x
].name
, code
)) {
934 if (opcmds
[x
].add_args
) {
935 res
= opcmds
[x
].add_args(sub
->data
+ sub
->datalen
,
936 code
, opcmds
[x
].id
, args
, state
, script
, lineno
);
937 if ((sub
->datalen
+ res
+ 1) <= max
)
940 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
);
944 if ((unused
= get_token(&args
, script
, lineno
)))
945 ast_log(LOG_WARNING
, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds
[x
].name
, lineno
, script
, unused
);
946 if ((sub
->datalen
+ 2) <= max
) {
947 sub
->data
[sub
->datalen
] = opcmds
[x
].id
;
950 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
);
954 /* Separate commands with 0xff */
955 sub
->data
[sub
->datalen
] = 0xff;
964 static int adsi_process(struct adsi_script
*state
, char *buf
, char *script
, int lineno
)
974 struct adsi_display
*disp
;
975 struct adsi_subscript
*newsub
;
976 /* Find the first keyword */
977 keyword
= get_token(&buf
, script
, lineno
);
980 switch(state
->state
) {
982 if (!strcasecmp(keyword
, "DESCRIPTION")) {
983 args
= get_token(&buf
, script
, lineno
);
985 if (process_token(state
->desc
, args
, sizeof(state
->desc
) - 1, ARG_STRING
))
986 ast_log(LOG_WARNING
, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args
, lineno
, script
);
988 ast_log(LOG_WARNING
, "Missing argument for DESCRIPTION at line %d of %s\n", lineno
, script
);
989 } else if (!strcasecmp(keyword
, "VERSION")) {
990 args
= get_token(&buf
, script
, lineno
);
992 if (process_token(&state
->ver
, args
, sizeof(state
->ver
) - 1, ARG_NUMBER
))
993 ast_log(LOG_WARNING
, "'%s' is not a valid token for VERSION at line %d of %s\n", args
, lineno
, script
);
995 ast_log(LOG_WARNING
, "Missing argument for VERSION at line %d of %s\n", lineno
, script
);
996 } else if (!strcasecmp(keyword
, "SECURITY")) {
997 args
= get_token(&buf
, script
, lineno
);
999 if (process_token(state
->sec
, args
, sizeof(state
->sec
) - 1, ARG_STRING
| ARG_NUMBER
))
1000 ast_log(LOG_WARNING
, "'%s' is not a valid token for SECURITY at line %d of %s\n", args
, lineno
, script
);
1002 ast_log(LOG_WARNING
, "Missing argument for SECURITY at line %d of %s\n", lineno
, script
);
1003 } else if (!strcasecmp(keyword
, "FDN")) {
1004 args
= get_token(&buf
, script
, lineno
);
1006 if (process_token(state
->fdn
, args
, sizeof(state
->fdn
) - 1, ARG_STRING
| ARG_NUMBER
))
1007 ast_log(LOG_WARNING
, "'%s' is not a valid token for FDN at line %d of %s\n", args
, lineno
, script
);
1009 ast_log(LOG_WARNING
, "Missing argument for FDN at line %d of %s\n", lineno
, script
);
1010 } else if (!strcasecmp(keyword
, "KEY")) {
1011 args
= get_token(&buf
, script
, lineno
);
1013 ast_log(LOG_WARNING
, "KEY definition missing name at line %d of %s\n", lineno
, script
);
1016 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1017 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1020 state
->key
= getkeybyname(state
, vname
, script
, lineno
);
1022 ast_log(LOG_WARNING
, "Out of key space at line %d of %s\n", lineno
, script
);
1025 if (state
->key
->defined
) {
1026 ast_log(LOG_WARNING
, "Cannot redefine key '%s' at line %d of %s\n", vname
, lineno
, script
);
1029 args
= get_token(&buf
, script
, lineno
);
1030 if (!args
|| strcasecmp(args
, "IS")) {
1031 ast_log(LOG_WARNING
, "Expecting 'IS', but got '%s' at line %d of %s\n", args
? args
: "<nothing>", lineno
, script
);
1034 args
= get_token(&buf
, script
, lineno
);
1036 ast_log(LOG_WARNING
, "KEY definition missing short name at line %d of %s\n", lineno
, script
);
1039 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1040 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY short name at line %d of %s\n", args
, lineno
, script
);
1043 args
= get_token(&buf
, script
, lineno
);
1045 if (strcasecmp(args
, "OR")) {
1046 ast_log(LOG_WARNING
, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args
, lineno
, script
);
1049 args
= get_token(&buf
, script
, lineno
);
1051 ast_log(LOG_WARNING
, "KEY definition missing optional long name at line %d of %s\n", lineno
, script
);
1054 if (process_token(tmp2
, args
, sizeof(tmp2
) - 1, ARG_STRING
)) {
1055 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY long name at line %d of %s\n", args
, lineno
, script
);
1059 ast_copy_string(tmp2
, tmp
, sizeof(tmp2
));
1061 if (strlen(tmp2
) > 18) {
1062 ast_log(LOG_WARNING
, "Truncating full name to 18 characters at line %d of %s\n", lineno
, script
);
1065 if (strlen(tmp
) > 7) {
1066 ast_log(LOG_WARNING
, "Truncating short name to 7 bytes at line %d of %s\n", lineno
, script
);
1069 /* Setup initial stuff */
1070 state
->key
->retstr
[0] = 128;
1071 /* 1 has the length */
1072 state
->key
->retstr
[2] = state
->key
->id
;
1073 /* Put the Full name in */
1074 memcpy(state
->key
->retstr
+ 3, tmp2
, strlen(tmp2
));
1076 state
->key
->retstrlen
= strlen(tmp2
) + 3;
1077 /* Put trailing 0xff */
1078 state
->key
->retstr
[state
->key
->retstrlen
++] = 0xff;
1079 /* Put the short name */
1080 memcpy(state
->key
->retstr
+ state
->key
->retstrlen
, tmp
, strlen(tmp
));
1082 state
->key
->retstrlen
+= strlen(tmp
);
1083 /* Put trailing 0xff */
1084 state
->key
->retstr
[state
->key
->retstrlen
++] = 0xff;
1085 /* Record initial length */
1086 state
->key
->initlen
= state
->key
->retstrlen
;
1087 state
->state
= STATE_INKEY
;
1088 } else if (!strcasecmp(keyword
, "SUB")) {
1089 args
= get_token(&buf
, script
, lineno
);
1091 ast_log(LOG_WARNING
, "SUB definition missing name at line %d of %s\n", lineno
, script
);
1094 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1095 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1098 state
->sub
= getsubbyname(state
, vname
, script
, lineno
);
1100 ast_log(LOG_WARNING
, "Out of subroutine space at line %d of %s\n", lineno
, script
);
1103 if (state
->sub
->defined
) {
1104 ast_log(LOG_WARNING
, "Cannot redefine subroutine '%s' at line %d of %s\n", vname
, lineno
, script
);
1108 state
->sub
->data
[0] = 130;
1109 /* 1 is the length */
1110 state
->sub
->data
[2] = 0x0; /* Clear extensibility bit */
1111 state
->sub
->datalen
= 3;
1112 if (state
->sub
->id
) {
1113 /* If this isn't the main subroutine, make a subroutine label for it */
1114 state
->sub
->data
[3] = 9;
1115 state
->sub
->data
[4] = state
->sub
->id
;
1117 state
->sub
->data
[6] = 0xff;
1118 state
->sub
->datalen
= 7;
1120 args
= get_token(&buf
, script
, lineno
);
1121 if (!args
|| strcasecmp(args
, "IS")) {
1122 ast_log(LOG_WARNING
, "Expecting 'IS', but got '%s' at line %d of %s\n", args
? args
: "<nothing>", lineno
, script
);
1125 state
->state
= STATE_INSUB
;
1126 } else if (!strcasecmp(keyword
, "STATE")) {
1127 args
= get_token(&buf
, script
, lineno
);
1129 ast_log(LOG_WARNING
, "STATE definition missing name at line %d of %s\n", lineno
, script
);
1132 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1133 ast_log(LOG_WARNING
, "'%s' is not a valid token for a STATE name at line %d of %s\n", args
, lineno
, script
);
1136 if (getstatebyname(state
, vname
, script
, lineno
, 0)) {
1137 ast_log(LOG_WARNING
, "State '%s' is already defined at line %d of %s\n", vname
, lineno
, script
);
1140 getstatebyname(state
, vname
, script
, lineno
, 1);
1141 } else if (!strcasecmp(keyword
, "FLAG")) {
1142 args
= get_token(&buf
, script
, lineno
);
1144 ast_log(LOG_WARNING
, "FLAG definition missing name at line %d of %s\n", lineno
, script
);
1147 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1148 ast_log(LOG_WARNING
, "'%s' is not a valid token for a FLAG name at line %d of %s\n", args
, lineno
, script
);
1151 if (getflagbyname(state
, vname
, script
, lineno
, 0)) {
1152 ast_log(LOG_WARNING
, "Flag '%s' is already defined\n", vname
);
1155 getflagbyname(state
, vname
, script
, lineno
, 1);
1156 } else if (!strcasecmp(keyword
, "DISPLAY")) {
1159 args
= get_token(&buf
, script
, lineno
);
1161 ast_log(LOG_WARNING
, "SUB definition missing name at line %d of %s\n", lineno
, script
);
1164 if (process_token(vname
, args
, sizeof(vname
) - 1, ARG_STRING
)) {
1165 ast_log(LOG_WARNING
, "'%s' is not a valid token for a KEY name at line %d of %s\n", args
, lineno
, script
);
1168 if (getdisplaybyname(state
, vname
, script
, lineno
, 0)) {
1169 ast_log(LOG_WARNING
, "State '%s' is already defined\n", vname
);
1172 disp
= getdisplaybyname(state
, vname
, script
, lineno
, 1);
1175 args
= get_token(&buf
, script
, lineno
);
1176 if (!args
|| strcasecmp(args
, "IS")) {
1177 ast_log(LOG_WARNING
, "Missing 'IS' at line %d of %s\n", lineno
, script
);
1180 args
= get_token(&buf
, script
, lineno
);
1182 ast_log(LOG_WARNING
, "Missing Column 1 text at line %d of %s\n", lineno
, script
);
1185 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1186 ast_log(LOG_WARNING
, "Token '%s' is not valid column 1 text at line %d of %s\n", args
, lineno
, script
);
1189 if (strlen(tmp
) > 20) {
1190 ast_log(LOG_WARNING
, "Truncating column one to 20 characters at line %d of %s\n", lineno
, script
);
1193 memcpy(disp
->data
+ 5, tmp
, strlen(tmp
));
1194 disp
->datalen
= strlen(tmp
) + 5;
1195 disp
->data
[disp
->datalen
++] = 0xff;
1197 args
= get_token(&buf
, script
, lineno
);
1198 if (args
&& !process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1199 /* Got a column two */
1200 if (strlen(tmp
) > 20) {
1201 ast_log(LOG_WARNING
, "Truncating column two to 20 characters at line %d of %s\n", lineno
, script
);
1204 memcpy(disp
->data
+ disp
->datalen
, tmp
, strlen(tmp
));
1205 disp
->datalen
+= strlen(tmp
);
1206 args
= get_token(&buf
, script
, lineno
);
1209 if (!strcasecmp(args
, "JUSTIFY")) {
1210 args
= get_token(&buf
, script
, lineno
);
1212 ast_log(LOG_WARNING
, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno
, script
);
1215 lrci
= getjustifybyname(args
);
1217 ast_log(LOG_WARNING
, "'%s' is not a valid justification at line %d of %s\n", args
, lineno
, script
);
1220 } else if (!strcasecmp(args
, "WRAP")) {
1223 ast_log(LOG_WARNING
, "'%s' is not a known qualifier at line %d of %s\n", args
, lineno
, script
);
1226 args
= get_token(&buf
, script
, lineno
);
1229 /* Something bad happened */
1232 disp
->data
[0] = 129;
1233 disp
->data
[1] = disp
->datalen
- 2;
1234 disp
->data
[2] = ((lrci
& 0x3) << 6) | disp
->id
;
1236 disp
->data
[4] = 0xff;
1238 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword
);
1242 if (process_returncode(state
->key
, keyword
, buf
, state
, script
, lineno
)) {
1243 if (!strcasecmp(keyword
, "ENDKEY")) {
1244 /* Return to normal operation and increment current key */
1245 state
->state
= STATE_NORMAL
;
1246 state
->key
->defined
= 1;
1247 state
->key
->retstr
[1] = state
->key
->retstrlen
- 2;
1250 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword
, lineno
, script
);
1255 if (process_opcode(state
->sub
, keyword
, buf
, state
, script
, lineno
)) {
1256 if (!strcasecmp(keyword
, "ENDIF")) {
1257 /* Return to normal SUB operation and increment current key */
1258 state
->state
= STATE_INSUB
;
1259 state
->sub
->defined
= 1;
1260 /* Store the proper number of instructions */
1261 state
->sub
->ifdata
[2] = state
->sub
->ifinscount
;
1262 } else if (!strcasecmp(keyword
, "GOTO")) {
1263 args
= get_token(&buf
, script
, lineno
);
1265 ast_log(LOG_WARNING
, "GOTO clause missing Subscript name at line %d of %s\n", lineno
, script
);
1268 if (process_token(tmp
, args
, sizeof(tmp
) - 1, ARG_STRING
)) {
1269 ast_log(LOG_WARNING
, "'%s' is not a valid subscript name token at line %d of %s\n", args
, lineno
, script
);
1272 newsub
= getsubbyname(state
, tmp
, script
, lineno
);
1275 /* Somehow you use GOTO to go to another place */
1276 state
->sub
->data
[state
->sub
->datalen
++] = 0x8;
1277 state
->sub
->data
[state
->sub
->datalen
++] = state
->sub
->ifdata
[1];
1278 state
->sub
->data
[state
->sub
->datalen
++] = newsub
->id
;
1280 state
->sub
->data
[state
->sub
->datalen
++] = 0xff;
1281 /* Increment counters */
1282 state
->sub
->inscount
++;
1283 state
->sub
->ifinscount
++;
1285 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword
, lineno
, script
);
1288 state
->sub
->ifinscount
++;
1291 if (process_opcode(state
->sub
, keyword
, buf
, state
, script
, lineno
)) {
1292 if (!strcasecmp(keyword
, "ENDSUB")) {
1293 /* Return to normal operation and increment current key */
1294 state
->state
= STATE_NORMAL
;
1295 state
->sub
->defined
= 1;
1296 /* Store the proper length */
1297 state
->sub
->data
[1] = state
->sub
->datalen
- 2;
1298 if (state
->sub
->id
) {
1299 /* if this isn't main, store number of instructions, too */
1300 state
->sub
->data
[5] = state
->sub
->inscount
;
1303 } else if (!strcasecmp(keyword
, "IFEVENT")) {
1304 args
= get_token(&buf
, script
, lineno
);
1306 ast_log(LOG_WARNING
, "IFEVENT clause missing Event name at line %d of %s\n", lineno
, script
);
1309 event
= geteventbyname(args
);
1311 ast_log(LOG_WARNING
, "'%s' is not a valid event\n", args
);
1314 args
= get_token(&buf
, script
, lineno
);
1315 if (!args
|| strcasecmp(args
, "THEN")) {
1316 ast_log(LOG_WARNING
, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno
, script
);
1319 state
->sub
->ifinscount
= 0;
1320 state
->sub
->ifdata
= state
->sub
->data
+
1321 state
->sub
->datalen
;
1322 /* Reserve header and insert op codes */
1323 state
->sub
->ifdata
[0] = 0x1;
1324 state
->sub
->ifdata
[1] = event
;
1325 /* 2 is for the number of instructions */
1326 state
->sub
->ifdata
[3] = 0xff;
1327 state
->sub
->datalen
+= 4;
1328 /* Update Subscript instruction count */
1329 state
->sub
->inscount
++;
1330 state
->state
= STATE_INIF
;
1332 ast_log(LOG_WARNING
, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword
, lineno
, script
);
1337 ast_log(LOG_WARNING
, "Can't process keyword '%s' in weird state %d\n", keyword
, state
->state
);
1342 static struct adsi_script
*compile_script(char *script
)
1350 struct adsi_script
*scr
;
1351 if (script
[0] == '/')
1352 ast_copy_string(fn
, script
, sizeof(fn
));
1354 snprintf(fn
, sizeof(fn
), "%s/%s", (char *)ast_config_AST_CONFIG_DIR
, script
);
1357 ast_log(LOG_WARNING
, "Can't open file '%s'\n", fn
);
1360 if (!(scr
= ast_calloc(1, sizeof(*scr
)))) {
1364 /* Create "main" as first subroutine */
1365 getsubbyname(scr
, "main", NULL
, 0);
1367 fgets(buf
, sizeof(buf
), f
);
1370 /* Trim off trailing return */
1371 buf
[strlen(buf
) - 1] = '\0';
1372 c
= strchr(buf
, ';');
1373 /* Strip comments */
1376 if (!ast_strlen_zero(buf
))
1377 adsi_process(scr
, buf
, script
, lineno
);
1381 /* Make sure we're in the main routine again */
1382 switch(scr
->state
) {
1386 ast_log(LOG_WARNING
, "Missing ENDSUB at end of file %s\n", script
);
1390 ast_log(LOG_WARNING
, "Missing ENDKEY at end of file %s\n", script
);
1396 /* Resolve all keys and record their lengths */
1397 for (x
=0;x
<scr
->numkeys
;x
++) {
1398 if (!scr
->keys
[x
].defined
) {
1399 ast_log(LOG_WARNING
, "Key '%s' referenced but never defined in file %s\n", scr
->keys
[x
].vname
, fn
);
1404 /* Resolve all subs */
1405 for (x
=0;x
<scr
->numsubs
;x
++) {
1406 if (!scr
->subs
[x
].defined
) {
1407 ast_log(LOG_WARNING
, "Subscript '%s' referenced but never defined in file %s\n", scr
->subs
[x
].vname
, fn
);
1410 if (x
== (scr
->numsubs
- 1)) {
1411 /* Clear out extension bit on last message */
1412 scr
->subs
[x
].data
[2] = 0x80;
1423 #ifdef DUMP_MESSAGES
1424 static void dump_message(char *type
, char *vname
, unsigned char *buf
, int buflen
)
1427 printf("%s %s: [ ", type
, vname
);
1428 for (x
=0;x
<buflen
;x
++)
1429 printf("%02x ", buf
[x
]);
1434 static int adsi_prog(struct ast_channel
*chan
, char *script
)
1436 struct adsi_script
*scr
;
1438 unsigned char buf
[1024];
1440 scr
= compile_script(script
);
1444 /* Start an empty ADSI Session */
1445 if (ast_adsi_load_session(chan
, NULL
, 0, 1) < 1)
1448 /* Now begin the download attempt */
1449 if (ast_adsi_begin_download(chan
, scr
->desc
, scr
->fdn
, scr
->sec
, scr
->ver
)) {
1450 /* User rejected us for some reason */
1451 if (option_verbose
> 2)
1452 ast_verbose(VERBOSE_PREFIX_3
"User rejected download attempt\n");
1453 ast_log(LOG_NOTICE
, "User rejected download on channel %s\n", chan
->name
);
1459 /* Start with key definitions */
1460 for (x
=0;x
<scr
->numkeys
;x
++) {
1461 if (bytes
+ scr
->keys
[x
].retstrlen
> 253) {
1462 /* Send what we've collected so far */
1463 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1464 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1469 memcpy(buf
+ bytes
, scr
->keys
[x
].retstr
, scr
->keys
[x
].retstrlen
);
1470 bytes
+= scr
->keys
[x
].retstrlen
;
1471 #ifdef DUMP_MESSAGES
1472 dump_message("Key", scr
->keys
[x
].vname
, scr
->keys
[x
].retstr
, scr
->keys
[x
].retstrlen
);
1476 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1477 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1483 /* Continue with the display messages */
1484 for (x
=0;x
<scr
->numdisplays
;x
++) {
1485 if (bytes
+ scr
->displays
[x
].datalen
> 253) {
1486 /* Send what we've collected so far */
1487 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1488 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1493 memcpy(buf
+ bytes
, scr
->displays
[x
].data
, scr
->displays
[x
].datalen
);
1494 bytes
+= scr
->displays
[x
].datalen
;
1495 #ifdef DUMP_MESSAGES
1496 dump_message("Display", scr
->displays
[x
].vname
, scr
->displays
[x
].data
, scr
->displays
[x
].datalen
);
1500 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1501 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1507 /* Send subroutines */
1508 for (x
=0;x
<scr
->numsubs
;x
++) {
1509 if (bytes
+ scr
->subs
[x
].datalen
> 253) {
1510 /* Send what we've collected so far */
1511 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1512 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1517 memcpy(buf
+ bytes
, scr
->subs
[x
].data
, scr
->subs
[x
].datalen
);
1518 bytes
+= scr
->subs
[x
].datalen
;
1519 #ifdef DUMP_MESSAGES
1520 dump_message("Sub", scr
->subs
[x
].vname
, scr
->subs
[x
].data
, scr
->subs
[x
].datalen
);
1524 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
)) {
1525 ast_log(LOG_WARNING
, "Unable to send chunk ending at %d\n", x
);
1532 bytes
+= ast_adsi_display(buf
, ADSI_INFO_PAGE
, 1, ADSI_JUST_LEFT
, 0, "Download complete.", "");
1533 bytes
+= ast_adsi_set_line(buf
, ADSI_INFO_PAGE
, 1);
1534 if (ast_adsi_transmit_message(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
) < 0)
1536 if (ast_adsi_end_download(chan
)) {
1537 /* Download failed for some reason */
1538 if (option_verbose
> 2)
1539 ast_verbose(VERBOSE_PREFIX_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
)
1552 struct ast_module_user
*u
;
1554 u
= ast_module_user_add(chan
);
1556 if (ast_strlen_zero(data
))
1557 data
= "asterisk.adsi";
1559 if (!ast_adsi_available(chan
)) {
1560 if (option_verbose
> 2)
1561 ast_verbose(VERBOSE_PREFIX_3
"ADSI Unavailable on CPE. Not bothering to try.\n");
1563 if (option_verbose
> 2)
1564 ast_verbose(VERBOSE_PREFIX_3
"ADSI Available on CPE. Attempting Upload.\n");
1565 res
= adsi_prog(chan
, data
);
1568 ast_module_user_remove(u
);
1573 static int unload_module(void)
1577 ast_module_user_hangup_all();
1579 res
= ast_unregister_application(app
);
1585 static int load_module(void)
1587 return ast_register_application(app
, adsi_exec
, synopsis
, descrip
);
1590 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Asterisk ADSI Programming Application");