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>
<support_level>extended</support_level>
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 const char app[] = "ADSIProg";
/*** DOCUMENTATION
<application name="ADSIProg" language="en_US">
<synopsis>
Load Asterisk ADSI Scripts into phone
</synopsis>
<syntax>
<parameter name="script" required="false">
<para>adsi script to use. If not given uses the default script <filename>asterisk.adsi</filename></para>
</parameter>
</syntax>
<description>
<para>This application programs an ADSI Phone with the given script</para>
</description>
<see-also>
<ref type="application">GetCPEID</ref>
<ref type="filename">adsi.conf</ref>
</see-also>
/* #define DUMP_MESSAGES */
struct adsi_event {
int id;
const char *name;
static const 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 const 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)
char vname[40]; /* Which "variable" is associated with it */
int retstrlen; /* Length of return string */
int initlen; /* initial length */
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
};
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 */
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 */
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 */
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, const char *script, int lineno)
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/* 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, const 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;
}
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++;
}
static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, const 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;
}
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;
static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, const 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;
}
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;
static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, const 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;
static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, const 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;
}
static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
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;
static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
for (x = 0; x < state->numflags; 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, const 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;
static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, const 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);
static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, const 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 < ARRAY_LEN(events); x++) {
if (!strcasecmp(events[x].name, name))
return events[x].id;
}
return 0;
}
static int getjustifybyname(char *name)
{
int x;
for (x = 0; x < ARRAY_LEN(justify); x++) {
if (!strcasecmp(justify[x].name, name))
return justify[x].id;
}
static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, const char *script, int lineno)
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++;
static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, const char *script, int lineno)
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++;
static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, const char *script, int lineno, int create)
for (x = 0; x <state->numstates; 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, const char *script, int lineno, int create)
for (x = 0; x < state->numdisplays; x++) {
if (!strcasecmp(state->displays[x].vname, name))
/* 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, const 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 */
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);
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);
if (!(key = getkeybyname(state, newkey, script, lineno)))
break;
keyid[x] = key->id;
}
buf[0] = id;
buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, const 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 */
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);
}
static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
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, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
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, const 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, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
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, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
char subscr[80];
if (!tok) {
ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
return 0;
}
if (process_token(subscr, tok, sizeof(subscr) - 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, subscr, script, lineno)))
static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, const char *script, int lineno)
char *tok = get_token(&args, script, lineno);
char subscr[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;
}
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) == NULL)) {
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>";
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(subscr, tok, sizeof(subscr) - 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, subscr, script, lineno)))
return 0;
buf[0] = 8;
buf[1] = event;
buf[2] = sub->id | 0x80;
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, const char *script, int lineno);
static const 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' */
{ "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 const 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, const char *script, int lineno)
for (x = 0; x < ARRAY_LEN(kcmds); 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)
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++;
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, const char *script, int lineno)
int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
for (x = 0; x < ARRAY_LEN(opcmds); x++) {
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);
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);