aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2002-06-21 01:40:13 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2002-06-21 01:40:13 +0000
commit87909fa28e55346e164f7c1ea3bec21aa9e1e01d (patch)
treeeb3b9515fd164afd1e2242b99a26c047f8719bfe
parent74d376fd3728d44299a0fa2a9c15cd8012cb1b47 (diff)
Version 0.1.12 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@465 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xMakefile63
-rwxr-xr-xapps/app_adsiprog.c1567
-rwxr-xr-xapps/app_system.c5
-rwxr-xr-xchannel.c449
-rwxr-xr-xchannels/adtranvofr.h2
-rwxr-xr-xchannels/chan_phone.c68
-rwxr-xr-xcodecs/Makefile6
-rwxr-xr-xcodecs/lpc10/Makefile3
-rwxr-xr-xformats/format_jpeg.c2
-rwxr-xr-xformats/format_wav.c5
-rwxr-xr-xinclude/asterisk/logger.h6
-rwxr-xr-xlogger.c39
-rwxr-xr-xpbx.c417
-rwxr-xr-xres/res_adsi.c338
14 files changed, 2700 insertions, 270 deletions
diff --git a/Makefile b/Makefile
index 68e843087..0dc248632 100755
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,6 @@
# the GNU General Public License
#
-
.EXPORT_ALL_VARIABLES:
INSTALL_PREFIX=
@@ -22,14 +21,20 @@ AGI_DIR=$(INSTALL_PREFIX)/var/lib/asterisk/agi-bin
# Pentium Pro Optimize
#PROC=i686
# Pentium Optimize
-PROC=i586
+#PROC=i586
+#PROC=k6
+#PROC=ppc
+PROC=$(shell uname -m)
DEBUG=-g #-pg
INCLUDE=-Iinclude -I../include
-CFLAGS=-pipe -Wall -Wmissing-prototypes -Wmissing-declarations -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT
+CFLAGS=-pipe -Wall -Wmissing-prototypes -Wmissing-declarations -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE
#CFLAGS+=-Werror
CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
+CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
+
ASTERISKVERSION=$(shell if [ -f .version ]; then cat .version; fi)
+HTTPDIR=$(shell if [ -d /var/www ]; then echo "/var/www"; else echo "/home/httpd"; fi)
RPMVERSION=$(shell sed 's/[-\/:]/_/g' .version)
CFLAGS+=-DASTERISK_VERSION=\"$(ASTERISKVERSION)\"
# Optional debugging parameters
@@ -38,11 +43,11 @@ CFLAGS+= -DDO_CRASH -DDEBUG_THREADS
#CLFAGS+= -DTRACE_FRAMES
CFLAGS+=# -fomit-frame-pointer
SUBDIRS=res channels pbx apps codecs formats agi cdr
-LIBS=-ldl -lpthread -lreadline -lncurses -lm
+LIBS=-ldl -lpthread -lreadline -lncurses -lm #-lnjamd
OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
- translate.o file.o say.o pbx.o cli.o md5.o \
+ translate.o file.o say.o pbx.o cli.o md5.o term.o \
ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
- cdr.o tdd.o asterisk.o
+ cdr.o tdd.o acl.o rtp.o asterisk.o
CC=gcc
INSTALL=install
@@ -81,9 +86,10 @@ datafiles: all
for x in sounds/digits/*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds/digits ; \
done
- for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-*; do \
+ for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-* sounds/conf-*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds ; \
done
+ mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/mohmp3
mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/images
for x in images/*.jpg; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/images ; \
@@ -93,8 +99,10 @@ datafiles: all
install: all datafiles
mkdir -p $(MODULES_DIR)
mkdir -p $(INSTALL_PREFIX)/usr/sbin
+ mkdir -p $(INSTALL_PREFIX)/etc/asterisk
install -m 755 asterisk $(INSTALL_PREFIX)/usr/sbin/
install -m 755 astgenkey $(INSTALL_PREFIX)/usr/sbin/
+ install -m 755 safe_asterisk $(INSTALL_PREFIX)/usr/sbin/
for x in $(SUBDIRS); do $(MAKE) -C $$x install || exit 1 ; done
install -d $(INSTALL_PREFIX)/usr/include/asterisk
install include/asterisk/*.h $(INSTALL_PREFIX)/usr/include/asterisk
@@ -128,7 +136,15 @@ install: all datafiles
@echo " + **Note** This requires that you have +"
@echo " + doxygen installed on your local system +"
@echo " +-------------------------------------------+"
-samples: all datafiles
+adsi: all
+ mkdir -p /etc/asterisk
+ for x in configs/*.adsi; do \
+ if ! [ -f $(INSTALL_PREFIX)/etc/asterisk/$$x ]; then \
+ install -m 644 $$x $(INSTALL_PREFIX)/etc/asterisk/`basename $$x` ; \
+ fi ; \
+ done
+
+samples: all datafiles adsi
mkdir -p $(INSTALL_PREFIX)/etc/asterisk
for x in configs/*.sample; do \
if [ -f $(INSTALL_PREFIX)/etc/asterisk/`basename $$x .sample` ]; then \
@@ -139,6 +155,9 @@ samples: all datafiles
for x in sounds/demo-*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds; \
done
+ for x in sounds/*.mp3; do \
+ install $$x $(INSTALL_PREFIX)/var/lib/asterisk/mohmp3 ; \
+ done
mkdir -p $(INSTALL_PREFIX)/var/spool/asterisk/vm/1234/INBOX
:> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/unavail.gsm
for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isunavail; do \
@@ -149,6 +168,24 @@ samples: all datafiles
cat $(INSTALL_PREFIX)/var/lib/asterisk/sounds/$$x.gsm >> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/busy.gsm ; \
done
+webvmail:
+ @[ -d $(HTTPDIR) ] || ( echo "No HTTP directory" && exit 1 )
+ @[ -d $(HTTPDIR)/html ] || ( echo "No http directory" && exit 1 )
+ @[ -d $(HTTPDIR)/cgi-bin ] || ( echo "No cgi-bin directory" && exit 1 )
+ install -m 4755 -o root -g root vmail.cgi $(HTTPDIR)/cgi-bin/vmail.cgi
+ mkdir -p $(HTTPDIR)/html/_asterisk
+ for x in images/*.gif; do \
+ install -m 644 $$x $(HTTPDIR)/html/_asterisk/; \
+ done
+ @echo " +--------- Asterisk Web Voicemail ----------+"
+ @echo " + +"
+ @echo " + Asterisk Web Voicemail is installed in +"
+ @echo " + your cgi-bin directory. IT USES A SETUID +"
+ @echo " + ROOT PERL SCRIPT, SO IF YOU DON'T LIKE +"
+ @echo " + THAT, UNINSTALL IT! +"
+ @echo " + +"
+ @echo " +-------------------------------------------+"
+
mailbox:
./addmailbox
@@ -171,3 +208,13 @@ __rpm: _version
progdocs:
doxygen asterisk-ng-doxygen
+
+config:
+ if [ -d /etc/rc.d/init.d ]; then \
+ install -m 755 init.asterisk /etc/rc.d/init.d/asterisk; \
+ /sbin/chkconfig --add asterisk; \
+ elif [ -d /etc/init.d ]; then \
+ install -m 755 init.asterisk /etc/init.d/asterisk; \
+ fi
+
+
diff --git a/apps/app_adsiprog.c b/apps/app_adsiprog.c
new file mode 100755
index 000000000..531b2c423
--- /dev/null
+++ b/apps/app_adsiprog.c
@@ -0,0 +1,1567 @@
+/*
+ * Asterisk -- A telephony toolkit for Linux.
+ *
+ * Program Asterisk ADSI Scripts into phone
+ *
+ * Copyright (C) 1999, Mark Spencer
+ *
+ * Mark Spencer <markster@linux-support.net>
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License
+ */
+
+#include <asterisk/file.h>
+#include <asterisk/logger.h>
+#include <asterisk/channel.h>
+#include <asterisk/pbx.h>
+#include <asterisk/module.h>
+#include <asterisk/adsi.h>
+#include <asterisk/options.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <pthread.h>
+
+#include "../asterisk.h"
+
+static char *tdesc = "Asterisk ADSI Programming Application";
+
+static char *app = "ADSIProg";
+
+static char *synopsis = "Load Asterisk ADSI Scripts into phone";
+
+/* #define DUMP_MESSAGES */
+
+static char *descrip =
+" ADSIProg(script): Programs an ADSI Phone with the given script.\n"
+"If none is specified, the default is used. Returns 0 unless CPE\n"
+"is hungup.\n";
+
+STANDARD_LOCAL_USER;
+
+LOCAL_USER_DECL;
+
+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 */
+ char sec[5];
+ char desc[19];
+ char fdn[5];
+ 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';
+ } else if (strlen(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));
+ }
+ } else if ((strlen(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)
+{
+ char *tmp = *buf;
+ char *keyword;
+ int quoted = 0;
+ /* 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];
+ char *a;
+ int bytes=0;
+ a = get_token(&args, script, lineno);
+ if (!a) {
+ 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;
+ }
+ a = dtmfstr;
+ 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;
+ char *gline;
+ int line;
+ unsigned char cmd;
+ page = get_token(&args, script, lineno);
+ 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;
+ char *gline;
+ int line;
+ unsigned char cmd;
+ dir = get_token(&args, script, lineno);
+ 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;
+ int ms;
+ 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;
+ }
+ buf[0] = 0x90;
+ 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;
+ int state;
+ 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;
+ }
+ buf[0] = id;
+ buf[1] = state;
+ return 2;
+}
+
+static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok;
+ 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;
+ }
+ strncpy(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname) - 1);
+ 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;
+ char sname[80];
+ struct adsi_flag *flag;
+ 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;
+ }
+ flag = getflagbyname(state, sname, script, lineno, 0);
+ if (!flag) {
+ 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;
+ struct adsi_flag *flag;
+ char sname[80];
+ 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;
+ }
+ flag = getflagbyname(state, sname, script, lineno, 0);
+ if (!flag) {
+ 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;
+ int secs;
+ 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;
+ for (x=0;x<state->numkeys;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;
+ }
+ strncpy(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname) - 1);
+ 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;
+ for (x=0;x<state->numsubs;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;
+ }
+ strncpy(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname) - 1);
+ 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;
+ }
+ strncpy(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname) - 1);
+ 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;
+ }
+ strncpy(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname) - 1);
+ 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;
+ char newkey[80];
+ int bytes;
+ unsigned char keyid[6];
+ int x;
+ int flagid=0;
+ struct adsi_soft_key *key;
+ struct adsi_flag *flag;
+
+ for (x=0;x<7;x++) {
+ /* Up to 6 key arguments */
+ tok = get_token(&args, script, lineno);
+ if (!tok)
+ break;
+ if (!strcasecmp(tok, "UNLESS")) {
+ /* Check for trailing UNLESS flag */
+ tok = get_token(&args, script, lineno);
+ if (!tok) {
+ 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;
+ }
+
+ key = getkeybyname(state, newkey, script, lineno);
+ if (!key)
+ break;
+ keyid[x] = key->id;
+ }
+ buf[0] = id;
+ buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
+ for (bytes=0;bytes<x;bytes++) {
+ 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;
+ char dispname[80];
+ int line=0;
+ int flag=0;
+ int cmd = 3;
+ struct adsi_display *disp;
+
+ /* Get display */
+ tok = get_token(&args, script, lineno);
+ if (!tok || 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;
+ }
+ disp = getdisplaybyname(state, dispname, script, lineno, 0);
+ if (!disp) {
+ ast_log(LOG_WARNING, "Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
+ return 0;
+ }
+
+ tok = get_token(&args, script, lineno);
+ if (!tok || strcasecmp(tok, "AT")) {
+ ast_log(LOG_WARNING, "Missing token 'AT' at line %d of %s\n", lineno, script);
+ return 0;
+ }
+ /* Get line number */
+ tok = get_token(&args, script, lineno);
+ if (!tok || 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;
+ }
+ tok = get_token(&args, script, lineno);
+ if (tok && !strcasecmp(tok, "NOUPDATE")) {
+ cmd = 1;
+ tok = get_token(&args, script, lineno);
+ }
+ if (tok && !strcasecmp(tok, "UNLESS")) {
+ /* Check for trailing UNLESS flag */
+ tok = get_token(&args, script, lineno);
+ if (!tok) {
+ 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 & 0x2f);
+ buf[2] = ((line & 0x1f) << 3) | (flag & 0x7);
+ return 3;
+}
+
+static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok;
+ 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;
+ 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 digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok;
+ 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;
+ char subscript[80];
+ struct adsi_subscript *sub;
+ tok = get_token(&args, script, lineno);
+ 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;
+ }
+ sub = getsubbyname(state, subscript, script, lineno);
+ if (!sub)
+ return 0;
+ buf[0] = 0x9d;
+ buf[1] = sub->id;
+ return 2;
+}
+
+static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok;
+ char subscript[80];
+ char sname[80];
+ int sawin=0;
+ int event;
+ int snums[8];
+ int scnt = 0;
+ int x;
+ struct adsi_subscript *sub;
+ tok = get_token(&args, script, lineno);
+ if (!tok) {
+ ast_log(LOG_WARNING, "Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
+ return 0;
+ }
+ event = geteventbyname(tok);
+ if (event < 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++;
+ tok = get_token(&args, script, lineno);
+ if (!tok)
+ 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);
+ }
+ tok = get_token(&args, script, lineno);
+ 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 subscript '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+ sub = getsubbyname(state, subscript, script, lineno);
+ if (!sub)
+ return 0;
+ buf[0] = 8;
+ buf[1] = event;
+ buf[2] = sub->id | 0x80;
+ for (x=0;x<scnt;x++)
+ 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' */
+ { "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)
+{
+ int x;
+ char *unused;
+ int res;
+ 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;
+ char *unused;
+ int res;
+ int max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
+ for (x=0;x<sizeof(opcmds) / sizeof(opcmds[0]);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);
+ 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)
+{
+ char *keyword;
+ char *args;
+ char vname[256];
+ char tmp[80];
+ char tmp2[80];
+ int lrci;
+ int wi;
+ int event;
+ struct adsi_display *disp;
+ struct adsi_subscript *newsub;
+ /* Find the first keyword */
+ keyword = get_token(&buf, script, lineno);
+ if (!keyword)
+ return 0;
+ switch(state->state) {
+ case STATE_NORMAL:
+ if (!strcasecmp(keyword, "DESCRIPTION")) {
+ args = get_token(&buf, script, lineno);
+ if (args) {
+ if (process_token(state->desc, args, sizeof(state->desc) - 1, ARG_STRING))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for DESCRIPTION at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "VERSION")) {
+ args = get_token(&buf, script, lineno);
+ if (args) {
+ if (process_token(&state->ver, args, sizeof(state->ver) - 1, ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for VERSION at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for VERSION at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "SECURITY")) {
+ args = get_token(&buf, script, lineno);
+ if (args) {
+ if (process_token(state->sec, args, sizeof(state->sec) - 1, ARG_STRING | ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for SECURITY at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for SECURITY at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "FDN")) {
+ args = get_token(&buf, script, lineno);
+ if (args) {
+ if (process_token(state->fdn, args, sizeof(state->fdn) - 1, ARG_STRING | ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for FDN at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for FDN at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "KEY")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "KEY definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ state->key = getkeybyname(state, vname, script, lineno);
+ if (!state->key) {
+ ast_log(LOG_WARNING, "Out of key space at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (state->key->defined) {
+ ast_log(LOG_WARNING, "Cannot redefine key '%s' at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "KEY definition missing short name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a KEY short name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (args) {
+ if (strcasecmp(args, "OR")) {
+ ast_log(LOG_WARNING, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "KEY definition missing optional long name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp2, args, sizeof(tmp2) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a KEY long name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ } else {
+ strncpy(tmp2, tmp, sizeof(tmp2) - 1);
+ }
+ if (strlen(tmp2) > 18) {
+ ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
+ tmp2[18] = '\0';
+ }
+ if (strlen(tmp) > 7) {
+ ast_log(LOG_WARNING, "Truncating short name to 7 bytes at line %d of %s\n", lineno, script);
+ tmp[7] = '\0';
+ }
+ /* Setup initial stuff */
+ state->key->retstr[0] = 128;
+ /* 1 has the length */
+ state->key->retstr[2] = state->key->id;
+ /* Put the Full name in */
+ memcpy(state->key->retstr + 3, tmp2, strlen(tmp2));
+ /* Update length */
+ state->key->retstrlen = strlen(tmp2) + 3;
+ /* Put trailing 0xff */
+ state->key->retstr[state->key->retstrlen++] = 0xff;
+ /* Put the short name */
+ memcpy(state->key->retstr + state->key->retstrlen, tmp, strlen(tmp));
+ /* Update length */
+ state->key->retstrlen += strlen(tmp);
+ /* Put trailing 0xff */
+ state->key->retstr[state->key->retstrlen++] = 0xff;
+ /* Record initial length */
+ state->key->initlen = state->key->retstrlen;
+ state->state = STATE_INKEY;
+ } else if (!strcasecmp(keyword, "SUB")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ state->sub = getsubbyname(state, vname, script, lineno);
+ if (!state->sub) {
+ ast_log(LOG_WARNING, "Out of subroutine space at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (state->sub->defined) {
+ ast_log(LOG_WARNING, "Cannot redefine subroutine '%s' at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ /* Setup sub */
+ state->sub->data[0] = 130;
+ /* 1 is the length */
+ state->sub->data[2] = 0x0; /* Clear extensibility bit */
+ state->sub->datalen = 3;
+ if (state->sub->id) {
+ /* If this isn't the main subroutine, make a subroutine label for it */
+ state->sub->data[3] = 9;
+ state->sub->data[4] = state->sub->id;
+ /* 5 is length */
+ state->sub->data[6] = 0xff;
+ state->sub->datalen = 7;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
+ break;
+ }
+ state->state = STATE_INSUB;
+ } else if (!strcasecmp(keyword, "STATE")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "STATE definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a STATE name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getstatebyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "State '%s' is already defined at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ getstatebyname(state, vname, script, lineno, 1);
+ } else if (!strcasecmp(keyword, "FLAG")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "FLAG definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a FLAG name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getflagbyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "Flag '%s' is already defined\n", vname);
+ break;
+ }
+ getflagbyname(state, vname, script, lineno, 1);
+ } else if (!strcasecmp(keyword, "DISPLAY")) {
+ lrci = 0;
+ wi = 0;
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getdisplaybyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "State '%s' is already defined\n", vname);
+ break;
+ }
+ disp = getdisplaybyname(state, vname, script, lineno, 1);
+ if (!disp)
+ break;
+ args = get_token(&buf, script, lineno);
+ if (!args || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Missing 'IS' at line %d of %s\n", lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "Missing Column 1 text at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Token '%s' is not valid column 1 text at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (strlen(tmp) > 20) {
+ ast_log(LOG_WARNING, "Truncating column one to 20 characters at line %d of %s\n", lineno, script);
+ tmp[20] = '\0';
+ }
+ memcpy(disp->data + 5, tmp, strlen(tmp));
+ disp->datalen = strlen(tmp) + 5;
+ disp->data[disp->datalen++] = 0xff;
+
+ args = get_token(&buf, script, lineno);
+ if (args && !process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ /* Got a column two */
+ if (strlen(tmp) > 20) {
+ ast_log(LOG_WARNING, "Truncating column two to 20 characters at line %d of %s\n", lineno, script);
+ tmp[20] = '\0';
+ }
+ memcpy(disp->data + disp->datalen, tmp, strlen(tmp));
+ disp->datalen += strlen(tmp);
+ args = get_token(&buf, script, lineno);
+ }
+ while(args) {
+ if (!strcasecmp(args, "JUSTIFY")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno, script);
+ break;
+ }
+ lrci = getjustifybyname(args);
+ if (lrci < 0) {
+ ast_log(LOG_WARNING, "'%s' is not a valid justification at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ } else if (!strcasecmp(args, "WRAP")) {
+ wi = 0x80;
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a known qualifier at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ }
+ if (args) {
+ /* Something bad happened */
+ break;
+ }
+ disp->data[0] = 129;
+ disp->data[1] = disp->datalen - 2;
+ disp->data[2] = ((lrci & 0x3) << 6) | disp->id;
+ disp->data[3] = wi;
+ disp->data[4] = 0xff;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword);
+ }
+ break;
+ case STATE_INKEY:
+ if (process_returncode(state->key, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDKEY")) {
+ /* Return to normal operation and increment current key */
+ state->state = STATE_NORMAL;
+ state->key->defined = 1;
+ state->key->retstr[1] = state->key->retstrlen - 2;
+ state->key = NULL;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword, lineno, script);
+ }
+ }
+ break;
+ case STATE_INIF:
+ if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDIF")) {
+ /* Return to normal SUB operation and increment current key */
+ state->state = STATE_INSUB;
+ state->sub->defined = 1;
+ /* Store the proper number of instructions */
+ state->sub->ifdata[2] = state->sub->ifinscount;
+ } else if (!strcasecmp(keyword, "GOTO")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "GOTO clause missing Subscript name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid subscript name token at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ newsub = getsubbyname(state, tmp, script, lineno);
+ if (!newsub)
+ break;
+ /* Somehow you use GOTO to go to another place */
+ state->sub->data[state->sub->datalen++] = 0x8;
+ state->sub->data[state->sub->datalen++] = state->sub->ifdata[1];
+ state->sub->data[state->sub->datalen++] = newsub->id;
+ /* Terminate */
+ state->sub->data[state->sub->datalen++] = 0xff;
+ /* Increment counters */
+ state->sub->inscount++;
+ state->sub->ifinscount++;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword, lineno, script);
+ }
+ } else
+ state->sub->ifinscount++;
+ break;
+ case STATE_INSUB:
+ if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDSUB")) {
+ /* Return to normal operation and increment current key */
+ state->state = STATE_NORMAL;
+ state->sub->defined = 1;
+ /* Store the proper length */
+ state->sub->data[1] = state->sub->datalen - 2;
+ if (state->sub->id) {
+ /* if this isn't main, store number of instructions, too */
+ state->sub->data[5] = state->sub->inscount;
+ }
+ state->sub = NULL;
+ } else if (!strcasecmp(keyword, "IFEVENT")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "IFEVENT clause missing Event name at line %d of %s\n", lineno, script);
+ break;
+ }
+ event = geteventbyname(args);
+ if (event < 1) {
+ ast_log(LOG_WARNING, "'%s' is not a valid event\n", args);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ if (!args || strcasecmp(args, "THEN")) {
+ ast_log(LOG_WARNING, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno, script);
+ break;
+ }
+ state->sub->ifinscount = 0;
+ state->sub->ifdata = state->sub->data +
+ state->sub->datalen;
+ /* Reserve header and insert op codes */
+ state->sub->ifdata[0] = 0x1;
+ state->sub->ifdata[1] = event;
+ /* 2 is for the number of instructions */
+ state->sub->ifdata[3] = 0xff;
+ state->sub->datalen += 4;
+ /* Update Subscript instruction count */
+ state->sub->inscount++;
+ state->state = STATE_INIF;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword, lineno, script);
+ }
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Can't process keyword '%s' in weird state %d\n", keyword, state->state);
+ }
+ return 0;
+}
+
+static struct adsi_script *compile_script(char *script)
+{
+ FILE *f;
+ char fn[256];
+ char buf[256];
+ char *c;
+ int lineno=0;
+ int x, err;
+ struct adsi_script *scr;
+ if (script[0] == '/')
+ strncpy(fn, script, sizeof(fn) - 1);
+ else
+ snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, script);
+ f = fopen(fn, "r");
+ if (!f) {
+ ast_log(LOG_WARNING, "Can't open file '%s'\n", fn);
+ return NULL;
+ }
+ scr = malloc(sizeof(struct adsi_script));
+ if (!scr) {
+ fclose(f);
+ ast_log(LOG_WARNING, "Out of memory loading script '%s'\n", fn);
+ return NULL;
+ }
+ memset(scr, 0, sizeof(struct adsi_script));
+ /* Create "main" as first subroutine */
+ getsubbyname(scr, "main", NULL, 0);
+ while(!feof(f)) {
+ fgets(buf, sizeof(buf), f);
+ if (!feof(f)) {
+ lineno++;
+ /* Trim off trailing return */
+ buf[strlen(buf) - 1] = '\0';
+ c = strchr(buf, ';');
+ /* Strip comments */
+ if (c)
+ *c = '\0';
+ if (strlen(buf))
+ adsi_process(scr, buf, script, lineno);
+ }
+ }
+ fclose(f);
+ /* Make sure we're in the main routine again */
+ switch(scr->state) {
+ case STATE_NORMAL:
+ break;
+ case STATE_INSUB:
+ ast_log(LOG_WARNING, "Missing ENDSUB at end of file %s\n", script);
+ free(scr);
+ return NULL;
+ case STATE_INKEY:
+ ast_log(LOG_WARNING, "Missing ENDKEY at end of file %s\n", script);
+ free(scr);
+ return NULL;
+ }
+ err = 0;
+
+ /* Resolve all keys and record their lengths */
+ for (x=0;x<scr->numkeys;x++) {
+ if (!scr->keys[x].defined) {
+ ast_log(LOG_WARNING, "Key '%s' referenced but never defined in file %s\n", scr->keys[x].vname, fn);
+ err++;
+ }
+ }
+
+ /* Resolve all subs */
+ for (x=0;x<scr->numsubs;x++) {
+ if (!scr->subs[x].defined) {
+ ast_log(LOG_WARNING, "Subscript '%s' referenced but never defined in file %s\n", scr->subs[x].vname, fn);
+ err++;
+ }
+ if (x == (scr->numsubs - 1)) {
+ /* Clear out extension bit on last message */
+ scr->subs[x].data[2] = 0x80;
+ }
+ }
+
+ if (err) {
+ free(scr);
+ return NULL;
+ }
+ return scr;
+}
+
+#ifdef DUMP_MESSAGES
+static void dump_message(char *type, char *vname, unsigned char *buf, int buflen)
+{
+ int x;
+ printf("%s %s: [ ", type, vname);
+ for (x=0;x<buflen;x++)
+ printf("%02x ", buf[x]);
+ printf("]\n");
+}
+#endif
+
+static int adsi_prog(struct ast_channel *chan, char *script)
+{
+ struct adsi_script *scr;
+ int x;
+ char buf[1024];
+ int bytes;
+ scr = compile_script(script);
+ if (!scr)
+ return -1;
+
+ /* Start an empty ADSI Session */
+ if (adsi_load_session(chan, NULL, 0, 1) < 1)
+ return -1;
+
+ /* Now begin the download attempt */
+ if (adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
+ /* User rejected us for some reason */
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "User rejected download attempt\n");
+ ast_log(LOG_NOTICE, "User rejected download on channel %s\n", chan->name);
+ free(scr);
+ return -1;
+ }
+
+ bytes = 0;
+ /* Start with key definitions */
+ for (x=0;x<scr->numkeys;x++) {
+ if (bytes + scr->keys[x].retstrlen > 254) {
+ /* Send what we've collected so far */
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->keys[x].retstr, scr->keys[x].retstrlen);
+ bytes += scr->keys[x].retstrlen;
+#ifdef DUMP_MESSAGES
+ dump_message("Key", scr->keys[x].vname, scr->keys[x].retstr, scr->keys[x].retstrlen);
+#endif
+ }
+ if (bytes) {
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+ bytes = 0;
+ /* Continue with the display messages */
+ for (x=0;x<scr->numdisplays;x++) {
+ if (bytes + scr->displays[x].datalen > 254) {
+ /* Send what we've collected so far */
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->displays[x].data, scr->displays[x].datalen);
+ bytes += scr->displays[x].datalen;
+#ifdef DUMP_MESSAGES
+ dump_message("Display", scr->displays[x].vname, scr->displays[x].data, scr->displays[x].datalen);
+#endif
+ }
+ if (bytes) {
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+ bytes = 0;
+ /* Send subroutines */
+ for (x=0;x<scr->numsubs;x++) {
+ if (bytes + scr->subs[x].datalen > 254) {
+ /* Send what we've collected so far */
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->subs[x].data, scr->subs[x].datalen);
+ bytes += scr->subs[x].datalen;
+#ifdef DUMP_MESSAGES
+ dump_message("Sub", scr->subs[x].vname, scr->subs[x].data, scr->subs[x].datalen);
+#endif
+ }
+ if (bytes) {
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+
+ bytes = 0;
+ bytes += adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
+ bytes += adsi_set_line(buf, ADSI_INFO_PAGE, 1);
+ if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
+ return -1;
+ if (adsi_end_download(chan)) {
+ /* Download failed for some reason */
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Download attempt failed\n");
+ ast_log(LOG_NOTICE, "Download failed on %s\n", chan->name);
+ free(scr);
+ return -1;
+ }
+ free(scr);
+ adsi_unload_session(chan);
+ return 0;
+}
+
+static int adsi_exec(struct ast_channel *chan, void *data)
+{
+ int res=0;
+ struct localuser *u;
+ if (!data || !strlen(data))
+ data = "asterisk.adsi";
+ LOCAL_USER_ADD(u);
+ if (!adsi_available(chan)) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE. Not bothering to try.\n");
+ } else {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "ADSI Available on CPE. Attempting Upload.\n");
+ res = adsi_prog(chan, data);
+ }
+ LOCAL_USER_REMOVE(u);
+ return res;
+}
+
+int unload_module(void)
+{
+ STANDARD_HANGUP_LOCALUSERS;
+ return ast_unregister_application(app);
+}
+
+int load_module(void)
+{
+ return ast_register_application(app, adsi_exec, synopsis, descrip);
+}
+
+char *description(void)
+{
+ return tdesc;
+}
+
+int usecount(void)
+{
+ int res;
+ STANDARD_USECOUNT(res);
+ return res;
+}
+
+char *key()
+{
+ return ASTERISK_GPL_KEY;
+}
diff --git a/apps/app_system.c b/apps/app_system.c
index a4369125f..539515e4e 100755
--- a/apps/app_system.c
+++ b/apps/app_system.c
@@ -11,6 +11,7 @@
* the GNU General Public License
*/
+#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
@@ -53,10 +54,10 @@ static int skel_exec(struct ast_channel *chan, void *data)
/* Do our thing here */
res = system((char *)data);
if (res < 0) {
- ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
+ ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
res = -1;
} else if (res == 127) {
- ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
+ ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
res = -1;
} else {
if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
diff --git a/channel.c b/channel.c
index fdd7c8f66..f975db52f 100755
--- a/channel.c
+++ b/channel.c
@@ -18,7 +18,9 @@
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
+#include <asterisk/lock.h>
#include <unistd.h>
+#include <math.h> /* For PI */
#include <asterisk/frame.h>
#include <asterisk/sched.h>
#include <asterisk/options.h>
@@ -28,6 +30,7 @@
#include <asterisk/file.h>
#include <asterisk/translate.h>
+static int shutting_down = 0;
/* XXX Lock appropriately in more functions XXX */
@@ -62,7 +65,7 @@ struct ast_channel *channels = NULL;
/* Protect the channel list (highly unlikely that two things would change
it at the same time, but still! */
-static pthread_mutex_t chlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t chlock = AST_MUTEX_INITIALIZER;
int ast_check_hangup(struct ast_channel *chan)
{
@@ -79,6 +82,45 @@ time_t myt;
return 1;
}
+void ast_begin_shutdown(int hangup)
+{
+ struct ast_channel *c;
+ shutting_down = 1;
+ if (hangup) {
+ PTHREAD_MUTEX_LOCK(&chlock);
+ c = channels;
+ while(c) {
+ c->softhangup = 1;
+ c = c->next;
+ }
+ PTHREAD_MUTEX_UNLOCK(&chlock);
+ }
+}
+
+int ast_active_channels(void)
+{
+ struct ast_channel *c;
+ int cnt = 0;
+ PTHREAD_MUTEX_LOCK(&chlock);
+ c = channels;
+ while(c) {
+ cnt++;
+ c = c->next;
+ }
+ PTHREAD_MUTEX_UNLOCK(&chlock);
+ return cnt;
+}
+
+void ast_cancel_shutdown(void)
+{
+ shutting_down = 0;
+}
+
+int ast_shutting_down(void)
+{
+ return shutting_down;
+}
+
void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
{
time_t myt;
@@ -189,11 +231,15 @@ int ast_best_codec(int fmts)
return 0;
}
-struct ast_channel *ast_channel_alloc(void)
+struct ast_channel *ast_channel_alloc(int needqueue)
{
struct ast_channel *tmp;
struct ast_channel_pvt *pvt;
int x;
+ int flags;
+ /* If shutting down, don't allocate any new channels */
+ if (shutting_down)
+ return NULL;
PTHREAD_MUTEX_LOCK(&chlock);
tmp = malloc(sizeof(struct ast_channel));
memset(tmp, 0, sizeof(struct ast_channel));
@@ -203,24 +249,43 @@ struct ast_channel *ast_channel_alloc(void)
memset(pvt, 0, sizeof(struct ast_channel_pvt));
tmp->sched = sched_context_create();
if (tmp->sched) {
- for (x=0;x<AST_MAX_FDS;x++)
+ for (x=0;x<AST_MAX_FDS - 1;x++)
tmp->fds[x] = -1;
- strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
- tmp->pvt = pvt;
- tmp->state = AST_STATE_DOWN;
- tmp->stack = -1;
- tmp->streamid = -1;
- tmp->appl = NULL;
- tmp->data = NULL;
- pthread_mutex_init(&tmp->lock, NULL);
- strncpy(tmp->context, "default", sizeof(tmp->context)-1);
- strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
- strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
- tmp->priority=1;
- tmp->amaflags = ast_default_amaflags;
- strncpy(tmp->accountcode, ast_default_accountcode, sizeof(tmp->accountcode)-1);
- tmp->next = channels;
- channels= tmp;
+ if (needqueue &&
+ pipe(pvt->alertpipe)) {
+ ast_log(LOG_WARNING, "Alert pipe creation failed!\n");
+ free(pvt);
+ free(tmp);
+ tmp = NULL;
+ pvt = NULL;
+ } else {
+ /* Make sure we've got it done right if they don't */
+ if (needqueue) {
+ flags = fcntl(pvt->alertpipe[0], F_GETFL);
+ fcntl(pvt->alertpipe[0], F_SETFL, flags | O_NONBLOCK);
+ flags = fcntl(pvt->alertpipe[1], F_GETFL);
+ fcntl(pvt->alertpipe[1], F_SETFL, flags | O_NONBLOCK);
+ } else
+ pvt->alertpipe[0] = pvt->alertpipe[1] = -1;
+ /* Always watch the alertpipe */
+ tmp->fds[AST_MAX_FDS-1] = pvt->alertpipe[0];
+ strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
+ tmp->pvt = pvt;
+ tmp->state = AST_STATE_DOWN;
+ tmp->stack = -1;
+ tmp->streamid = -1;
+ tmp->appl = NULL;
+ tmp->data = NULL;
+ ast_pthread_mutex_init(&tmp->lock);
+ strncpy(tmp->context, "default", sizeof(tmp->context)-1);
+ strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
+ strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
+ tmp->priority=1;
+ tmp->amaflags = ast_default_amaflags;
+ strncpy(tmp->accountcode, ast_default_accountcode, sizeof(tmp->accountcode)-1);
+ tmp->next = channels;
+ channels= tmp;
+ }
} else {
ast_log(LOG_WARNING, "Unable to create schedule context\n");
free(tmp);
@@ -237,6 +302,56 @@ struct ast_channel *ast_channel_alloc(void)
return tmp;
}
+int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
+{
+ struct ast_frame *f;
+ struct ast_frame *prev, *cur;
+ int blah = 1;
+ int qlen = 0;
+ f = ast_frdup(fin);
+ if (!f) {
+ ast_log(LOG_WARNING, "Unable to duplicate frame\n");
+ return -1;
+ }
+ if (lock)
+ ast_pthread_mutex_lock(&chan->lock);
+ prev = NULL;
+ cur = chan->pvt->readq;
+ while(cur) {
+ prev = cur;
+ cur = cur->next;
+ qlen++;
+ }
+ if (prev)
+ prev->next = f;
+ else
+ chan->pvt->readq = f;
+ if (chan->pvt->alertpipe[1] > -1) {
+ if (write(chan->pvt->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
+ ast_log(LOG_WARNING, "Unable to write to alert pipe, frametype/subclass %d/%d (qlen = %d): %s!\n",
+ f->frametype, f->subclass, qlen, strerror(errno));
+ }
+ if (qlen > 128) {
+ ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
+ }
+ if (lock)
+ ast_pthread_mutex_unlock(&chan->lock);
+ return 0;
+}
+
+int ast_queue_hangup(struct ast_channel *chan, int lock)
+{
+ struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
+ return ast_queue_frame(chan, &f, lock);
+}
+
+int ast_queue_control(struct ast_channel *chan, int control, int lock)
+{
+ struct ast_frame f = { AST_FRAME_CONTROL, };
+ f.subclass = control;
+ return ast_queue_frame(chan, &f, lock);
+}
+
int ast_channel_defer_dtmf(struct ast_channel *chan)
{
int pre = 0;
@@ -272,9 +387,28 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
}
+int ast_safe_sleep(struct ast_channel *chan, int ms)
+{
+ struct ast_frame *f;
+ while(ms > 0) {
+ ms = ast_waitfor(chan, ms);
+ if (ms <0)
+ return -1;
+ if (ms > 0) {
+ f = ast_read(chan);
+ if (!f)
+ return -1;
+ ast_frfree(f);
+ }
+ }
+ return 0;
+}
+
void ast_channel_free(struct ast_channel *chan)
{
struct ast_channel *last=NULL, *cur;
+ int fd;
+ struct ast_frame *f, *fp;
PTHREAD_MUTEX_LOCK(&chlock);
cur = channels;
while(cur) {
@@ -306,6 +440,17 @@ void ast_channel_free(struct ast_channel *chan)
if (chan->ani)
free(chan->ani);
pthread_mutex_destroy(&chan->lock);
+ /* Close pipes if appropriate */
+ if ((fd = chan->pvt->alertpipe[0]) > -1)
+ close(fd);
+ if ((fd = chan->pvt->alertpipe[1]) > -1)
+ close(fd);
+ f = chan->pvt->readq;
+ while(f) {
+ fp = f;
+ f = f->next;
+ ast_frfree(fp);
+ }
free(chan->pvt);
free(chan);
PTHREAD_MUTEX_UNLOCK(&chlock);
@@ -359,6 +504,11 @@ int ast_hangup(struct ast_channel *chan)
ast_stopstream(chan);
if (chan->sched)
sched_context_destroy(chan->sched);
+ /* Clear any tone stuff remaining */
+ if (chan->generatordata)
+ chan->generator->release(chan, chan->generatordata);
+ chan->generatordata = NULL;
+ chan->generator = NULL;
if (chan->cdr) {
/* End the CDR if it hasn't already */
ast_cdr_end(chan->cdr);
@@ -434,6 +584,29 @@ int ast_answer(struct ast_channel *chan)
return 0;
}
+void ast_deactivate_generator(struct ast_channel *chan)
+{
+ if (chan->generatordata) {
+ chan->generator->release(chan, chan->generatordata);
+ chan->generatordata = NULL;
+ chan->writeinterrupt = 0;
+ }
+}
+
+int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
+{
+ if (chan->generatordata) {
+ chan->generator->release(chan, chan->generatordata);
+ chan->generatordata = NULL;
+ }
+ if ((chan->generatordata = gen->alloc(chan, params))) {
+ chan->generator = gen;
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
{
/* Wait for x amount of time on a file descriptor to have input. */
@@ -511,9 +684,10 @@ struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds,
tv.tv_usec = (*ms % 1000) * 1000;
FD_ZERO(&rfds);
FD_ZERO(&efds);
+
for (x=0;x<n;x++) {
for (y=0;y<AST_MAX_FDS;y++) {
- if (c[x]->fds[y] > 0) {
+ if (c[x]->fds[y] > -1) {
FD_SET(c[x]->fds[y], &rfds);
FD_SET(c[x]->fds[y], &efds);
if (c[x]->fds[y] > max)
@@ -623,12 +797,13 @@ char ast_waitfordigit(struct ast_channel *c, int ms)
struct ast_frame *ast_read(struct ast_channel *chan)
{
struct ast_frame *f = NULL;
+ int blah;
static struct ast_frame null_frame =
{
AST_FRAME_NULL,
};
- pthread_mutex_lock(&chan->lock);
+ ast_pthread_mutex_lock(&chan->lock);
if (chan->masq) {
if (ast_do_masquerade(chan)) {
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
@@ -644,7 +819,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
pthread_mutex_unlock(&chan->lock);
return NULL;
}
-
+
if (!chan->deferdtmf && strlen(chan->dtmfq)) {
/* We have DTMF that has been deferred. Return it now */
chan->dtmff.frametype = AST_FRAME_DTMF;
@@ -655,19 +830,35 @@ struct ast_frame *ast_read(struct ast_channel *chan)
return &chan->dtmff;
}
- chan->blocker = pthread_self();
- if (chan->exception) {
- if (chan->pvt->exception)
- f = chan->pvt->exception(chan);
+ /* Read and ignore anything on the alertpipe, but read only
+ one sizeof(blah) per frame that we send from it */
+ if (chan->pvt->alertpipe[0] > -1) {
+ read(chan->pvt->alertpipe[0], &blah, sizeof(blah));
+ }
+
+ /* Check for pending read queue */
+ if (chan->pvt->readq) {
+ f = chan->pvt->readq;
+ chan->pvt->readq = f->next;
+ /* Interpret hangup and return NULL */
+ if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))
+ f = NULL;
+ } else {
+ chan->blocker = pthread_self();
+ if (chan->exception) {
+ if (chan->pvt->exception)
+ f = chan->pvt->exception(chan);
+ else
+ ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
+ /* Clear the exception flag */
+ chan->exception = 0;
+ } else
+ if (chan->pvt->read)
+ f = chan->pvt->read(chan);
else
- ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
- /* Clear the exception flag */
- chan->exception = 0;
- } else
- if (chan->pvt->read)
- f = chan->pvt->read(chan);
- else
- ast_log(LOG_WARNING, "No read routine on channel %s\n", chan);
+ ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
+ }
+
if (f && (f->frametype == AST_FRAME_VOICE)) {
if (chan->pvt->readtrans) {
f = ast_translate(chan->pvt->readtrans, f, 1);
@@ -675,6 +866,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
f = &null_frame;
}
}
+
/* Make sure we always return NULL in the future */
if (!f) {
chan->softhangup = 1;
@@ -689,10 +881,26 @@ struct ast_frame *ast_read(struct ast_channel *chan)
f = &null_frame;
} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
/* Answer the CDR */
+ chan->state = AST_STATE_UP;
ast_cdr_answer(chan->cdr);
}
pthread_mutex_unlock(&chan->lock);
+ /* Run any generator sitting on the line */
+ if (f && (f->frametype == AST_FRAME_VOICE) && chan->generatordata) {
+ /* Mask generator data temporarily */
+ void *tmp;
+ int res;
+ tmp = chan->generatordata;
+ chan->generatordata = NULL;
+ res = chan->generator->generate(chan, tmp, f->datalen);
+ chan->generatordata = tmp;
+ if (res) {
+ ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
+ ast_deactivate_generator(chan);
+ }
+ }
+
return f;
}
@@ -769,6 +977,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
if (chan->masqr)
return 0;
+ if (chan->generatordata) {
+ if (chan->writeinterrupt)
+ ast_deactivate_generator(chan);
+ else
+ return 0;
+ }
CHECK_BLOCKING(chan);
switch(fr->frametype) {
case AST_FRAME_CONTROL:
@@ -796,6 +1010,9 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
}
}
chan->blocking = 0;
+ /* Consider a write failure to force a soft hangup */
+ if (res < 0)
+ chan->softhangup = 1;
return res;
}
@@ -899,7 +1116,7 @@ int ast_call(struct ast_channel *chan, char *addr, int timeout)
return anyway. */
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
- pthread_mutex_lock(&chan->lock);
+ ast_pthread_mutex_lock(&chan->lock);
if (!chan->zombie && !ast_check_hangup(chan))
if (chan->pvt->call)
res = chan->pvt->call(chan, addr, timeout);
@@ -975,19 +1192,19 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
chanf = chan->nativeformats;
res = ast_translator_best_choice(&peerf, &chanf);
if (res < 0) {
- ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan, chan->nativeformats, peer, peer->nativeformats);
+ ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, chan->nativeformats, peer->name, peer->nativeformats);
return -1;
}
/* Set read format on channel */
res = ast_set_read_format(chan, peerf);
if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan, chanf);
+ ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set write format on peer channel */
res = ast_set_write_format(peer, peerf);
if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer, peerf);
+ ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, peerf);
return -1;
}
/* Now we go the other way */
@@ -995,19 +1212,19 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
chanf = chan->nativeformats;
res = ast_translator_best_choice(&chanf, &peerf);
if (res < 0) {
- ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer, peer->nativeformats, chan, chan->nativeformats);
+ ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, peer->nativeformats, chan->name, chan->nativeformats);
return -1;
}
/* Set writeformat on channel */
res = ast_set_write_format(chan, chanf);
if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan, chanf);
+ ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set read format on peer channel */
res = ast_set_read_format(peer, chanf);
if (res < 0) {
- ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer, peerf);
+ ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, peerf);
return -1;
}
return 0;
@@ -1057,7 +1274,7 @@ static int ast_do_masquerade(struct ast_channel *original)
free_translation(original);
/* We need the clone's lock, too */
- pthread_mutex_lock(&clone->lock);
+ ast_pthread_mutex_lock(&clone->lock);
/* Unlink the masquerade */
original->masq = NULL;
@@ -1224,7 +1441,8 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
}
- if ((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) {
+ if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) &&
+ !(c0->generator || c1->generator)) {
if (ast_channel_make_compatible(c0, c1)) {
ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
return -1;
@@ -1282,10 +1500,14 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
last = who;
#endif
tackygoto:
- if (who == c0)
- ast_write(c1, f);
- else
- ast_write(c0, f);
+ /* Don't copy packets if there is a generator on either one, since they're
+ not supposed to be listening anyway */
+ if (!c0->generator && !c1->generator) {
+ if (who == c0)
+ ast_write(c1, f);
+ else
+ ast_write(c0, f);
+ }
}
ast_frfree(f);
} else
@@ -1320,3 +1542,136 @@ int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int
return 0;
}
+struct tonepair_def {
+ int freq1;
+ int freq2;
+ int duration;
+ int vol;
+};
+
+struct tonepair_state {
+ float freq1;
+ float freq2;
+ float vol;
+ int duration;
+ int pos;
+ int origrfmt;
+ int origwfmt;
+ struct ast_frame f;
+ unsigned char offset[AST_FRIENDLY_OFFSET];
+ short data[4000];
+};
+
+static void tonepair_release(struct ast_channel *chan, void *params)
+{
+ struct tonepair_state *ts = params;
+ if (chan) {
+ ast_set_write_format(chan, ts->origwfmt);
+ ast_set_read_format(chan, ts->origrfmt);
+ }
+ free(ts);
+}
+
+static void * tonepair_alloc(struct ast_channel *chan, void *params)
+{
+ struct tonepair_state *ts;
+ struct tonepair_def *td = params;
+ ts = malloc(sizeof(struct tonepair_state));
+ if (!ts)
+ return NULL;
+ memset(ts, 0, sizeof(struct tonepair_state));
+ ts->origrfmt = chan->readformat;
+ ts->origwfmt = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+ ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
+ tonepair_release(NULL, ts);
+ ts = NULL;
+ } else if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
+ ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (read)\n", chan->name);
+ ast_set_write_format(chan, ts->origwfmt);
+ tonepair_release(NULL, ts);
+ ts = NULL;
+ } else {
+ ts->freq1 = td->freq1;
+ ts->freq2 = td->freq2;
+ ts->duration = td->duration;
+ ts->vol = td->vol;
+ }
+ /* Let interrupts interrupt :) */
+ chan->writeinterrupt = 1;
+ return ts;
+}
+
+static int tonepair_generator(struct ast_channel *chan, void *data, int len)
+{
+ struct tonepair_state *ts = data;
+ int x;
+ if (len > sizeof(ts->data) / 2 - 1) {
+ ast_log(LOG_WARNING, "Can't generate that much data!\n");
+ return -1;
+ }
+ memset(&ts->f, 0, sizeof(ts->f));
+ for (x=0;x<len/2;x++) {
+ ts->data[x] = ts->vol * (
+ sin((ts->freq1 * 2.0 * M_PI / 8000.0) * (ts->pos + x)) +
+ sin((ts->freq2 * 2.0 * M_PI / 8000.0) * (ts->pos + x))
+ );
+ }
+ ts->f.frametype = AST_FRAME_VOICE;
+ ts->f.subclass = AST_FORMAT_SLINEAR;
+ ts->f.datalen = len;
+ ts->f.timelen = len/8;
+ ts->f.offset = AST_FRIENDLY_OFFSET;
+ ts->f.data = ts->data;
+ ast_write(chan, &ts->f);
+ ts->pos += x;
+ if (ts->duration > 0) {
+ if (ts->pos >= ts->duration * 8)
+ return -1;
+ }
+ return 0;
+}
+
+static struct ast_generator tonepair = {
+ alloc: tonepair_alloc,
+ release: tonepair_release,
+ generate: tonepair_generator,
+};
+
+int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
+{
+ struct tonepair_def d = { 0, };
+ d.freq1 = freq1;
+ d.freq2 = freq2;
+ d.duration = duration;
+ if (vol < 1)
+ d.vol = 8192;
+ else
+ d.vol = vol;
+ if (ast_activate_generator(chan, &tonepair, &d))
+ return -1;
+ return 0;
+}
+
+void ast_tonepair_stop(struct ast_channel *chan)
+{
+ ast_deactivate_generator(chan);
+}
+
+int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
+{
+ struct ast_frame *f;
+ int res;
+ if ((res = ast_tonepair_start(chan, freq1, freq2, duration, vol)))
+ return res;
+
+ /* Give us some wiggle room */
+ while(chan->generatordata && (ast_waitfor(chan, 100) >= 0)) {
+ f = ast_read(chan);
+ if (f)
+ ast_frfree(f);
+ else
+ return -1;
+ }
+ return 0;
+}
diff --git a/channels/adtranvofr.h b/channels/adtranvofr.h
index 9a45402b8..88fd428ee 100755
--- a/channels/adtranvofr.h
+++ b/channels/adtranvofr.h
@@ -80,7 +80,7 @@ struct vofr_hdr {
u_int8_t cid; /* Channel ID */
u_int8_t mod:4; /* Modulation */
u_int8_t remid:4; /* Remote ID */
-#elif __BYTE__ORDER == __BIG_ENDIAN
+#elif __BYTE_ORDER == __BIG_ENDIAN
u_int8_t ctag:4; /* Connect tag */
u_int8_t dtype:4; /* Data type */
u_int8_t vflags:4; /* Voice Routing Flags */
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index 7300646b6..ee45e39d0 100755
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -14,6 +14,7 @@
#include <stdio.h>
#include <pthread.h>
#include <string.h>
+#include <asterisk/lock.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/config.h>
@@ -55,14 +56,14 @@ static int silencesupression = 0;
static int prefformat = AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW;
-static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
/* Protect the interface list (of phone_pvt's) */
-static pthread_mutex_t iflock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t iflock = AST_MUTEX_INITIALIZER;
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it's doing something critical. */
-static pthread_mutex_t monlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t monlock = AST_MUTEX_INITIALIZER;
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use. */
@@ -140,7 +141,31 @@ static int phone_digit(struct ast_channel *ast, char digit)
static int phone_call(struct ast_channel *ast, char *dest, int timeout)
{
struct phone_pvt *p;
+ struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_RINGING };
+
+ // CID stuff for the phonejack...
+
+ PHONE_CID cid;
+ time_t UtcTime;
+ struct tm *t;
+
+
+ if (ast->callerid) {
+ time(&UtcTime);
+ t = localtime(&UtcTime);
+
+ if(t != NULL) {
+ sprintf(cid.month, "%02d",(t->tm_mon + 1));
+ sprintf(cid.day, "%02d", t->tm_mday);
+ sprintf(cid.hour, "%02d", t->tm_hour);
+ sprintf(cid.min, "%02d", t->tm_min);
+ }
+ strcpy(cid.name, "Unknown");
+ sprintf(cid.number,"%s",ast->callerid);
+ }
+
p = ast->pvt->pvt;
+
if ((ast->state != AST_STATE_DOWN) && (ast->state != AST_STATE_RESERVED)) {
ast_log(LOG_WARNING, "phone_call called on %s, neither down nor reserved\n", ast->name);
return -1;
@@ -149,7 +174,9 @@ static int phone_call(struct ast_channel *ast, char *dest, int timeout)
ring the phone and wait for someone to answer */
if (option_debug)
ast_log(LOG_DEBUG, "Ringing %s on %s (%d)\n", dest, ast->name, ast->fds[0]);
- ioctl(p->fd, PHONE_RING_START);
+
+ ioctl(p->fd, PHONE_RING_START,&cid);
+ ast_queue_frame(ast, &f, 0);
ast->state = AST_STATE_RINGING;
return 0;
}
@@ -336,7 +363,7 @@ static struct ast_frame *phone_exception(struct ast_channel *ast)
if (phonee.bits.pstn_ring)
ast_verbose("Unit is ringing\n");
if (phonee.bits.caller_id) {
- ast_verbose("We have caller ID: %s\n");
+ ast_verbose("We have caller ID\n");
}
if (phonee.bits.pstn_wink)
ast_verbose("Detected Wink\n");
@@ -351,6 +378,7 @@ static struct ast_frame *phone_read(struct ast_channel *ast)
{
int res;
struct phone_pvt *p = ast->pvt->pvt;
+
/* Some nice norms */
p->fr.datalen = 0;
@@ -448,14 +476,13 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
char tmpbuf[4];
/* Write a frame of (presumably voice) data */
if (frame->frametype != AST_FRAME_VOICE) {
- ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
- ast_frfree(frame);
- return -1;
+ if (frame->frametype != AST_FRAME_IMAGE)
+ ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
+ return 0;
}
if (!(frame->subclass &
(AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW))) {
ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
- ast_frfree(frame);
return -1;
}
/* If we're not in up mode, go into up mode now */
@@ -560,17 +587,20 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
res = phone_write_buf(p, pos, expected, maxfr);
}
if (res != expected) {
- if (res < 0)
- ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
-/*
- * Card is in non-blocking mode now and it works well now, but there are
- * lot of messages like this. So, this message is temporarily disabled.
- */
+ if (errno != EAGAIN) {
+ if (res < 0)
+ ast_log(LOG_WARNING, "Write returned error (%s)\n", strerror(errno));
+ /*
+ * Card is in non-blocking mode now and it works well now, but there are
+ * lot of messages like this. So, this message is temporarily disabled.
+ */
#if 0
- else
- ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
+ else
+ ast_log(LOG_WARNING, "Only wrote %d of %d bytes\n", res, frame->datalen);
#endif
- return -1;
+ return -1;
+ } else /* Pretend it worked */
+ res = expected;
}
sofar += res;
pos += res;
@@ -581,7 +611,7 @@ static int phone_write(struct ast_channel *ast, struct ast_frame *frame)
static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *context)
{
struct ast_channel *tmp;
- tmp = ast_channel_alloc();
+ tmp = ast_channel_alloc(1);
if (tmp) {
snprintf(tmp->name, sizeof(tmp->name), "Phone/%s", i->dev + 5);
tmp->type = type;
diff --git a/codecs/Makefile b/codecs/Makefile
index 027225eb8..39aa85ec1 100755
--- a/codecs/Makefile
+++ b/codecs/Makefile
@@ -25,6 +25,8 @@ CFLAGS+=
LIBG723=g723.1/libg723.a
LIBG723B=g723.1b/libg723b.a
LIBGSM=gsm/lib/libgsm.a
+LIBGSM=$(shell if uname -m | grep -q 86; then echo gsm/lib/libgsm.a; else echo "-lgsm" ; fi)
+LIBGSMT=$(shell if uname -m | grep -q 86; then echo gsm/lib/libgsm.a; fi)
LIBMP3=mp3/libmp3.a
LIBLPC10=lpc10/liblpc10.a
@@ -44,7 +46,7 @@ clean:
$(LIBG723):
make -C g723.1 all
-$(LIBGSM):
+gsm/lib/libgsm.a:
make -C gsm lib/libgsm.a
$(LIBG723B):
@@ -65,7 +67,7 @@ codec_g723_1b.o : codec_g723_1.c
codec_g723_1b.so : codec_g723_1b.o $(LIBG723B)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBG723B) -lm
-codec_gsm.so: codec_gsm.o $(LIBGSM)
+codec_gsm.so: codec_gsm.o $(LIBGSMT)
$(CC) -shared -Xlinker -x -o $@ $< $(LIBGSM)
codec_lpc10.so: codec_lpc10.o $(LIBLPC10)
diff --git a/codecs/lpc10/Makefile b/codecs/lpc10/Makefile
index cce4c4d92..af5131d77 100755
--- a/codecs/lpc10/Makefile
+++ b/codecs/lpc10/Makefile
@@ -22,7 +22,8 @@ LIB_TARGET_DIR = .
#
WARNINGS = -Wall -Wno-comment -Wno-error
-CFLAGS = -O6 -mpentium -I$(LIB_TARGET_DIR) $(WARNINGS)
+CFLAGS = -O6 -I$(LIB_TARGET_DIR) $(WARNINGS)
+CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi)
LIB = $(LIB_TARGET_DIR)/liblpc10.a
diff --git a/formats/format_jpeg.c b/formats/format_jpeg.c
index 7e10af884..4e9f0f4c3 100755
--- a/formats/format_jpeg.c
+++ b/formats/format_jpeg.c
@@ -80,7 +80,7 @@ static int jpeg_write_image(int fd, struct ast_frame *fr)
if (fr->datalen) {
res = write(fd, fr->data, fr->datalen);
if (res != fr->datalen) {
- ast_log(LOG_WARNING, "Only wrote %d of %d bytes: %s\n", res, fr->datalen);
+ ast_log(LOG_WARNING, "Only wrote %d of %d bytes: %s\n", res, fr->datalen, strerror(errno));
return -1;
}
}
diff --git a/formats/format_wav.c b/formats/format_wav.c
index 77ac71916..667f66f24 100755
--- a/formats/format_wav.c
+++ b/formats/format_wav.c
@@ -11,6 +11,7 @@
* the GNU General Public License
*/
+#include <asterisk/lock.h>
#include <asterisk/channel.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
@@ -51,7 +52,7 @@ struct ast_filestream {
static struct ast_filestream *glist = NULL;
-static pthread_mutex_t wav_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t wav_lock = AST_MUTEX_INITIALIZER;
static int glistcnt = 0;
static char *name = "wav";
@@ -167,7 +168,7 @@ static int check_header(int fd)
return -1;
}
if (read(fd, &bisam, 2) != 2) {
- ast_log(LOG_WARNING, "Read failed (Bits Per Sample): &d\n", ltohs(bisam));
+ ast_log(LOG_WARNING, "Read failed (Bits Per Sample): %d\n", ltohs(bisam));
return -1;
}
/* Begin data chunk */
diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h
index c819d7ac5..793ed30c7 100755
--- a/include/asterisk/logger.h
+++ b/include/asterisk/logger.h
@@ -37,7 +37,8 @@ extern "C" {
* ast_log(LOG_WHATEVER, "Problem with the %s Captain. We should get some more. Will %d be enough?", "flux capacitor", 10);
* where WHATEVER is one of ERROR, DEBUG, EVENT, NOTICE, or WARNING depending on which log you wish to output to.
*/
-extern void ast_log(int level, char *file, int line, char *function, char *fmt, ...);
+extern void ast_log(int level, char *file, int line, char *function, char *fmt, ...)
+ __attribute__ ((format (printf, 5, 6)));
//! Send a verbose message (based on verbose level)
/*!
@@ -47,7 +48,8 @@ extern void ast_log(int level, char *file, int line, char *function, char *fmt,
* Note the abscence of a comma after the VERBOSE_PREFIX_3. This is important.
* VERBOSE_PREFIX_1 through VERBOSE_PREFIX_3 are defined.
*/
-extern void ast_verbose(char *fmt, ...);
+extern void ast_verbose(char *fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
extern int ast_register_verbose(void (*verboser)(char *string, int opos, int replacelast, int complete));
extern int ast_unregister_verbose(void (*verboser)(char *string, int opos, int replacelast, int complete));
diff --git a/logger.c b/logger.c
index ba4f493ea..9da8b62e7 100755
--- a/logger.c
+++ b/logger.c
@@ -15,10 +15,12 @@
#include <stdio.h>
#include <unistd.h>
#include <time.h>
+#include <asterisk/lock.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/config.h>
+#include <asterisk/term.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
@@ -30,8 +32,8 @@
#define MAX_MSG_QUEUE 200
-static pthread_mutex_t msglist_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t loglock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t msglist_lock = AST_MUTEX_INITIALIZER;
+static pthread_mutex_t loglock = AST_MUTEX_INITIALIZER;
static struct msglist {
char *msg;
@@ -59,6 +61,14 @@ static char *levels[] = {
"ERROR"
};
+static int colors[] = {
+ COLOR_BRGREEN,
+ COLOR_BRBLUE,
+ COLOR_YELLOW,
+ COLOR_BRRED,
+ COLOR_RED
+};
+
static int make_components(char *s, int lineno)
{
char *w;
@@ -207,14 +217,21 @@ int reload_logger(void)
extern void ast_log(int level, char *file, int line, char *function, char *fmt, ...)
{
char date[256];
+ char tmp[80];
+ char tmp2[80];
+ char tmp3[80];
+ char tmp4[80];
+ char linestr[80];
time_t t;
struct tm *tm;
struct logfile *f;
va_list ap;
va_start(ap, fmt);
- if (!option_verbose && !option_debug && (!level))
+ if (!option_verbose && !option_debug && (!level)) {
+ va_end(ap);
return;
+ }
ast_pthread_mutex_lock(&loglock);
if (level == 1 /* Event */) {
time(&t);
@@ -226,7 +243,9 @@ extern void ast_log(int level, char *file, int line, char *function, char *fmt,
vfprintf(eventlog, fmt, ap);
fflush(eventlog);
} else
- ast_log(LOG_WARNING, "Unable to retrieve local time?\n");
+ /** Cannot use ast_log() from locked section of ast_log()!
+ ast_log(LOG_WARNING, "Unable to retrieve local time?\n"); **/
+ fprintf(stderr, "ast_log: Unable to retrieve local time for %d?\n", t);
} else {
if (logfiles) {
f = logfiles;
@@ -238,16 +257,26 @@ extern void ast_log(int level, char *file, int line, char *function, char *fmt,
strftime(date, sizeof(date), "%b %e %T", tm);
fprintf(f->f, "%s %s[%ld]: File %s, Line %d (%s): ", date, levels[level], pthread_self(), file, line, function);
} else {
- fprintf(f->f, "%s[%ld]: File %s, Line %d (%s): ", levels[level], pthread_self(), file, line, function);
+ sprintf(linestr, "%d", line);
+ fprintf(f->f, "%s[%ld]: File %s, Line %s (%s): ",
+ term_color(tmp, levels[level], colors[level], 0, sizeof(tmp)),
+ pthread_self(),
+ term_color(tmp2, file, COLOR_BRWHITE, 0, sizeof(tmp2)),
+ term_color(tmp3, linestr, COLOR_BRWHITE, 0, sizeof(tmp3)),
+ term_color(tmp4, function, COLOR_BRWHITE, 0, sizeof(tmp4)));
}
vfprintf(f->f, fmt, ap);
+ va_start(ap, fmt);
fflush(f->f);
+ va_end(ap);
}
f = f->next;
}
} else {
fprintf(stdout, "%s[%ld]: File %s, Line %d (%s): ", levels[level], pthread_self(), file, line, function);
+ va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
+ va_end(ap);
fflush(stdout);
}
}
diff --git a/pbx.c b/pbx.c
index 55df966dd..ec52c0598 100755
--- a/pbx.c
+++ b/pbx.c
@@ -11,7 +11,7 @@
* the GNU General Public License
*/
-#include <pthread.h>
+#include <asterisk/lock.h>
#include <asterisk/cli.h>
#include <asterisk/pbx.h>
#include <asterisk/channel.h>
@@ -20,6 +20,7 @@
#include <asterisk/file.h>
#include <asterisk/callerid.h>
#include <asterisk/cdr.h>
+#include <asterisk/term.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
@@ -71,7 +72,13 @@ struct ast_exten {
struct ast_include {
char name[AST_MAX_EXTENSION];
+ char rname[AST_MAX_EXTENSION];
char *registrar;
+ int hastime;
+ unsigned int monthmask;
+ unsigned int daymask;
+ unsigned int dowmask;
+ unsigned int minmask[24];
struct ast_include *next;
};
@@ -244,14 +251,14 @@ static struct pbx_builtin {
};
/* Lock for the application list */
-static pthread_mutex_t applock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t applock = AST_MUTEX_INITIALIZER;
static struct ast_context *contexts = NULL;
/* Lock for the ast_context list */
-static pthread_mutex_t conlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t conlock = AST_MUTEX_INITIALIZER;
static struct ast_app *apps = NULL;
/* Lock for switches */
-static pthread_mutex_t switchlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t switchlock = AST_MUTEX_INITIALIZER;
struct ast_switch *switches = NULL;
int pbx_exec(struct ast_channel *c, /* Channel */
@@ -342,6 +349,47 @@ static struct ast_switch *pbx_findswitch(char *sw)
return asw;
}
+static inline int include_valid(struct ast_include *i)
+{
+ struct tm *tm;
+ time_t t;
+ if (!i->hastime)
+ return 1;
+ time(&t);
+ tm = localtime(&t);
+ if (!tm) {
+ ast_log(LOG_WARNING, "Failed to get local time\n");
+ return 0;
+ }
+
+ /* If it's not the right month, return */
+ if (!(i->monthmask & (1 << tm->tm_mon))) {
+ return 0;
+ }
+
+ /* If it's not that time of the month.... */
+ if (!(i->daymask & (1 << tm->tm_mday)))
+ return 0;
+
+ /* If it's not the right day of the week */
+ if (!(i->dowmask & (1 << tm->tm_wday)))
+ return 0;
+
+ /* Sanity check the hour just to be safe */
+ if ((tm->tm_hour < 0) || (tm->tm_hour > 23)) {
+ ast_log(LOG_WARNING, "Insane time...\n");
+ return 0;
+ }
+
+ /* Now the tough part, we calculate if it fits
+ in the right time based on min/hour */
+ if (!(i->minmask[tm->tm_hour] & (1 << (tm->tm_min / 2))))
+ return 0;
+
+ /* If we got this far, then we're good */
+ return 1;
+}
+
static void pbx_destroy(struct ast_pbx *p)
{
free(p);
@@ -561,10 +609,12 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont
/* Now try any includes we have in this context */
i = tmp->includes;
while(i) {
- if ((e = pbx_find_extension(chan, i->name, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
- return e;
- if (*swo)
- return NULL;
+ if (include_valid(i)) {
+ if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
+ return e;
+ if (*swo)
+ return NULL;
+ }
i = i->next;
}
}
@@ -584,6 +634,9 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
int status = 0;
char *incstack[AST_PBX_MAX_STACK];
int stacklen = 0;
+ char tmp[80];
+ char tmp2[80];
+ char tmp3[256];
if (ast_pthread_mutex_lock(&conlock)) {
ast_log(LOG_WARNING, "Unable to obtain lock\n");
if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH))
@@ -614,7 +667,10 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
else if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
- app->name, c->name, (e->data ? (char *)e->data : NULL), (newstack ? "in new stack" : "in same stack"));
+ term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
+ term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
+ term_color(tmp3, (e->data ? (char *)e->data : NULL), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
+ (newstack ? "in new stack" : "in same stack"));
res = pbx_exec(c, app, e->data, newstack);
return res;
} else {
@@ -675,41 +731,6 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte
}
-#if 0
-int ast_pbx_longest_extension(char *context)
-{
- /* XXX Not include-aware XXX */
- struct ast_context *tmp;
- struct ast_exten *e;
- int len = 0;
- if (ast_pthread_mutex_lock(&conlock)) {
- ast_log(LOG_WARNING, "Unable to obtain lock\n");
- return -1;
- }
- tmp = contexts;
- while(tmp) {
- if (!strcasecmp(tmp->name, context)) {
- /* By locking tmp, not only can the state of its entries not
- change, but it cannot be destroyed either. */
- ast_pthread_mutex_lock(&tmp->lock);
- /* But we can relieve the conlock, as tmp will not change */
- ast_pthread_mutex_unlock(&conlock);
- e = tmp->root;
- while(e) {
- if (strlen(e->exten) > len)
- len = strlen(e->exten);
- e = e->next;
- }
- ast_pthread_mutex_unlock(&tmp->lock);
- return len;
- }
- tmp = tmp->next;
- }
- ast_log(LOG_WARNING, "No such context '%s'\n", context);
- return -1;
-}
-#endif
-
int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
{
return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
@@ -736,7 +757,7 @@ int ast_pbx_run(struct ast_channel *c)
/* A little initial setup here */
if (c->pbx)
- ast_log(LOG_WARNING, "%s already has PBX structure??\n");
+ ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
c->pbx = malloc(sizeof(struct ast_pbx));
if (!c->pbx) {
ast_log(LOG_WARNING, "Out of memory\n");
@@ -744,7 +765,7 @@ int ast_pbx_run(struct ast_channel *c)
}
if (c->amaflags) {
if (c->cdr) {
- ast_log(LOG_WARNING, "%s already has a call record??\n");
+ ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
} else {
c->cdr = ast_cdr_alloc();
if (!c->cdr) {
@@ -890,6 +911,22 @@ int ast_pbx_run(struct ast_channel *c)
if (firstpass)
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
out:
+ if (ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
+ strcpy(c->exten, "h");
+ c->priority = 1;
+ while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
+ if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
+ /* Something bad happened, or a hangup has been requested. */
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
+ else if (option_verbose > 1)
+ ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
+ break;
+ }
+ c->priority++;
+ }
+ }
+
pbx_destroy(c->pbx);
c->pbx = NULL;
if (res != AST_PBX_KEEPALIVE)
@@ -973,7 +1010,7 @@ int ast_context_remove_include2(struct ast_context *con, char *include, char *re
{
struct ast_include *i, *pi = NULL;
- if (pthread_mutex_lock(&con->lock)) return -1;
+ if (ast_pthread_mutex_lock(&con->lock)) return -1;
/* walk includes */
i = con->includes;
@@ -1045,7 +1082,7 @@ int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, ch
{
struct ast_sw *i, *pi = NULL;
- if (pthread_mutex_lock(&con->lock)) return -1;
+ if (ast_pthread_mutex_lock(&con->lock)) return -1;
/* walk switchs */
i = con->alts;
@@ -1215,6 +1252,7 @@ int ast_context_remove_extension2(struct ast_context *con, char *extension, int
int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
{
struct ast_app *tmp;
+ char tmps[80];
if (ast_pthread_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
@@ -1230,6 +1268,7 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
}
tmp = malloc(sizeof(struct ast_app));
if (tmp) {
+ memset(tmp, 0, sizeof(struct ast_app));
strncpy(tmp->name, app, sizeof(tmp->name)-1);
tmp->execute = execute;
tmp->synopsis = synopsis;
@@ -1242,7 +1281,7 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
return -1;
}
if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", tmp->name);
+ ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
ast_pthread_mutex_unlock(&applock);
return 0;
}
@@ -1769,7 +1808,7 @@ struct ast_context *ast_context_create(char *name, char *registrar)
tmp = malloc(sizeof(struct ast_context));
if (tmp) {
memset(tmp, 0, sizeof(struct ast_context));
- pthread_mutex_init(&tmp->lock, NULL);
+ ast_pthread_mutex_init(&tmp->lock);
strncpy(tmp->name, name, sizeof(tmp->name)-1);
tmp->root = NULL;
tmp->registrar = registrar;
@@ -1821,6 +1860,255 @@ int ast_context_add_include(char *context, char *include, char *registrar)
return -1;
}
+#define FIND_NEXT \
+do { \
+ c = info; \
+ while(*c && (*c != '|')) c++; \
+ if (*c) *c = '\0'; else c = NULL; \
+} while(0)
+
+static void get_timerange(struct ast_include *i, char *times)
+{
+ char *e;
+ int x;
+ int s1, s2;
+ int e1, e2;
+ /* Star is all times */
+ if (!strlen(times) || !strcmp(times, "*")) {
+ for (x=0;x<24;x++)
+ i->minmask[x] = (1 << 30) - 1;
+ return;
+ }
+ /* Otherwise expect a range */
+ e = strchr(times, '-');
+ if (!e) {
+ ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
+ return;
+ }
+ *e = '\0';
+ e++;
+ while(*e && !isdigit(*e)) e++;
+ if (!*e) {
+ ast_log(LOG_WARNING, "Invalid time range. Assuming no time.\n");
+ return;
+ }
+ if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
+ ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", times);
+ return;
+ }
+ if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
+ ast_log(LOG_WARNING, "%s isn't a time. Assuming no time.\n", e);
+ return;
+ }
+ s1 = s1 * 30 + s2/2;
+ if ((s1 < 0) || (s1 >= 24*30)) {
+ ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
+ return;
+ }
+ e1 = e1 * 30 + e2/2;
+ if ((e1 < 0) || (e2 >= 24*30)) {
+ ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
+ return;
+ }
+ /* Go through the time and enable each appropriate bit */
+ for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
+ i->minmask[x/30] |= (1 << (x % 30));
+ }
+ /* Do the last one */
+ i->minmask[x/30] |= (1 << (x % 30));
+ /* All done */
+}
+
+static char *days[] =
+{
+ "sun",
+ "mon",
+ "tue",
+ "wed",
+ "thu",
+ "fri",
+ "sat",
+};
+
+static unsigned int get_dow(char *dow)
+{
+ char *c;
+ /* The following line is coincidence, really! */
+ int s, e, x;
+ unsigned mask;
+ /* Check for all days */
+ if (!strlen(dow) || !strcmp(dow, "*"))
+ return (1 << 7) - 1;
+ /* Get start and ending days */
+ c = strchr(dow, '-');
+ if (c) {
+ *c = '\0';
+ c++;
+ }
+ /* Find the start */
+ s = 0;
+ while((s < 7) && strcasecmp(dow, days[s])) s++;
+ if (s >= 7) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
+ return 0;
+ }
+ if (c) {
+ e = 0;
+ while((e < 7) && strcasecmp(dow, days[e])) e++;
+ if (e >= 7) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+ return 0;
+ }
+ } else
+ e = s;
+ mask = 0;
+ for (x=s;x!=e;x = (x + 1) % 7) {
+ mask |= (1 << x);
+ }
+ /* One last one */
+ mask |= (1 << x);
+ return mask;
+}
+
+static unsigned int get_day(char *day)
+{
+ char *c;
+ /* The following line is coincidence, really! */
+ int s, e, x;
+ unsigned int mask;
+ /* Check for all days */
+ if (!strlen(day) || !strcmp(day, "*")) {
+ mask = (1 << 30) + ((1 << 30) - 1);
+ }
+ /* Get start and ending days */
+ c = strchr(day, '-');
+ if (c) {
+ *c = '\0';
+ c++;
+ }
+ /* Find the start */
+ if (sscanf(day, "%d", &s) != 1) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
+ return 0;
+ }
+ if ((s < 1) || (s > 31)) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
+ return 0;
+ }
+ s--;
+ if (c) {
+ if (sscanf(c, "%d", &e) != 1) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+ return 0;
+ }
+ if ((e < 1) || (e > 31)) {
+ ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+ return 0;
+ }
+ e--;
+ } else
+ e = s;
+ mask = 0;
+ for (x=s;x!=e;x = (x + 1) % 31) {
+ mask |= (1 << x);
+ }
+ mask |= (1 << x);
+ return mask;
+}
+
+static char *months[] =
+{
+ "jan",
+ "feb",
+ "mar",
+ "apr",
+ "may",
+ "jun",
+ "jul",
+ "aug",
+ "sep",
+ "oct",
+ "nov",
+ "dec",
+};
+
+static unsigned int get_month(char *mon)
+{
+ char *c;
+ /* The following line is coincidence, really! */
+ int s, e, x;
+ unsigned int mask;
+ /* Check for all days */
+ if (!strlen(mon) || !strcmp(mon, "*"))
+ return (1 << 12) - 1;
+ /* Get start and ending days */
+ c = strchr(mon, '-');
+ if (c) {
+ *c = '\0';
+ c++;
+ }
+ /* Find the start */
+ s = 0;
+ while((s < 12) && strcasecmp(mon, months[s])) s++;
+ if (s >= 12) {
+ ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
+ return 0;
+ }
+ if (c) {
+ e = 0;
+ while((e < 12) && strcasecmp(mon, months[e])) e++;
+ if (e >= 12) {
+ ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
+ return 0;
+ }
+ } else
+ e = s;
+ mask = 0;
+ for (x=s;x!=e;x = (x + 1) % 12) {
+ mask |= (1 << x);
+ }
+ /* One last one */
+ mask |= (1 << x);
+ return mask;
+}
+
+static void build_timing(struct ast_include *i, char *info)
+{
+ char *c;
+ /* Check for empty just in case */
+ if (!strlen(info))
+ return;
+ i->hastime = 1;
+ /* Assume everything except time */
+ i->monthmask = (1 << 12) - 1;
+ i->daymask = (1 << 30) - 1 + (1 << 30);
+ i->dowmask = (1 << 7) - 1;
+ /* Avoid using strtok */
+ FIND_NEXT;
+
+ /* Info has the time range, start with that */
+ get_timerange(i, info);
+ info = c;
+ if (!info)
+ return;
+ FIND_NEXT;
+ /* Now check for day of week */
+ i->dowmask = get_dow(info);
+
+ info = c;
+ if (!info)
+ return;
+ FIND_NEXT;
+ /* Now check for the day of the month */
+ i->daymask = get_day(info);
+ info = c;
+ if (!info)
+ return;
+ FIND_NEXT;
+ /* And finally go for the month */
+ i->monthmask = get_month(info);
+}
+
/*
* errno values
* ENOMEM - out of memory
@@ -1832,6 +2120,7 @@ int ast_context_add_include2(struct ast_context *con, char *value,
char *registrar)
{
struct ast_include *new_include;
+ char *c;
struct ast_include *i, *il = NULL; /* include, include_last */
/* allocate new include structure ... */
@@ -1842,7 +2131,17 @@ int ast_context_add_include2(struct ast_context *con, char *value,
}
/* ... fill in this structure ... */
+ memset(new_include, 0, sizeof(struct ast_include));
strncpy(new_include->name, value, sizeof(new_include->name)-1);
+ strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
+ c = new_include->rname;
+ /* Strip off timing info */
+ while(*c && (*c != '|')) c++;
+ /* Process if it's there */
+ if (*c) {
+ build_timing(new_include, c+1);
+ *c = '\0';
+ }
new_include->next = NULL;
new_include->registrar = registrar;
@@ -1932,6 +2231,7 @@ int ast_context_add_switch2(struct ast_context *con, char *value,
}
/* ... fill in this structure ... */
+ memset(new_sw, 0, sizeof(struct ast_sw));
strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
if (data)
strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
@@ -2068,10 +2368,11 @@ int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *regis
errno = ENOMEM;
return -1;
}
+ memset(ignorepat, 0, sizeof(struct ast_ignorepat));
strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
ignorepat->next = NULL;
ignorepat->registrar = registrar;
- pthread_mutex_lock(&con->lock);
+ ast_pthread_mutex_lock(&con->lock);
ignorepatc = con->ignorepats;
while(ignorepatc) {
ignorepatl = ignorepatc;
@@ -2194,6 +2495,7 @@ int ast_add_extension2(struct ast_context *con,
/* Be optimistic: Build the extension structure first */
tmp = malloc(sizeof(struct ast_exten));
if (tmp) {
+ memset(tmp, 0, sizeof(struct ast_exten));
ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
tmp->priority = priority;
if (callerid) {
@@ -2474,21 +2776,10 @@ static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
static int pbx_builtin_wait(struct ast_channel *chan, void *data)
{
int ms;
- struct ast_frame *f;
/* Wait for "n" seconds */
if (data && atoi((char *)data)) {
ms = atoi((char *)data) * 1000;
- while(ms > 0) {
- ms = ast_waitfor(chan, ms);
- if (ms <0)
- return -1;
- if (ms > 0) {
- f = ast_read(chan);
- if (!f)
- return -1;
- ast_frfree(f);
- }
- }
+ return ast_safe_sleep(chan, ms);
}
return 0;
}
diff --git a/res/res_adsi.c b/res/res_adsi.c
index e464c0151..11a23c987 100755
--- a/res/res_adsi.c
+++ b/res/res_adsi.c
@@ -99,27 +99,6 @@ static int adsi_generate(unsigned char *buf, int msgtype, char *msg, int msglen,
}
-#if 0
-static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remainder)
-{
- int res;
- fd_set fds;
- while(len) {
- FD_ZERO(&fds);
- FD_SET(chan->fds[0], &fds);
- select(chan->fds[0] + 1, NULL, &fds, NULL, NULL);
- res = write(chan->fds[0], buf, len);
- if (res < 1) {
- ast_log(LOG_WARNING, "Failed to write: %s\n", strerror(errno));
- return -1;
- }
- buf += res;
- len -= res;
- }
- return 0;
-}
-
-#else
static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remainder)
{
/* Sends carefully on a full duplex channel by using reading for
@@ -190,7 +169,6 @@ static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int l
}
return 0;
}
-#endif
static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype)
{
@@ -305,7 +283,7 @@ static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **ms
break;
else {
retries++;
- ast_log(LOG_DEBUG, "Retransmitting (%d), from %d\n", start + 1);
+ ast_log(LOG_DEBUG, "Retransmitting (%d), from %d\n", retries, start + 1);
}
} else {
retries++;
@@ -502,14 +480,15 @@ int adsi_download_connect(unsigned char *buf, unsigned char *service, unsigned
/* Delimiter */
buf[bytes++] = 0xff;
- for (x=0;x<4;x++)
+ for (x=0;x<4;x++) {
buf[bytes++] = fdn[x];
+ }
for (x=0;x<4;x++)
buf[bytes++] = sec[x];
- if (ver > -1)
- buf[bytes++] = ver & 0xff;
+ buf[bytes++] = ver & 0xff;
buf[1] = bytes - 2;
+
return bytes;
}
@@ -529,6 +508,158 @@ int adsi_disconnect_session(unsigned char *buf)
}
+int adsi_query_cpeid(unsigned char *buf)
+{
+ int bytes = 0;
+ buf[bytes++] = ADSI_QUERY_CPEID;
+ /* Reserve space for length */
+ bytes++;
+ buf[1] = bytes - 2;
+ return bytes;
+}
+
+int adsi_query_cpeinfo(unsigned char *buf)
+{
+ int bytes = 0;
+ buf[bytes++] = ADSI_QUERY_CONFIG;
+ /* Reserve space for length */
+ bytes++;
+ buf[1] = bytes - 2;
+ return bytes;
+}
+
+int adsi_read_encoded_dtmf(struct ast_channel *chan, unsigned char *buf, int maxlen)
+{
+ int bytes = 0;
+ int res;
+ unsigned char current = 0;
+ int gotstar = 0;
+ int pos = 0;
+ memset(buf, 0, sizeof(buf));
+ while(bytes <= maxlen) {
+ /* Wait up to a second for a digit */
+ res = ast_waitfordigit(chan, 1000);
+ if (!res)
+ break;
+ if (res == '*') {
+ gotstar = 1;
+ continue;
+ }
+ /* Ignore anything other than a digit */
+ if ((res < '0') || (res > '9'))
+ continue;
+ res -= '0';
+ if (gotstar)
+ res += 9;
+ if (pos) {
+ pos = 0;
+ buf[bytes++] = (res << 4) | current;
+ } else {
+ pos = 1;
+ current = res;
+ }
+ gotstar = 0;
+ }
+ return bytes;
+}
+
+int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice)
+{
+ char buf[256];
+ int bytes = 0;
+ int res;
+ bytes += adsi_data_mode(buf);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+
+ bytes = 0;
+ bytes += adsi_query_cpeid(buf);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+
+ /* Get response */
+ memset(buf, 0, sizeof(buf));
+ res = adsi_read_encoded_dtmf(chan, cpeid, 4);
+ if (res != 4) {
+ ast_log(LOG_WARNING, "Got %d bytes back of encoded DTMF, expecting 4\n", res);
+ res = 0;
+ } else {
+ res = 1;
+ }
+
+ if (voice) {
+ bytes = 0;
+ bytes += adsi_voice_mode(buf, 0);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ /* Ignore the resulting DTMF B announcing it's in voice mode */
+ ast_waitfordigit(chan, 1000);
+ }
+ return res;
+}
+
+int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *buttons, int voice)
+{
+ char buf[256];
+ int bytes = 0;
+ int res;
+ bytes += adsi_data_mode(buf);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+
+ bytes = 0;
+ bytes += adsi_query_cpeinfo(buf);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+
+ /* Get width */
+ memset(buf, 0, sizeof(buf));
+ res = ast_readstring(chan, buf, 2, 1000, 500, "");
+ if (res < 0)
+ return res;
+ if (strlen(buf) != 2) {
+ ast_log(LOG_WARNING, "Got %d bytes of width, expecting 2\n", res);
+ res = 0;
+ } else {
+ res = 1;
+ }
+ if (width)
+ *width = atoi(buf);
+ /* Get height */
+ memset(buf, 0, sizeof(buf));
+ if (res) {
+ res = ast_readstring(chan, buf, 2, 1000, 500, "");
+ if (res < 0)
+ return res;
+ if (strlen(buf) != 2) {
+ ast_log(LOG_WARNING, "Got %d bytes of height, expecting 2\n", res);
+ res = 0;
+ } else {
+ res = 1;
+ }
+ if (height)
+ *height= atoi(buf);
+ }
+ /* Get buttons */
+ memset(buf, 0, sizeof(buf));
+ if (res) {
+ res = ast_readstring(chan, buf, 1, 1000, 500, "");
+ if (res < 0)
+ return res;
+ if (strlen(buf) != 1) {
+ ast_log(LOG_WARNING, "Got %d bytes of buttons, expecting 1\n", res);
+ res = 0;
+ } else {
+ res = 1;
+ }
+ if (buttons)
+ *buttons = atoi(buf);
+ }
+ if (voice) {
+ bytes = 0;
+ bytes += adsi_voice_mode(buf, 0);
+ adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ /* Ignore the resulting DTMF B announcing it's in voice mode */
+ ast_waitfordigit(chan, 1000);
+ }
+ return res;
+}
+
int adsi_data_mode(unsigned char *buf)
{
int bytes=0;
@@ -544,6 +675,36 @@ int adsi_data_mode(unsigned char *buf)
}
+int adsi_clear_soft_keys(unsigned char *buf)
+{
+ int bytes=0;
+
+ /* Message type */
+ buf[bytes++] = ADSI_CLEAR_SOFTKEY;
+
+ /* Reserve space for length */
+ bytes++;
+
+ buf[1] = bytes - 2;
+ return bytes;
+
+}
+
+int adsi_clear_screen(unsigned char *buf)
+{
+ int bytes=0;
+
+ /* Message type */
+ buf[bytes++] = ADSI_CLEAR_SCREEN;
+
+ /* Reserve space for length */
+ bytes++;
+
+ buf[1] = bytes - 2;
+ return bytes;
+
+}
+
int adsi_voice_mode(unsigned char *buf, int when)
{
int bytes=0;
@@ -719,53 +880,7 @@ int adsi_set_line(unsigned char *buf, int page, int line)
static int total = 0;
static int speeds = 0;
-#if 0
-int adsi_channel_init(struct ast_channel *chan)
-{
- char dsp[256];
- char keys[256];
- int bytes;
- int x;
- unsigned char *msgs[3];
- unsigned char keyd[6];
- int lens[3];
- int types[3];
- memset(dsp, 0, sizeof(dsp));
- memset(keys, 0, sizeof(keys));
- memset(msgs, 0, sizeof(msgs));
-
- /* Start with initial display setup */
- bytes = 0;
- bytes += adsi_connect_session(dsp, NULL, -1);
- for (x=0;x<total;x++) {
- bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
- strlen(intro[x]) ? intro[x] : " ", "");
- }
- bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
- msgs[0] = dsp;
- lens[0] = bytes;
- types[0] = ADSI_MSG_DISPLAY;
-
- /* Prepare key setup messages */
-
- if (speeds) {
- bytes = 0;
- memset(keyd, 0, sizeof(keyd));
- for (x=0;x<speeds;x++) {
- bytes += adsi_load_soft_key(keys + bytes, ADSI_SPEED_DIAL + x,
- speeddial[x][1], speeddial[x][2], speeddial[x][0]);
- keyd[x] = ADSI_SPEED_DIAL + x;
- }
- bytes += adsi_set_keys(keys + bytes, keyd);
- msgs[1] = keys;
- lens[1] = bytes;
- types[1] = ADSI_MSG_DISPLAY;
- }
- adsi_transmit_messages(chan, msgs, lens, types);
- return 0;
-}
-#else
-int adsi_channel_init(struct ast_channel *chan)
+int adsi_channel_restore(struct ast_channel *chan)
{
char dsp[256];
int bytes;
@@ -776,11 +891,6 @@ int adsi_channel_init(struct ast_channel *chan)
/* Start with initial display setup */
bytes = 0;
- bytes += adsi_connect_session(dsp, NULL, -1);
- for (x=0;x<total;x++) {
- bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
- strlen(intro[x]) ? intro[x] : " ", "");
- }
bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
/* Prepare key setup messages */
@@ -788,42 +898,33 @@ int adsi_channel_init(struct ast_channel *chan)
if (speeds) {
memset(keyd, 0, sizeof(keyd));
for (x=0;x<speeds;x++) {
- bytes += adsi_load_soft_key(dsp + bytes, ADSI_SPEED_DIAL + x,
- speeddial[x][1], speeddial[x][2], speeddial[x][0], 0);
keyd[x] = ADSI_SPEED_DIAL + x;
}
bytes += adsi_set_keys(dsp + bytes, keyd);
}
adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
return 0;
+
}
-#endif
-int adsi_channel_restore(struct ast_channel *chan)
+int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice)
{
- char dsp[256];
- int bytes;
+ char buf[4096];
+ int bytes=0;
+ int res;
int x;
- unsigned char keyd[6];
-
- memset(dsp, 0, sizeof(dsp));
-
- /* Start with initial display setup */
- bytes = 0;
- bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
-
- /* Prepare key setup messages */
-
- if (speeds) {
- memset(keyd, 0, sizeof(keyd));
- for (x=0;x<speeds;x++) {
- keyd[x] = ADSI_SPEED_DIAL + x;
- }
- bytes += adsi_set_keys(dsp + bytes, keyd);
+ for(x=0;lines[x];x++)
+ bytes += adsi_display(buf + bytes, ADSI_INFO_PAGE, x+1, aligns[x],0, lines[x], "");
+ bytes += adsi_set_line(buf + bytes, ADSI_INFO_PAGE, 1);
+ if (voice) {
+ bytes += adsi_voice_mode(buf + bytes, 0);
}
- adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
- return 0;
-
+ res = adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ if (voice) {
+ /* Ignore the resulting DTMF B announcing it's in voice mode */
+ ast_waitfordigit(chan, 1000);
+ }
+ return res;
}
int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
@@ -845,21 +946,24 @@ int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int
/* Prepare key setup messages */
if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
return -1;
- res = ast_readstring(chan, resp, 1, 1200, 1200, "");
- if (res < 0)
- return -1;
- if (res) {
- ast_log(LOG_DEBUG, "No response from CPE about version. Assuming not there.\n");
- return 0;
- }
- if (!strcmp(resp, "B")) {
- ast_log(LOG_DEBUG, "CPE has script '%s' version %d already loaded\n", app, ver);
+ if (app) {
+ res = ast_readstring(chan, resp, 1, 1200, 1200, "");
+ if (res < 0)
+ return -1;
+ if (res) {
+ ast_log(LOG_DEBUG, "No response from CPE about version. Assuming not there.\n");
+ return 0;
+ }
+ if (!strcmp(resp, "B")) {
+ ast_log(LOG_DEBUG, "CPE has script '%s' version %d already loaded\n", app, ver);
+ return 1;
+ } else if (!strcmp(resp, "A")) {
+ ast_log(LOG_DEBUG, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
+ } else {
+ ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
+ }
+ } else
return 1;
- } else if (!strcmp(resp, "A")) {
- ast_log(LOG_DEBUG, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
- } else {
- ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
- }
return 0;
}