"README.md" did not exist on "a881c52c7848d5ac36a0882a5e03e09c3b17cce2"
Newer
Older
* Asterisk -- An open source telephony toolkit.
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
* \brief Program Asterisk ADSI Scripts into phone
*
* \author Mark Spencer <markster@digium.com>
*
/*** MODULEINFO
<depend>res_adsi</depend>
***/
Kevin P. Fleming
committed
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/adsi.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
static char *app = "ADSIProg";
static char *synopsis = "Load Asterisk ADSI Scripts into phone";
/* #define DUMP_MESSAGES */
static char *descrip =
" ADSIProg(script): This application programs an ADSI Phone with the given\n"
"script. If nothing is specified, the default script (asterisk.adsi) is used.\n";
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
struct adsi_event {
int id;
char *name;
};
static struct adsi_event events[] = {
{ 1, "CALLERID" },
{ 2, "VMWI" },
{ 3, "NEARANSWER" },
{ 4, "FARANSWER" },
{ 5, "ENDOFRING" },
{ 6, "IDLE" },
{ 7, "OFFHOOK" },
{ 8, "CIDCW" },
{ 9, "BUSY" },
{ 10, "FARRING" },
{ 11, "DIALTONE" },
{ 12, "RECALL" },
{ 13, "MESSAGE" },
{ 14, "REORDER" },
{ 15, "DISTINCTIVERING" },
{ 16, "RING" },
{ 17, "REMINDERRING" },
{ 18, "SPECIALRING" },
{ 19, "CODEDRING" },
{ 20, "TIMER" },
{ 21, "INUSE" },
{ 22, "EVENT22" },
{ 23, "EVENT23" },
{ 24, "CPEID" },
};
static struct adsi_event justify[] = {
{ 0, "CENTER" },
{ 1, "RIGHT" },
{ 2, "LEFT" },
{ 3, "INDENT" },
};
#define STATE_NORMAL 0
#define STATE_INKEY 1
#define STATE_INSUB 2
#define STATE_INIF 3
#define MAX_RET_CODE 20
#define MAX_SUB_LEN 255
#define MAX_MAIN_LEN 1600
#define ARG_STRING (1 << 0)
#define ARG_NUMBER (1 << 1)
struct adsi_soft_key {
char vname[40]; /* Which "variable" is associated with it */
int retstrlen; /* Length of return string */
int initlen; /* initial length */
int id;
int defined;
char retstr[80]; /* Return string data */
};
struct adsi_subscript {
char vname[40];
int id;
int defined;
int datalen;
int inscount;
int ifinscount;
char *ifdata;
char data[2048];
};
struct adsi_state {
char vname[40];
int id;
};
struct adsi_flag {
char vname[40];
int id;
};
struct adsi_display {
char vname[40];
int id;
char data[70];
int datalen;
};
struct adsi_script {
int state;
int numkeys;
int numsubs;
int numstates;
int numdisplays;
int numflags;
struct adsi_soft_key *key;
struct adsi_subscript *sub;
/* Pre-defined displays */
struct adsi_display displays[63];
/* ADSI States 1 (initial) - 254 */
struct adsi_state states[256];
/* Keys 2-63 */
struct adsi_soft_key keys[62];
/* Subscripts 0 (main) to 127 */
struct adsi_subscript subs[128];
/* Flags 1-7 */
struct adsi_flag flags[7];
/* Stuff from adsi script */
int ver;
};
static int process_token(void *out, char *src, int maxlen, int argtype)
{
if ((strlen(src) > 1) && src[0] == '\"') {
/* This is a quoted string */
if (!(argtype & ARG_STRING))
return -1;
src++;
/* Don't take more than what's there */
if (maxlen > strlen(src) - 1)
maxlen = strlen(src) - 1;
memcpy(out, src, maxlen);
((char *)out)[maxlen] = '\0';
Mark Spencer
committed
} else if (!ast_strlen_zero(src) && (src[0] == '\\')) {
if (!(argtype & ARG_NUMBER))
return -1;
/* Octal value */
if (sscanf(src, "%o", (int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
*((unsigned int *)out) = htonl(*((unsigned int *)out));
}
} else if ((strlen(src) > 2) && (src[0] == '0') && (tolower(src[1]) == 'x')) {
if (!(argtype & ARG_NUMBER))
return -1;
/* Hex value */
if (sscanf(src + 2, "%x", (unsigned int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
*((unsigned int *)out) = htonl(*((unsigned int *)out));
}
Mark Spencer
committed
} else if ((!ast_strlen_zero(src) && isdigit(src[0]))) {
if (!(argtype & ARG_NUMBER))
return -1;
/* Hex value */
if (sscanf(src, "%d", (int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
*((unsigned int *)out) = htonl(*((unsigned int *)out));
}
} else
return -1;
return 0;
}
static char *get_token(char **buf, char *script, int lineno)
{
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* Advance past any white space */
while(*tmp && (*tmp < 33))
tmp++;
if (!*tmp)
return NULL;
keyword = tmp;
while(*tmp && ((*tmp > 32) || quoted)) {
if (*tmp == '\"') {
quoted = !quoted;
}
tmp++;
}
if (quoted) {
ast_log(LOG_WARNING, "Mismatched quotes at line %d of %s\n", lineno, script);
return NULL;
}
*tmp = '\0';
tmp++;
while(*tmp && (*tmp < 33))
tmp++;
/* Note where we left off */
*buf = tmp;
return keyword;
}
static char *validdtmf = "123456789*0#ABCD";
static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char dtmfstr[80], *a;
int bytes = 0;
if (!(a = get_token(&args, script, lineno))) {
ast_log(LOG_WARNING, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(dtmfstr, a, sizeof(dtmfstr) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid token for SENDDTMF at line %d of %s\n", lineno, script);
return 0;
}
while(*a) {
if (strchr(validdtmf, *a)) {
*buf = *a;
buf++;
bytes++;
} else
ast_log(LOG_WARNING, "'%c' is not a valid DTMF tone at line %d of %s\n", *a, lineno, script);
a++;
}
return bytes;
}
static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *page = get_token(&args, script, lineno);
char *gline = get_token(&args, script, lineno);
if (!page || !gline) {
ast_log(LOG_WARNING, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno, script);
return 0;
}
if (!strcasecmp(page, "INFO")) {
cmd = 0;
} else if (!strcasecmp(page, "COMM")) {
cmd = 0x80;
} else {
ast_log(LOG_WARNING, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page, lineno, script);
return 0;
}
if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
return 0;
}
cmd |= line;
buf[0] = 0x8b;
buf[1] = cmd;
return 2;
}
static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *dir = get_token(&args, script, lineno);
char *gline = get_token(&args, script, lineno);
if (!dir || !gline) {
ast_log(LOG_WARNING, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno, script);
return 0;
}
if (!strcasecmp(dir, "UP")) {
cmd = 0;
} else if (!strcasecmp(dir, "DOWN")) {
cmd = 0x20;
} else {
ast_log(LOG_WARNING, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir, lineno, script);
return 0;
}
if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
return 0;
}
cmd |= line;
buf[0] = 0x8c;
buf[1] = cmd;
return 2;
}
static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *gtime = get_token(&args, script, lineno);
if (!gtime) {
ast_log(LOG_WARNING, "Expecting number of milliseconds to wait at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(&ms, gtime, sizeof(ms), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime, lineno, script);
return 0;
}
if (id == 11)
buf[1] = ms / 100;
else
buf[1] = ms / 10;
return 2;
}
static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *gstate = get_token(&args, script, lineno);
if (!gstate) {
ast_log(LOG_WARNING, "Expecting state number at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(&state, gstate, sizeof(state), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid state number '%s' at line %d of %s\n", gstate, lineno, script);
return 0;
}
return 2;
}
static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (tok)
ast_log(LOG_WARNING, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
buf[0] = id;
/* For some reason the clear code is different slightly */
if (id == 7)
buf[1] = 0x10;
else
buf[1] = 0x00;
return 2;
}
static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
{
int x;
for (x = 0; x < state->numflags; x++) {
if (!strcasecmp(state->flags[x].vname, name))
return &state->flags[x];
/* Return now if we're not allowed to create */
if (!create)
return NULL;
if (state->numflags > 6) {
ast_log(LOG_WARNING, "No more flag space at line %d of %s\n", lineno, script);
return NULL;
}
ast_copy_string(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname));
state->flags[state->numflags].id = state->numflags + 1;
state->numflags++;
return &state->flags[state->numflags-1];
}
static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (!tok) {
ast_log(LOG_WARNING, "Setting flag requires a flag number at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
return 0;
}
if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
return 0;
}
buf[0] = id;
buf[1] = ((flag->id & 0x7) << 4) | 1;
return 2;
}
static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (!tok) {
ast_log(LOG_WARNING, "Clearing flag requires a flag number at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
return 0;
}
if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
return 0;
}
buf[0] = id;
buf[1] = ((flag->id & 0x7) << 4);
return 2;
}
static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (!tok) {
ast_log(LOG_WARNING, "Missing number of seconds at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(&secs, tok, sizeof(secs), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
return 0;
}
buf[0] = id;
buf[1] = 0x1;
buf[2] = secs;
return 3;
}
static int geteventbyname(char *name)
{
int x;
for (x = 0; x < sizeof(events) / sizeof(events[0]); x++) {
if (!strcasecmp(events[x].name, name))
return events[x].id;
}
return 0;
}
static int getjustifybyname(char *name)
{
int x;
for (x = 0; x <sizeof(justify) / sizeof(justify[0]); x++) {
if (!strcasecmp(justify[x].name, name))
return justify[x].id;
}
return -1;
}
static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, char *script, int lineno)
{
int x;
if (!strcasecmp(state->keys[x].vname, name))
return &state->keys[x];
if (state->numkeys > 61) {
ast_log(LOG_WARNING, "No more key space at line %d of %s\n", lineno, script);
return NULL;
}
ast_copy_string(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname));
state->keys[state->numkeys].id = state->numkeys + 2;
state->numkeys++;
return &state->keys[state->numkeys-1];
}
static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, char *script, int lineno)
{
int x;
if (!strcasecmp(state->subs[x].vname, name))
return &state->subs[x];
if (state->numsubs > 127) {
ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
return NULL;
}
ast_copy_string(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname));
state->subs[state->numsubs].id = state->numsubs;
state->numsubs++;
return &state->subs[state->numsubs-1];
}
static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
{
int x;
for (x = 0; x <state->numstates; x++) {
if (!strcasecmp(state->states[x].vname, name))
return &state->states[x];
/* Return now if we're not allowed to create */
if (!create)
return NULL;
if (state->numstates > 253) {
ast_log(LOG_WARNING, "No more state space at line %d of %s\n", lineno, script);
return NULL;
}
ast_copy_string(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname));
state->states[state->numstates].id = state->numstates + 1;
state->numstates++;
return &state->states[state->numstates-1];
}
static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
{
int x;
for (x = 0; x < state->numdisplays; x++) {
if (!strcasecmp(state->displays[x].vname, name))
return &state->displays[x];
/* Return now if we're not allowed to create */
if (!create)
return NULL;
if (state->numdisplays > 61) {
ast_log(LOG_WARNING, "No more display space at line %d of %s\n", lineno, script);
return NULL;
}
ast_copy_string(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname));
state->displays[state->numdisplays].id = state->numdisplays + 1;
state->numdisplays++;
return &state->displays[state->numdisplays-1];
}
static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok, newkey[80];
int bytes, x, flagid = 0;
unsigned char keyid[6];
struct adsi_soft_key *key;
struct adsi_flag *flag;
if (!(tok = get_token(&args, script, lineno)))
break;
if (!strcasecmp(tok, "UNLESS")) {
/* Check for trailing UNLESS flag */
if (!(tok = get_token(&args, script, lineno))) {
ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
} else if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid flag name '%s' at line %d of %s\n", tok, lineno, script);
} else if (!(flag = getflagbyname(state, newkey, script, lineno, 0))) {
ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", newkey, lineno, script);
} else
flagid = flag->id;
if ((tok = get_token(&args, script, lineno)))
ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
break;
}
if (x > 5) {
ast_log(LOG_WARNING, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok, lineno, script);
break;
}
if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid token for key name: %s\n", tok);
continue;
}
if (!(key = getkeybyname(state, newkey, script, lineno)))
break;
keyid[x] = key->id;
}
buf[0] = id;
buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
buf[bytes + 2] = keyid[bytes];
}
return 2 + x;
}
static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok, dispname[80];
int line = 0, flag = 0, cmd = 3;
struct adsi_display *disp;
/* Get display */
if (!(tok = get_token(&args, script, lineno)) || process_token(dispname, tok, sizeof(dispname) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid display name: %s at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
return 0;
}
if (!(disp = getdisplaybyname(state, dispname, script, lineno, 0))) {
ast_log(LOG_WARNING, "Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
return 0;
}
if (!(tok = get_token(&args, script, lineno)) || strcasecmp(tok, "AT")) {
ast_log(LOG_WARNING, "Missing token 'AT' at line %d of %s\n", lineno, script);
return 0;
}
if (!(tok = get_token(&args, script, lineno)) || process_token(&line, tok, sizeof(line), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid line: '%s' at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
return 0;
}
if ((tok = get_token(&args, script, lineno)) && !strcasecmp(tok, "NOUPDATE")) {
cmd = 1;
tok = get_token(&args, script, lineno);
}
if (tok && !strcasecmp(tok, "UNLESS")) {
/* Check for trailing UNLESS flag */
if (!(tok = get_token(&args, script, lineno))) {
ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
} else if (process_token(&flag, tok, sizeof(flag), ARG_NUMBER)) {
ast_log(LOG_WARNING, "Invalid flag number '%s' at line %d of %s\n", tok, lineno, script);
}
if ((tok = get_token(&args, script, lineno)))
ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
}
buf[0] = id;
buf[1] = (cmd << 6) | (disp->id & 0x3f);
return 3;
}
static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (tok)
ast_log(LOG_WARNING, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
buf[0] = id;
buf[1] = 0x00;
return 2;
}
static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (tok)
ast_log(LOG_WARNING, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
buf[0] = id;
buf[1] = 0x7;
return 2;
}
static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (tok)
ast_log(LOG_WARNING, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
buf[0] = id;
buf[1] = 0;
return 2;
}
static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
if (tok)
ast_log(LOG_WARNING, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
buf[0] = id;
buf[1] = 0xf;
return 2;
}
static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
char subscript[80];
struct adsi_subscript *sub;
if (!tok) {
ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
return 0;
}
if (!(sub = getsubbyname(state, subscript, script, lineno)))
return 2;
}
static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
{
char *tok = get_token(&args, script, lineno);
char subscript[80], sname[80];
int sawin = 0, event, snums[8], scnt = 0, x;
if (!tok) {
ast_log(LOG_WARNING, "Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
return 0;
}
if ((event = geteventbyname(tok)) < 1) {
ast_log(LOG_WARNING, "'%s' is not a valid event name, at line %d of %s\n", args, lineno, script);
return 0;
}
tok = get_token(&args, script, lineno);
while ((!sawin && !strcasecmp(tok, "IN")) ||
(sawin && !strcasecmp(tok, "OR"))) {
sawin = 1;
if (scnt > 7) {
ast_log(LOG_WARNING, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno, script);
return 0;
}
/* Process 'in' things */
tok = get_token(&args, script, lineno);
if (process_token(sname, tok, sizeof(sname), ARG_STRING)) {
ast_log(LOG_WARNING, "'%s' is not a valid state name at line %d of %s\n", tok, lineno, script);
return 0;
}
if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) < 0)) {
ast_log(LOG_WARNING, "State '%s' not declared at line %d of %s\n", sname, lineno, script);
return 0;
}
scnt++;
if (!(tok = get_token(&args, script, lineno)))
break;
}
if (!tok || strcasecmp(tok, "GOTO")) {
if (!tok)
tok = "<nothing>";
if (sawin)
ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok, lineno, script);
else
ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok, lineno, script);
}
if (!(tok = get_token(&args, script, lineno))) {
ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
ast_log(LOG_WARNING, "Invalid subscript '%s' at line %d of %s\n", tok, lineno, script);
return 0;
}
if (!(sub = getsubbyname(state, subscript, script, lineno)))
return 0;
buf[0] = 8;
buf[1] = event;
buf[2] = sub->id | 0x80;
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
buf[3 + x] = snums[x];
return 3 + scnt;
}
struct adsi_key_cmd {
char *name;
int id;
int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno);
};
static struct adsi_key_cmd kcmds[] = {
{ "SENDDTMF", 0, send_dtmf },
/* Encoded DTMF would go here */
{ "ONHOOK", 0x81 },
{ "OFFHOOK", 0x82 },
{ "FLASH", 0x83 },
{ "WAITDIALTONE", 0x84 },
/* Send line number */
{ "BLANK", 0x86 },
{ "SENDCHARS", 0x87 },
{ "CLEARCHARS", 0x88 },
{ "BACKSPACE", 0x89 },
/* Tab column */
{ "GOTOLINE", 0x8b, goto_line },
{ "GOTOLINEREL", 0x8c, goto_line_rel },
{ "PAGEUP", 0x8d },
{ "PAGEDOWN", 0x8e },
/* Extended DTMF */
{ "DELAY", 0x90, send_delay },
{ "DIALPULSEONE", 0x91 },
{ "DATAMODE", 0x92 },
{ "VOICEMODE", 0x93 },
/* Display call buffer 'n' */
/* Clear call buffer 'n' */
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
{ "DIGITCOLLECT", 0x96, digitcollect },
{ "DIGITDIRECT", 0x96, digitdirect },
{ "CLEAR", 0x97 },
{ "SHOWDISPLAY", 0x98, showdisplay },
{ "CLEARDISPLAY", 0x98, cleardisplay },
{ "SHOWKEYS", 0x99, showkeys },
{ "SETSTATE", 0x9a, set_state },
{ "TIMERSTART", 0x9b, starttimer },
{ "TIMERCLEAR", 0x9b, cleartimer },
{ "SETFLAG", 0x9c, setflag },
{ "CLEARFLAG", 0x9c, clearflag },
{ "GOTO", 0x9d, subscript },
{ "EVENT22", 0x9e },
{ "EVENT23", 0x9f },
{ "EXIT", 0xa0 },
};
static struct adsi_key_cmd opcmds[] = {
/* 1 - Branch on event -- handled specially */
{ "SHOWKEYS", 2, showkeys },
/* Display Control */
{ "SHOWDISPLAY", 3, showdisplay },
{ "CLEARDISPLAY", 3, cleardisplay },
{ "CLEAR", 5 },
{ "SETSTATE", 6, set_state },
{ "TIMERSTART", 7, starttimer },
{ "TIMERCLEAR", 7, cleartimer },
{ "ONEVENT", 8, onevent },
/* 9 - Subroutine label, treated specially */
{ "SETFLAG", 10, setflag },
{ "CLEARFLAG", 10, clearflag },
{ "DELAY", 11, send_delay },
{ "EXIT", 12 },
};
static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, char *script, int lineno)
{
for (x = 0; x < sizeof(kcmds) / sizeof(kcmds[0]); x++) {
if ((kcmds[x].id > -1) && !strcasecmp(kcmds[x].name, code)) {
if (kcmds[x].add_args) {
res = kcmds[x].add_args(key->retstr + key->retstrlen,
code, kcmds[x].id, args, state, script, lineno);
if ((key->retstrlen + res - key->initlen) <= MAX_RET_CODE)
key->retstrlen += res;
else
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);
} else {
if ((unused = get_token(&args, script, lineno)))
ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds[x].name, lineno, script, unused);
if ((key->retstrlen + 1 - key->initlen) <= MAX_RET_CODE) {
key->retstr[key->retstrlen] = kcmds[x].id;
key->retstrlen++;
} else
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);
}
return 0;
}
}
return -1;
}
static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, char *script, int lineno)
{
int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
for (x = 0; x < sizeof(opcmds) / sizeof(opcmds[0]); x++) {
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
if ((opcmds[x].id > -1) && !strcasecmp(opcmds[x].name, code)) {
if (opcmds[x].add_args) {
res = opcmds[x].add_args(sub->data + sub->datalen,
code, opcmds[x].id, args, state, script, lineno);
if ((sub->datalen + res + 1) <= max)
sub->datalen += res;
else {
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);
return -1;
}
} else {
if ((unused = get_token(&args, script, lineno)))
ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds[x].name, lineno, script, unused);
if ((sub->datalen + 2) <= max) {
sub->data[sub->datalen] = opcmds[x].id;
sub->datalen++;
} else {
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);
return -1;
}
}
/* Separate commands with 0xff */
sub->data[sub->datalen] = 0xff;
sub->datalen++;
sub->inscount++;
return 0;
}
}
return -1;
}
static int adsi_process(struct adsi_script *state, char *buf, char *script, int lineno)