diff options
Diffstat (limited to '1.2-netsec/res')
-rw-r--r-- | 1.2-netsec/res/Makefile | 122 | ||||
-rw-r--r-- | 1.2-netsec/res/res_adsi.c | 1141 | ||||
-rw-r--r-- | 1.2-netsec/res/res_agi.c | 2142 | ||||
-rw-r--r-- | 1.2-netsec/res/res_config_odbc.c | 540 | ||||
-rw-r--r-- | 1.2-netsec/res/res_crypto.c | 622 | ||||
-rw-r--r-- | 1.2-netsec/res/res_features.c | 2187 | ||||
-rw-r--r-- | 1.2-netsec/res/res_indications.c | 435 | ||||
-rw-r--r-- | 1.2-netsec/res/res_monitor.c | 592 | ||||
-rw-r--r-- | 1.2-netsec/res/res_musiconhold.c | 1237 | ||||
-rw-r--r-- | 1.2-netsec/res/res_odbc.c | 618 | ||||
-rw-r--r-- | 1.2-netsec/res/res_osp.c | 886 |
11 files changed, 0 insertions, 10522 deletions
diff --git a/1.2-netsec/res/Makefile b/1.2-netsec/res/Makefile deleted file mode 100644 index a32465282..000000000 --- a/1.2-netsec/res/Makefile +++ /dev/null @@ -1,122 +0,0 @@ -# -# Asterisk -- A telephony toolkit for Linux. -# -# Makefile for resource modules -# -# Copyright (C) 1999-2005, Digium -# -# Mark Spencer <markster@digium.com> -# -# This program is free software, distributed under the terms of -# the GNU General Public License -# - -MODS=res_indications.so res_monitor.so res_adsi.so res_agi.so res_features.so - -ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/odbcinst.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/odbcinst.h),) - ifneq (${OSARCH},FreeBSD) - MODS+=res_config_odbc.so - else - MODS+=$(shell if test ${BSDVERSION} -ge 500000 ; then echo "res_config_odbc.so"; fi) - endif - MODS+=res_odbc.so -endif - -ifneq ($(NOCRYPTO),yes) - MODS+=res_crypto.so -endif - -ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/lib/libosptk.a),) - MODS+=res_osp.so - OSPLIB=$(CROSS_COMPILE_TARGET)/usr/lib/libosptk.a -else - ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/lib/libosptk.a),) - MODS+=res_osp.so - OSPLIB=$(CROSS_COMPILE_TARGET)/usr/local/lib/libosptk.a - endif -endif - -ifeq ($(findstring BSD,${OSARCH}),BSD) - CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include - SOLINK+=-L$(CROSS_COMPILE_TARGET)/usr/local/lib -endif - -ifeq (${OSARCH},CYGWIN) -CYGSOLINK=-Wl,--out-implib=lib$@.a -Wl,--export-all-symbols -CYGSOLIB=-L.. -L. -lasterisk.dll -CYG_RES_CONFIG_ODBC_LIB=-lres_odbc.so -CYG_RES_FEATURES_LIB=-lres_adsi.so -lres_monitor.so -else -MODS+=res_musiconhold.so -endif - -CRYPTO_LIBS=-lssl -lcrypto - -CFLAGS+= - -ifndef WITHOUT_ZAPTEL -ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),) - CFLAGS+=-DZAPATA_MOH -endif -endif # WITHOUT_ZAPTEL - -# -# Work around buggy RedHat 9.0 -# -ifeq (${OSARCH},CYGWIN) -CFLAGS+=-DOPENSSL_NO_KRB5 -else -CFLAGS+=-DOPENSSL_NO_KRB5 -fPIC -endif - -all: depend $(MODS) - -install: all - rm -f $(DESTDIR)$(ASTHEADERDIR)/parking.h - rm -f $(DESTDIR)$(MODULES_DIR)/app_agi.so - rm -f $(DESTDIR)$(MODULES_DIR)/res_parking.so - for x in $(MODS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done - @if [ x`which mpg123 2>/dev/null | grep -v '^no'` != x ] ; then \ - if mpg123 --longhelp 2>&1 | grep -q .59r 2>&1 >/dev/null ; then echo ; else \ - echo "*************************************************************";\ - echo "*** You have the WRONG version of mpg123... you need .59r ***";\ - echo "*** Use 'make mpg123' to get the right verison ***";\ - echo "*************************************************************";\ - fi ;\ - else \ - echo "*** You don't have mpg123 installed. You may need ***";\ - echo "*** it if you want to use MusicOnHold ***";\ - fi - -res_crypto.so: res_crypto.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CRYPTO_LIBS) - -clean: - rm -f *.so *.o .depend - -res_odbc.so: res_odbc.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lodbc - -res_osp.so: res_osp.o $(OSPLIB) - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(OSPLIB) - -%.so : %.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} - -res_features.so: res_features.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_FEATURES_LIB} - -res_config_odbc.so: res_config_odbc.o - $(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} ${CYG_RES_CONFIG_ODBC_LIB} - -ifneq ($(wildcard .depend),) - include .depend -endif - -depend: .depend - -.depend: - ../build_tools/mkdep $(CFLAGS) `ls *.c` - -env: - env diff --git a/1.2-netsec/res/res_adsi.c b/1.2-netsec/res/res_adsi.c deleted file mode 100644 index 18e7849f3..000000000 --- a/1.2-netsec/res/res_adsi.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * Includes code and algorithms from the Zapata library. - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief ADSI support - * - */ - -#include <time.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <math.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/ulaw.h" -#include "asterisk/alaw.h" -#include "asterisk/callerid.h" -#include "asterisk/logger.h" -#include "asterisk/fskmodem.h" -#include "asterisk/channel.h" -#include "asterisk/adsi.h" -#include "asterisk/module.h" -#include "asterisk/config.h" -#include "asterisk/file.h" - -#define DEFAULT_ADSI_MAX_RETRIES 3 - -#define ADSI_MAX_INTRO 20 -#define ADSI_MAX_SPEED_DIAL 6 - -#define ADSI_FLAG_DATAMODE (1 << 8) - -static int maxretries = DEFAULT_ADSI_MAX_RETRIES; - -/* Asterisk ADSI button definitions */ -#define ADSI_SPEED_DIAL 10 /* 10-15 are reserved for speed dial */ - -static char intro[ADSI_MAX_INTRO][20]; -static int aligns[ADSI_MAX_INTRO]; - -static char speeddial[ADSI_MAX_SPEED_DIAL][3][20]; - -static int alignment = 0; - -static int adsi_generate(unsigned char *buf, int msgtype, unsigned char *msg, int msglen, int msgnum, int last, int codec) -{ - int sum; - int x; - int bytes=0; - /* Initial carrier (imaginary) */ - float cr = 1.0; - float ci = 0.0; - float scont = 0.0; - - if (msglen > 255) - msglen = 255; - - /* If first message, Send 150ms of MARK's */ - if (msgnum == 1) { - for (x=0;x<150;x++) /* was 150 */ - PUT_CLID_MARKMS; - } - /* Put message type */ - PUT_CLID(msgtype); - sum = msgtype; - - /* Put message length (plus one for the message number) */ - PUT_CLID(msglen + 1); - sum += msglen + 1; - - /* Put message number */ - PUT_CLID(msgnum); - sum += msgnum; - - /* Put actual message */ - for (x=0;x<msglen;x++) { - PUT_CLID(msg[x]); - sum += msg[x]; - } - - /* Put 2's compliment of sum */ - PUT_CLID(256-(sum & 0xff)); - -#if 0 - if (last) { - /* Put trailing marks */ - for (x=0;x<50;x++) - PUT_CLID_MARKMS; - } -#endif - return bytes; - -} - -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 - timing */ - struct ast_frame *inf, outf; - int amt; - - /* Zero out our outgoing frame */ - memset(&outf, 0, sizeof(outf)); - - if (remainder && *remainder) { - amt = len; - - /* Send remainder if provided */ - if (amt > *remainder) - amt = *remainder; - else - *remainder = *remainder - amt; - outf.frametype = AST_FRAME_VOICE; - outf.subclass = AST_FORMAT_ULAW; - outf.data = buf; - outf.datalen = amt; - outf.samples = amt; - if (ast_write(chan, &outf)) { - ast_log(LOG_WARNING, "Failed to carefully write frame\n"); - return -1; - } - /* Update pointers and lengths */ - buf += amt; - len -= amt; - } - - while(len) { - amt = len; - /* If we don't get anything at all back in a second, forget - about it */ - if (ast_waitfor(chan, 1000) < 1) - return -1; - inf = ast_read(chan); - /* Detect hangup */ - if (!inf) - return -1; - if (inf->frametype == AST_FRAME_VOICE) { - /* Read a voice frame */ - if (inf->subclass != AST_FORMAT_ULAW) { - ast_log(LOG_WARNING, "Channel not in ulaw?\n"); - return -1; - } - /* Send no more than they sent us */ - if (amt > inf->datalen) - amt = inf->datalen; - else if (remainder) - *remainder = inf->datalen - amt; - outf.frametype = AST_FRAME_VOICE; - outf.subclass = AST_FORMAT_ULAW; - outf.data = buf; - outf.datalen = amt; - outf.samples = amt; - if (ast_write(chan, &outf)) { - ast_log(LOG_WARNING, "Failed to carefully write frame\n"); - return -1; - } - /* Update pointers and lengths */ - buf += amt; - len -= amt; - } - ast_frfree(inf); - } - return 0; -} - -static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype) -{ - /* msglen must be no more than 256 bits, each */ - unsigned char buf[24000 * 5]; - int pos = 0, res; - int x; - int start=0; - int retries = 0; - - char ack[3]; - - /* Wait up to 500 ms for initial ACK */ - int waittime; - struct ast_frame *f; - int rem = 0; - int def; - - if (chan->adsicpe == AST_ADSI_UNAVAILABLE) { - /* Don't bother if we know they don't support ADSI */ - errno = ENOSYS; - return -1; - } - - while(retries < maxretries) { - if (!(chan->adsicpe & ADSI_FLAG_DATAMODE)) { - /* Generate CAS (no SAS) */ - ast_gen_cas(buf, 0, 680, AST_FORMAT_ULAW); - - /* Send CAS */ - if (adsi_careful_send(chan, buf, 680, NULL)) { - ast_log(LOG_WARNING, "Unable to send CAS\n"); - } - /* Wait For DTMF result */ - waittime = 500; - for(;;) { - if (((res = ast_waitfor(chan, waittime)) < 1)) { - /* Didn't get back DTMF A in time */ - ast_log(LOG_DEBUG, "No ADSI CPE detected (%d)\n", res); - if (!chan->adsicpe) - chan->adsicpe = AST_ADSI_UNAVAILABLE; - errno = ENOSYS; - return -1; - } - waittime = res; - f = ast_read(chan); - if (!f) { - ast_log(LOG_DEBUG, "Hangup in ADSI\n"); - return -1; - } - if (f->frametype == AST_FRAME_DTMF) { - if (f->subclass == 'A') { - /* Okay, this is an ADSI CPE. Note this for future reference, too */ - if (!chan->adsicpe) - chan->adsicpe = AST_ADSI_AVAILABLE; - break; - } else { - if (f->subclass == 'D') { - ast_log(LOG_DEBUG, "Off-hook capable CPE only, not ADSI\n"); - } else - ast_log(LOG_WARNING, "Unknown ADSI response '%c'\n", f->subclass); - if (!chan->adsicpe) - chan->adsicpe = AST_ADSI_UNAVAILABLE; - errno = ENOSYS; - return -1; - } - } - ast_frfree(f); - } - - ast_log(LOG_DEBUG, "ADSI Compatible CPE Detected\n"); - } else - ast_log(LOG_DEBUG, "Already in data mode\n"); - - x = 0; - pos = 0; -#if 1 - def= ast_channel_defer_dtmf(chan); -#endif - while((x < 6) && msg[x]) { - res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], AST_FORMAT_ULAW); - if (res < 0) { - ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, chan->name); - return -1; - } - ast_log(LOG_DEBUG, "Message %d, of %d input bytes, %d output bytes\n", - x + 1, msglen[x], res); - pos += res; - x++; - } - - - rem = 0; - res = adsi_careful_send(chan, buf, pos, &rem); - if (!def) - ast_channel_undefer_dtmf(chan); - if (res) - return -1; - - ast_log(LOG_DEBUG, "Sent total spill of %d bytes\n", pos); - - memset(ack, 0, sizeof(ack)); - /* Get real result */ - res = ast_readstring(chan, ack, 2, 1000, 1000, ""); - /* Check for hangup */ - if (res < 0) - return -1; - if (ack[0] == 'D') { - ast_log(LOG_DEBUG, "Acked up to message %d\n", atoi(ack + 1)); - start += atoi(ack + 1); - if (start >= x) - break; - else { - retries++; - ast_log(LOG_DEBUG, "Retransmitting (%d), from %d\n", retries, start + 1); - } - } else { - retries++; - ast_log(LOG_WARNING, "Unexpected response to ack: %s (retry %d)\n", ack, retries); - } - } - if (retries >= maxretries) { - ast_log(LOG_WARNING, "Maximum ADSI Retries (%d) exceeded\n", maxretries); - errno = ETIMEDOUT; - return -1; - } - return 0; - -} - -int adsi_begin_download(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version) -{ - int bytes; - unsigned char buf[256]; - char ack[2]; - bytes = 0; - /* Setup the resident soft key stuff, a piece at a time */ - /* Upload what scripts we can for voicemail ahead of time */ - bytes += adsi_download_connect(buf + bytes, service, fdn, sec, version); - if (adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) - return -1; - if (ast_readstring(chan, ack, 1, 10000, 10000, "")) - return -1; - if (ack[0] == 'B') - return 0; - ast_log(LOG_DEBUG, "Download was denied by CPE\n"); - return -1; -} - -int adsi_end_download(struct ast_channel *chan) -{ - int bytes; - unsigned char buf[256]; - bytes = 0; - /* Setup the resident soft key stuff, a piece at a time */ - /* Upload what scripts we can for voicemail ahead of time */ - bytes += adsi_download_disconnect(buf + bytes); - if (adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) - return -1; - return 0; -} - -int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait) -{ - unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL }; - int msglens[5]; - int msgtypes[5]; - int newdatamode; - int res; - int x; - int writeformat, readformat; - int waitforswitch = 0; - - writeformat = chan->writeformat; - readformat = chan->readformat; - - newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE; - - for (x=0;x<msglen;x+=(msg[x+1]+2)) { - if (msg[x] == ADSI_SWITCH_TO_DATA) { - ast_log(LOG_DEBUG, "Switch to data is sent!\n"); - waitforswitch++; - newdatamode = ADSI_FLAG_DATAMODE; - } - - if (msg[x] == ADSI_SWITCH_TO_VOICE) { - ast_log(LOG_DEBUG, "Switch to voice is sent!\n"); - waitforswitch++; - newdatamode = 0; - } - } - msgs[0] = msg; - - msglens[0] = msglen; - msgtypes[0] = msgtype; - - if (msglen > 253) { - ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen); - return -1; - } - - ast_stopstream(chan); - - if (ast_set_write_format(chan, AST_FORMAT_ULAW)) { - ast_log(LOG_WARNING, "Unable to set write format to ULAW\n"); - return -1; - } - - if (ast_set_read_format(chan, AST_FORMAT_ULAW)) { - ast_log(LOG_WARNING, "Unable to set read format to ULAW\n"); - if (writeformat) { - if (ast_set_write_format(chan, writeformat)) - ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat); - } - return -1; - } - res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes); - - if (dowait) { - ast_log(LOG_DEBUG, "Wait for switch is '%d'\n", waitforswitch); - while(waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) { res = 0; ast_log(LOG_DEBUG, "Waiting for 'B'...\n"); } - } - - if (!res) - chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode; - - if (writeformat) - ast_set_write_format(chan, writeformat); - if (readformat) - ast_set_read_format(chan, readformat); - - if (!res) - res = ast_safe_sleep(chan, 100 ); - return res; -} - -int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype) -{ - return adsi_transmit_message_full(chan, msg, msglen, msgtype, 1); -} - -static inline int ccopy(unsigned char *dst, unsigned char *src, int max) -{ - int x=0; - /* Carefully copy the requested data */ - while ((x < max) && src[x] && (src[x] != 0xff)) { - dst[x] = src[x]; - x++; - } - return x; -} - -int adsi_load_soft_key(unsigned char *buf, int key, char *llabel, char *slabel, char *ret, int data) -{ - int bytes=0; - - /* Abort if invalid key specified */ - if ((key < 2) || (key > 33)) - return -1; - buf[bytes++] = ADSI_LOAD_SOFTKEY; - /* Reserve for length */ - bytes++; - /* Which key */ - buf[bytes++] = key; - - /* Carefully copy long label */ - bytes += ccopy(buf + bytes, (unsigned char *)llabel, 18); - - /* Place delimiter */ - buf[bytes++] = 0xff; - - /* Short label */ - bytes += ccopy(buf + bytes, (unsigned char *)slabel, 7); - - - /* If specified, copy return string */ - if (ret) { - /* Place delimiter */ - buf[bytes++] = 0xff; - if (data) - buf[bytes++] = ADSI_SWITCH_TO_DATA2; - /* Carefully copy return string */ - bytes += ccopy(buf + bytes, (unsigned char *)ret, 20); - - } - /* Replace parameter length */ - buf[1] = bytes - 2; - return bytes; - -} - -int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver) -{ - int bytes=0; - int x; - - /* Message type */ - buf[bytes++] = ADSI_CONNECT_SESSION; - - /* Reserve space for length */ - bytes++; - - if (fdn) { - for (x=0;x<4;x++) - buf[bytes++] = fdn[x]; - if (ver > -1) - buf[bytes++] = ver & 0xff; - } - - buf[1] = bytes - 2; - return bytes; - -} - -int adsi_download_connect(unsigned char *buf, char *service, unsigned char *fdn, unsigned char *sec, int ver) -{ - int bytes=0; - int x; - - /* Message type */ - buf[bytes++] = ADSI_DOWNLOAD_CONNECT; - - /* Reserve space for length */ - bytes++; - - /* Primary column */ - bytes+= ccopy(buf + bytes, (unsigned char *)service, 18); - - /* Delimiter */ - buf[bytes++] = 0xff; - - for (x=0;x<4;x++) { - buf[bytes++] = fdn[x]; - } - for (x=0;x<4;x++) - buf[bytes++] = sec[x]; - buf[bytes++] = ver & 0xff; - - buf[1] = bytes - 2; - - return bytes; - -} - -int adsi_disconnect_session(unsigned char *buf) -{ - int bytes=0; - - /* Message type */ - buf[bytes++] = ADSI_DISC_SESSION; - - /* Reserve space for length */ - bytes++; - - buf[1] = bytes - 2; - return bytes; - -} - -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) -{ - unsigned char buf[256]; - int bytes = 0; - int res; - bytes += adsi_data_mode(buf); - adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - - bytes = 0; - bytes += adsi_query_cpeid(buf); - adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - - /* 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_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - /* 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) -{ - unsigned char buf[256]; - int bytes = 0; - int res; - bytes += adsi_data_mode(buf); - adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - - bytes = 0; - bytes += adsi_query_cpeinfo(buf); - adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - - /* Get width */ - memset(buf, 0, sizeof(buf)); - res = ast_readstring(chan, (char *)buf, 2, 1000, 500, ""); - if (res < 0) - return res; - if (strlen((char *)buf) != 2) { - ast_log(LOG_WARNING, "Got %d bytes of width, expecting 2\n", res); - res = 0; - } else { - res = 1; - } - if (width) - *width = atoi((char *)buf); - /* Get height */ - memset(buf, 0, sizeof(buf)); - if (res) { - res = ast_readstring(chan, (char *)buf, 2, 1000, 500, ""); - if (res < 0) - return res; - if (strlen((char *)buf) != 2) { - ast_log(LOG_WARNING, "Got %d bytes of height, expecting 2\n", res); - res = 0; - } else { - res = 1; - } - if (height) - *height= atoi((char *)buf); - } - /* Get buttons */ - memset(buf, 0, sizeof(buf)); - if (res) { - res = ast_readstring(chan, (char *)buf, 1, 1000, 500, ""); - if (res < 0) - return res; - if (strlen((char *)buf) != 1) { - ast_log(LOG_WARNING, "Got %d bytes of buttons, expecting 1\n", res); - res = 0; - } else { - res = 1; - } - if (buttons) - *buttons = atoi((char *)buf); - } - if (voice) { - bytes = 0; - bytes += adsi_voice_mode(buf, 0); - adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - /* 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; - - /* Message type */ - buf[bytes++] = ADSI_SWITCH_TO_DATA; - - /* Reserve space for length */ - bytes++; - - buf[1] = bytes - 2; - return bytes; - -} - -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; - - /* Message type */ - buf[bytes++] = ADSI_SWITCH_TO_VOICE; - - /* Reserve space for length */ - bytes++; - - buf[bytes++] = when & 0x7f; - - buf[1] = bytes - 2; - return bytes; - -} - -int adsi_available(struct ast_channel *chan) -{ - int cpe = chan->adsicpe & 0xff; - if ((cpe == AST_ADSI_AVAILABLE) || - (cpe == AST_ADSI_UNKNOWN)) - return 1; - return 0; -} - -int adsi_download_disconnect(unsigned char *buf) -{ - int bytes=0; - - /* Message type */ - buf[bytes++] = ADSI_DOWNLOAD_DISC; - - /* Reserve space for length */ - bytes++; - - buf[1] = bytes - 2; - return bytes; - -} - -int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, - char *col1, char *col2) -{ - int bytes=0; - - /* Sanity check line number */ - - if (page) { - if (line > 4) return -1; - } else { - if (line > 33) return -1; - } - - if (line < 1) - return -1; - /* Parameter type */ - buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP; - - /* Reserve space for size */ - bytes++; - - /* Page and wrap indicator */ - buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f); - - /* Justification */ - buf[bytes++] = (just & 0x3) << 5; - - /* Omit highlight mode definition */ - buf[bytes++] = 0xff; - - /* Primary column */ - bytes+= ccopy(buf + bytes, (unsigned char *)col1, 20); - - /* Delimiter */ - buf[bytes++] = 0xff; - - /* Secondary column */ - bytes += ccopy(buf + bytes, (unsigned char *)col2, 20); - - /* Update length */ - buf[1] = bytes - 2; - - return bytes; - -} - -int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just) -{ - int bytes=0; - - if (page) { - if (line > 4) return -1; - } else { - if (line > 33) return -1; - } - - if (line < 1) - return -1; - - buf[bytes++] = ADSI_INPUT_CONTROL; - bytes++; - buf[bytes++] = ((page & 1) << 7) | (line & 0x3f); - buf[bytes++] = ((display & 1) << 7) | ((just & 0x3) << 4) | (format & 0x7); - - buf[1] = bytes - 2; - return bytes; - -} - -int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2) -{ - int bytes = 0; - - if (!strlen((char *)format1)) - return -1; - - buf[bytes++] = ADSI_INPUT_FORMAT; - bytes++; - buf[bytes++] = ((dir & 1) << 7) | ((wrap & 1) << 6) | (num & 0x7); - bytes += ccopy(buf + bytes, (unsigned char *)format1, 20); - buf[bytes++] = 0xff; - if (format2 && strlen((char *)format2)) { - bytes += ccopy(buf + bytes, (unsigned char *)format2, 20); - } - buf[1] = bytes - 2; - return bytes; -} - -int adsi_set_keys(unsigned char *buf, unsigned char *keys) -{ - int bytes=0; - int x; - /* Message type */ - buf[bytes++] = ADSI_INIT_SOFTKEY_LINE; - /* Space for size */ - bytes++; - /* Key definitions */ - for (x=0;x<6;x++) - buf[bytes++] = (keys[x] & 0x3f) ? keys[x] : (keys[x] | 0x1); - buf[1] = bytes - 2; - return bytes; -} - -int adsi_set_line(unsigned char *buf, int page, int line) -{ - int bytes=0; - - /* Sanity check line number */ - - if (page) { - if (line > 4) return -1; - } else { - if (line > 33) return -1; - } - - if (line < 1) - return -1; - /* Parameter type */ - buf[bytes++] = ADSI_LINE_CONTROL; - - /* Reserve space for size */ - bytes++; - - /* Page and line */ - buf[bytes++] = ((page & 0x1) << 7) | (line & 0x3f); - - buf[1] = bytes - 2; - return bytes; - -}; - -static int total = 0; -static int speeds = 0; - -int adsi_channel_restore(struct ast_channel *chan) -{ - unsigned char dsp[256]; - int bytes; - 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); - } - adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0); - return 0; - -} - -int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice) -{ - unsigned char buf[4096]; - int bytes=0; - int res; - int x; - 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); - } - res = adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0); - 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) -{ - unsigned char dsp[256]; - int bytes; - int res; - char resp[2]; - - memset(dsp, 0, sizeof(dsp)); - - /* Connect to session */ - bytes = 0; - bytes += adsi_connect_session(dsp + bytes, app, ver); - - if (data) - bytes += adsi_data_mode(dsp + bytes); - - /* Prepare key setup messages */ - if (adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) - return -1; - 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; - return 0; - -} - -int adsi_unload_session(struct ast_channel *chan) -{ - unsigned char dsp[256]; - int bytes; - - memset(dsp, 0, sizeof(dsp)); - - /* Connect to session */ - bytes = 0; - bytes += adsi_disconnect_session(dsp + bytes); - bytes += adsi_voice_mode(dsp + bytes, 0); - - /* Prepare key setup messages */ - if (adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) - return -1; - return 0; -} - -static int str2align(char *s) -{ - if (!strncasecmp(s, "l", 1)) - return ADSI_JUST_LEFT; - else if (!strncasecmp(s, "r", 1)) - return ADSI_JUST_RIGHT; - else if (!strncasecmp(s, "i", 1)) - return ADSI_JUST_IND; - else - return ADSI_JUST_CENT; -} - -static void init_state(void) -{ - int x; - - for (x=0;x<ADSI_MAX_INTRO;x++) - aligns[x] = ADSI_JUST_CENT; - strncpy(intro[0], "Welcome to the", sizeof(intro[0]) - 1); - strncpy(intro[1], "Asterisk", sizeof(intro[1]) - 1); - strncpy(intro[2], "Open Source PBX", sizeof(intro[2]) - 1); - total = 3; - speeds = 0; - for (x=3;x<ADSI_MAX_INTRO;x++) - intro[x][0] = '\0'; - memset(speeddial, 0, sizeof(speeddial)); - alignment = ADSI_JUST_CENT; -} - -static void adsi_load(void) -{ - int x; - struct ast_config *conf; - struct ast_variable *v; - char *name, *sname; - init_state(); - conf = ast_config_load("adsi.conf"); - if (conf) { - x=0; - v = ast_variable_browse(conf, "intro"); - while(v) { - if (!strcasecmp(v->name, "alignment")) - alignment = str2align(v->value); - else if (!strcasecmp(v->name, "greeting")) { - if (x < ADSI_MAX_INTRO) { - aligns[x] = alignment; - strncpy(intro[x], v->value, sizeof(intro[x]) - 1); - intro[x][sizeof(intro[x]) - 1] = '\0'; - x++; - } - } else if (!strcasecmp(v->name, "maxretries")) { - if (atoi(v->value) > 0) - maxretries = atoi(v->value); - } - v = v->next; - } - v = ast_variable_browse(conf, "speeddial"); - if (x) - total = x; - x = 0; - while(v) { - char *stringp=NULL; - stringp=v->value; - name = strsep(&stringp, ","); - sname = strsep(&stringp, ","); - if (!sname) - sname = name; - if (x < ADSI_MAX_SPEED_DIAL) { - /* Up to 20 digits */ - strncpy(speeddial[x][0], v->name, sizeof(speeddial[x][0]) - 1); - strncpy(speeddial[x][1], name, 18); - strncpy(speeddial[x][2], sname, 7); - x++; - } - v = v->next; - - } - if (x) - speeds = x; - ast_config_destroy(conf); - } -} - -int reload(void) -{ - adsi_load(); - return 0; -} - -int load_module(void) -{ - adsi_load(); - return 0; -} - -int unload_module(void) -{ - /* Can't unload this once we're loaded */ - return -1; -} - -char *description(void) -{ - return "ADSI Resource"; -} - -int usecount(void) -{ - /* We should never be unloaded */ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_agi.c b/1.2-netsec/res/res_agi.c deleted file mode 100644 index 8f9654443..000000000 --- a/1.2-netsec/res/res_agi.c +++ /dev/null @@ -1,2142 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2006, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief AGI - the Asterisk Gateway Interface - * - */ - -#include <sys/types.h> -#include <netdb.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <math.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <signal.h> -#include <sys/time.h> -#include <stdio.h> -#include <fcntl.h> -#include <errno.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/astdb.h" -#include "asterisk/callerid.h" -#include "asterisk/cli.h" -#include "asterisk/logger.h" -#include "asterisk/options.h" -#include "asterisk/image.h" -#include "asterisk/say.h" -#include "asterisk/app.h" -#include "asterisk/dsp.h" -#include "asterisk/musiconhold.h" -#include "asterisk/manager.h" -#include "asterisk/utils.h" -#include "asterisk/lock.h" -#include "asterisk/strings.h" -#include "asterisk/agi.h" - -#define MAX_ARGS 128 -#define MAX_COMMANDS 128 - -/* Recycle some stuff from the CLI interface */ -#define fdprintf agi_debug_cli - -static char *tdesc = "Asterisk Gateway Interface (AGI)"; - -static char *app = "AGI"; - -static char *eapp = "EAGI"; - -static char *deadapp = "DeadAGI"; - -static char *synopsis = "Executes an AGI compliant application"; -static char *esynopsis = "Executes an EAGI compliant application"; -static char *deadsynopsis = "Executes AGI on a hungup channel"; - -static char *descrip = -" [E|Dead]AGI(command|args): Executes an Asterisk Gateway Interface compliant\n" -"program on a channel. AGI allows Asterisk to launch external programs\n" -"written in any language to control a telephony channel, play audio,\n" -"read DTMF digits, etc. by communicating with the AGI protocol on stdin\n" -"and stdout.\n" -"Returns -1 on hangup (except for DeadAGI) or if application requested\n" -" hangup, or 0 on non-hangup exit. \n" -"Using 'EAGI' provides enhanced AGI, with incoming audio available out of band\n" -"on file descriptor 3\n\n" -"Use the CLI command 'show agi' to list available agi commands\n"; - -static int agidebug = 0; - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - - -#define TONE_BLOCK_SIZE 200 - -/* Max time to connect to an AGI remote host */ -#define MAX_AGI_CONNECT 2000 - -#define AGI_PORT 4573 - -static void agi_debug_cli(int fd, char *fmt, ...) -{ - char *stuff; - int res = 0; - - va_list ap; - va_start(ap, fmt); - res = vasprintf(&stuff, fmt, ap); - va_end(ap); - if (res == -1) { - ast_log(LOG_ERROR, "Out of memory\n"); - } else { - if (agidebug) - ast_verbose("AGI Tx >> %s", stuff); - ast_carefulwrite(fd, stuff, strlen(stuff), 100); - free(stuff); - } -} - -/* launch_netscript: The fastagi handler. - FastAGI defaults to port 4573 */ -static int launch_netscript(char *agiurl, char *argv[], int *fds, int *efd, int *opid) -{ - int s; - int flags; - struct pollfd pfds[1]; - char *host; - char *c; int port = AGI_PORT; - char *script=""; - struct sockaddr_in sin; - struct hostent *hp; - struct ast_hostent ahp; - - host = ast_strdupa(agiurl + 6); /* Remove agi:// */ - if (!host) - return -1; - /* Strip off any script name */ - if ((c = strchr(host, '/'))) { - *c = '\0'; - c++; - script = c; - } - if ((c = strchr(host, ':'))) { - *c = '\0'; - c++; - port = atoi(c); - } - if (efd) { - ast_log(LOG_WARNING, "AGI URI's don't support Enhanced AGI yet\n"); - return -1; - } - hp = ast_gethostbyname(host, &ahp); - if (!hp) { - ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host); - return -1; - } - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) { - ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); - return -1; - } - flags = fcntl(s, F_GETFL); - if (flags < 0) { - ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno)); - close(s); - return -1; - } - if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) { - ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno)); - close(s); - return -1; - } - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) && (errno != EINPROGRESS)) { - ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno)); - close(s); - return -1; - } - - pfds[0].fd = s; - pfds[0].events = POLLOUT; - while (poll(pfds, 1, MAX_AGI_CONNECT) != 1) { - if (errno != EINTR) { - ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); - close(s); - return -1; - } - } - - while (write(s, "agi_network: yes\n", strlen("agi_network: yes\n")) < 0) { - if (errno != EINTR) { - ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno)); - close(s); - return -1; - } - } - - /* If we have a script parameter, relay it to the fastagi server */ - if (!ast_strlen_zero(script)) - fdprintf(s, "agi_network_script: %s\n", script); - - if (option_debug > 3) - ast_log(LOG_DEBUG, "Wow, connected!\n"); - fds[0] = s; - fds[1] = s; - *opid = -1; - return 0; -} - -static int launch_script(char *script, char *argv[], int *fds, int *efd, int *opid) -{ - char tmp[256]; - int pid; - int toast[2]; - int fromast[2]; - int audio[2]; - int x; - int res; - sigset_t signal_set; - - if (!strncasecmp(script, "agi://", 6)) - return launch_netscript(script, argv, fds, efd, opid); - - if (script[0] != '/') { - snprintf(tmp, sizeof(tmp), "%s/%s", (char *)ast_config_AST_AGI_DIR, script); - script = tmp; - } - if (pipe(toast)) { - ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno)); - return -1; - } - if (pipe(fromast)) { - ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno)); - close(toast[0]); - close(toast[1]); - return -1; - } - if (efd) { - if (pipe(audio)) { - ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno)); - close(fromast[0]); - close(fromast[1]); - close(toast[0]); - close(toast[1]); - return -1; - } - res = fcntl(audio[1], F_GETFL); - if (res > -1) - res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK); - if (res < 0) { - ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno)); - close(fromast[0]); - close(fromast[1]); - close(toast[0]); - close(toast[1]); - close(audio[0]); - close(audio[1]); - return -1; - } - } - pid = fork(); - if (pid < 0) { - ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); - return -1; - } - if (!pid) { - /* Redirect stdin and out, provide enhanced audio channel if desired */ - dup2(fromast[0], STDIN_FILENO); - dup2(toast[1], STDOUT_FILENO); - if (efd) { - dup2(audio[0], STDERR_FILENO + 1); - } else { - close(STDERR_FILENO + 1); - } - - /* unblock important signal handlers */ - if (sigfillset(&signal_set) || pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) { - ast_log(LOG_WARNING, "unable to unblock signals for AGI script: %s\n", strerror(errno)); - exit(1); - } - - /* Close everything but stdin/out/error */ - for (x=STDERR_FILENO + 2;x<1024;x++) - close(x); - - /* Don't run AGI scripts with realtime priority -- it causes audio stutter */ - ast_set_priority(0); - - /* Execute script */ - execv(script, argv); - /* Can't use ast_log since FD's are closed */ - fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno)); - exit(1); - } - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script); - fds[0] = toast[0]; - fds[1] = fromast[1]; - if (efd) { - *efd = audio[1]; - } - /* close what we're not using in the parent */ - close(toast[1]); - close(fromast[0]); - - if (efd) { - /* [PHM 12/18/03] */ - close(audio[0]); - } - - *opid = pid; - return 0; - -} - -static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced) -{ - /* Print initial environment, with agi_request always being the first - thing */ - fdprintf(fd, "agi_request: %s\n", request); - fdprintf(fd, "agi_channel: %s\n", chan->name); - fdprintf(fd, "agi_language: %s\n", chan->language); - fdprintf(fd, "agi_type: %s\n", chan->type); - fdprintf(fd, "agi_uniqueid: %s\n", chan->uniqueid); - - /* ANI/DNIS */ - fdprintf(fd, "agi_callerid: %s\n", chan->cid.cid_num ? chan->cid.cid_num : "unknown"); - fdprintf(fd, "agi_calleridname: %s\n", chan->cid.cid_name ? chan->cid.cid_name : "unknown"); - fdprintf(fd, "agi_callingpres: %d\n", chan->cid.cid_pres); - fdprintf(fd, "agi_callingani2: %d\n", chan->cid.cid_ani2); - fdprintf(fd, "agi_callington: %d\n", chan->cid.cid_ton); - fdprintf(fd, "agi_callingtns: %d\n", chan->cid.cid_tns); - fdprintf(fd, "agi_dnid: %s\n", chan->cid.cid_dnid ? chan->cid.cid_dnid : "unknown"); - fdprintf(fd, "agi_rdnis: %s\n", chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "unknown"); - - /* Context information */ - fdprintf(fd, "agi_context: %s\n", chan->context); - fdprintf(fd, "agi_extension: %s\n", chan->exten); - fdprintf(fd, "agi_priority: %d\n", chan->priority); - fdprintf(fd, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0"); - - /* User information */ - fdprintf(fd, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : ""); - - /* End with empty return */ - fdprintf(fd, "\n"); -} - -static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - res = 0; - if (chan->_state != AST_STATE_UP) { - /* Answer the chan */ - res = ast_answer(chan); - } - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - int to; - if (argc != 4) - return RESULT_SHOWUSAGE; - if (sscanf(argv[3], "%d", &to) != 1) - return RESULT_SHOWUSAGE; - res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl); - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - if (argc != 3) - return RESULT_SHOWUSAGE; - /* At the moment, the parser (perhaps broken) returns with - the last argument PLUS the newline at the end of the input - buffer. This probably needs to be fixed, but I wont do that - because other stuff may break as a result. The right way - would probably be to strip off the trailing newline before - parsing, then here, add a newline at the end of the string - before sending it to ast_sendtext --DUDE */ - res = ast_sendtext(chan, argv[2]); - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - if (argc != 3) - return RESULT_SHOWUSAGE; - res = ast_recvchar(chan,atoi(argv[2])); - if (res == 0) { - fdprintf(agi->fd, "200 result=%d (timeout)\n", res); - return RESULT_SUCCESS; - } - if (res > 0) { - fdprintf(agi->fd, "200 result=%d\n", res); - return RESULT_SUCCESS; - } - else { - fdprintf(agi->fd, "200 result=%d (hangup)\n", res); - return RESULT_FAILURE; - } -} - -static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - char *buf; - - if (argc != 3) - return RESULT_SHOWUSAGE; - buf = ast_recvtext(chan,atoi(argv[2])); - if (buf) { - fdprintf(agi->fd, "200 result=1 (%s)\n", buf); - free(buf); - } else { - fdprintf(agi->fd, "200 result=-1\n"); - } - return RESULT_SUCCESS; -} - -static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res,x; - if (argc != 3) - return RESULT_SHOWUSAGE; - if (!strncasecmp(argv[2],"on",2)) - x = 1; - else - x = 0; - if (!strncasecmp(argv[2],"mate",4)) - x = 2; - if (!strncasecmp(argv[2],"tdd",3)) - x = 1; - res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0); - if (res != RESULT_SUCCESS) - fdprintf(agi->fd, "200 result=0\n"); - else - fdprintf(agi->fd, "200 result=1\n"); - return RESULT_SUCCESS; -} - -static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - if (argc != 3) - return RESULT_SHOWUSAGE; - res = ast_send_image(chan, argv[2]); - if (!ast_check_hangup(chan)) - res = 0; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res = 0; - int skipms = 3000; - char *fwd = NULL; - char *rev = NULL; - char *pause = NULL; - char *stop = NULL; - - if (argc < 5 || argc > 9) - return RESULT_SHOWUSAGE; - - if (!ast_strlen_zero(argv[4])) - stop = argv[4]; - else - stop = NULL; - - if ((argc > 5) && (sscanf(argv[5], "%d", &skipms) != 1)) - return RESULT_SHOWUSAGE; - - if (argc > 6 && !ast_strlen_zero(argv[8])) - fwd = argv[6]; - else - fwd = "#"; - - if (argc > 7 && !ast_strlen_zero(argv[8])) - rev = argv[7]; - else - rev = "*"; - - if (argc > 8 && !ast_strlen_zero(argv[8])) - pause = argv[8]; - else - pause = NULL; - - res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, pause, NULL, skipms); - - fdprintf(agi->fd, "200 result=%d\n", res); - - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - struct ast_filestream *fs; - long sample_offset = 0; - long max_length; - - if (argc < 4) - return RESULT_SHOWUSAGE; - if (argc > 5) - return RESULT_SHOWUSAGE; - if ((argc > 4) && (sscanf(argv[4], "%ld", &sample_offset) != 1)) - return RESULT_SHOWUSAGE; - - fs = ast_openstream(chan, argv[2], chan->language); - if (!fs){ - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset); - return RESULT_SUCCESS; - } - ast_seekstream(fs, 0, SEEK_END); - max_length = ast_tellstream(fs); - ast_seekstream(fs, sample_offset, SEEK_SET); - res = ast_applystream(chan, fs); - res = ast_playstream(fs); - if (res) { - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); - if (res >= 0) - return RESULT_SHOWUSAGE; - else - return RESULT_FAILURE; - } - res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); - /* this is to check for if ast_waitstream closed the stream, we probably are at - * the end of the stream, return that amount, else check for the amount */ - sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length; - ast_stopstream(chan); - if (res == 1) { - /* Stop this command, don't print a result line, as there is a new command */ - return RESULT_SUCCESS; - } - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -/* get option - really similar to the handle_streamfile, but with a timeout */ -static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - struct ast_filestream *fs; - long sample_offset = 0; - long max_length; - int timeout = 0; - char *edigits = NULL; - - if ( argc < 4 || argc > 5 ) - return RESULT_SHOWUSAGE; - - if ( argv[3] ) - edigits = argv[3]; - - if ( argc == 5 ) - timeout = atoi(argv[4]); - else if (chan->pbx->dtimeout) { - /* by default dtimeout is set to 5sec */ - timeout = chan->pbx->dtimeout * 1000; /* in msec */ - } - - fs = ast_openstream(chan, argv[2], chan->language); - if (!fs){ - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", 0, sample_offset); - ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]); - return RESULT_SUCCESS; - } - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout); - - ast_seekstream(fs, 0, SEEK_END); - max_length = ast_tellstream(fs); - ast_seekstream(fs, sample_offset, SEEK_SET); - res = ast_applystream(chan, fs); - res = ast_playstream(fs); - if (res) { - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); - if (res >= 0) - return RESULT_SHOWUSAGE; - else - return RESULT_FAILURE; - } - res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl); - /* this is to check for if ast_waitstream closed the stream, we probably are at - * the end of the stream, return that amount, else check for the amount */ - sample_offset = (chan->stream)?ast_tellstream(fs):max_length; - ast_stopstream(chan); - if (res == 1) { - /* Stop this command, don't print a result line, as there is a new command */ - return RESULT_SUCCESS; - } - - /* If the user didnt press a key, wait for digitTimeout*/ - if (res == 0 ) { - res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl); - /* Make sure the new result is in the escape digits of the GET OPTION */ - if ( !strchr(edigits,res) ) - res=0; - } - - fdprintf(agi->fd, "200 result=%d endpos=%ld\n", res, sample_offset); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - - - - -/*--- handle_saynumber: Say number in various language syntaxes ---*/ -/* Need to add option for gender here as well. Coders wanted */ -/* While waiting, we're sending a (char *) NULL. */ -static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - int num; - if (argc != 4) - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; - res = ast_say_number_full(chan, num, argv[3], chan->language, (char *) NULL, agi->audio, agi->ctrl); - if (res == 1) - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - int num; - - if (argc != 4) - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; - - res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - - if (argc != 4) - return RESULT_SHOWUSAGE; - - res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - int num; - if (argc != 4) - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; - res = ast_say_date(chan, num, argv[3], chan->language); - if (res == 1) - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - int num; - if (argc != 4) - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &num) != 1) - return RESULT_SHOWUSAGE; - res = ast_say_time(chan, num, argv[3], chan->language); - if (res == 1) - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res=0; - long unixtime; - char *format, *zone=NULL; - - if (argc < 4) - return RESULT_SHOWUSAGE; - - if (argc > 4) { - format = argv[4]; - } else { - if (!strcasecmp(chan->language, "de")) { - format = "A dBY HMS"; - } else { - format = "ABdY 'digits/at' IMp"; - } - } - - if (argc > 5 && !ast_strlen_zero(argv[5])) - zone = argv[5]; - - if (sscanf(argv[2], "%ld", &unixtime) != 1) - return RESULT_SHOWUSAGE; - - res = ast_say_date_with_format(chan, (time_t) unixtime, argv[3], chan->language, format, zone); - if (res == 1) - return RESULT_SUCCESS; - - fdprintf(agi->fd, "200 result=%d\n", res); - - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - - if (argc != 4) - return RESULT_SHOWUSAGE; - - res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl); - if (res == 1) /* New command */ - return RESULT_SUCCESS; - fdprintf(agi->fd, "200 result=%d\n", res); - if (res >= 0) - return RESULT_SUCCESS; - else - return RESULT_FAILURE; -} - -static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int res; - char data[1024]; - int max; - int timeout; - - if (argc < 3) - return RESULT_SHOWUSAGE; - if (argc >= 4) - timeout = atoi(argv[3]); - else - timeout = 0; - if (argc >= 5) - max = atoi(argv[4]); - else - max = 1024; - res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl); - if (res == 2) /* New command */ - return RESULT_SUCCESS; - else if (res == 1) - fdprintf(agi->fd, "200 result=%s (timeout)\n", data); - else if (res < 0 ) - fdprintf(agi->fd, "200 result=-1\n"); - else - fdprintf(agi->fd, "200 result=%s\n", data); - return RESULT_SUCCESS; -} - -static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_copy_string(chan->context, argv[2], sizeof(chan->context)); - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - if (argc != 3) - return RESULT_SHOWUSAGE; - ast_copy_string(chan->exten, argv[2], sizeof(chan->exten)); - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int pri; - if (argc != 3) - return RESULT_SHOWUSAGE; - - if (sscanf(argv[2], "%d", &pri) != 1) { - if ((pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2], chan->cid.cid_num)) < 1) - return RESULT_SHOWUSAGE; - } - - ast_explicit_goto(chan, NULL, NULL, pri); - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - struct ast_filestream *fs; - struct ast_frame *f; - struct timeval start; - long sample_offset = 0; - int res = 0; - int ms; - - struct ast_dsp *sildet=NULL; /* silence detector dsp */ - int totalsilence = 0; - int dspsilence = 0; - int silence = 0; /* amount of silence to allow */ - int gotsilence = 0; /* did we timeout for silence? */ - char *silencestr=NULL; - int rfmt=0; - - - /* XXX EAGI FIXME XXX */ - - if (argc < 6) - return RESULT_SHOWUSAGE; - if (sscanf(argv[5], "%d", &ms) != 1) - return RESULT_SHOWUSAGE; - - if (argc > 6) - silencestr = strchr(argv[6],'s'); - if ((argc > 7) && (!silencestr)) - silencestr = strchr(argv[7],'s'); - if ((argc > 8) && (!silencestr)) - silencestr = strchr(argv[8],'s'); - - if (silencestr) { - if (strlen(silencestr) > 2) { - if ((silencestr[0] == 's') && (silencestr[1] == '=')) { - silencestr++; - silencestr++; - if (silencestr) - silence = atoi(silencestr); - if (silence > 0) - silence *= 1000; - } - } - } - - if (silence > 0) { - rfmt = chan->readformat; - res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); - if (res < 0) { - ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); - return -1; - } - sildet = ast_dsp_new(); - if (!sildet) { - ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); - return -1; - } - ast_dsp_set_threshold(sildet, 256); - } - - /* backward compatibility, if no offset given, arg[6] would have been - * caught below and taken to be a beep, else if it is a digit then it is a - * offset */ - if ((argc >6) && (sscanf(argv[6], "%ld", &sample_offset) != 1) && (!strchr(argv[6], '='))) - res = ast_streamfile(chan, "beep", chan->language); - - if ((argc > 7) && (!strchr(argv[7], '='))) - res = ast_streamfile(chan, "beep", chan->language); - - if (!res) - res = ast_waitstream(chan, argv[4]); - if (res) { - fdprintf(agi->fd, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset); - } else { - fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, 0644); - if (!fs) { - res = -1; - fdprintf(agi->fd, "200 result=%d (writefile)\n", res); - if (sildet) - ast_dsp_free(sildet); - return RESULT_FAILURE; - } - - chan->stream = fs; - ast_applystream(chan,fs); - /* really should have checks */ - ast_seekstream(fs, sample_offset, SEEK_SET); - ast_truncstream(fs); - - start = ast_tvnow(); - while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) { - res = ast_waitfor(chan, -1); - if (res < 0) { - ast_closestream(fs); - fdprintf(agi->fd, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset); - if (sildet) - ast_dsp_free(sildet); - return RESULT_FAILURE; - } - f = ast_read(chan); - if (!f) { - fdprintf(agi->fd, "200 result=%d (hangup) endpos=%ld\n", 0, sample_offset); - ast_closestream(fs); - if (sildet) - ast_dsp_free(sildet); - return RESULT_FAILURE; - } - switch(f->frametype) { - case AST_FRAME_DTMF: - if (strchr(argv[4], f->subclass)) { - /* This is an interrupting chracter, so rewind to chop off any small - amount of DTMF that may have been recorded - */ - ast_stream_rewind(fs, 200); - ast_truncstream(fs); - sample_offset = ast_tellstream(fs); - fdprintf(agi->fd, "200 result=%d (dtmf) endpos=%ld\n", f->subclass, sample_offset); - ast_closestream(fs); - ast_frfree(f); - if (sildet) - ast_dsp_free(sildet); - return RESULT_SUCCESS; - } - break; - case AST_FRAME_VOICE: - ast_writestream(fs, f); - /* this is a safe place to check progress since we know that fs - * is valid after a write, and it will then have our current - * location */ - sample_offset = ast_tellstream(fs); - if (silence > 0) { - dspsilence = 0; - ast_dsp_silence(sildet, f, &dspsilence); - if (dspsilence) { - totalsilence = dspsilence; - } else { - totalsilence = 0; - } - if (totalsilence > silence) { - /* Ended happily with silence */ - ast_frfree(f); - gotsilence = 1; - break; - } - } - break; - } - ast_frfree(f); - if (gotsilence) - break; - } - - if (gotsilence) { - ast_stream_rewind(fs, silence-1000); - ast_truncstream(fs); - sample_offset = ast_tellstream(fs); - } - fdprintf(agi->fd, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset); - ast_closestream(fs); - } - - if (silence > 0) { - res = ast_set_read_format(chan, rfmt); - if (res) - ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); - ast_dsp_free(sildet); - } - return RESULT_SUCCESS; -} - -static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - int timeout; - - if (argc != 3) - return RESULT_SHOWUSAGE; - if (sscanf(argv[2], "%d", &timeout) != 1) - return RESULT_SHOWUSAGE; - if (timeout < 0) - timeout = 0; - if (timeout) - chan->whentohangup = time(NULL) + timeout; - else - chan->whentohangup = 0; - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - struct ast_channel *c; - if (argc == 1) { - /* no argument: hangup the current channel */ - ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT); - fdprintf(agi->fd, "200 result=1\n"); - return RESULT_SUCCESS; - } else if (argc == 2) { - /* one argument: look for info on the specified channel */ - c = ast_get_channel_by_name_locked(argv[1]); - if (c) { - /* we have a matching channel */ - ast_softhangup(c,AST_SOFTHANGUP_EXPLICIT); - fdprintf(agi->fd, "200 result=1\n"); - ast_mutex_unlock(&c->lock); - return RESULT_SUCCESS; - } - /* if we get this far no channel name matched the argument given */ - fdprintf(agi->fd, "200 result=-1\n"); - return RESULT_SUCCESS; - } else { - return RESULT_SHOWUSAGE; - } -} - -static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int res; - struct ast_app *app; - - if (argc < 2) - return RESULT_SHOWUSAGE; - - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argv[2]); - - app = pbx_findapp(argv[1]); - - if (app) { - res = pbx_exec(chan, app, argv[2], 1); - } else { - ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]); - res = -2; - } - fdprintf(agi->fd, "200 result=%d\n", res); - - return res; -} - -static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - char tmp[256]=""; - char *l = NULL, *n = NULL; - - if (argv[2]) { - ast_copy_string(tmp, argv[2], sizeof(tmp)); - ast_callerid_parse(tmp, &n, &l); - if (l) - ast_shrink_phone_number(l); - else - l = ""; - if (!n) - n = ""; - ast_set_callerid(chan, l, n, NULL); - } - - fdprintf(agi->fd, "200 result=1\n"); - return RESULT_SUCCESS; -} - -static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - struct ast_channel *c; - if (argc == 2) { - /* no argument: supply info on the current channel */ - fdprintf(agi->fd, "200 result=%d\n", chan->_state); - return RESULT_SUCCESS; - } else if (argc == 3) { - /* one argument: look for info on the specified channel */ - c = ast_get_channel_by_name_locked(argv[2]); - if (c) { - fdprintf(agi->fd, "200 result=%d\n", c->_state); - ast_mutex_unlock(&c->lock); - return RESULT_SUCCESS; - } - /* if we get this far no channel name matched the argument given */ - fdprintf(agi->fd, "200 result=-1\n"); - return RESULT_SUCCESS; - } else { - return RESULT_SHOWUSAGE; - } -} - -static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - if (argv[3]) - pbx_builtin_setvar_helper(chan, argv[2], argv[3]); - - fdprintf(agi->fd, "200 result=1\n"); - return RESULT_SUCCESS; -} - -static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - char *ret; - char tempstr[1024]; - - if (argc != 3) - return RESULT_SHOWUSAGE; - - /* check if we want to execute an ast_custom_function */ - if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) { - ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)); - } else { - pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL); - } - - if (ret) - fdprintf(agi->fd, "200 result=1 (%s)\n", ret); - else - fdprintf(agi->fd, "200 result=0\n"); - - return RESULT_SUCCESS; -} - -static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - char tmp[4096] = ""; - struct ast_channel *chan2=NULL; - - if ((argc != 4) && (argc != 5)) - return RESULT_SHOWUSAGE; - if (argc == 5) { - chan2 = ast_get_channel_by_name_locked(argv[4]); - } else { - chan2 = chan; - } - if (chan) { /* XXX isn't this chan2 ? */ - pbx_substitute_variables_helper(chan2, argv[3], tmp, sizeof(tmp) - 1); - fdprintf(agi->fd, "200 result=1 (%s)\n", tmp); - } else { - fdprintf(agi->fd, "200 result=0\n"); - } - if (chan2 && (chan2 != chan)) - ast_mutex_unlock(&chan2->lock); - return RESULT_SUCCESS; -} - -static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int level = 0; - char *prefix; - - if (argc < 2) - return RESULT_SHOWUSAGE; - - if (argv[2]) - sscanf(argv[2], "%d", &level); - - switch (level) { - case 4: - prefix = VERBOSE_PREFIX_4; - break; - case 3: - prefix = VERBOSE_PREFIX_3; - break; - case 2: - prefix = VERBOSE_PREFIX_2; - break; - case 1: - default: - prefix = VERBOSE_PREFIX_1; - break; - } - - if (level <= option_verbose) - ast_verbose("%s %s: %s\n", prefix, chan->data, argv[1]); - - fdprintf(agi->fd, "200 result=1\n"); - - return RESULT_SUCCESS; -} - -static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int res; - char tmp[256]; - - if (argc != 4) - return RESULT_SHOWUSAGE; - res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp)); - if (res) - fdprintf(agi->fd, "200 result=0\n"); - else - fdprintf(agi->fd, "200 result=1 (%s)\n", tmp); - - return RESULT_SUCCESS; -} - -static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int res; - - if (argc != 5) - return RESULT_SHOWUSAGE; - res = ast_db_put(argv[2], argv[3], argv[4]); - if (res) - fdprintf(agi->fd, "200 result=0\n"); - else - fdprintf(agi->fd, "200 result=1\n"); - - return RESULT_SUCCESS; -} - -static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int res; - - if (argc != 4) - return RESULT_SHOWUSAGE; - res = ast_db_del(argv[2], argv[3]); - if (res) - fdprintf(agi->fd, "200 result=0\n"); - else - fdprintf(agi->fd, "200 result=1\n"); - - return RESULT_SUCCESS; -} - -static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, char **argv) -{ - int res; - if ((argc < 3) || (argc > 4)) - return RESULT_SHOWUSAGE; - if (argc == 4) - res = ast_db_deltree(argv[2], argv[3]); - else - res = ast_db_deltree(argv[2], NULL); - - if (res) - fdprintf(agi->fd, "200 result=0\n"); - else - fdprintf(agi->fd, "200 result=1\n"); - return RESULT_SUCCESS; -} - -static char debug_usage[] = -"Usage: agi debug\n" -" Enables dumping of AGI transactions for debugging purposes\n"; - -static char no_debug_usage[] = -"Usage: agi no debug\n" -" Disables dumping of AGI transactions for debugging purposes\n"; - -static int agi_do_debug(int fd, int argc, char *argv[]) -{ - if (argc != 2) - return RESULT_SHOWUSAGE; - agidebug = 1; - ast_cli(fd, "AGI Debugging Enabled\n"); - return RESULT_SUCCESS; -} - -static int agi_no_debug(int fd, int argc, char *argv[]) -{ - if (argc != 3) - return RESULT_SHOWUSAGE; - agidebug = 0; - ast_cli(fd, "AGI Debugging Disabled\n"); - return RESULT_SUCCESS; -} - -static struct ast_cli_entry cli_debug = - { { "agi", "debug", NULL }, agi_do_debug, "Enable AGI debugging", debug_usage }; - -static struct ast_cli_entry cli_no_debug = - { { "agi", "no", "debug", NULL }, agi_no_debug, "Disable AGI debugging", no_debug_usage }; - -static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, char *argv[]) -{ - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, char *argv[]) -{ - if (!strncasecmp(argv[2],"on",2)) { - if (argc > 3) - ast_moh_start(chan, argv[3]); - else - ast_moh_start(chan, NULL); - } - if (!strncasecmp(argv[2],"off",3)) { - ast_moh_stop(chan); - } - fdprintf(agi->fd, "200 result=0\n"); - return RESULT_SUCCESS; -} - -static char usage_setmusic[] = -" Usage: SET MUSIC ON <on|off> <class>\n" -" Enables/Disables the music on hold generator. If <class> is\n" -" not specified, then the default music on hold class will be used.\n" -" Always returns 0.\n"; - -static char usage_dbput[] = -" Usage: DATABASE PUT <family> <key> <value>\n" -" Adds or updates an entry in the Asterisk database for a\n" -" given family, key, and value.\n" -" Returns 1 if successful, 0 otherwise.\n"; - -static char usage_dbget[] = -" Usage: DATABASE GET <family> <key>\n" -" Retrieves an entry in the Asterisk database for a\n" -" given family and key.\n" -" Returns 0 if <key> is not set. Returns 1 if <key>\n" -" is set and returns the variable in parentheses.\n" -" Example return code: 200 result=1 (testvariable)\n"; - -static char usage_dbdel[] = -" Usage: DATABASE DEL <family> <key>\n" -" Deletes an entry in the Asterisk database for a\n" -" given family and key.\n" -" Returns 1 if successful, 0 otherwise.\n"; - -static char usage_dbdeltree[] = -" Usage: DATABASE DELTREE <family> [keytree]\n" -" Deletes a family or specific keytree within a family\n" -" in the Asterisk database.\n" -" Returns 1 if successful, 0 otherwise.\n"; - -static char usage_verbose[] = -" Usage: VERBOSE <message> <level>\n" -" Sends <message> to the console via verbose message system.\n" -" <level> is the the verbose level (1-4)\n" -" Always returns 1.\n"; - -static char usage_getvariable[] = -" Usage: GET VARIABLE <variablename>\n" -" Returns 0 if <variablename> is not set. Returns 1 if <variablename>\n" -" is set and returns the variable in parentheses.\n" -" example return code: 200 result=1 (testvariable)\n"; - -static char usage_getvariablefull[] = -" Usage: GET FULL VARIABLE <variablename> [<channel name>]\n" -" Returns 0 if <variablename> is not set or channel does not exist. Returns 1\n" -"if <variablename> is set and returns the variable in parenthesis. Understands\n" -"complex variable names and builtin variables, unlike GET VARIABLE.\n" -" example return code: 200 result=1 (testvariable)\n"; - -static char usage_setvariable[] = -" Usage: SET VARIABLE <variablename> <value>\n"; - -static char usage_channelstatus[] = -" Usage: CHANNEL STATUS [<channelname>]\n" -" Returns the status of the specified channel.\n" -" If no channel name is given the returns the status of the\n" -" current channel. Return values:\n" -" 0 Channel is down and available\n" -" 1 Channel is down, but reserved\n" -" 2 Channel is off hook\n" -" 3 Digits (or equivalent) have been dialed\n" -" 4 Line is ringing\n" -" 5 Remote end is ringing\n" -" 6 Line is up\n" -" 7 Line is busy\n"; - -static char usage_setcallerid[] = -" Usage: SET CALLERID <number>\n" -" Changes the callerid of the current channel.\n"; - -static char usage_exec[] = -" Usage: EXEC <application> <options>\n" -" Executes <application> with given <options>.\n" -" Returns whatever the application returns, or -2 on failure to find application\n"; - -static char usage_hangup[] = -" Usage: HANGUP [<channelname>]\n" -" Hangs up the specified channel.\n" -" If no channel name is given, hangs up the current channel\n"; - -static char usage_answer[] = -" Usage: ANSWER\n" -" Answers channel if not already in answer state. Returns -1 on\n" -" channel failure, or 0 if successful.\n"; - -static char usage_waitfordigit[] = -" Usage: WAIT FOR DIGIT <timeout>\n" -" Waits up to 'timeout' milliseconds for channel to receive a DTMF digit.\n" -" Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n" -" the numerical value of the ascii of the digit if one is received. Use -1\n" -" for the timeout value if you desire the call to block indefinitely.\n"; - -static char usage_sendtext[] = -" Usage: SEND TEXT \"<text to send>\"\n" -" Sends the given text on a channel. Most channels do not support the\n" -" transmission of text. Returns 0 if text is sent, or if the channel does not\n" -" support text transmission. Returns -1 only on error/hangup. Text\n" -" consisting of greater than one word should be placed in quotes since the\n" -" command only accepts a single argument.\n"; - -static char usage_recvchar[] = -" Usage: RECEIVE CHAR <timeout>\n" -" Receives a character of text on a channel. Specify timeout to be the\n" -" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n" -" do not support the reception of text. Returns the decimal value of the character\n" -" if one is received, or 0 if the channel does not support text reception. Returns\n" -" -1 only on error/hangup.\n"; - -static char usage_recvtext[] = -" Usage: RECEIVE TEXT <timeout>\n" -" Receives a string of text on a channel. Specify timeout to be the\n" -" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n" -" do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses.\n"; - -static char usage_tddmode[] = -" Usage: TDD MODE <on|off>\n" -" Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n" -" successful, or 0 if channel is not TDD-capable.\n"; - -static char usage_sendimage[] = -" Usage: SEND IMAGE <image>\n" -" Sends the given image on a channel. Most channels do not support the\n" -" transmission of images. Returns 0 if image is sent, or if the channel does not\n" -" support image transmission. Returns -1 only on error/hangup. Image names\n" -" should not include extensions.\n"; - -static char usage_streamfile[] = -" Usage: STREAM FILE <filename> <escape digits> [sample offset]\n" -" Send the given file, allowing playback to be interrupted by the given\n" -" digits, if any. Use double quotes for the digits if you wish none to be\n" -" permitted. If sample offset is provided then the audio will seek to sample\n" -" offset before play starts. Returns 0 if playback completes without a digit\n" -" being pressed, or the ASCII numerical value of the digit if one was pressed,\n" -" or -1 on error or if the channel was disconnected. Remember, the file\n" -" extension must not be included in the filename.\n"; - -static char usage_controlstreamfile[] = -" Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr]\n" -" Send the given file, allowing playback to be controled by the given\n" -" digits, if any. Use double quotes for the digits if you wish none to be\n" -" permitted. Returns 0 if playback completes without a digit\n" -" being pressed, or the ASCII numerical value of the digit if one was pressed,\n" -" or -1 on error or if the channel was disconnected. Remember, the file\n" -" extension must not be included in the filename.\n\n" -" Note: ffchar and rewchar default to * and # respectively.\n"; - -static char usage_getoption[] = -" Usage: GET OPTION <filename> <escape_digits> [timeout]\n" -" Behaves similar to STREAM FILE but used with a timeout option.\n"; - -static char usage_saynumber[] = -" Usage: SAY NUMBER <number> <escape digits>\n" -" Say a given number, returning early if any of the given DTMF digits\n" -" are received on the channel. Returns 0 if playback completes without a digit\n" -" being pressed, or the ASCII numerical value of the digit if one was pressed or\n" -" -1 on error/hangup.\n"; - -static char usage_saydigits[] = -" Usage: SAY DIGITS <number> <escape digits>\n" -" Say a given digit string, returning early if any of the given DTMF digits\n" -" are received on the channel. Returns 0 if playback completes without a digit\n" -" being pressed, or the ASCII numerical value of the digit if one was pressed or\n" -" -1 on error/hangup.\n"; - -static char usage_sayalpha[] = -" Usage: SAY ALPHA <number> <escape digits>\n" -" Say a given character string, returning early if any of the given DTMF digits\n" -" are received on the channel. Returns 0 if playback completes without a digit\n" -" being pressed, or the ASCII numerical value of the digit if one was pressed or\n" -" -1 on error/hangup.\n"; - -static char usage_saydate[] = -" Usage: SAY DATE <date> <escape digits>\n" -" Say a given date, returning early if any of the given DTMF digits are\n" -" received on the channel. <date> is number of seconds elapsed since 00:00:00\n" -" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n" -" completes without a digit being pressed, or the ASCII numerical value of the\n" -" digit if one was pressed or -1 on error/hangup.\n"; - -static char usage_saytime[] = -" Usage: SAY TIME <time> <escape digits>\n" -" Say a given time, returning early if any of the given DTMF digits are\n" -" received on the channel. <time> is number of seconds elapsed since 00:00:00\n" -" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback\n" -" completes without a digit being pressed, or the ASCII numerical value of the\n" -" digit if one was pressed or -1 on error/hangup.\n"; - -static char usage_saydatetime[] = -" Usage: SAY DATETIME <time> <escape digits> [format] [timezone]\n" -" Say a given time, returning early if any of the given DTMF digits are\n" -" received on the channel. <time> is number of seconds elapsed since 00:00:00\n" -" on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format\n" -" the time should be said in. See voicemail.conf (defaults to \"ABdY\n" -" 'digits/at' IMp\"). Acceptable values for [timezone] can be found in\n" -" /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback\n" -" completes without a digit being pressed, or the ASCII numerical value of the\n" -" digit if one was pressed or -1 on error/hangup.\n"; - -static char usage_sayphonetic[] = -" Usage: SAY PHONETIC <string> <escape digits>\n" -" Say a given character string with phonetics, returning early if any of the\n" -" given DTMF digits are received on the channel. Returns 0 if playback\n" -" completes without a digit pressed, the ASCII numerical value of the digit\n" -" if one was pressed, or -1 on error/hangup.\n"; - -static char usage_getdata[] = -" Usage: GET DATA <file to be streamed> [timeout] [max digits]\n" -" Stream the given file, and recieve DTMF data. Returns the digits received\n" -"from the channel at the other end.\n"; - -static char usage_setcontext[] = -" Usage: SET CONTEXT <desired context>\n" -" Sets the context for continuation upon exiting the application.\n"; - -static char usage_setextension[] = -" Usage: SET EXTENSION <new extension>\n" -" Changes the extension for continuation upon exiting the application.\n"; - -static char usage_setpriority[] = -" Usage: SET PRIORITY <priority>\n" -" Changes the priority for continuation upon exiting the application.\n" -" The priority must be a valid priority or label.\n"; - -static char usage_recordfile[] = -" Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\\n" -" [offset samples] [BEEP] [s=silence]\n" -" Record to a file until a given dtmf digit in the sequence is received\n" -" Returns -1 on hangup or error. The format will specify what kind of file\n" -" will be recorded. The timeout is the maximum record time in milliseconds, or\n" -" -1 for no timeout. \"Offset samples\" is optional, and, if provided, will seek\n" -" to the offset without exceeding the end of the file. \"silence\" is the number\n" -" of seconds of silence allowed before the function returns despite the\n" -" lack of dtmf digits or reaching timeout. Silence value must be\n" -" preceeded by \"s=\" and is also optional.\n"; - -static char usage_autohangup[] = -" Usage: SET AUTOHANGUP <time>\n" -" Cause the channel to automatically hangup at <time> seconds in the\n" -" future. Of course it can be hungup before then as well. Setting to 0 will\n" -" cause the autohangup feature to be disabled on this channel.\n"; - -static char usage_noop[] = -" Usage: NoOp\n" -" Does nothing.\n"; - -static agi_command commands[MAX_COMMANDS] = { - { { "answer", NULL }, handle_answer, "Answer channel", usage_answer }, - { { "channel", "status", NULL }, handle_channelstatus, "Returns status of the connected channel", usage_channelstatus }, - { { "database", "del", NULL }, handle_dbdel, "Removes database key/value", usage_dbdel }, - { { "database", "deltree", NULL }, handle_dbdeltree, "Removes database keytree/value", usage_dbdeltree }, - { { "database", "get", NULL }, handle_dbget, "Gets database value", usage_dbget }, - { { "database", "put", NULL }, handle_dbput, "Adds/updates database value", usage_dbput }, - { { "exec", NULL }, handle_exec, "Executes a given Application", usage_exec }, - { { "get", "data", NULL }, handle_getdata, "Prompts for DTMF on a channel", usage_getdata }, - { { "get", "full", "variable", NULL }, handle_getvariablefull, "Evaluates a channel expression", usage_getvariablefull }, - { { "get", "option", NULL }, handle_getoption, "Stream file, prompt for DTMF, with timeout", usage_getoption }, - { { "get", "variable", NULL }, handle_getvariable, "Gets a channel variable", usage_getvariable }, - { { "hangup", NULL }, handle_hangup, "Hangup the current channel", usage_hangup }, - { { "noop", NULL }, handle_noop, "Does nothing", usage_noop }, - { { "receive", "char", NULL }, handle_recvchar, "Receives one character from channels supporting it", usage_recvchar }, - { { "receive", "text", NULL }, handle_recvtext, "Receives text from channels supporting it", usage_recvtext }, - { { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile }, - { { "say", "alpha", NULL }, handle_sayalpha, "Says a given character string", usage_sayalpha }, - { { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits }, - { { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber }, - { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic }, - { { "say", "date", NULL }, handle_saydate, "Says a given date", usage_saydate }, - { { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime }, - { { "say", "datetime", NULL }, handle_saydatetime, "Says a given time as specfied by the format given", usage_saydatetime }, - { { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage }, - { { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext }, - { { "set", "autohangup", NULL }, handle_autohangup, "Autohangup channel in some time", usage_autohangup }, - { { "set", "callerid", NULL }, handle_setcallerid, "Sets callerid for the current channel", usage_setcallerid }, - { { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext }, - { { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension }, - { { "set", "music", NULL }, handle_setmusic, "Enable/Disable Music on hold generator", usage_setmusic }, - { { "set", "priority", NULL }, handle_setpriority, "Set channel dialplan priority", usage_setpriority }, - { { "set", "variable", NULL }, handle_setvariable, "Sets a channel variable", usage_setvariable }, - { { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile }, - { { "control", "stream", "file", NULL }, handle_controlstreamfile, "Sends audio file on channel and allows the listner to control the stream", usage_controlstreamfile }, - { { "tdd", "mode", NULL }, handle_tddmode, "Toggles TDD mode (for the deaf)", usage_tddmode }, - { { "verbose", NULL }, handle_verbose, "Logs a message to the asterisk verbose log", usage_verbose }, - { { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit }, -}; - -static void join(char *s, size_t len, char *w[]) -{ - int x; - - /* Join words into a string */ - if (!s) { - return; - } - s[0] = '\0'; - for (x=0; w[x]; x++) { - if (x) - strncat(s, " ", len - strlen(s) - 1); - strncat(s, w[x], len - strlen(s) - 1); - } -} - -static int help_workhorse(int fd, char *match[]) -{ - char fullcmd[80]; - char matchstr[80]; - int x; - struct agi_command *e; - if (match) - join(matchstr, sizeof(matchstr), match); - for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { - if (!commands[x].cmda[0]) break; - e = &commands[x]; - if (e) - join(fullcmd, sizeof(fullcmd), e->cmda); - /* Hide commands that start with '_' */ - if (fullcmd[0] == '_') - continue; - if (match) { - if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) { - continue; - } - } - ast_cli(fd, "%20.20s %s\n", fullcmd, e->summary); - } - return 0; -} - -int agi_register(agi_command *agi) -{ - int x; - for (x=0; x<MAX_COMMANDS - 1; x++) { - if (commands[x].cmda[0] == agi->cmda[0]) { - ast_log(LOG_WARNING, "Command already registered!\n"); - return -1; - } - } - for (x=0; x<MAX_COMMANDS - 1; x++) { - if (!commands[x].cmda[0]) { - commands[x] = *agi; - return 0; - } - } - ast_log(LOG_WARNING, "No more room for new commands!\n"); - return -1; -} - -void agi_unregister(agi_command *agi) -{ - int x; - for (x=0; x<MAX_COMMANDS - 1; x++) { - if (commands[x].cmda[0] == agi->cmda[0]) { - memset(&commands[x], 0, sizeof(agi_command)); - } - } -} - -static agi_command *find_command(char *cmds[], int exact) -{ - int x; - int y; - int match; - - for (x=0; x < sizeof(commands) / sizeof(commands[0]); x++) { - if (!commands[x].cmda[0]) - break; - /* start optimistic */ - match = 1; - for (y=0; match && cmds[y]; y++) { - /* If there are no more words in the command (and we're looking for - an exact match) or there is a difference between the two words, - then this is not a match */ - if (!commands[x].cmda[y] && !exact) - break; - /* don't segfault if the next part of a command doesn't exist */ - if (!commands[x].cmda[y]) - return NULL; - if (strcasecmp(commands[x].cmda[y], cmds[y])) - match = 0; - } - /* If more words are needed to complete the command then this is not - a candidate (unless we're looking for a really inexact answer */ - if ((exact > -1) && commands[x].cmda[y]) - match = 0; - if (match) - return &commands[x]; - } - return NULL; -} - - -static int parse_args(char *s, int *max, char *argv[]) -{ - int x=0; - int quoted=0; - int escaped=0; - int whitespace=1; - char *cur; - - cur = s; - while(*s) { - switch(*s) { - case '"': - /* If it's escaped, put a literal quote */ - if (escaped) - goto normal; - else - quoted = !quoted; - if (quoted && whitespace) { - /* If we're starting a quote, coming off white space start a new word, too */ - argv[x++] = cur; - whitespace=0; - } - escaped = 0; - break; - case ' ': - case '\t': - if (!quoted && !escaped) { - /* If we're not quoted, mark this as whitespace, and - end the previous argument */ - whitespace = 1; - *(cur++) = '\0'; - } else - /* Otherwise, just treat it as anything else */ - goto normal; - break; - case '\\': - /* If we're escaped, print a literal, otherwise enable escaping */ - if (escaped) { - goto normal; - } else { - escaped=1; - } - break; - default: -normal: - if (whitespace) { - if (x >= MAX_ARGS -1) { - ast_log(LOG_WARNING, "Too many arguments, truncating\n"); - break; - } - /* Coming off of whitespace, start the next argument */ - argv[x++] = cur; - whitespace=0; - } - *(cur++) = *s; - escaped=0; - } - s++; - } - /* Null terminate */ - *(cur++) = '\0'; - argv[x] = NULL; - *max = x; - return 0; -} - -static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf) -{ - char *argv[MAX_ARGS]; - int argc = 0; - int res; - agi_command *c; - argc = MAX_ARGS; - - parse_args(buf, &argc, argv); -#if 0 - { int x; - for (x=0; x<argc; x++) - fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); } -#endif - c = find_command(argv, 0); - if (c) { - res = c->handler(chan, agi, argc, argv); - switch(res) { - case RESULT_SHOWUSAGE: - fdprintf(agi->fd, "520-Invalid command syntax. Proper usage follows:\n"); - fdprintf(agi->fd, c->usage); - fdprintf(agi->fd, "520 End of proper usage.\n"); - break; - case AST_PBX_KEEPALIVE: - /* We've been asked to keep alive, so do so */ - return AST_PBX_KEEPALIVE; - break; - case RESULT_FAILURE: - /* They've already given the failure. We've been hung up on so handle this - appropriately */ - return -1; - } - } else { - fdprintf(agi->fd, "510 Invalid or unknown command\n"); - } - return 0; -} -#define RETRY 3 -static int run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead) -{ - struct ast_channel *c; - int outfd; - int ms; - int returnstatus = 0; - struct ast_frame *f; - char buf[2048]; - FILE *readf; - /* how many times we'll retry if ast_waitfor_nandfs will return without either - channel or file descriptor in case select is interrupted by a system call (EINTR) */ - int retry = RETRY; - - if (!(readf = fdopen(agi->ctrl, "r"))) { - ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n"); - if (pid > -1) - kill(pid, SIGHUP); - close(agi->ctrl); - return -1; - } - setlinebuf(readf); - setup_env(chan, request, agi->fd, (agi->audio > -1)); - for (;;) { - ms = -1; - c = ast_waitfor_nandfds(&chan, dead ? 0 : 1, &agi->ctrl, 1, NULL, &outfd, &ms); - if (c) { - retry = RETRY; - /* Idle the channel until we get a command */ - f = ast_read(c); - if (!f) { - ast_log(LOG_DEBUG, "%s hungup\n", chan->name); - returnstatus = -1; - break; - } else { - /* If it's voice, write it to the audio pipe */ - if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) { - /* Write, ignoring errors */ - write(agi->audio, f->data, f->datalen); - } - ast_frfree(f); - } - } else if (outfd > -1) { - retry = RETRY; - if (!fgets(buf, sizeof(buf), readf)) { - /* Program terminated */ - if (returnstatus) - returnstatus = -1; - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus); - /* No need to kill the pid anymore, since they closed us */ - pid = -1; - break; - } - /* get rid of trailing newline, if any */ - if (*buf && buf[strlen(buf) - 1] == '\n') - buf[strlen(buf) - 1] = 0; - if (agidebug) - ast_verbose("AGI Rx << %s\n", buf); - returnstatus |= agi_handle_command(chan, agi, buf); - /* If the handle_command returns -1, we need to stop */ - if ((returnstatus < 0) || (returnstatus == AST_PBX_KEEPALIVE)) { - break; - } - } else { - if (--retry <= 0) { - ast_log(LOG_WARNING, "No channel, no fd?\n"); - returnstatus = -1; - break; - } - } - } - /* Notify process */ - if (pid > -1) { - if (kill(pid, SIGHUP)) - ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno)); - } - fclose(readf); - return returnstatus; -} - -static int handle_showagi(int fd, int argc, char *argv[]) { - struct agi_command *e; - char fullcmd[80]; - if ((argc < 2)) - return RESULT_SHOWUSAGE; - if (argc > 2) { - e = find_command(argv + 2, 1); - if (e) - ast_cli(fd, e->usage); - else { - if (find_command(argv + 2, -1)) { - return help_workhorse(fd, argv + 1); - } else { - join(fullcmd, sizeof(fullcmd), argv+1); - ast_cli(fd, "No such command '%s'.\n", fullcmd); - } - } - } else { - return help_workhorse(fd, NULL); - } - return RESULT_SUCCESS; -} - -static int handle_dumpagihtml(int fd, int argc, char *argv[]) { - struct agi_command *e; - char fullcmd[80]; - char *tempstr; - int x; - FILE *htmlfile; - - if ((argc < 3)) - return RESULT_SHOWUSAGE; - - if (!(htmlfile = fopen(argv[2], "wt"))) { - ast_cli(fd, "Could not create file '%s'\n", argv[2]); - return RESULT_SHOWUSAGE; - } - - fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n"); - fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n"); - - - fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n"); - - for (x=0;x<sizeof(commands)/sizeof(commands[0]);x++) { - char *stringp=NULL; - if (!commands[x].cmda[0]) break; - e = &commands[x]; - if (e) - join(fullcmd, sizeof(fullcmd), e->cmda); - /* Hide commands that start with '_' */ - if (fullcmd[0] == '_') - continue; - - fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n"); - fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TD></TR>\n", fullcmd,e->summary); - - - stringp=e->usage; - tempstr = strsep(&stringp, "\n"); - - fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">%s</TD></TR>\n", tempstr); - - fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n"); - while ((tempstr = strsep(&stringp, "\n")) != NULL) { - fprintf(htmlfile, "%s<BR>\n",tempstr); - - } - fprintf(htmlfile, "</TD></TR>\n"); - fprintf(htmlfile, "</TABLE></TD></TR>\n\n"); - - } - - fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n"); - fclose(htmlfile); - ast_cli(fd, "AGI HTML Commands Dumped to: %s\n", argv[2]); - return RESULT_SUCCESS; -} - -static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int dead) -{ - int res=0; - struct localuser *u; - char *argv[MAX_ARGS]; - char buf[2048]=""; - char *tmp = (char *)buf; - int argc = 0; - int fds[2]; - int efd = -1; - int pid; - char *stringp; - AGI agi; - - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "AGI requires an argument (script)\n"); - return -1; - } - ast_copy_string(buf, data, sizeof(buf)); - - memset(&agi, 0, sizeof(agi)); - while ((stringp = strsep(&tmp, "|")) && argc < MAX_ARGS - 1) - argv[argc++] = stringp; - argv[argc] = NULL; - - LOCAL_USER_ADD(u); -#if 0 - /* Answer if need be */ - if (chan->_state != AST_STATE_UP) { - if (ast_answer(chan)) { - LOCAL_USER_REMOVE(u); - return -1; - } - } -#endif - res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid); - if (!res) { - agi.fd = fds[1]; - agi.ctrl = fds[0]; - agi.audio = efd; - res = run_agi(chan, argv[0], &agi, pid, dead); - close(fds[1]); - if (efd > -1) - close(efd); - } - LOCAL_USER_REMOVE(u); - return res; -} - -static int agi_exec(struct ast_channel *chan, void *data) -{ - if (chan->_softhangup) - ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); - return agi_exec_full(chan, data, 0, 0); -} - -static int eagi_exec(struct ast_channel *chan, void *data) -{ - int readformat; - int res; - - if (chan->_softhangup) - ast_log(LOG_WARNING, "If you want to run AGI on hungup channels you should use DeadAGI!\n"); - readformat = chan->readformat; - if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) { - ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name); - return -1; - } - res = agi_exec_full(chan, data, 1, 0); - if (!res) { - if (ast_set_read_format(chan, readformat)) { - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat)); - } - } - return res; -} - -static int deadagi_exec(struct ast_channel *chan, void *data) -{ - return agi_exec_full(chan, data, 0, 1); -} - -static char showagi_help[] = -"Usage: show agi [topic]\n" -" When called with a topic as an argument, displays usage\n" -" information on the given command. If called without a\n" -" topic, it provides a list of AGI commands.\n"; - - -static char dumpagihtml_help[] = -"Usage: dump agihtml <filename>\n" -" Dumps the agi command list in html format to given filename\n"; - -static struct ast_cli_entry showagi = -{ { "show", "agi", NULL }, handle_showagi, "Show AGI commands or specific help", showagi_help }; - -static struct ast_cli_entry dumpagihtml = -{ { "dump", "agihtml", NULL }, handle_dumpagihtml, "Dumps a list of agi command in html format", dumpagihtml_help }; - -int unload_module(void) -{ - STANDARD_HANGUP_LOCALUSERS; - ast_cli_unregister(&showagi); - ast_cli_unregister(&dumpagihtml); - ast_cli_unregister(&cli_debug); - ast_cli_unregister(&cli_no_debug); - ast_unregister_application(eapp); - ast_unregister_application(deadapp); - return ast_unregister_application(app); -} - -int load_module(void) -{ - ast_cli_register(&showagi); - ast_cli_register(&dumpagihtml); - ast_cli_register(&cli_debug); - ast_cli_register(&cli_no_debug); - ast_register_application(deadapp, deadagi_exec, deadsynopsis, descrip); - ast_register_application(eapp, eagi_exec, esynopsis, descrip); - return ast_register_application(app, agi_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/1.2-netsec/res/res_config_odbc.c b/1.2-netsec/res/res_config_odbc.c deleted file mode 100644 index e10f4ff7f..000000000 --- a/1.2-netsec/res/res_config_odbc.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief odbc+odbc plugin for portable configuration engine - * - * http://www.unixodbc.org - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/config.h" -#include "asterisk/module.h" -#include "asterisk/lock.h" -#include "asterisk/options.h" -#include "asterisk/res_odbc.h" -#include "asterisk/utils.h" - -static char *tdesc = "ODBC Configuration"; -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap) -{ - odbc_obj *obj; - SQLHSTMT stmt; - char sql[1024]; - char coltitle[256]; - char rowdata[2048]; - char *op; - const char *newparam, *newval; - char *stringp; - char *chunk; - SQLSMALLINT collen; - int res; - int x; - struct ast_variable *var=NULL, *prev=NULL; - SQLULEN colsize; - SQLSMALLINT colcount=0; - SQLSMALLINT datatype; - SQLSMALLINT decimaldigits; - SQLSMALLINT nullable; - SQLINTEGER indicator; - va_list aq; - - va_copy(aq, ap); - - - if (!table) - return NULL; - - obj = fetch_odbc_obj(database, 0); - if (!obj) - return NULL; - - res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); - return NULL; - } - - newparam = va_arg(aq, const char *); - if (!newparam) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - newval = va_arg(aq, const char *); - if (!strchr(newparam, ' ')) op = " ="; else op = ""; - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op); - while((newparam = va_arg(aq, const char *))) { - if (!strchr(newparam, ' ')) op = " ="; else op = ""; - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op); - newval = va_arg(aq, const char *); - } - va_end(aq); - res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - /* Now bind the parameters */ - x = 1; - - while((newparam = va_arg(ap, const char *))) { - newval = va_arg(ap, const char *); - SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); - } - - res = odbc_smart_execute(obj, stmt); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - res = SQLNumResultCols(stmt, &colcount); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - res = SQLFetch(stmt); - if (res == SQL_NO_DATA) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - for (x=0;x<colcount;x++) { - rowdata[0] = '\0'; - collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, - &datatype, &colsize, &decimaldigits, &nullable); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); - if (var) - ast_variables_destroy(var); - return NULL; - } - - indicator = 0; - res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator); - if (indicator == SQL_NULL_DATA) - continue; - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - if (var) - ast_variables_destroy(var); - return NULL; - } - stringp = rowdata; - while(stringp) { - chunk = strsep(&stringp, ";"); - if (!ast_strlen_zero(ast_strip(chunk))) { - if (prev) { - prev->next = ast_variable_new(coltitle, chunk); - if (prev->next) - prev = prev->next; - } else - prev = var = ast_variable_new(coltitle, chunk); - - } - } - } - - - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return var; -} - -static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap) -{ - odbc_obj *obj; - SQLHSTMT stmt; - char sql[1024]; - char coltitle[256]; - char rowdata[2048]; - const char *initfield=NULL; - char *op; - const char *newparam, *newval; - char *stringp; - char *chunk; - SQLSMALLINT collen; - int res; - int x; - struct ast_variable *var=NULL; - struct ast_config *cfg=NULL; - struct ast_category *cat=NULL; - struct ast_realloca ra; - SQLULEN colsize; - SQLSMALLINT colcount=0; - SQLSMALLINT datatype; - SQLSMALLINT decimaldigits; - SQLSMALLINT nullable; - SQLINTEGER indicator; - - va_list aq; - va_copy(aq, ap); - - - if (!table) - return NULL; - memset(&ra, 0, sizeof(ra)); - - obj = fetch_odbc_obj(database, 0); - if (!obj) - return NULL; - - res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); - return NULL; - } - - newparam = va_arg(aq, const char *); - if (!newparam) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - initfield = ast_strdupa(newparam); - if (initfield && (op = strchr(initfield, ' '))) - *op = '\0'; - newval = va_arg(aq, const char *); - if (!strchr(newparam, ' ')) op = " ="; else op = ""; - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?", table, newparam, op); - while((newparam = va_arg(aq, const char *))) { - if (!strchr(newparam, ' ')) op = " ="; else op = ""; - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?", newparam, op); - newval = va_arg(aq, const char *); - } - if (initfield) - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield); - va_end(aq); - res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - /* Now bind the parameters */ - x = 1; - - while((newparam = va_arg(ap, const char *))) { - newval = va_arg(ap, const char *); - SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); - } - - res = odbc_smart_execute(obj, stmt); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - res = SQLNumResultCols(stmt, &colcount); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - cfg = ast_config_new(); - if (!cfg) { - ast_log(LOG_WARNING, "Out of memory!\n"); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - while ((res=SQLFetch(stmt)) != SQL_NO_DATA) { - var = NULL; - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql); - continue; - } - cat = ast_category_new(""); - if (!cat) { - ast_log(LOG_WARNING, "Out of memory!\n"); - continue; - } - for (x=0;x<colcount;x++) { - rowdata[0] = '\0'; - collen = sizeof(coltitle); - res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, - &datatype, &colsize, &decimaldigits, &nullable); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql); - ast_category_destroy(cat); - continue; - } - - indicator = 0; - res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator); - if (indicator == SQL_NULL_DATA) - continue; - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); - ast_category_destroy(cat); - continue; - } - stringp = rowdata; - while(stringp) { - chunk = strsep(&stringp, ";"); - if (!ast_strlen_zero(ast_strip(chunk))) { - if (initfield && !strcmp(initfield, coltitle)) - ast_category_rename(cat, chunk); - var = ast_variable_new(coltitle, chunk); - ast_variable_append(cat, var); - } - } - } - ast_category_append(cfg, cat); - } - - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return cfg; -} - -static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap) -{ - odbc_obj *obj; - SQLHSTMT stmt; - char sql[256]; - SQLLEN rowcount=0; - const char *newparam, *newval; - int res; - int x; - va_list aq; - - va_copy(aq, ap); - - if (!table) - return -1; - - obj = fetch_odbc_obj (database, 0); - if (!obj) - return -1; - - res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); - return -1; - } - - newparam = va_arg(aq, const char *); - if (!newparam) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return -1; - } - newval = va_arg(aq, const char *); - snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam); - while((newparam = va_arg(aq, const char *))) { - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam); - newval = va_arg(aq, const char *); - } - va_end(aq); - snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield); - - res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return -1; - } - - /* Now bind the parameters */ - x = 1; - - while((newparam = va_arg(ap, const char *))) { - newval = va_arg(ap, const char *); - SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL); - } - - SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(lookup), 0, (void *)lookup, 0, NULL); - - res = odbc_smart_execute(obj, stmt); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return -1; - } - - res = SQLRowCount(stmt, &rowcount); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql); - return -1; - } - - if (rowcount >= 0) - return (int)rowcount; - - return -1; -} - -static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg) -{ - struct ast_variable *new_v; - struct ast_category *cur_cat; - int res = 0; - odbc_obj *obj; - SQLINTEGER err=0, commented=0, cat_metric=0, var_metric=0, last_cat_metric=0; - SQLBIGINT id; - char sql[255] = "", filename[128], category[128], var_name[128], var_val[512]; - SQLSMALLINT rowcount=0; - SQLHSTMT stmt; - char last[128] = ""; - - if (!file || !strcmp (file, "res_config_odbc.conf")) - return NULL; /* cant configure myself with myself ! */ - - obj = fetch_odbc_obj(database, 0); - if (!obj) - return NULL; - - res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); - - SQLBindCol (stmt, 1, SQL_C_ULONG, &id, sizeof (id), &err); - SQLBindCol (stmt, 2, SQL_C_ULONG, &cat_metric, sizeof (cat_metric), &err); - SQLBindCol (stmt, 3, SQL_C_ULONG, &var_metric, sizeof (var_metric), &err); - SQLBindCol (stmt, 4, SQL_C_ULONG, &commented, sizeof (commented), &err); - SQLBindCol (stmt, 5, SQL_C_CHAR, &filename, sizeof (filename), &err); - SQLBindCol (stmt, 6, SQL_C_CHAR, &category, sizeof (category), &err); - SQLBindCol (stmt, 7, SQL_C_CHAR, &var_name, sizeof (var_name), &err); - SQLBindCol (stmt, 8, SQL_C_CHAR, &var_val, sizeof (var_val), &err); - - snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE filename='%s' and commented=0 ORDER BY filename,cat_metric desc,var_metric asc,category,var_name,var_val,id", table, file); - - res = odbc_smart_direct_execute(obj, stmt, sql); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log (LOG_WARNING, "SQL select error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - res = SQLNumResultCols (stmt, &rowcount); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log (LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql); - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - - if (!rowcount) { - ast_log (LOG_NOTICE, "found nothing\n"); - return cfg; - } - - cur_cat = ast_config_get_current_category(cfg); - - while ((res = SQLFetch(stmt)) != SQL_NO_DATA) { - if (!strcmp (var_name, "#include")) { - if (!ast_config_internal_load(var_val, cfg)) { - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return NULL; - } - continue; - } - if (strcmp(last, category) || last_cat_metric != cat_metric) { - cur_cat = ast_category_new(category); - if (!cur_cat) { - ast_log(LOG_WARNING, "Out of memory!\n"); - break; - } - strcpy(last, category); - last_cat_metric = cat_metric; - ast_category_append(cfg, cur_cat); - } - - new_v = ast_variable_new(var_name, var_val); - ast_variable_append(cur_cat, new_v); - } - - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - return cfg; -} - -static struct ast_config_engine odbc_engine = { - .name = "odbc", - .load_func = config_odbc, - .realtime_func = realtime_odbc, - .realtime_multi_func = realtime_multi_odbc, - .update_func = update_odbc -}; - -int unload_module (void) -{ - ast_config_engine_deregister(&odbc_engine); - if (option_verbose) - ast_verbose("res_config_odbc unloaded.\n"); - STANDARD_HANGUP_LOCALUSERS; - return 0; -} - -int load_module (void) -{ - ast_config_engine_register(&odbc_engine); - if (option_verbose) - ast_verbose("res_config_odbc loaded.\n"); - return 0; -} - -char *description (void) -{ - return tdesc; -} - -int usecount (void) -{ - /* never unload a config module */ - return 1; -} - -char *key () -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_crypto.c b/1.2-netsec/res/res_crypto.c deleted file mode 100644 index 037ff8e79..000000000 --- a/1.2-netsec/res/res_crypto.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Provide Cryptographic Signature capability - * - */ - -#include <sys/types.h> -#include <openssl/ssl.h> -#include <openssl/err.h> -#include <stdio.h> -#include <dirent.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/channel.h" -#include "asterisk/logger.h" -#include "asterisk/say.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/crypto.h" -#include "asterisk/md5.h" -#include "asterisk/cli.h" -#include "asterisk/io.h" -#include "asterisk/lock.h" -#include "asterisk/utils.h" - -/* - * Asterisk uses RSA keys with SHA-1 message digests for its - * digital signatures. The choice of RSA is due to its higher - * throughput on verification, and the choice of SHA-1 based - * on the recently discovered collisions in MD5's compression - * algorithm and recommendations of avoiding MD5 in new schemes - * from various industry experts. - * - * We use OpenSSL to provide our crypto routines, although we never - * actually use full-up SSL - * - */ - -/* - * XXX This module is not very thread-safe. It is for everyday stuff - * like reading keys and stuff, but there are all kinds of weird - * races with people running reload and key init at the same time - * for example - * - * XXXX - */ - -AST_MUTEX_DEFINE_STATIC(keylock); - -#define KEY_NEEDS_PASSCODE (1 << 16) - -struct ast_key { - /* Name of entity */ - char name[80]; - /* File name */ - char fn[256]; - /* Key type (AST_KEY_PUB or AST_KEY_PRIV, along with flags from above) */ - int ktype; - /* RSA structure (if successfully loaded) */ - RSA *rsa; - /* Whether we should be deleted */ - int delme; - /* FD for input (or -1 if no input allowed, or -2 if we needed input) */ - int infd; - /* FD for output */ - int outfd; - /* Last MD5 Digest */ - unsigned char digest[16]; - struct ast_key *next; -}; - -static struct ast_key *keys = NULL; - - -#if 0 -static int fdprint(int fd, char *s) -{ - return write(fd, s, strlen(s) + 1); -} -#endif -static int pw_cb(char *buf, int size, int rwflag, void *userdata) -{ - struct ast_key *key = (struct ast_key *)userdata; - char prompt[256]; - int res; - int tmp; - if (key->infd > -1) { - snprintf(prompt, sizeof(prompt), ">>>> passcode for %s key '%s': ", - key->ktype == AST_KEY_PRIVATE ? "PRIVATE" : "PUBLIC", key->name); - write(key->outfd, prompt, strlen(prompt)); - memset(buf, 0, sizeof(buf)); - tmp = ast_hide_password(key->infd); - memset(buf, 0, size); - res = read(key->infd, buf, size); - ast_restore_tty(key->infd, tmp); - if (buf[strlen(buf) -1] == '\n') - buf[strlen(buf) - 1] = '\0'; - return strlen(buf); - } else { - /* Note that we were at least called */ - key->infd = -2; - } - return -1; -} - -static struct ast_key *__ast_key_get(const char *kname, int ktype) -{ - struct ast_key *key; - ast_mutex_lock(&keylock); - key = keys; - while(key) { - if (!strcmp(kname, key->name) && - (ktype == key->ktype)) - break; - key = key->next; - } - ast_mutex_unlock(&keylock); - return key; -} - -static struct ast_key *try_load_key (char *dir, char *fname, int ifd, int ofd, int *not2) -{ - int ktype = 0; - char *c = NULL; - char ffname[256]; - unsigned char digest[16]; - FILE *f; - struct MD5Context md5; - struct ast_key *key; - static int notice = 0; - int found = 0; - - /* Make sure its name is a public or private key */ - - if ((c = strstr(fname, ".pub")) && !strcmp(c, ".pub")) { - ktype = AST_KEY_PUBLIC; - } else if ((c = strstr(fname, ".key")) && !strcmp(c, ".key")) { - ktype = AST_KEY_PRIVATE; - } else - return NULL; - - /* Get actual filename */ - snprintf(ffname, sizeof(ffname), "%s/%s", dir, fname); - - ast_mutex_lock(&keylock); - key = keys; - while(key) { - /* Look for an existing version already */ - if (!strcasecmp(key->fn, ffname)) - break; - key = key->next; - } - ast_mutex_unlock(&keylock); - - /* Open file */ - f = fopen(ffname, "r"); - if (!f) { - ast_log(LOG_WARNING, "Unable to open key file %s: %s\n", ffname, strerror(errno)); - return NULL; - } - MD5Init(&md5); - while(!feof(f)) { - /* Calculate a "whatever" quality md5sum of the key */ - char buf[256]; - memset(buf, 0, 256); - fgets(buf, sizeof(buf), f); - if (!feof(f)) { - MD5Update(&md5, (unsigned char *) buf, strlen(buf)); - } - } - MD5Final(digest, &md5); - if (key) { - /* If the MD5 sum is the same, and it isn't awaiting a passcode - then this is far enough */ - if (!memcmp(digest, key->digest, 16) && - !(key->ktype & KEY_NEEDS_PASSCODE)) { - fclose(f); - key->delme = 0; - return NULL; - } else { - /* Preserve keytype */ - ktype = key->ktype; - /* Recycle the same structure */ - found++; - } - } - - /* Make fname just be the normal name now */ - *c = '\0'; - if (!key) { - key = (struct ast_key *)malloc(sizeof(struct ast_key)); - if (!key) { - ast_log(LOG_WARNING, "Out of memory\n"); - fclose(f); - return NULL; - } - memset(key, 0, sizeof(struct ast_key)); - } - /* At this point we have a key structure (old or new). Time to - fill it with what we know */ - /* Gotta lock if this one already exists */ - if (found) - ast_mutex_lock(&keylock); - /* First the filename */ - ast_copy_string(key->fn, ffname, sizeof(key->fn)); - /* Then the name */ - ast_copy_string(key->name, fname, sizeof(key->name)); - key->ktype = ktype; - /* Yes, assume we're going to be deleted */ - key->delme = 1; - /* Keep the key type */ - memcpy(key->digest, digest, 16); - /* Can I/O takes the FD we're given */ - key->infd = ifd; - key->outfd = ofd; - /* Reset the file back to the beginning */ - rewind(f); - /* Now load the key with the right method */ - if (ktype == AST_KEY_PUBLIC) - key->rsa = PEM_read_RSA_PUBKEY(f, NULL, pw_cb, key); - else - key->rsa = PEM_read_RSAPrivateKey(f, NULL, pw_cb, key); - fclose(f); - if (key->rsa) { - if (RSA_size(key->rsa) == 128) { - /* Key loaded okay */ - key->ktype &= ~KEY_NEEDS_PASSCODE; - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Loaded %s key '%s'\n", key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name); - if (option_debug) - ast_log(LOG_DEBUG, "Key '%s' loaded OK\n", key->name); - key->delme = 0; - } else - ast_log(LOG_NOTICE, "Key '%s' is not expected size.\n", key->name); - } else if (key->infd != -2) { - ast_log(LOG_WARNING, "Key load %s '%s' failed\n",key->ktype == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", key->name); - if (ofd > -1) { - ERR_print_errors_fp(stderr); - } else - ERR_print_errors_fp(stderr); - } else { - ast_log(LOG_NOTICE, "Key '%s' needs passcode.\n", key->name); - key->ktype |= KEY_NEEDS_PASSCODE; - if (!notice) { - if (!option_initcrypto) - ast_log(LOG_NOTICE, "Add the '-i' flag to the asterisk command line if you want to automatically initialize passcodes at launch.\n"); - notice++; - } - /* Keep it anyway */ - key->delme = 0; - /* Print final notice about "init keys" when done */ - *not2 = 1; - } - if (found) - ast_mutex_unlock(&keylock); - if (!found) { - ast_mutex_lock(&keylock); - key->next = keys; - keys = key; - ast_mutex_unlock(&keylock); - } - return key; -} - -#if 0 - -static void dump(unsigned char *src, int len) -{ - int x; - for (x=0;x<len;x++) - printf("%02x", *(src++)); - printf("\n"); -} - -static char *binary(int y, int len) -{ - static char res[80]; - int x; - memset(res, 0, sizeof(res)); - for (x=0;x<len;x++) { - if (y & (1 << x)) - res[(len - x - 1)] = '1'; - else - res[(len - x - 1)] = '0'; - } - return res; -} - -#endif - -static int __ast_sign_bin(struct ast_key *key, const char *msg, int msglen, unsigned char *dsig) -{ - unsigned char digest[20]; - unsigned int siglen = 128; - int res; - - if (key->ktype != AST_KEY_PRIVATE) { - ast_log(LOG_WARNING, "Cannot sign with a public key\n"); - return -1; - } - - /* Calculate digest of message */ - SHA1((unsigned char *)msg, msglen, digest); - - /* Verify signature */ - res = RSA_sign(NID_sha1, digest, sizeof(digest), dsig, &siglen, key->rsa); - - if (!res) { - ast_log(LOG_WARNING, "RSA Signature (key %s) failed\n", key->name); - return -1; - } - - if (siglen != 128) { - ast_log(LOG_WARNING, "Unexpected signature length %d, expecting %d\n", (int)siglen, (int)128); - return -1; - } - - return 0; - -} - -static int __ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key) -{ - int res; - int pos = 0; - if (key->ktype != AST_KEY_PRIVATE) { - ast_log(LOG_WARNING, "Cannot decrypt with a public key\n"); - return -1; - } - - if (srclen % 128) { - ast_log(LOG_NOTICE, "Tried to decrypt something not a multiple of 128 bytes\n"); - return -1; - } - while(srclen) { - /* Process chunks 128 bytes at a time */ - res = RSA_private_decrypt(128, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING); - if (res < 0) - return -1; - pos += res; - src += 128; - srclen -= 128; - dst += res; - } - return pos; -} - -static int __ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key) -{ - int res; - int bytes; - int pos = 0; - if (key->ktype != AST_KEY_PUBLIC) { - ast_log(LOG_WARNING, "Cannot encrypt with a private key\n"); - return -1; - } - - while(srclen) { - bytes = srclen; - if (bytes > 128 - 41) - bytes = 128 - 41; - /* Process chunks 128-41 bytes at a time */ - res = RSA_public_encrypt(bytes, src, dst, key->rsa, RSA_PKCS1_OAEP_PADDING); - if (res != 128) { - ast_log(LOG_NOTICE, "How odd, encrypted size is %d\n", res); - return -1; - } - src += bytes; - srclen -= bytes; - pos += res; - dst += res; - } - return pos; -} - -static int __ast_sign(struct ast_key *key, char *msg, char *sig) -{ - unsigned char dsig[128]; - int siglen = sizeof(dsig); - int res; - res = ast_sign_bin(key, msg, strlen(msg), dsig); - if (!res) - /* Success -- encode (256 bytes max as documented) */ - ast_base64encode(sig, dsig, siglen, 256); - return res; - -} - -static int __ast_check_signature_bin(struct ast_key *key, const char *msg, int msglen, const unsigned char *dsig) -{ - unsigned char digest[20]; - int res; - - if (key->ktype != AST_KEY_PUBLIC) { - /* Okay, so of course you really *can* but for our purposes - we're going to say you can't */ - ast_log(LOG_WARNING, "Cannot check message signature with a private key\n"); - return -1; - } - - /* Calculate digest of message */ - SHA1((unsigned char *)msg, msglen, digest); - - /* Verify signature */ - res = RSA_verify(NID_sha1, digest, sizeof(digest), (unsigned char *)dsig, 128, key->rsa); - - if (!res) { - ast_log(LOG_DEBUG, "Key failed verification: %s\n", key->name); - return -1; - } - /* Pass */ - return 0; -} - -static int __ast_check_signature(struct ast_key *key, const char *msg, const char *sig) -{ - unsigned char dsig[128]; - int res; - - /* Decode signature */ - res = ast_base64decode(dsig, sig, sizeof(dsig)); - if (res != sizeof(dsig)) { - ast_log(LOG_WARNING, "Signature improper length (expect %d, got %d)\n", (int)sizeof(dsig), (int)res); - return -1; - } - res = ast_check_signature_bin(key, msg, strlen(msg), dsig); - return res; -} - -static void crypto_load(int ifd, int ofd) -{ - struct ast_key *key, *nkey, *last; - DIR *dir = NULL; - struct dirent *ent; - int note = 0; - /* Mark all keys for deletion */ - ast_mutex_lock(&keylock); - key = keys; - while(key) { - key->delme = 1; - key = key->next; - } - ast_mutex_unlock(&keylock); - /* Load new keys */ - dir = opendir((char *)ast_config_AST_KEY_DIR); - if (dir) { - while((ent = readdir(dir))) { - try_load_key((char *)ast_config_AST_KEY_DIR, ent->d_name, ifd, ofd, ¬e); - } - closedir(dir); - } else - ast_log(LOG_WARNING, "Unable to open key directory '%s'\n", (char *)ast_config_AST_KEY_DIR); - if (note) { - ast_log(LOG_NOTICE, "Please run the command 'init keys' to enter the passcodes for the keys\n"); - } - ast_mutex_lock(&keylock); - key = keys; - last = NULL; - while(key) { - nkey = key->next; - if (key->delme) { - ast_log(LOG_DEBUG, "Deleting key %s type %d\n", key->name, key->ktype); - /* Do the delete */ - if (last) - last->next = nkey; - else - keys = nkey; - if (key->rsa) - RSA_free(key->rsa); - free(key); - } else - last = key; - key = nkey; - } - ast_mutex_unlock(&keylock); -} - -static void md52sum(char *sum, unsigned char *md5) -{ - int x; - for (x=0;x<16;x++) - sum += sprintf(sum, "%02x", *(md5++)); -} - -static int show_keys(int fd, int argc, char *argv[]) -{ - struct ast_key *key; - char sum[16 * 2 + 1]; - int count_keys = 0; - - ast_mutex_lock(&keylock); - key = keys; - ast_cli(fd, "%-18s %-8s %-16s %-33s\n", "Key Name", "Type", "Status", "Sum"); - while(key) { - md52sum(sum, key->digest); - ast_cli(fd, "%-18s %-8s %-16s %-33s\n", key->name, - (key->ktype & 0xf) == AST_KEY_PUBLIC ? "PUBLIC" : "PRIVATE", - key->ktype & KEY_NEEDS_PASSCODE ? "[Needs Passcode]" : "[Loaded]", sum); - - key = key->next; - count_keys++; - } - ast_mutex_unlock(&keylock); - ast_cli(fd, "%d known RSA keys.\n", count_keys); - return RESULT_SUCCESS; -} - -static int init_keys(int fd, int argc, char *argv[]) -{ - struct ast_key *key; - int ign; - char *kn; - char tmp[256] = ""; - - key = keys; - while(key) { - /* Reload keys that need pass codes now */ - if (key->ktype & KEY_NEEDS_PASSCODE) { - kn = key->fn + strlen(ast_config_AST_KEY_DIR) + 1; - ast_copy_string(tmp, kn, sizeof(tmp)); - try_load_key((char *)ast_config_AST_KEY_DIR, tmp, fd, fd, &ign); - } - key = key->next; - } - return RESULT_SUCCESS; -} - -static char show_key_usage[] = -"Usage: show keys\n" -" Displays information about RSA keys known by Asterisk\n"; - -static char init_keys_usage[] = -"Usage: init keys\n" -" Initializes private keys (by reading in pass code from the user)\n"; - -static struct ast_cli_entry cli_show_keys = -{ { "show", "keys", NULL }, show_keys, "Displays RSA key information", show_key_usage }; - -static struct ast_cli_entry cli_init_keys = -{ { "init", "keys", NULL }, init_keys, "Initialize RSA key passcodes", init_keys_usage }; - -static int crypto_init(void) -{ - SSL_library_init(); - ERR_load_crypto_strings(); - ast_cli_register(&cli_show_keys); - ast_cli_register(&cli_init_keys); - - /* Install ourselves into stubs */ - ast_key_get = __ast_key_get; - ast_check_signature = __ast_check_signature; - ast_check_signature_bin = __ast_check_signature_bin; - ast_sign = __ast_sign; - ast_sign_bin = __ast_sign_bin; - ast_encrypt_bin = __ast_encrypt_bin; - ast_decrypt_bin = __ast_decrypt_bin; - return 0; -} - -int reload(void) -{ - crypto_load(-1, -1); - return 0; -} - -int load_module(void) -{ - crypto_init(); - if (option_initcrypto) - crypto_load(STDIN_FILENO, STDOUT_FILENO); - else - crypto_load(-1, -1); - return 0; -} - -int unload_module(void) -{ - /* Can't unload this once we're loaded */ - return -1; -} - -char *description(void) -{ - return "Cryptographic Digital Signatures"; -} - -int usecount(void) -{ - /* We should never be unloaded */ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_features.c b/1.2-netsec/res/res_features.c deleted file mode 100644 index bf23129ae..000000000 --- a/1.2-netsec/res/res_features.c +++ /dev/null @@ -1,2187 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2006, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Routines implementing call parking - * - */ - -#include <pthread.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/time.h> -#include <sys/signal.h> -#include <netinet/in.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/options.h" -#include "asterisk/causes.h" -#include "asterisk/module.h" -#include "asterisk/translate.h" -#include "asterisk/app.h" -#include "asterisk/say.h" -#include "asterisk/features.h" -#include "asterisk/musiconhold.h" -#include "asterisk/config.h" -#include "asterisk/cli.h" -#include "asterisk/manager.h" -#include "asterisk/utils.h" -#include "asterisk/adsi.h" -#include "asterisk/monitor.h" - -#ifdef __AST_DEBUG_MALLOC -static void FREE(void *ptr) -{ - free(ptr); -} -#else -#define FREE free -#endif - -#define DEFAULT_PARK_TIME 45000 -#define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000 -#define DEFAULT_FEATURE_DIGIT_TIMEOUT 500 - -#define AST_MAX_WATCHERS 256 - -static char *parkedcall = "ParkedCall"; - -/* No more than 45 seconds parked before you do something with them */ -static int parkingtime = DEFAULT_PARK_TIME; - -/* Context for which parking is made accessible */ -static char parking_con[AST_MAX_EXTENSION]; - -/* Context for dialback for parking (KLUDGE) */ -static char parking_con_dial[AST_MAX_EXTENSION]; - -/* Extension you type to park the call */ -static char parking_ext[AST_MAX_EXTENSION]; - -static char pickup_ext[AST_MAX_EXTENSION]; - -/* Default sounds */ -static char courtesytone[256]; -static char xfersound[256]; -static char xferfailsound[256]; - -/* First available extension for parking */ -static int parking_start; - -/* Last available extension for parking */ -static int parking_stop; - -static int parking_offset; - -static int parkfindnext; - -static int adsipark; - -static int transferdigittimeout; -static int featuredigittimeout; - -/* Default courtesy tone played when party joins conference */ - -/* Registrar for operations */ -static char *registrar = "res_features"; - -static char *synopsis = "Answer a parked call"; - -static char *descrip = "ParkedCall(exten):" -"Used to connect to a parked call. This application is always\n" -"registered internally and does not need to be explicitly added\n" -"into the dialplan, although you should include the 'parkedcalls'\n" -"context.\n"; - -static char *parkcall = "Park"; - -static char *synopsis2 = "Park yourself"; - -static char *descrip2 = "Park(exten):" -"Used to park yourself (typically in combination with a supervised\n" -"transfer to know the parking space). This application is always\n" -"registered internally and does not need to be explicitly added\n" -"into the dialplan, although you should include the 'parkedcalls'\n" -"context.\n"; - -static struct ast_app *monitor_app=NULL; -static int monitor_ok=1; - -struct parkeduser { - struct ast_channel *chan; - struct timeval start; - int parkingnum; - /* Where to go if our parking time expires */ - char context[AST_MAX_CONTEXT]; - char exten[AST_MAX_EXTENSION]; - int priority; - int parkingtime; - int notquiteyet; - char peername[1024]; - unsigned char moh_trys; - struct parkeduser *next; -}; - -static struct parkeduser *parkinglot; - -AST_MUTEX_DEFINE_STATIC(parking_lock); - -static pthread_t parking_thread; - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -char *ast_parking_ext(void) -{ - return parking_ext; -} - -char *ast_pickup_ext(void) -{ - return pickup_ext; -} - -struct ast_bridge_thread_obj -{ - struct ast_bridge_config bconfig; - struct ast_channel *chan; - struct ast_channel *peer; -}; - -static void check_goto_on_transfer(struct ast_channel *chan) -{ - struct ast_channel *xferchan; - char *goto_on_transfer; - - goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR"); - - if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) { - char *x; - struct ast_frame *f; - - for (x = goto_on_transfer; x && *x; x++) - if (*x == '^') - *x = '|'; - - strcpy(xferchan->name, chan->name); - /* Make formats okay */ - xferchan->readformat = chan->readformat; - xferchan->writeformat = chan->writeformat; - ast_channel_masquerade(xferchan, chan); - ast_parseable_goto(xferchan, goto_on_transfer); - xferchan->_state = AST_STATE_UP; - ast_clear_flag(xferchan, AST_FLAGS_ALL); - xferchan->_softhangup = 0; - if ((f = ast_read(xferchan))) { - ast_frfree(f); - f = NULL; - ast_pbx_start(xferchan); - } else { - ast_hangup(xferchan); - } - } -} - -static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name); - - -static void *ast_bridge_call_thread(void *data) -{ - struct ast_bridge_thread_obj *tobj = data; - - tobj->chan->appl = "Transferred Call"; - tobj->chan->data = tobj->peer->name; - tobj->peer->appl = "Transferred Call"; - tobj->peer->data = tobj->chan->name; - if (tobj->chan->cdr) { - ast_cdr_reset(tobj->chan->cdr, NULL); - ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name); - } - if (tobj->peer->cdr) { - ast_cdr_reset(tobj->peer->cdr, NULL); - ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name); - } - - ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig); - ast_hangup(tobj->chan); - ast_hangup(tobj->peer); - tobj->chan = tobj->peer = NULL; - free(tobj); - tobj=NULL; - return NULL; -} - -static void ast_bridge_call_thread_launch(void *data) -{ - pthread_t thread; - pthread_attr_t attr; - struct sched_param sched; - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data); - pthread_attr_destroy(&attr); - memset(&sched, 0, sizeof(sched)); - pthread_setschedparam(thread, SCHED_RR, &sched); -} - - - -static int adsi_announce_park(struct ast_channel *chan, int parkingnum) -{ - int res; - int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; - char tmp[256]; - char *message[5] = {NULL, NULL, NULL, NULL, NULL}; - - snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum); - message[0] = tmp; - res = adsi_load_session(chan, NULL, 0, 1); - if (res == -1) { - return res; - } - return adsi_print(chan, message, justify, 1); -} - -/*--- ast_park_call: Park a call */ -/* We put the user in the parking list, then wake up the parking thread to be sure it looks - after these channels too */ -int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout) -{ - struct parkeduser *pu, *cur; - int i,x,parking_range; - char exten[AST_MAX_EXTENSION]; - struct ast_context *con; - - pu = malloc(sizeof(struct parkeduser)); - if (!pu) { - ast_log(LOG_WARNING, "Out of memory\n"); - return -1; - } - memset(pu, 0, sizeof(struct parkeduser)); - ast_mutex_lock(&parking_lock); - parking_range = parking_stop - parking_start+1; - for (i = 0; i < parking_range; i++) { - x = (i + parking_offset) % parking_range + parking_start; - cur = parkinglot; - while(cur) { - if (cur->parkingnum == x) - break; - cur = cur->next; - } - if (!cur) - break; - } - - if (!(i < parking_range)) { - ast_log(LOG_WARNING, "No more parking spaces\n"); - free(pu); - ast_mutex_unlock(&parking_lock); - return -1; - } - if (parkfindnext) - parking_offset = x - parking_start + 1; - chan->appl = "Parked Call"; - chan->data = NULL; - - pu->chan = chan; - /* Start music on hold */ - if (chan != peer) { - ast_indicate(pu->chan, AST_CONTROL_HOLD); - ast_moh_start(pu->chan, NULL); - } - pu->start = ast_tvnow(); - pu->parkingnum = x; - if (timeout > 0) - pu->parkingtime = timeout; - else - pu->parkingtime = parkingtime; - if (extout) - *extout = x; - if (peer) - ast_copy_string(pu->peername, peer->name, sizeof(pu->peername)); - - /* Remember what had been dialed, so that if the parking - expires, we try to come back to the same place */ - if (!ast_strlen_zero(chan->macrocontext)) - ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context)); - else - ast_copy_string(pu->context, chan->context, sizeof(pu->context)); - if (!ast_strlen_zero(chan->macroexten)) - ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten)); - else - ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten)); - if (chan->macropriority) - pu->priority = chan->macropriority; - else - pu->priority = chan->priority; - pu->next = parkinglot; - parkinglot = pu; - /* If parking a channel directly, don't quiet yet get parking running on it */ - if (peer == chan) - pu->notquiteyet = 1; - ast_mutex_unlock(&parking_lock); - /* Wake up the (presumably select()ing) thread */ - pthread_kill(parking_thread, SIGURG); - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000)); - - manager_event(EVENT_FLAG_CALL, "ParkedCall", - "Exten: %d\r\n" - "Channel: %s\r\n" - "From: %s\r\n" - "Timeout: %ld\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" - ,pu->parkingnum, pu->chan->name, peer->name - ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL) - ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") - ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") - ); - - if (peer) { - if (adsipark && adsi_available(peer)) { - adsi_announce_park(peer, pu->parkingnum); - } - if (adsipark && adsi_available(peer)) { - adsi_unload_session(peer); - } - } - con = ast_context_find(parking_con); - if (!con) { - con = ast_context_create(NULL, parking_con, registrar); - if (!con) { - ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); - } - } - if (con) { - snprintf(exten, sizeof(exten), "%d", x); - ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar); - } - if (peer) - ast_say_digits(peer, pu->parkingnum, "", peer->language); - if (pu->notquiteyet) { - /* Wake up parking thread if we're really done */ - ast_moh_start(pu->chan, NULL); - pu->notquiteyet = 0; - pthread_kill(parking_thread, SIGURG); - } - return 0; -} - -int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout) -{ - struct ast_channel *chan; - struct ast_frame *f; - - /* Make a new, fake channel that we'll use to masquerade in the real one */ - chan = ast_channel_alloc(0); - if (chan) { - /* Let us keep track of the channel name */ - snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name); - - /* Make formats okay */ - chan->readformat = rchan->readformat; - chan->writeformat = rchan->writeformat; - ast_channel_masquerade(chan, rchan); - - /* Setup the extensions and such */ - ast_copy_string(chan->context, rchan->context, sizeof(chan->context)); - ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten)); - chan->priority = rchan->priority; - - /* Make the masq execute */ - f = ast_read(chan); - if (f) - ast_frfree(f); - ast_park_call(chan, peer, timeout, extout); - } else { - ast_log(LOG_WARNING, "Unable to create parked channel\n"); - return -1; - } - return 0; -} - - -#define FEATURE_RETURN_HANGUP -1 -#define FEATURE_RETURN_SUCCESSBREAK 0 -#define FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE -#define FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER -#define FEATURE_RETURN_PASSDIGITS 21 -#define FEATURE_RETURN_STOREDIGITS 22 -#define FEATURE_RETURN_SUCCESS 23 - -#define FEATURE_SENSE_CHAN (1 << 0) -#define FEATURE_SENSE_PEER (1 << 1) - - -static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL; - int x = 0; - size_t len; - struct ast_channel *caller_chan = NULL, *callee_chan = NULL; - - - if(sense == 2) { - caller_chan = peer; - callee_chan = chan; - } else { - callee_chan = peer; - caller_chan = chan; - } - - if (!monitor_ok) { - ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); - return -1; - } - - if (!monitor_app) { - if (!(monitor_app = pbx_findapp("Monitor"))) { - monitor_ok=0; - ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n"); - return -1; - } - } - if (!ast_strlen_zero(courtesytone)) { - if (ast_autoservice_start(callee_chan)) - return -1; - if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) { - if (ast_waitstream(caller_chan, "") < 0) { - ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); - ast_autoservice_stop(callee_chan); - return -1; - } - } - if (ast_autoservice_stop(callee_chan)) - return -1; - } - - if (callee_chan->monitor) { - if (option_verbose > 3) - ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code); - ast_monitor_stop(callee_chan, 1); - return FEATURE_RETURN_SUCCESS; - } - - if (caller_chan && callee_chan) { - touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT"); - if (!touch_format) - touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT"); - - touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR"); - if (!touch_monitor) - touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR"); - - if (touch_monitor) { - len = strlen(touch_monitor) + 50; - args = alloca(len); - snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor); - } else { - caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name); - callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name); - len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50; - args = alloca(len); - snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id); - } - - for( x = 0; x < strlen(args); x++) - if (args[x] == '/') - args[x] = '-'; - - if (option_verbose > 3) - ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args); - - pbx_exec(callee_chan, monitor_app, args, 1); - - return FEATURE_RETURN_SUCCESS; - } - - ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n"); - return -1; -} - -static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - if (option_verbose > 3) - ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code); - return FEATURE_RETURN_HANGUP; -} - -static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - struct ast_channel *transferer; - struct ast_channel *transferee; - char *transferer_real_context; - char newext[256]; - int res; - - if (sense == FEATURE_SENSE_PEER) { - transferer = peer; - transferee = chan; - } else { - transferer = chan; - transferee = peer; - } - if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && - !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { - /* Use the non-macro context to transfer the call */ - if (!ast_strlen_zero(transferer->macrocontext)) - transferer_real_context = transferer->macrocontext; - else - transferer_real_context = transferer->context; - } - /* Start autoservice on chan while we talk - to the originator */ - ast_indicate(transferee, AST_CONTROL_HOLD); - ast_autoservice_start(transferee); - ast_moh_start(transferee, NULL); - - memset(newext, 0, sizeof(newext)); - - /* Transfer */ - if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } - if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } else if (res > 0) { - /* If they've typed a digit already, handle it */ - newext[0] = (char) res; - } - - ast_stopstream(transferer); - res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout); - if (res < 0) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } - if (!strcmp(newext, ast_parking_ext())) { - ast_moh_stop(transferee); - - res = ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - if (res) - res = -1; - else if (!ast_park_call(transferee, transferer, 0, NULL)) { - /* We return non-zero, but tell the PBX not to hang the channel when - the thread dies -- We have to be careful now though. We are responsible for - hanging up the channel, else it will never be hung up! */ - - if (transferer == peer) - res = AST_PBX_KEEPALIVE; - else - res = AST_PBX_NO_HANGUP_PEER; - return res; - } else { - ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name); - } - /* XXX Maybe we should have another message here instead of invalid extension XXX */ - } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) { - pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name); - pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name); - ast_moh_stop(transferee); - res=ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - if (!transferee->pbx) { - /* Doh! Use our handy async_goto functions */ - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n" - ,transferee->name, newext, transferer_real_context); - if (ast_async_goto(transferee, transferer_real_context, newext, 1)) - ast_log(LOG_WARNING, "Async goto failed :-(\n"); - res = -1; - } else { - /* Set the channel's new extension, since it exists, using transferer context */ - ast_copy_string(transferee->exten, newext, sizeof(transferee->exten)); - ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context)); - transferee->priority = 0; - } - check_goto_on_transfer(transferer); - return res; - } else { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context); - } - if (!ast_strlen_zero(xferfailsound)) - res = ast_streamfile(transferer, xferfailsound, transferee->language); - else - res = 0; - if (res) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } - res = ast_waitstream(transferer, AST_DIGIT_ANY); - ast_stopstream(transferer); - ast_moh_stop(transferee); - res = ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - if (res) { - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name); - return res; - } - return FEATURE_RETURN_SUCCESS; -} - -static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - struct ast_channel *transferer; - struct ast_channel *transferee; - struct ast_channel *newchan, *xferchan=NULL; - int outstate=0; - struct ast_bridge_config bconfig; - char *transferer_real_context; - char xferto[256],dialstr[265]; - char *cid_num; - char *cid_name; - int res; - struct ast_frame *f = NULL; - struct ast_bridge_thread_obj *tobj; - - ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense); - if (sense == FEATURE_SENSE_PEER) { - transferer = peer; - transferee = chan; - } else { - transferer = chan; - transferee = peer; - } - if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) && - !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) { - /* Use the non-macro context to transfer the call */ - if (!ast_strlen_zero(transferer->macrocontext)) - transferer_real_context = transferer->macrocontext; - else - transferer_real_context = transferer->context; - } - /* Start autoservice on chan while we talk - to the originator */ - ast_indicate(transferee, AST_CONTROL_HOLD); - ast_autoservice_start(transferee); - ast_moh_start(transferee, NULL); - memset(xferto, 0, sizeof(xferto)); - /* Transfer */ - if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } - if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - return res; - } else if(res > 0) { - /* If they've typed a digit already, handle it */ - xferto[0] = (char) res; - } - if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) { - cid_num = transferer->cid.cid_num; - cid_name = transferer->cid.cid_name; - if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) { - snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context); - newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name); - ast_indicate(transferer, -1); - if (newchan) { - res = ast_channel_make_compatible(transferer, newchan); - if (res < 0) { - ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name); - ast_hangup(newchan); - return -1; - } - memset(&bconfig,0,sizeof(struct ast_bridge_config)); - ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT); - ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT); - res = ast_bridge_call(transferer,newchan,&bconfig); - if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) { - ast_hangup(newchan); - if (f) { - ast_frfree(f); - f = NULL; - } - if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) { - if (ast_waitstream(transferer, "") < 0) { - ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); - } - } - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - transferer->_softhangup = 0; - return FEATURE_RETURN_SUCCESS; - } - - res = ast_channel_make_compatible(transferee, newchan); - if (res < 0) { - ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name); - ast_hangup(newchan); - return -1; - } - - - ast_moh_stop(transferee); - - if ((ast_autoservice_stop(transferee) < 0) - || (ast_waitfordigit(transferee, 100) < 0) - || (ast_waitfordigit(newchan, 100) < 0) - || ast_check_hangup(transferee) - || ast_check_hangup(newchan)) { - ast_hangup(newchan); - res = -1; - return -1; - } - - if ((xferchan = ast_channel_alloc(0))) { - snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name); - /* Make formats okay */ - xferchan->readformat = transferee->readformat; - xferchan->writeformat = transferee->writeformat; - ast_channel_masquerade(xferchan, transferee); - ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority); - xferchan->_state = AST_STATE_UP; - ast_clear_flag(xferchan, AST_FLAGS_ALL); - xferchan->_softhangup = 0; - - if ((f = ast_read(xferchan))) { - ast_frfree(f); - f = NULL; - } - - } else { - ast_hangup(newchan); - return -1; - } - - newchan->_state = AST_STATE_UP; - ast_clear_flag(newchan, AST_FLAGS_ALL); - newchan->_softhangup = 0; - - tobj = malloc(sizeof(struct ast_bridge_thread_obj)); - if (tobj) { - memset(tobj,0,sizeof(struct ast_bridge_thread_obj)); - tobj->chan = xferchan; - tobj->peer = newchan; - tobj->bconfig = *config; - - if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) { - if (ast_waitstream(newchan, "") < 0) { - ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); - } - } - ast_bridge_call_thread_launch(tobj); - } else { - ast_log(LOG_WARNING, "Out of memory!\n"); - ast_hangup(xferchan); - ast_hangup(newchan); - } - return -1; - - } else { - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - /* any reason besides user requested cancel and busy triggers the failed sound */ - if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) { - res = ast_streamfile(transferer, xferfailsound, transferer->language); - if (!res && (ast_waitstream(transferer, "") < 0)) { - return -1; - } - } - return FEATURE_RETURN_SUCCESS; - } - } else { - ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context); - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - res = ast_streamfile(transferer, "beeperr", transferer->language); - if (!res && (ast_waitstream(transferer, "") < 0)) { - return -1; - } - } - } else { - ast_log(LOG_WARNING, "Did not read data.\n"); - res = ast_streamfile(transferer, "beeperr", transferer->language); - if (ast_waitstream(transferer, "") < 0) { - return -1; - } - } - ast_moh_stop(transferee); - ast_autoservice_stop(transferee); - ast_indicate(transferee, AST_CONTROL_UNHOLD); - - return FEATURE_RETURN_SUCCESS; -} - - -/* add atxfer and automon as undefined so you can only use em if you configure them */ -#define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0])) -struct ast_call_feature builtin_features[] = - { - { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF }, - { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF }, - { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF }, - { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF }, -}; - - -static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list; - -/* register new feature into feature_list*/ -void ast_register_feature(struct ast_call_feature *feature) -{ - if (!feature) { - ast_log(LOG_NOTICE,"You didn't pass a feature!\n"); - return; - } - - AST_LIST_LOCK(&feature_list); - AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry); - AST_LIST_UNLOCK(&feature_list); - - if (option_verbose >= 2) - ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname); -} - -/* unregister feature from feature_list */ -void ast_unregister_feature(struct ast_call_feature *feature) -{ - if (!feature) return; - - AST_LIST_LOCK(&feature_list); - AST_LIST_REMOVE(&feature_list,feature,feature_entry); - AST_LIST_UNLOCK(&feature_list); - free(feature); -} - -static void ast_unregister_features(void) -{ - struct ast_call_feature *feature; - - AST_LIST_LOCK(&feature_list); - while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry))) - free(feature); - AST_LIST_UNLOCK(&feature_list); -} - -/* find a feature by name */ -static struct ast_call_feature *find_feature(char *name) -{ - struct ast_call_feature *tmp; - - AST_LIST_LOCK(&feature_list); - AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) { - if (!strcasecmp(tmp->sname, name)) - break; - } - AST_LIST_UNLOCK(&feature_list); - - return tmp; -} - -/* exec an app by feature */ -static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - struct ast_app *app; - struct ast_call_feature *feature; - int res; - - AST_LIST_LOCK(&feature_list); - AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) { - if (!strcasecmp(feature->exten,code)) break; - } - AST_LIST_UNLOCK(&feature_list); - - if (!feature) { /* shouldn't ever happen! */ - ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n"); - return -1; - } - - app = pbx_findapp(feature->app); - if (app) { - struct ast_channel *work = chan; - if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) - work = peer; - res = pbx_exec(work, app, feature->app_args, 1); - if (res < 0) - return res; - } else { - ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app); - return -2; - } - - return FEATURE_RETURN_SUCCESS; -} - -static void unmap_features(void) -{ - int x; - for (x = 0; x < FEATURES_COUNT; x++) - strcpy(builtin_features[x].exten, builtin_features[x].default_exten); -} - -static int remap_feature(const char *name, const char *value) -{ - int x; - int res = -1; - for (x = 0; x < FEATURES_COUNT; x++) { - if (!strcasecmp(name, builtin_features[x].sname)) { - ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten)); - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten); - res = 0; - } else if (!strcmp(value, builtin_features[x].exten)) - ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name); - } - return res; -} - -static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) -{ - int x; - struct ast_flags features; - int res = FEATURE_RETURN_PASSDIGITS; - struct ast_call_feature *feature; - char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES"); - - if (sense == FEATURE_SENSE_CHAN) - ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL); - else - ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL); - ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags); - - for (x=0; x < FEATURES_COUNT; x++) { - if ((ast_test_flag(&features, builtin_features[x].feature_mask)) && - !ast_strlen_zero(builtin_features[x].exten)) { - /* Feature is up for consideration */ - if (!strcmp(builtin_features[x].exten, code)) { - res = builtin_features[x].operation(chan, peer, config, code, sense); - break; - } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) { - if (res == FEATURE_RETURN_PASSDIGITS) - res = FEATURE_RETURN_STOREDIGITS; - } - } - } - - - if (!ast_strlen_zero(dynamic_features)) { - char *tmp = ast_strdupa(dynamic_features); - char *tok; - - if (!tmp) - return res; - - while ((tok = strsep(&tmp, "#")) != NULL) { - feature = find_feature(tok); - - if (feature) { - /* Feature is up for consideration */ - if (!strcmp(feature->exten, code)) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok); - res = feature->operation(chan, peer, config, code, sense); - break; - } else if (!strncmp(feature->exten, code, strlen(code))) { - res = FEATURE_RETURN_STOREDIGITS; - } - } - } - } - - return res; -} - -static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config) -{ - int x; - - ast_clear_flag(config, AST_FLAGS_ALL); - for (x = 0; x < FEATURES_COUNT; x++) { - if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) { - if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask)) - ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); - - if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask)) - ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); - } - } - - if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) { - char *dynamic_features; - - dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"); - - if (dynamic_features) { - char *tmp = ast_strdupa(dynamic_features); - char *tok; - struct ast_call_feature *feature; - - if (!tmp) { - return; - } - - /* while we have a feature */ - while (NULL != (tok = strsep(&tmp, "#"))) { - if ((feature = find_feature(tok))) { - if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) { - if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER)) - ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0); - if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE)) - ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1); - } - } - } - } - } -} - - -static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name) -{ - int state = 0; - int cause = 0; - int to; - struct ast_channel *chan; - struct ast_channel *monitor_chans[2]; - struct ast_channel *active_channel; - struct ast_frame *f = NULL; - int res = 0, ready = 0; - - if ((chan = ast_request(type, format, data, &cause))) { - ast_set_callerid(chan, cid_num, cid_name, cid_num); - ast_channel_inherit_variables(caller, chan); - if (!ast_call(chan, data, timeout)) { - struct timeval started; - int x, len = 0; - char *disconnect_code = NULL, *dialed_code = NULL; - - ast_indicate(caller, AST_CONTROL_RINGING); - /* support dialing of the featuremap disconnect code while performing an attended tranfer */ - for (x=0; x < FEATURES_COUNT; x++) { - if (strcasecmp(builtin_features[x].sname, "disconnect")) - continue; - - disconnect_code = builtin_features[x].exten; - len = strlen(disconnect_code) + 1; - dialed_code = alloca(len); - memset(dialed_code, 0, len); - break; - } - x = 0; - started = ast_tvnow(); - to = timeout; - while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) { - monitor_chans[0] = caller; - monitor_chans[1] = chan; - active_channel = ast_waitfor_n(monitor_chans, 2, &to); - - /* see if the timeout has been violated */ - if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) { - state = AST_CONTROL_UNHOLD; - ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n"); - break; /*doh! timeout*/ - } - - if (!active_channel) { - continue; - } - - if (chan && (chan == active_channel)){ - f = ast_read(chan); - if (f == NULL) { /*doh! where'd he go?*/ - state = AST_CONTROL_HANGUP; - res = 0; - break; - } - - if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) { - if (f->subclass == AST_CONTROL_RINGING) { - state = f->subclass; - if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name); - ast_indicate(caller, AST_CONTROL_RINGING); - } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) { - state = f->subclass; - ast_frfree(f); - f = NULL; - break; - } else if (f->subclass == AST_CONTROL_ANSWER) { - /* This is what we are hoping for */ - state = f->subclass; - ast_frfree(f); - f = NULL; - ready=1; - break; - } else { - ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass); - } - /* else who cares */ - } - - } else if (caller && (active_channel == caller)) { - f = ast_read(caller); - if (f == NULL) { /*doh! where'd he go?*/ - if (caller->_softhangup && !chan->_softhangup) { - /* make this a blind transfer */ - ready = 1; - break; - } - state = AST_CONTROL_HANGUP; - res = 0; - break; - } - - if (f->frametype == AST_FRAME_DTMF) { - dialed_code[x++] = f->subclass; - dialed_code[x] = '\0'; - if (strlen(dialed_code) == len) { - x = 0; - } else if (x && strncmp(dialed_code, disconnect_code, x)) { - x = 0; - dialed_code[x] = '\0'; - } - if (*dialed_code && !strcmp(dialed_code, disconnect_code)) { - /* Caller Canceled the call */ - state = AST_CONTROL_UNHOLD; - ast_frfree(f); - f = NULL; - break; - } - } - } - if (f) { - ast_frfree(f); - } - } - } else - ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data); - } else { - ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data); - switch(cause) { - case AST_CAUSE_BUSY: - state = AST_CONTROL_BUSY; - break; - case AST_CAUSE_CONGESTION: - state = AST_CONTROL_CONGESTION; - break; - } - } - - ast_indicate(caller, -1); - if (chan && ready) { - if (chan->_state == AST_STATE_UP) - state = AST_CONTROL_ANSWER; - res = 0; - } else if(chan) { - res = -1; - ast_hangup(chan); - chan = NULL; - } else { - res = -1; - } - - if (outstate) - *outstate = state; - - if (chan && res <= 0) { - if (!chan->cdr) { - chan->cdr = ast_cdr_alloc(); - } - if (chan->cdr) { - char tmp[256]; - ast_cdr_init(chan->cdr, chan); - snprintf(tmp, 256, "%s/%s", type, (char *)data); - ast_cdr_setapp(chan->cdr,"Dial",tmp); - ast_cdr_update(chan); - ast_cdr_start(chan->cdr); - ast_cdr_end(chan->cdr); - /* If the cause wasn't handled properly */ - if (ast_cdr_disposition(chan->cdr,chan->hangupcause)) - ast_cdr_failed(chan->cdr); - } else { - ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); - } - } - - return chan; -} - -int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config) -{ - /* Copy voice back and forth between the two channels. Give the peer - the ability to transfer calls with '#<extension' syntax. */ - struct ast_frame *f; - struct ast_channel *who; - char chan_featurecode[FEATURE_MAX_LEN + 1]=""; - char peer_featurecode[FEATURE_MAX_LEN + 1]=""; - int res; - int diff; - int hasfeatures=0; - int hadfeatures=0; - struct ast_option_header *aoh; - struct timeval start = { 0 , 0 }; - struct ast_bridge_config backup_config; - char *monitor_exec; - - memset(&backup_config, 0, sizeof(backup_config)); - - config->start_time = ast_tvnow(); - - if (chan && peer) { - pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name); - pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name); - } else if (chan) - pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL); - - if (monitor_ok) { - if (!monitor_app) { - if (!(monitor_app = pbx_findapp("Monitor"))) - monitor_ok=0; - } - if (monitor_app) { - if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) - pbx_exec(chan, monitor_app, monitor_exec, 1); - else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR"))) - pbx_exec(peer, monitor_app, monitor_exec, 1); - } - } - - set_config_flags(chan, peer, config); - config->firstpass = 1; - - /* Answer if need be */ - if (ast_answer(chan)) - return -1; - peer->appl = "Bridged Call"; - peer->data = chan->name; - - /* copy the userfield from the B-leg to A-leg if applicable */ - if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) { - char tmp[256]; - if (!ast_strlen_zero(chan->cdr->userfield)) { - snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield); - ast_cdr_appenduserfield(chan, tmp); - } else - ast_cdr_setuserfield(chan, peer->cdr->userfield); - /* free the peer's cdr without ast_cdr_free complaining */ - free(peer->cdr); - peer->cdr = NULL; - } - for (;;) { - if (config->feature_timer) - start = ast_tvnow(); - - res = ast_channel_bridge(chan, peer, config, &f, &who); - - if (config->feature_timer) { - /* Update time limit for next pass */ - diff = ast_tvdiff_ms(ast_tvnow(), start); - config->feature_timer -= diff; - if (hasfeatures) { - /* Running on backup config, meaning a feature might be being - activated, but that's no excuse to keep things going - indefinitely! */ - if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) { - ast_log(LOG_DEBUG, "Timed out, realtime this time!\n"); - config->feature_timer = 0; - who = chan; - if (f) - ast_frfree(f); - f = NULL; - res = 0; - } else if (config->feature_timer <= 0) { - /* Not *really* out of time, just out of time for - digits to come in for features. */ - ast_log(LOG_DEBUG, "Timed out for feature!\n"); - if (!ast_strlen_zero(peer_featurecode)) { - ast_dtmf_stream(chan, peer, peer_featurecode, 0); - memset(peer_featurecode, 0, sizeof(peer_featurecode)); - } - if (!ast_strlen_zero(chan_featurecode)) { - ast_dtmf_stream(peer, chan, chan_featurecode, 0); - memset(chan_featurecode, 0, sizeof(chan_featurecode)); - } - if (f) - ast_frfree(f); - hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); - if (!hasfeatures) { - /* Restore original (possibly time modified) bridge config */ - memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); - memset(&backup_config, 0, sizeof(backup_config)); - } - hadfeatures = hasfeatures; - /* Continue as we were */ - continue; - } - } else { - if (config->feature_timer <=0) { - /* We ran out of time */ - config->feature_timer = 0; - who = chan; - if (f) - ast_frfree(f); - f = NULL; - res = 0; - } - } - } - if (res < 0) { - ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); - return -1; - } - - if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || - (f->subclass == AST_CONTROL_CONGESTION)))) { - res = -1; - break; - } - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) { - if (who == chan) - ast_indicate(peer, AST_CONTROL_RINGING); - else - ast_indicate(chan, AST_CONTROL_RINGING); - } - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) { - if (who == chan) - ast_indicate(peer, -1); - else - ast_indicate(chan, -1); - } - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) { - if (who == chan) - ast_indicate(peer, AST_CONTROL_FLASH); - else - ast_indicate(chan, AST_CONTROL_FLASH); - } - if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) { - aoh = f->data; - /* Forward option Requests */ - if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) { - if (who == chan) - ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); - else - ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0); - } - } - /* check for '*', if we find it it's time to disconnect */ - if (f && (f->frametype == AST_FRAME_DTMF)) { - char *featurecode; - int sense; - struct ast_channel *other; - - hadfeatures = hasfeatures; - /* This cannot overrun because the longest feature is one shorter than our buffer */ - if (who == chan) { - other = peer; - sense = FEATURE_SENSE_CHAN; - featurecode = chan_featurecode; - } else { - other = chan; - sense = FEATURE_SENSE_PEER; - featurecode = peer_featurecode; - } - featurecode[strlen(featurecode)] = f->subclass; - config->feature_timer = backup_config.feature_timer; - res = ast_feature_interpret(chan, peer, config, featurecode, sense); - switch(res) { - case FEATURE_RETURN_PASSDIGITS: - ast_dtmf_stream(other, who, featurecode, 0); - /* Fall through */ - case FEATURE_RETURN_SUCCESS: - memset(featurecode, 0, sizeof(chan_featurecode)); - break; - } - if (res >= FEATURE_RETURN_PASSDIGITS) { - res = 0; - } else { - ast_frfree(f); - break; - } - hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode); - if (hadfeatures && !hasfeatures) { - /* Restore backup */ - memcpy(config, &backup_config, sizeof(struct ast_bridge_config)); - memset(&backup_config, 0, sizeof(struct ast_bridge_config)); - } else if (hasfeatures) { - if (!hadfeatures) { - /* Backup configuration */ - memcpy(&backup_config, config, sizeof(struct ast_bridge_config)); - /* Setup temporary config options */ - config->play_warning = 0; - ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING); - ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING); - config->warning_freq = 0; - config->warning_sound = NULL; - config->end_sound = NULL; - config->start_sound = NULL; - config->firstpass = 0; - } - config->feature_timer = featuredigittimeout; - ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer); - } - } - if (f) - ast_frfree(f); - } - return res; -} - -static void *do_parking_thread(void *ignore) -{ - int ms, tms, max; - struct parkeduser *pu, *pl, *pt = NULL; - struct timeval tv; - struct ast_frame *f; - char exten[AST_MAX_EXTENSION]; - char *peername,*cp; - char returnexten[AST_MAX_EXTENSION]; - struct ast_context *con; - int x; - fd_set rfds, efds; - fd_set nrfds, nefds; - FD_ZERO(&rfds); - FD_ZERO(&efds); - - for (;;) { - ms = -1; - max = -1; - ast_mutex_lock(&parking_lock); - pl = NULL; - pu = parkinglot; - FD_ZERO(&nrfds); - FD_ZERO(&nefds); - while(pu) { - if (pu->notquiteyet) { - /* Pretend this one isn't here yet */ - pl = pu; - pu = pu->next; - continue; - } - tms = ast_tvdiff_ms(ast_tvnow(), pu->start); - if (tms > pu->parkingtime) { - /* Stop music on hold */ - ast_moh_stop(pu->chan); - ast_indicate(pu->chan, AST_CONTROL_UNHOLD); - /* Get chan, exten from derived kludge */ - if (pu->peername[0]) { - peername = ast_strdupa(pu->peername); - cp = strrchr(peername, '-'); - if (cp) - *cp = 0; - con = ast_context_find(parking_con_dial); - if (!con) { - con = ast_context_create(NULL, parking_con_dial, registrar); - if (!con) { - ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial); - } - } - if (con) { - snprintf(returnexten, sizeof(returnexten), "%s||t", peername); - ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar); - } - ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten)); - ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context)); - pu->chan->priority = 1; - - } else { - /* They've been waiting too long, send them back to where they came. Theoretically they - should have their original extensions and such, but we copy to be on the safe side */ - ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)); - ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context)); - pu->chan->priority = pu->priority; - } - - manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut", - "Exten: %d\r\n" - "Channel: %s\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" - ,pu->parkingnum, pu->chan->name - ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") - ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") - ); - - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority); - /* Start up the PBX, or hang them up */ - if (ast_pbx_start(pu->chan)) { - ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name); - ast_hangup(pu->chan); - } - /* And take them out of the parking lot */ - if (pl) - pl->next = pu->next; - else - parkinglot = pu->next; - pt = pu; - pu = pu->next; - con = ast_context_find(parking_con); - if (con) { - snprintf(exten, sizeof(exten), "%d", pt->parkingnum); - if (ast_context_remove_extension2(con, exten, 1, NULL)) - ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); - } else - ast_log(LOG_WARNING, "Whoa, no parking context?\n"); - free(pt); - } else { - for (x = 0; x < AST_MAX_FDS; x++) { - if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) { - if (FD_ISSET(pu->chan->fds[x], &efds)) - ast_set_flag(pu->chan, AST_FLAG_EXCEPTION); - else - ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION); - pu->chan->fdno = x; - /* See if they need servicing */ - f = ast_read(pu->chan); - if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { - if (f) - ast_frfree(f); - manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp", - "Exten: %d\r\n" - "Channel: %s\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" - ,pu->parkingnum, pu->chan->name - ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") - ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") - ); - - /* There's a problem, hang them up*/ - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name); - ast_hangup(pu->chan); - /* And take them out of the parking lot */ - if (pl) - pl->next = pu->next; - else - parkinglot = pu->next; - pt = pu; - pu = pu->next; - con = ast_context_find(parking_con); - if (con) { - snprintf(exten, sizeof(exten), "%d", pt->parkingnum); - if (ast_context_remove_extension2(con, exten, 1, NULL)) - ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); - } else - ast_log(LOG_WARNING, "Whoa, no parking context?\n"); - free(pt); - break; - } else { - /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */ - ast_frfree(f); - if (pu->moh_trys < 3 && !pu->chan->generatordata) { - ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source. Restarting.\n"); - ast_moh_start(pu->chan, NULL); - pu->moh_trys++; - } - goto std; /* XXX Ick: jumping into an else statement??? XXX */ - } - } - } - if (x >= AST_MAX_FDS) { -std: for (x=0; x<AST_MAX_FDS; x++) { - /* Keep this one for next one */ - if (pu->chan->fds[x] > -1) { - FD_SET(pu->chan->fds[x], &nrfds); - FD_SET(pu->chan->fds[x], &nefds); - if (pu->chan->fds[x] > max) - max = pu->chan->fds[x]; - } - } - /* Keep track of our longest wait */ - if ((tms < ms) || (ms < 0)) - ms = tms; - pl = pu; - pu = pu->next; - } - } - } - ast_mutex_unlock(&parking_lock); - rfds = nrfds; - efds = nefds; - tv = ast_samp2tv(ms, 1000); - /* Wait for something to happen */ - ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL); - pthread_testcancel(); - } - return NULL; /* Never reached */ -} - -static int park_call_exec(struct ast_channel *chan, void *data) -{ - /* Data is unused at the moment but could contain a parking - lot context eventually */ - int res=0; - struct localuser *u; - LOCAL_USER_ADD(u); - /* Setup the exten/priority to be s/1 since we don't know - where this call should return */ - strcpy(chan->exten, "s"); - chan->priority = 1; - if (chan->_state != AST_STATE_UP) - res = ast_answer(chan); - if (!res) - res = ast_safe_sleep(chan, 1000); - if (!res) - res = ast_park_call(chan, chan, 0, NULL); - LOCAL_USER_REMOVE(u); - if (!res) - res = AST_PBX_KEEPALIVE; - return res; -} - -static int park_exec(struct ast_channel *chan, void *data) -{ - int res=0; - struct localuser *u; - struct ast_channel *peer=NULL; - struct parkeduser *pu, *pl=NULL; - char exten[AST_MAX_EXTENSION]; - struct ast_context *con; - int park; - int dres; - struct ast_bridge_config config; - - if (!data) { - ast_log(LOG_WARNING, "Park requires an argument (extension number)\n"); - return -1; - } - LOCAL_USER_ADD(u); - park = atoi((char *)data); - ast_mutex_lock(&parking_lock); - pu = parkinglot; - while(pu) { - if (pu->parkingnum == park) { - if (pl) - pl->next = pu->next; - else - parkinglot = pu->next; - break; - } - pl = pu; - pu = pu->next; - } - ast_mutex_unlock(&parking_lock); - if (pu) { - peer = pu->chan; - con = ast_context_find(parking_con); - if (con) { - snprintf(exten, sizeof(exten), "%d", pu->parkingnum); - if (ast_context_remove_extension2(con, exten, 1, NULL)) - ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n"); - } else - ast_log(LOG_WARNING, "Whoa, no parking context?\n"); - - manager_event(EVENT_FLAG_CALL, "UnParkedCall", - "Exten: %d\r\n" - "Channel: %s\r\n" - "From: %s\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" - ,pu->parkingnum, pu->chan->name, chan->name - ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>") - ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>") - ); - - free(pu); - } - /* JK02: it helps to answer the channel if not already up */ - if (chan->_state != AST_STATE_UP) { - ast_answer(chan); - } - - if (peer) { - /* Play a courtesy beep in the calling channel to prefix the bridge connecting */ - if (!ast_strlen_zero(courtesytone)) { - if (!ast_streamfile(chan, courtesytone, chan->language)) { - if (ast_waitstream(chan, "") < 0) { - ast_log(LOG_WARNING, "Failed to play courtesy tone!\n"); - ast_hangup(peer); - return -1; - } - } - } - - ast_moh_stop(peer); - ast_indicate(peer, AST_CONTROL_UNHOLD); - res = ast_channel_make_compatible(chan, peer); - if (res < 0) { - ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); - ast_hangup(peer); - return -1; - } - /* This runs sorta backwards, since we give the incoming channel control, as if it - were the person called. */ - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); - - memset(&config, 0, sizeof(struct ast_bridge_config)); - ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); - ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); - config.timelimit = 0; - config.play_warning = 0; - config.warning_freq = 0; - config.warning_sound=NULL; - res = ast_bridge_call(chan, peer, &config); - - /* Simulate the PBX hanging up */ - if (res != AST_PBX_NO_HANGUP_PEER) - ast_hangup(peer); - return res; - } else { - /* XXX Play a message XXX */ - dres = ast_streamfile(chan, "pbx-invalidpark", chan->language); - if (!dres) - dres = ast_waitstream(chan, ""); - else { - ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name); - dres = 0; - } - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park); - res = -1; - } - LOCAL_USER_REMOVE(u); - return res; -} - -static int handle_showfeatures(int fd, int argc, char *argv[]) -{ - int i; - int fcount; - struct ast_call_feature *feature; - char format[] = "%-25s %-7s %-7s\n"; - - ast_cli(fd, format, "Builtin Feature", "Default", "Current"); - ast_cli(fd, format, "---------------", "-------", "-------"); - - ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext()); /* default hardcoded above, so we'll hardcode it here */ - - fcount = sizeof(builtin_features) / sizeof(builtin_features[0]); - - for (i = 0; i < fcount; i++) - { - ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten); - } - ast_cli(fd, "\n"); - ast_cli(fd, format, "Dynamic Feature", "Default", "Current"); - ast_cli(fd, format, "---------------", "-------", "-------"); - if (AST_LIST_EMPTY(&feature_list)) { - ast_cli(fd, "(none)\n"); - } - else { - AST_LIST_LOCK(&feature_list); - AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) { - ast_cli(fd, format, feature->sname, "no def", feature->exten); - } - AST_LIST_UNLOCK(&feature_list); - } - ast_cli(fd, "\nCall parking\n"); - ast_cli(fd, "------------\n"); - ast_cli(fd,"%-20s: %s\n", "Parking extension", parking_ext); - ast_cli(fd,"%-20s: %s\n", "Parking context", parking_con); - ast_cli(fd,"%-20s: %d-%d\n", "Parked call extensions", parking_start, parking_stop); - ast_cli(fd,"\n"); - - return RESULT_SUCCESS; -} - -static char showfeatures_help[] = -"Usage: show features\n" -" Lists currently configured features.\n"; - -static struct ast_cli_entry showfeatures = -{ { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help }; - -static int handle_parkedcalls(int fd, int argc, char *argv[]) -{ - struct parkeduser *cur; - int numparked = 0; - - ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel" - , "Context", "Extension", "Pri", "Timeout"); - - ast_mutex_lock(&parking_lock); - - cur = parkinglot; - while(cur) { - ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n" - ,cur->parkingnum, cur->chan->name, cur->context, cur->exten - ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)); - - cur = cur->next; - numparked++; - } - ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : ""); - - ast_mutex_unlock(&parking_lock); - - return RESULT_SUCCESS; -} - -static char showparked_help[] = -"Usage: show parkedcalls\n" -" Lists currently parked calls.\n"; - -static struct ast_cli_entry showparked = -{ { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help }; - -/* Dump lot status */ -static int manager_parking_status( struct mansession *s, struct message *m ) -{ - struct parkeduser *cur; - char *id = astman_get_header(m,"ActionID"); - char idText[256] = ""; - - if (!ast_strlen_zero(id)) - snprintf(idText,256,"ActionID: %s\r\n",id); - - astman_send_ack(s, m, "Parked calls will follow"); - - ast_mutex_lock(&parking_lock); - - cur=parkinglot; - while(cur) { - ast_cli(s->fd, "Event: ParkedCall\r\n" - "Exten: %d\r\n" - "Channel: %s\r\n" - "Timeout: %ld\r\n" - "CallerID: %s\r\n" - "CallerIDName: %s\r\n" - "%s" - "\r\n" - ,cur->parkingnum, cur->chan->name - ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL) - ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "") - ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "") - ,idText); - - cur = cur->next; - } - - ast_cli(s->fd, - "Event: ParkedCallsComplete\r\n" - "%s" - "\r\n",idText); - - ast_mutex_unlock(&parking_lock); - - return RESULT_SUCCESS; -} - - -int ast_pickup_call(struct ast_channel *chan) -{ - struct ast_channel *cur = NULL; - int res = -1; - - while ( (cur = ast_channel_walk_locked(cur)) != NULL) { - if (!cur->pbx && - (cur != chan) && - (chan->pickupgroup & cur->callgroup) && - ((cur->_state == AST_STATE_RINGING) || - (cur->_state == AST_STATE_RING))) { - break; - } - ast_mutex_unlock(&cur->lock); - } - if (cur) { - if (option_debug) - ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name); - res = ast_answer(chan); - if (res) - ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name); - res = ast_queue_control(chan, AST_CONTROL_ANSWER); - if (res) - ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name); - res = ast_channel_masquerade(cur, chan); - if (res) - ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name); /* Done */ - ast_mutex_unlock(&cur->lock); - } else { - if (option_debug) - ast_log(LOG_DEBUG, "No call pickup possible...\n"); - } - return res; -} - -static int load_config(void) -{ - int start = 0, end = 0; - struct ast_context *con = NULL; - struct ast_config *cfg = NULL; - struct ast_variable *var = NULL; - char old_parking_ext[AST_MAX_EXTENSION]; - char old_parking_con[AST_MAX_EXTENSION] = ""; - - if (!ast_strlen_zero(parking_con)) { - strcpy(old_parking_ext, parking_ext); - strcpy(old_parking_con, parking_con); - } - - /* Reset to defaults */ - strcpy(parking_con, "parkedcalls"); - strcpy(parking_con_dial, "park-dial"); - strcpy(parking_ext, "700"); - strcpy(pickup_ext, "*8"); - courtesytone[0] = '\0'; - strcpy(xfersound, "beep"); - strcpy(xferfailsound, "pbx-invalid"); - parking_start = 701; - parking_stop = 750; - parkfindnext = 0; - - transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; - featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; - - cfg = ast_config_load("features.conf"); - if (!cfg) { - cfg = ast_config_load("parking.conf"); - if (cfg) - ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'. Please rename it.\n"); - } - if (cfg) { - var = ast_variable_browse(cfg, "general"); - while(var) { - if (!strcasecmp(var->name, "parkext")) { - ast_copy_string(parking_ext, var->value, sizeof(parking_ext)); - } else if (!strcasecmp(var->name, "context")) { - ast_copy_string(parking_con, var->value, sizeof(parking_con)); - } else if (!strcasecmp(var->name, "parkingtime")) { - if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) { - ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value); - parkingtime = DEFAULT_PARK_TIME; - } else - parkingtime = parkingtime * 1000; - } else if (!strcasecmp(var->name, "parkpos")) { - if (sscanf(var->value, "%d-%d", &start, &end) != 2) { - ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno); - } else { - parking_start = start; - parking_stop = end; - } - } else if (!strcasecmp(var->name, "findslot")) { - parkfindnext = (!strcasecmp(var->value, "next")); - } else if (!strcasecmp(var->name, "adsipark")) { - adsipark = ast_true(var->value); - } else if (!strcasecmp(var->name, "transferdigittimeout")) { - if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) { - ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value); - transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT; - } else - transferdigittimeout = transferdigittimeout * 1000; - } else if (!strcasecmp(var->name, "featuredigittimeout")) { - if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) { - ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value); - featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT; - } - } else if (!strcasecmp(var->name, "courtesytone")) { - ast_copy_string(courtesytone, var->value, sizeof(courtesytone)); - } else if (!strcasecmp(var->name, "xfersound")) { - ast_copy_string(xfersound, var->value, sizeof(xfersound)); - } else if (!strcasecmp(var->name, "xferfailsound")) { - ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound)); - } else if (!strcasecmp(var->name, "pickupexten")) { - ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext)); - } - var = var->next; - } - - unmap_features(); - var = ast_variable_browse(cfg, "featuremap"); - while(var) { - if (remap_feature(var->name, var->value)) - ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name); - var = var->next; - } - - /* Map a key combination to an application*/ - ast_unregister_features(); - var = ast_variable_browse(cfg, "applicationmap"); - while(var) { - char *tmp_val=strdup(var->value); - char *exten, *party=NULL, *app=NULL, *app_args=NULL; - - if (!tmp_val) { - ast_log(LOG_ERROR, "res_features: strdup failed"); - continue; - } - - - exten=strsep(&tmp_val,","); - if (exten) party=strsep(&tmp_val,","); - if (party) app=strsep(&tmp_val,","); - - if (app) app_args=strsep(&tmp_val,","); - - if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) { - ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name); - free(tmp_val); - var = var->next; - continue; - } - - { - struct ast_call_feature *feature=find_feature(var->name); - int mallocd=0; - - if (!feature) { - feature=malloc(sizeof(struct ast_call_feature)); - mallocd=1; - } - if (!feature) { - ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n"); - free(tmp_val); - var = var->next; - continue; - } - - memset(feature,0,sizeof(struct ast_call_feature)); - ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN); - ast_copy_string(feature->app,app,FEATURE_APP_LEN); - ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN); - free(tmp_val); - - if (app_args) - ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN); - - ast_copy_string(feature->exten, exten,sizeof(feature->exten)); - feature->operation=feature_exec_app; - ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF); - - if (!strcasecmp(party,"caller")) - ast_set_flag(feature,AST_FEATURE_FLAG_CALLER); - else if (!strcasecmp(party, "callee")) - ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE); - else { - ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name); - var = var->next; - continue; - } - - ast_register_feature(feature); - - if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten); - } - var = var->next; - } - } - ast_config_destroy(cfg); - - /* Remove the old parking extension */ - if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) { - ast_context_remove_extension2(con, old_parking_ext, 1, registrar); - ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con); - } - - if (!(con = ast_context_find(parking_con))) { - if (!(con = ast_context_create(NULL, parking_con, registrar))) { - ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con); - return -1; - } - } - return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar); -} - -int reload(void) { - return load_config(); -} - -int load_module(void) -{ - int res; - - AST_LIST_HEAD_INIT(&feature_list); - memset(parking_ext, 0, sizeof(parking_ext)); - memset(parking_con, 0, sizeof(parking_con)); - - if ((res = load_config())) - return res; - ast_cli_register(&showparked); - ast_cli_register(&showfeatures); - ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL); - res = ast_register_application(parkedcall, park_exec, synopsis, descrip); - if (!res) - res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2); - if (!res) { - ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" ); - } - return res; -} - - -int unload_module(void) -{ - STANDARD_HANGUP_LOCALUSERS; - - ast_manager_unregister("ParkedCalls"); - ast_cli_unregister(&showfeatures); - ast_cli_unregister(&showparked); - ast_unregister_application(parkcall); - return ast_unregister_application(parkedcall); -} - -char *description(void) -{ - return "Call Features Resource"; -} - -int usecount(void) -{ - /* Never allow parking to be unloaded because it will - unresolve needed symbols in the dialer */ -#if 0 - int res; - STANDARD_USECOUNT(res); - return res; -#else - return 1; -#endif -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_indications.c b/1.2-netsec/res/res_indications.c deleted file mode 100644 index 65ac3a9ba..000000000 --- a/1.2-netsec/res/res_indications.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 2002, Pauline Middelink - * - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file res_indications.c - * - * \brief Load the indications - * - * \author Pauline Middelink <middelink@polyware.nl> - * - * Load the country specific dialtones into the asterisk PBX. - */ - -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/cli.h" -#include "asterisk/logger.h" -#include "asterisk/config.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/translate.h" -#include "asterisk/indications.h" - - -/* Globals */ -static const char dtext[] = "Indications Configuration"; -static const char config[] = "indications.conf"; - -/* - * Help for commands provided by this module ... - */ -static char help_add_indication[] = -"Usage: indication add <country> <indication> \"<tonelist>\"\n" -" Add the given indication to the country.\n"; - -static char help_remove_indication[] = -"Usage: indication remove <country> <indication>\n" -" Remove the given indication from the country.\n"; - -static char help_show_indications[] = -"Usage: show indications [<country> ...]\n" -" Show either a condensed for of all country/indications, or the\n" -" indications for the specified countries.\n"; - -char *playtones_desc= -"PlayTones(arg): Plays a tone list. Execution will continue with the next step immediately,\n" -"while the tones continue to play.\n" -"Arg is either the tone name defined in the indications.conf configuration file, or a directly\n" -"specified list of frequencies and durations.\n" -"See the sample indications.conf for a description of the specification of a tonelist.\n\n" -"Use the StopPlayTones application to stop the tones playing. \n"; - -/* - * Implementation of functions provided by this module - */ - -/* - * ADD INDICATION command stuff - */ -static int handle_add_indication(int fd, int argc, char *argv[]) -{ - struct tone_zone *tz; - int created_country = 0; - if (argc != 5) return RESULT_SHOWUSAGE; - - tz = ast_get_indication_zone(argv[2]); - if (!tz) { - /* country does not exist, create it */ - ast_log(LOG_NOTICE, "Country '%s' does not exist, creating it.\n",argv[2]); - - tz = malloc(sizeof(struct tone_zone)); - if (!tz) { - ast_log(LOG_WARNING, "Out of memory\n"); - return -1; - } - memset(tz,0,sizeof(struct tone_zone)); - ast_copy_string(tz->country,argv[2],sizeof(tz->country)); - if (ast_register_indication_country(tz)) { - ast_log(LOG_WARNING, "Unable to register new country\n"); - free(tz); - return -1; - } - created_country = 1; - } - if (ast_register_indication(tz,argv[3],argv[4])) { - ast_log(LOG_WARNING, "Unable to register indication %s/%s\n",argv[2],argv[3]); - if (created_country) - ast_unregister_indication_country(argv[2]); - return -1; - } - return 0; -} - -/* - * REMOVE INDICATION command stuff - */ -static int handle_remove_indication(int fd, int argc, char *argv[]) -{ - struct tone_zone *tz; - if (argc != 3 && argc != 4) return RESULT_SHOWUSAGE; - - if (argc == 3) { - /* remove entiry country */ - if (ast_unregister_indication_country(argv[2])) { - ast_log(LOG_WARNING, "Unable to unregister indication country %s\n",argv[2]); - return -1; - } - return 0; - } - - tz = ast_get_indication_zone(argv[2]); - if (!tz) { - ast_log(LOG_WARNING, "Unable to unregister indication %s/%s, country does not exists\n",argv[2],argv[3]); - return -1; - } - if (ast_unregister_indication(tz,argv[3])) { - ast_log(LOG_WARNING, "Unable to unregister indication %s/%s\n",argv[2],argv[3]); - return -1; - } - return 0; -} - -/* - * SHOW INDICATIONS command stuff - */ -static int handle_show_indications(int fd, int argc, char *argv[]) -{ - struct tone_zone *tz; - char buf[256]; - int found_country = 0; - - if (ast_mutex_lock(&tzlock)) { - ast_log(LOG_WARNING, "Unable to lock tone_zones list\n"); - return 0; - } - if (argc == 2) { - /* no arguments, show a list of countries */ - ast_cli(fd,"Country Alias Description\n" - "===========================\n"); - for (tz=tone_zones; tz; tz=tz->next) { - ast_cli(fd,"%-7.7s %-7.7s %s\n", tz->country, tz->alias, tz->description); - } - ast_mutex_unlock(&tzlock); - return 0; - } - /* there was a request for specific country(ies), lets humor them */ - for (tz=tone_zones; tz; tz=tz->next) { - int i,j; - for (i=2; i<argc; i++) { - if (strcasecmp(tz->country,argv[i])==0 && - !tz->alias[0]) { - struct tone_zone_sound* ts; - if (!found_country) { - found_country = 1; - ast_cli(fd,"Country Indication PlayList\n" - "=====================================\n"); - } - j = snprintf(buf,sizeof(buf),"%-7.7s %-15.15s ",tz->country,"<ringcadence>"); - for (i=0; i<tz->nrringcadence; i++) { - j += snprintf(buf+j,sizeof(buf)-j,"%d,",tz->ringcadence[i]); - } - if (tz->nrringcadence) j--; - ast_copy_string(buf+j,"\n",sizeof(buf)-j); - ast_cli(fd,buf); - for (ts=tz->tones; ts; ts=ts->next) - ast_cli(fd,"%-7.7s %-15.15s %s\n",tz->country,ts->name,ts->data); - break; - } - } - } - if (!found_country) - ast_cli(fd,"No countries matched your criteria.\n"); - ast_mutex_unlock(&tzlock); - return -1; -} - -/* - * Playtones command stuff - */ -static int handle_playtones(struct ast_channel *chan, void *data) -{ - struct tone_zone_sound *ts; - int res; - - if (!data || !((char*)data)[0]) { - ast_log(LOG_NOTICE,"Nothing to play\n"); - return -1; - } - ts = ast_get_indication_tone(chan->zone, (const char*)data); - if (ts && ts->data[0]) - res = ast_playtones_start(chan, 0, ts->data, 0); - else - res = ast_playtones_start(chan, 0, (const char*)data, 0); - if (res) - ast_log(LOG_NOTICE,"Unable to start playtones\n"); - return res; -} - -/* - * StopPlaylist command stuff - */ -static int handle_stopplaytones(struct ast_channel *chan, void *data) -{ - ast_playtones_stop(chan); - return 0; -} - -/* - * Load module stuff - */ -static int ind_load_module(void) -{ - struct ast_config *cfg; - struct ast_variable *v; - char *cxt; - char *c; - struct tone_zone *tones; - const char *country = NULL; - - /* that the following cast is needed, is yuk! */ - /* yup, checked it out. It is NOT written to. */ - cfg = ast_config_load((char *)config); - if (!cfg) - return 0; - - /* Use existing config to populate the Indication table */ - cxt = ast_category_browse(cfg, NULL); - while(cxt) { - /* All categories but "general" are considered countries */ - if (!strcasecmp(cxt, "general")) { - cxt = ast_category_browse(cfg, cxt); - continue; - } - tones = malloc(sizeof(struct tone_zone)); - if (!tones) { - ast_log(LOG_WARNING,"Out of memory\n"); - ast_config_destroy(cfg); - return -1; - } - memset(tones,0,sizeof(struct tone_zone)); - ast_copy_string(tones->country,cxt,sizeof(tones->country)); - - v = ast_variable_browse(cfg, cxt); - while(v) { - if (!strcasecmp(v->name, "description")) { - ast_copy_string(tones->description, v->value, sizeof(tones->description)); - } else if ((!strcasecmp(v->name,"ringcadence"))||(!strcasecmp(v->name,"ringcadance"))) { - char *ring,*rings = ast_strdupa(v->value); - c = rings; - ring = strsep(&c,","); - while (ring) { - int *tmp, val; - if (!isdigit(ring[0]) || (val=atoi(ring))==-1) { - ast_log(LOG_WARNING,"Invalid ringcadence given '%s' at line %d.\n",ring,v->lineno); - ring = strsep(&c,","); - continue; - } - tmp = realloc(tones->ringcadence,(tones->nrringcadence+1)*sizeof(int)); - if (!tmp) { - ast_log(LOG_WARNING, "Out of memory\n"); - ast_config_destroy(cfg); - return -1; - } - tones->ringcadence = tmp; - tmp[tones->nrringcadence] = val; - tones->nrringcadence++; - /* next item */ - ring = strsep(&c,","); - } - } else if (!strcasecmp(v->name,"alias")) { - char *countries = ast_strdupa(v->value); - c = countries; - country = strsep(&c,","); - while (country) { - struct tone_zone* azone = malloc(sizeof(struct tone_zone)); - if (!azone) { - ast_log(LOG_WARNING,"Out of memory\n"); - ast_config_destroy(cfg); - return -1; - } - memset(azone,0,sizeof(struct tone_zone)); - ast_copy_string(azone->country, country, sizeof(azone->country)); - ast_copy_string(azone->alias, cxt, sizeof(azone->alias)); - if (ast_register_indication_country(azone)) { - ast_log(LOG_WARNING, "Unable to register indication alias at line %d.\n",v->lineno); - free(tones); - } - /* next item */ - country = strsep(&c,","); - } - } else { - /* add tone to country */ - struct tone_zone_sound *ps,*ts; - for (ps=NULL,ts=tones->tones; ts; ps=ts, ts=ts->next) { - if (strcasecmp(v->name,ts->name)==0) { - /* already there */ - ast_log(LOG_NOTICE,"Duplicate entry '%s', skipped.\n",v->name); - goto out; - } - } - /* not there, add it to the back */ - ts = malloc(sizeof(struct tone_zone_sound)); - if (!ts) { - ast_log(LOG_WARNING, "Out of memory\n"); - ast_config_destroy(cfg); - return -1; - } - ts->next = NULL; - ts->name = strdup(v->name); - ts->data = strdup(v->value); - if (ps) - ps->next = ts; - else - tones->tones = ts; - } -out: v = v->next; - } - if (tones->description[0] || tones->alias[0] || tones->tones) { - if (ast_register_indication_country(tones)) { - ast_log(LOG_WARNING, "Unable to register indication at line %d.\n",v->lineno); - free(tones); - } - } else free(tones); - - cxt = ast_category_browse(cfg, cxt); - } - - /* determine which country is the default */ - country = ast_variable_retrieve(cfg,"general","country"); - if (!country || !*country || ast_set_indication_country(country)) - ast_log(LOG_WARNING,"Unable to set the default country (for indication tones)\n"); - - ast_config_destroy(cfg); - return 0; -} - -/* - * CLI entries for commands provided by this module - */ -static struct ast_cli_entry add_indication_cli = - { { "indication", "add", NULL }, handle_add_indication, - "Add the given indication to the country", help_add_indication, - NULL }; - -static struct ast_cli_entry remove_indication_cli = - { { "indication", "remove", NULL }, handle_remove_indication, - "Remove the given indication from the country", help_remove_indication, - NULL }; - -static struct ast_cli_entry show_indications_cli = - { { "show", "indications", NULL }, handle_show_indications, - "Show a list of all country/indications", help_show_indications, - NULL }; - -/* - * Standard module functions ... - */ -int unload_module(void) -{ - /* remove the registed indications... */ - ast_unregister_indication_country(NULL); - - /* and the functions */ - ast_cli_unregister(&add_indication_cli); - ast_cli_unregister(&remove_indication_cli); - ast_cli_unregister(&show_indications_cli); - ast_unregister_application("PlayTones"); - ast_unregister_application("StopPlayTones"); - return 0; -} - - -int load_module(void) -{ - if (ind_load_module()) return -1; - - ast_cli_register(&add_indication_cli); - ast_cli_register(&remove_indication_cli); - ast_cli_register(&show_indications_cli); - ast_register_application("PlayTones", handle_playtones, "Play a tone list", playtones_desc); - ast_register_application("StopPlayTones", handle_stopplaytones, "Stop playing a tone list","Stop playing a tone list"); - - return 0; -} - -int reload(void) -{ - /* remove the registed indications... */ - ast_unregister_indication_country(NULL); - - return ind_load_module(); -} - -char *description(void) -{ - /* that the following cast is needed, is yuk! */ - return (char*)dtext; -} - -int usecount(void) -{ - return 0; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_monitor.c b/1.2-netsec/res/res_monitor.c deleted file mode 100644 index adc6144b5..000000000 --- a/1.2-netsec/res/res_monitor.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief PBX channel monitoring - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <libgen.h> /* dirname() */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/lock.h" -#include "asterisk/channel.h" -#include "asterisk/logger.h" -#include "asterisk/file.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/manager.h" -#include "asterisk/cli.h" -#include "asterisk/monitor.h" -#include "asterisk/app.h" -#include "asterisk/utils.h" -#include "asterisk/config.h" - -AST_MUTEX_DEFINE_STATIC(monitorlock); - -static unsigned long seq = 0; - -static char *monitor_synopsis = "Monitor a channel"; - -static char *monitor_descrip = "Monitor([file_format[:urlbase]|[fname_base]|[options]]):\n" -"Used to start monitoring a channel. The channel's input and output\n" -"voice packets are logged to files until the channel hangs up or\n" -"monitoring is stopped by the StopMonitor application.\n" -" file_format optional, if not set, defaults to \"wav\"\n" -" fname_base if set, changes the filename used to the one specified.\n" -" options:\n" -" m - when the recording ends mix the two leg files into one and\n" -" delete the two leg files. If the variable MONITOR_EXEC is set, the\n" -" application referenced in it will be executed instead of\n" -" soxmix and the raw leg files will NOT be deleted automatically.\n" -" soxmix or MONITOR_EXEC is handed 3 arguments, the two leg files\n" -" and a target mixed file name which is the same as the leg file names\n" -" only without the in/out designator.\n" -" If MONITOR_EXEC_ARGS is set, the contents will be passed on as\n" -" additional arguements to MONITOR_EXEC\n" -" Both MONITOR_EXEC and the Mix flag can be set from the\n" -" administrator interface\n" -"\n" -" b - Don't begin recording unless a call is bridged to another channel\n" -"\nReturns -1 if monitor files can't be opened or if the channel is already\n" -"monitored, otherwise 0.\n" -; - -static char *stopmonitor_synopsis = "Stop monitoring a channel"; - -static char *stopmonitor_descrip = "StopMonitor\n" - "Stops monitoring a channel. Has no effect if the channel is not monitored\n"; - -static char *changemonitor_synopsis = "Change monitoring filename of a channel"; - -static char *changemonitor_descrip = "ChangeMonitor(filename_base)\n" - "Changes monitoring filename of a channel. Has no effect if the channel is not monitored\n" - "The argument is the new filename base to use for monitoring this channel.\n"; - -/* Start monitoring a channel */ -int ast_monitor_start( struct ast_channel *chan, const char *format_spec, - const char *fname_base, int need_lock) -{ - int res = 0; - char tmp[256]; - - if (need_lock) { - if (ast_mutex_lock(&chan->lock)) { - ast_log(LOG_WARNING, "Unable to lock channel\n"); - return -1; - } - } - - if (!(chan->monitor)) { - struct ast_channel_monitor *monitor; - char *channel_name, *p; - - /* Create monitoring directory if needed */ - if (mkdir(ast_config_AST_MONITOR_DIR, 0770) < 0) { - if (errno != EEXIST) { - ast_log(LOG_WARNING, "Unable to create audio monitor directory: %s\n", - strerror(errno)); - } - } - - monitor = malloc(sizeof(struct ast_channel_monitor)); - if (!monitor) { - if (need_lock) - ast_mutex_unlock(&chan->lock); - return -1; - } - memset(monitor, 0, sizeof(struct ast_channel_monitor)); - - /* Determine file names */ - if (!ast_strlen_zero(fname_base)) { - int directory = strchr(fname_base, '/') ? 1 : 0; - /* try creating the directory just in case it doesn't exist */ - if (directory) { - char *name = strdup(fname_base); - snprintf(tmp, sizeof(tmp), "mkdir -p \"%s\"",dirname(name)); - free(name); - ast_safe_system(tmp); - } - snprintf(monitor->read_filename, FILENAME_MAX, "%s/%s-in", - directory ? "" : ast_config_AST_MONITOR_DIR, fname_base); - snprintf(monitor->write_filename, FILENAME_MAX, "%s/%s-out", - directory ? "" : ast_config_AST_MONITOR_DIR, fname_base); - ast_copy_string(monitor->filename_base, fname_base, sizeof(monitor->filename_base)); - } else { - ast_mutex_lock(&monitorlock); - snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld", - ast_config_AST_MONITOR_DIR, seq); - snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld", - ast_config_AST_MONITOR_DIR, seq); - seq++; - ast_mutex_unlock(&monitorlock); - - if((channel_name = ast_strdupa(chan->name))) { - while((p = strchr(channel_name, '/'))) { - *p = '-'; - } - snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s", - ast_config_AST_MONITOR_DIR, (int)time(NULL),channel_name); - monitor->filename_changed = 1; - } else { - ast_log(LOG_ERROR,"Failed to allocate Memory\n"); - return -1; - } - } - - monitor->stop = ast_monitor_stop; - - /* Determine file format */ - if (!ast_strlen_zero(format_spec)) { - monitor->format = strdup(format_spec); - } else { - monitor->format = strdup("wav"); - } - - /* open files */ - if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0) { - ast_filedelete(monitor->read_filename, NULL); - } - if (!(monitor->read_stream = ast_writefile(monitor->read_filename, - monitor->format, NULL, - O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) { - ast_log(LOG_WARNING, "Could not create file %s\n", - monitor->read_filename); - free(monitor); - ast_mutex_unlock(&chan->lock); - return -1; - } - if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) { - ast_filedelete(monitor->write_filename, NULL); - } - if (!(monitor->write_stream = ast_writefile(monitor->write_filename, - monitor->format, NULL, - O_CREAT|O_TRUNC|O_WRONLY, 0, 0644))) { - ast_log(LOG_WARNING, "Could not create file %s\n", - monitor->write_filename); - ast_closestream(monitor->read_stream); - free(monitor); - ast_mutex_unlock(&chan->lock); - return -1; - } - chan->monitor = monitor; - /* so we know this call has been monitored in case we need to bill for it or something */ - pbx_builtin_setvar_helper(chan, "__MONITORED","true"); - } else { - ast_log(LOG_DEBUG,"Cannot start monitoring %s, already monitored\n", - chan->name); - res = -1; - } - - if (need_lock) { - ast_mutex_unlock(&chan->lock); - } - return res; -} - -/* Stop monitoring a channel */ -int ast_monitor_stop(struct ast_channel *chan, int need_lock) -{ - char *execute, *execute_args; - int delfiles = 0; - - if (need_lock) { - if (ast_mutex_lock(&chan->lock)) { - ast_log(LOG_WARNING, "Unable to lock channel\n"); - return -1; - } - } - - if (chan->monitor) { - char filename[ FILENAME_MAX ]; - - if (chan->monitor->read_stream) { - ast_closestream(chan->monitor->read_stream); - } - if (chan->monitor->write_stream) { - ast_closestream(chan->monitor->write_stream); - } - - if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) { - if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) { - snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base); - if (ast_fileexists(filename, NULL, NULL) > 0) { - ast_filedelete(filename, NULL); - } - ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format); - } else { - ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename); - } - - if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) { - snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base); - if (ast_fileexists(filename, NULL, NULL) > 0) { - ast_filedelete(filename, NULL); - } - ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format); - } else { - ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename); - } - } - - if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) { - char tmp[1024]; - char tmp2[1024]; - char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format; - char *name = chan->monitor->filename_base; - int directory = strchr(name, '/') ? 1 : 0; - char *dir = directory ? "" : ast_config_AST_MONITOR_DIR; - - /* Set the execute application */ - execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC"); - if (ast_strlen_zero(execute)) { - execute = "nice -n 19 soxmix"; - delfiles = 1; - } - execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS"); - if (ast_strlen_zero(execute_args)) { - execute_args = ""; - } - - snprintf(tmp, sizeof(tmp), "%s \"%s/%s-in.%s\" \"%s/%s-out.%s\" \"%s/%s.%s\" %s &", execute, dir, name, format, dir, name, format, dir, name, format,execute_args); - if (delfiles) { - snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s/%s-\"* ) &",tmp, dir ,name); /* remove legs when done mixing */ - ast_copy_string(tmp, tmp2, sizeof(tmp)); - } - ast_log(LOG_DEBUG,"monitor executing %s\n",tmp); - if (ast_safe_system(tmp) == -1) - ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp); - } - - free(chan->monitor->format); - free(chan->monitor); - chan->monitor = NULL; - } - - if (need_lock) - ast_mutex_unlock(&chan->lock); - return 0; -} - -/* Change monitoring filename of a channel */ -int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock) -{ - char tmp[256]; - if (ast_strlen_zero(fname_base)) { - ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to null", chan->name); - return -1; - } - - if (need_lock) { - if (ast_mutex_lock(&chan->lock)) { - ast_log(LOG_WARNING, "Unable to lock channel\n"); - return -1; - } - } - - if (chan->monitor) { - int directory = strchr(fname_base, '/') ? 1 : 0; - /* try creating the directory just in case it doesn't exist */ - if (directory) { - char *name = strdup(fname_base); - snprintf(tmp, sizeof(tmp), "mkdir -p %s",dirname(name)); - free(name); - ast_safe_system(tmp); - } - - snprintf(chan->monitor->filename_base, FILENAME_MAX, "%s/%s", directory ? "" : ast_config_AST_MONITOR_DIR, fname_base); - } else { - ast_log(LOG_WARNING, "Cannot change monitor filename of channel %s to %s, monitoring not started\n", chan->name, fname_base); - } - - if (need_lock) - ast_mutex_unlock(&chan->lock); - - return 0; -} - -static int start_monitor_exec(struct ast_channel *chan, void *data) -{ - char *arg = NULL; - char *format = NULL; - char *fname_base = NULL; - char *options = NULL; - char *delay = NULL; - char *urlprefix = NULL; - char tmp[256]; - int joinfiles = 0; - int waitforbridge = 0; - int res = 0; - - /* Parse arguments. */ - if (!ast_strlen_zero((char*)data)) { - arg = ast_strdupa((char*)data); - format = arg; - fname_base = strchr(arg, '|'); - if (fname_base) { - *fname_base = 0; - fname_base++; - if ((options = strchr(fname_base, '|'))) { - *options = 0; - options++; - if (strchr(options, 'm')) - joinfiles = 1; - if (strchr(options, 'b')) - waitforbridge = 1; - } - } - arg = strchr(format,':'); - if (arg) { - *arg++ = 0; - urlprefix = arg; - } - } - if (urlprefix) { - snprintf(tmp,sizeof(tmp) - 1,"%s/%s.%s",urlprefix,fname_base, - ((strcmp(format,"gsm")) ? "wav" : "gsm")); - if (!chan->cdr) - chan->cdr = ast_cdr_alloc(); - ast_cdr_setuserfield(chan, tmp); - } - if (waitforbridge) { - /* We must remove the "b" option if listed. In principle none of - the following could give NULL results, but we check just to - be pedantic. Reconstructing with checks for 'm' option does not - work if we end up adding more options than 'm' in the future. */ - delay = ast_strdupa((char*)data); - if (delay) { - options = strrchr(delay, '|'); - if (options) { - arg = strchr(options, 'b'); - if (arg) { - *arg = 'X'; - pbx_builtin_setvar_helper(chan,"AUTO_MONITOR",delay); - } - } - } - return 0; - } - - res = ast_monitor_start(chan, format, fname_base, 1); - if (res < 0) - res = ast_monitor_change_fname(chan, fname_base, 1); - ast_monitor_setjoinfiles(chan, joinfiles); - - return res; -} - -static int stop_monitor_exec(struct ast_channel *chan, void *data) -{ - return ast_monitor_stop(chan, 1); -} - -static int change_monitor_exec(struct ast_channel *chan, void *data) -{ - return ast_monitor_change_fname(chan, (const char*)data, 1); -} - -static char start_monitor_action_help[] = -"Description: The 'Monitor' action may be used to record the audio on a\n" -" specified channel. The following parameters may be used to control\n" -" this:\n" -" Channel - Required. Used to specify the channel to record.\n" -" File - Optional. Is the name of the file created in the\n" -" monitor spool directory. Defaults to the same name\n" -" as the channel (with slashes replaced with dashes).\n" -" Format - Optional. Is the audio recording format. Defaults\n" -" to \"wav\".\n" -" Mix - Optional. Boolean parameter as to whether to mix\n" -" the input and output channels together after the\n" -" recording is finished.\n"; - -static int start_monitor_action(struct mansession *s, struct message *m) -{ - struct ast_channel *c = NULL; - char *name = astman_get_header(m, "Channel"); - char *fname = astman_get_header(m, "File"); - char *format = astman_get_header(m, "Format"); - char *mix = astman_get_header(m, "Mix"); - char *d; - - if (ast_strlen_zero(name)) { - astman_send_error(s, m, "No channel specified"); - return 0; - } - c = ast_get_channel_by_name_locked(name); - if (!c) { - astman_send_error(s, m, "No such channel"); - return 0; - } - - if (ast_strlen_zero(fname)) { - /* No filename base specified, default to channel name as per CLI */ - fname = malloc (FILENAME_MAX); - if (!fname) { - astman_send_error(s, m, "Could not start monitoring channel"); - ast_mutex_unlock(&c->lock); - return 0; - } - memset(fname, 0, FILENAME_MAX); - ast_copy_string(fname, c->name, FILENAME_MAX); - /* Channels have the format technology/channel_name - have to replace that / */ - if ((d=strchr(fname, '/'))) *d='-'; - } - - if (ast_monitor_start(c, format, fname, 1)) { - if (ast_monitor_change_fname(c, fname, 1)) { - astman_send_error(s, m, "Could not start monitoring channel"); - ast_mutex_unlock(&c->lock); - return 0; - } - } - - if (ast_true(mix)) { - ast_monitor_setjoinfiles(c, 1); - } - - ast_mutex_unlock(&c->lock); - astman_send_ack(s, m, "Started monitoring channel"); - return 0; -} - -static char stop_monitor_action_help[] = -"Description: The 'StopMonitor' action may be used to end a previously\n" -" started 'Monitor' action. The only parameter is 'Channel', the name\n" -" of the channel monitored.\n"; - -static int stop_monitor_action(struct mansession *s, struct message *m) -{ - struct ast_channel *c = NULL; - char *name = astman_get_header(m, "Channel"); - int res; - if (ast_strlen_zero(name)) { - astman_send_error(s, m, "No channel specified"); - return 0; - } - c = ast_get_channel_by_name_locked(name); - if (!c) { - astman_send_error(s, m, "No such channel"); - return 0; - } - res = ast_monitor_stop(c, 1); - ast_mutex_unlock(&c->lock); - if (res) { - astman_send_error(s, m, "Could not stop monitoring channel"); - return 0; - } - astman_send_ack(s, m, "Stopped monitoring channel"); - return 0; -} - -static char change_monitor_action_help[] = -"Description: The 'ChangeMonitor' action may be used to change the file\n" -" started by a previous 'Monitor' action. The following parameters may\n" -" be used to control this:\n" -" Channel - Required. Used to specify the channel to record.\n" -" File - Required. Is the new name of the file created in the\n" -" monitor spool directory.\n"; - -static int change_monitor_action(struct mansession *s, struct message *m) -{ - struct ast_channel *c = NULL; - char *name = astman_get_header(m, "Channel"); - char *fname = astman_get_header(m, "File"); - if (ast_strlen_zero(name)) { - astman_send_error(s, m, "No channel specified"); - return 0; - } - if (ast_strlen_zero(fname)) { - astman_send_error(s, m, "No filename specified"); - return 0; - } - c = ast_get_channel_by_name_locked(name); - if (!c) { - astman_send_error(s, m, "No such channel"); - return 0; - } - if (ast_monitor_change_fname(c, fname, 1)) { - astman_send_error(s, m, "Could not change monitored filename of channel"); - ast_mutex_unlock(&c->lock); - return 0; - } - ast_mutex_unlock(&c->lock); - astman_send_ack(s, m, "Changed monitor filename"); - return 0; -} - -void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon) -{ - if (chan->monitor) - chan->monitor->joinfiles = turnon; -} - -int load_module(void) -{ - ast_register_application("Monitor", start_monitor_exec, monitor_synopsis, monitor_descrip); - ast_register_application("StopMonitor", stop_monitor_exec, stopmonitor_synopsis, stopmonitor_descrip); - ast_register_application("ChangeMonitor", change_monitor_exec, changemonitor_synopsis, changemonitor_descrip); - ast_manager_register2("Monitor", EVENT_FLAG_CALL, start_monitor_action, monitor_synopsis, start_monitor_action_help); - ast_manager_register2("StopMonitor", EVENT_FLAG_CALL, stop_monitor_action, stopmonitor_synopsis, stop_monitor_action_help); - ast_manager_register2("ChangeMonitor", EVENT_FLAG_CALL, change_monitor_action, changemonitor_synopsis, change_monitor_action_help); - - return 0; -} - -int unload_module(void) -{ - ast_unregister_application("Monitor"); - ast_unregister_application("StopMonitor"); - ast_unregister_application("ChangeMonitor"); - ast_manager_unregister("Monitor"); - ast_manager_unregister("StopMonitor"); - ast_manager_unregister("ChangeMonitor"); - return 0; -} - -char *description(void) -{ - return "Call Monitoring Resource"; -} - -int usecount(void) -{ - /* Never allow monitor to be unloaded because it will - unresolve needed symbols in the channel */ -#if 0 - int res; - STANDARD_USECOUNT(res); - return res; -#else - return 1; -#endif -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_musiconhold.c b/1.2-netsec/res/res_musiconhold.c deleted file mode 100644 index 2a27dcec8..000000000 --- a/1.2-netsec/res/res_musiconhold.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Routines implementing music on hold - * - * \arg See also \ref Config_moh - * - */ - -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <string.h> -#include <signal.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/time.h> -#include <sys/signal.h> -#include <netinet/in.h> -#include <sys/stat.h> -#include <dirent.h> -#ifdef ZAPATA_MOH -#ifdef __linux__ -#include <linux/zaptel.h> -#else -#include <zaptel.h> -#endif /* __linux__ */ -#endif -#include <unistd.h> -#include <sys/ioctl.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/lock.h" -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/pbx.h" -#include "asterisk/options.h" -#include "asterisk/module.h" -#include "asterisk/translate.h" -#include "asterisk/say.h" -#include "asterisk/musiconhold.h" -#include "asterisk/config.h" -#include "asterisk/utils.h" -#include "asterisk/cli.h" - -#define MAX_MOHFILES 512 -#define MAX_MOHFILE_LEN 128 - -static char *app0 = "MusicOnHold"; -static char *app1 = "WaitMusicOnHold"; -static char *app2 = "SetMusicOnHold"; -static char *app3 = "StartMusicOnHold"; -static char *app4 = "StopMusicOnHold"; - -static char *synopsis0 = "Play Music On Hold indefinitely"; -static char *synopsis1 = "Wait, playing Music On Hold"; -static char *synopsis2 = "Set default Music On Hold class"; -static char *synopsis3 = "Play Music On Hold"; -static char *synopsis4 = "Stop Playing Music On Hold"; - -static char *descrip0 = "MusicOnHold(class): " -"Plays hold music specified by class. If omitted, the default\n" -"music source for the channel will be used. Set the default \n" -"class with the SetMusicOnHold() application.\n" -"Returns -1 on hangup.\n" -"Never returns otherwise.\n"; - -static char *descrip1 = "WaitMusicOnHold(delay): " -"Plays hold music specified number of seconds. Returns 0 when\n" -"done, or -1 on hangup. If no hold music is available, the delay will\n" -"still occur with no sound.\n"; - -static char *descrip2 = "SetMusicOnHold(class): " -"Sets the default class for music on hold for a given channel. When\n" -"music on hold is activated, this class will be used to select which\n" -"music is played.\n"; - -static char *descrip3 = "StartMusicOnHold(class): " -"Starts playing music on hold, uses default music class for channel.\n" -"Starts playing music specified by class. If omitted, the default\n" -"music source for the channel will be used. Always returns 0.\n"; - -static char *descrip4 = "StopMusicOnHold: " -"Stops playing music on hold.\n"; - -static int respawn_time = 20; - -struct moh_files_state { - struct mohclass *class; - int origwfmt; - int samples; - int sample_queue; - unsigned char pos; - unsigned char save_pos; -}; - -#define MOH_QUIET (1 << 0) -#define MOH_SINGLE (1 << 1) -#define MOH_CUSTOM (1 << 2) -#define MOH_RANDOMIZE (1 << 3) - -struct mohclass { - char name[MAX_MUSICCLASS]; - char dir[256]; - char args[256]; - char mode[80]; - char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN]; - unsigned int flags; - int total_files; - int format; - int pid; /* PID of mpg123 */ - time_t start; - pthread_t thread; - struct mohdata *members; - /* Source of audio */ - int srcfd; - /* FD for timing source */ - int pseudofd; - struct mohclass *next; -}; - -struct mohdata { - int pipe[2]; - int origwfmt; - struct mohclass *parent; - struct mohdata *next; -}; - -static struct mohclass *mohclasses; - -AST_MUTEX_DEFINE_STATIC(moh_lock); - -#define LOCAL_MPG_123 "/usr/local/bin/mpg123" -#define MPG_123 "/usr/bin/mpg123" -#define MAX_MP3S 256 - - -static void ast_moh_free_class(struct mohclass **class) -{ - struct mohdata *members, *mtmp; - - members = (*class)->members; - while(members) { - mtmp = members; - members = members->next; - free(mtmp); - } - free(*class); - *class = NULL; -} - - -static void moh_files_release(struct ast_channel *chan, void *data) -{ - struct moh_files_state *state = chan->music_state; - - if (chan && state) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); - - if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt); - } - state->save_pos = state->pos + 1; - } -} - - -static int ast_moh_files_next(struct ast_channel *chan) -{ - struct moh_files_state *state = chan->music_state; - int tries; - - if (state->save_pos) { - state->pos = state->save_pos - 1; - state->save_pos = 0; - } else { - /* Try 20 times to find something good */ - for (tries=0;tries < 20;tries++) { - state->samples = 0; - if (chan->stream) { - ast_closestream(chan->stream); - chan->stream = NULL; - state->pos++; - } - - if (ast_test_flag(state->class, MOH_RANDOMIZE)) - state->pos = rand(); - - /* check to see if this file's format can be opened */ - if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1) - break; - - } - } - - state->pos = state->pos % state->class->total_files; - - if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { - ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name); - return -1; - } - if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { - ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); - state->pos++; - return -1; - } - - if (option_debug) - ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); - - if (state->samples) - ast_seekstream(chan->stream, state->samples, SEEK_SET); - - return 0; -} - - -static struct ast_frame *moh_files_readframe(struct ast_channel *chan) -{ - struct ast_frame *f = NULL; - - if (!(chan->stream && (f = ast_readframe(chan->stream)))) { - if (!ast_moh_files_next(chan)) - f = ast_readframe(chan->stream); - } - - return f; -} - -static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples) -{ - struct moh_files_state *state = chan->music_state; - struct ast_frame *f = NULL; - int res = 0; - - state->sample_queue += samples; - - while (state->sample_queue > 0) { - if ((f = moh_files_readframe(chan))) { - state->samples += f->samples; - res = ast_write(chan, f); - state->sample_queue -= f->samples; - ast_frfree(f); - if (res < 0) { - ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); - return -1; - } - } else - return -1; - } - return res; -} - - -static void *moh_files_alloc(struct ast_channel *chan, void *params) -{ - struct moh_files_state *state; - struct mohclass *class = params; - int allocated = 0; - - if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) { - chan->music_state = state; - allocated = 1; - } else - state = chan->music_state; - - if (state) { - if (allocated || state->class != class) { - /* initialize */ - memset(state, 0, sizeof(struct moh_files_state)); - state->class = class; - } - - state->origwfmt = chan->writeformat; - - if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { - ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name); - free(chan->music_state); - chan->music_state = NULL; - } else { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name); - } - } - - return chan->music_state; -} - -static struct ast_generator moh_file_stream = -{ - alloc: moh_files_alloc, - release: moh_files_release, - generate: moh_files_generator, -}; - -static int spawn_mp3(struct mohclass *class) -{ - int fds[2]; - int files = 0; - char fns[MAX_MP3S][80]; - char *argv[MAX_MP3S + 50]; - char xargs[256]; - char *argptr; - int argc = 0; - DIR *dir = NULL; - struct dirent *de; - - - if (!strcasecmp(class->dir, "nodir")) { - files = 1; - } else { - dir = opendir(class->dir); - if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) { - ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); - return -1; - } - } - - if (!ast_test_flag(class, MOH_CUSTOM)) { - argv[argc++] = "mpg123"; - argv[argc++] = "-q"; - argv[argc++] = "-s"; - argv[argc++] = "--mono"; - argv[argc++] = "-r"; - argv[argc++] = "8000"; - - if (!ast_test_flag(class, MOH_SINGLE)) { - argv[argc++] = "-b"; - argv[argc++] = "2048"; - } - - argv[argc++] = "-f"; - - if (ast_test_flag(class, MOH_QUIET)) - argv[argc++] = "4096"; - else - argv[argc++] = "8192"; - - /* Look for extra arguments and add them to the list */ - strncpy(xargs, class->args, sizeof(xargs) - 1); - argptr = xargs; - while (!ast_strlen_zero(argptr)) { - argv[argc++] = argptr; - argptr = strchr(argptr, ','); - if (argptr) { - *argptr = '\0'; - argptr++; - } - } - } else { - /* Format arguments for argv vector */ - strncpy(xargs, class->args, sizeof(xargs) - 1); - argptr = xargs; - while (!ast_strlen_zero(argptr)) { - argv[argc++] = argptr; - argptr = strchr(argptr, ' '); - if (argptr) { - *argptr = '\0'; - argptr++; - } - } - } - - - if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) { - strncpy(fns[files], class->dir, sizeof(fns[files]) - 1); - argv[argc++] = fns[files]; - files++; - } else if (dir) { - while ((de = readdir(dir)) && (files < MAX_MP3S)) { - if ((strlen(de->d_name) > 3) && - ((ast_test_flag(class, MOH_CUSTOM) && - (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || - !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || - !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { - strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1); - argv[argc++] = fns[files]; - files++; - } - } - } - argv[argc] = NULL; - if (dir) { - closedir(dir); - } - if (pipe(fds)) { - ast_log(LOG_WARNING, "Pipe failed\n"); - return -1; - } -#if 0 - printf("%d files total, %d args total\n", files, argc); - { - int x; - for (x=0;argv[x];x++) - printf("arg%d: %s\n", x, argv[x]); - } -#endif - if (!files) { - ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); - close(fds[0]); - close(fds[1]); - return -1; - } - if (time(NULL) - class->start < respawn_time) { - sleep(respawn_time - (time(NULL) - class->start)); - } - time(&class->start); - class->pid = fork(); - if (class->pid < 0) { - close(fds[0]); - close(fds[1]); - ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); - return -1; - } - if (!class->pid) { - int x; - close(fds[0]); - /* Stdout goes to pipe */ - dup2(fds[1], STDOUT_FILENO); - /* Close unused file descriptors */ - for (x=3;x<8192;x++) { - if (-1 != fcntl(x, F_GETFL)) { - close(x); - } - } - /* Child */ - chdir(class->dir); - if (ast_test_flag(class, MOH_CUSTOM)) { - execv(argv[0], argv); - } else { - /* Default install is /usr/local/bin */ - execv(LOCAL_MPG_123, argv); - /* Many places have it in /usr/bin */ - execv(MPG_123, argv); - /* Check PATH as a last-ditch effort */ - execvp("mpg123", argv); - } - ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); - close(fds[1]); - exit(1); - } else { - /* Parent */ - close(fds[1]); - } - return fds[0]; -} - -static void *monmp3thread(void *data) -{ -#define MOH_MS_INTERVAL 100 - - struct mohclass *class = data; - struct mohdata *moh; - char buf[8192]; - short sbuf[8192]; - int res, res2; - int len; - struct timeval tv, tv_tmp; - - tv.tv_sec = 0; - tv.tv_usec = 0; - for(;/* ever */;) { - /* Spawn mp3 player if it's not there */ - if (class->srcfd < 0) { - if ((class->srcfd = spawn_mp3(class)) < 0) { - ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); - /* Try again later */ - sleep(500); - } - } - if (class->pseudofd > -1) { - /* Pause some amount of time */ - res = read(class->pseudofd, buf, sizeof(buf)); - } else { - long delta; - /* Reliable sleep */ - tv_tmp = ast_tvnow(); - if (ast_tvzero(tv)) - tv = tv_tmp; - delta = ast_tvdiff_ms(tv_tmp, tv); - if (delta < MOH_MS_INTERVAL) { /* too early */ - tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ - usleep(1000 * (MOH_MS_INTERVAL - delta)); - } else { - ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); - tv = tv_tmp; - } - res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ - } - if (!class->members) - continue; - /* Read mp3 audio */ - len = ast_codec_get_len(class->format, res); - - if ((res2 = read(class->srcfd, sbuf, len)) != len) { - if (!res2) { - close(class->srcfd); - class->srcfd = -1; - if (class->pid) { - kill(class->pid, SIGKILL); - class->pid = 0; - } - } else - ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len); - continue; - } - ast_mutex_lock(&moh_lock); - moh = class->members; - while (moh) { - /* Write data */ - if ((res = write(moh->pipe[1], sbuf, res2)) != res2) - if (option_debug) - ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2); - moh = moh->next; - } - ast_mutex_unlock(&moh_lock); - } - return NULL; -} - -static int moh0_exec(struct ast_channel *chan, void *data) -{ - if (ast_moh_start(chan, data)) { - ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name); - return -1; - } - while (!ast_safe_sleep(chan, 10000)); - ast_moh_stop(chan); - return -1; -} - -static int moh1_exec(struct ast_channel *chan, void *data) -{ - int res; - if (!data || !atoi(data)) { - ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); - return -1; - } - if (ast_moh_start(chan, NULL)) { - ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); - return -1; - } - res = ast_safe_sleep(chan, atoi(data) * 1000); - ast_moh_stop(chan); - return res; -} - -static int moh2_exec(struct ast_channel *chan, void *data) -{ - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); - return -1; - } - strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1); - return 0; -} - -static int moh3_exec(struct ast_channel *chan, void *data) -{ - char *class = NULL; - if (data && strlen(data)) - class = data; - if (ast_moh_start(chan, class)) - ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name); - - return 0; -} - -static int moh4_exec(struct ast_channel *chan, void *data) -{ - ast_moh_stop(chan); - - return 0; -} - -static struct mohclass *get_mohbyname(char *name) -{ - struct mohclass *moh; - moh = mohclasses; - while (moh) { - if (!strcasecmp(name, moh->name)) - return moh; - moh = moh->next; - } - return NULL; -} - -static struct mohdata *mohalloc(struct mohclass *cl) -{ - struct mohdata *moh; - long flags; - moh = malloc(sizeof(struct mohdata)); - if (!moh) - return NULL; - memset(moh, 0, sizeof(struct mohdata)); - if (pipe(moh->pipe)) { - ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); - free(moh); - return NULL; - } - /* Make entirely non-blocking */ - flags = fcntl(moh->pipe[0], F_GETFL); - fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); - flags = fcntl(moh->pipe[1], F_GETFL); - fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); - moh->parent = cl; - moh->next = cl->members; - cl->members = moh; - return moh; -} - -static void moh_release(struct ast_channel *chan, void *data) -{ - struct mohdata *moh = data, *prev, *cur; - int oldwfmt; - ast_mutex_lock(&moh_lock); - /* Unlink */ - prev = NULL; - cur = moh->parent->members; - while (cur) { - if (cur == moh) { - if (prev) - prev->next = cur->next; - else - moh->parent->members = cur->next; - break; - } - prev = cur; - cur = cur->next; - } - ast_mutex_unlock(&moh_lock); - close(moh->pipe[0]); - close(moh->pipe[1]); - oldwfmt = moh->origwfmt; - free(moh); - if (chan) { - if (oldwfmt && ast_set_write_format(chan, oldwfmt)) - ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt)); - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); - } -} - -static void *moh_alloc(struct ast_channel *chan, void *params) -{ - struct mohdata *res; - struct mohclass *class = params; - - res = mohalloc(class); - if (res) { - res->origwfmt = chan->writeformat; - if (ast_set_write_format(chan, class->format)) { - ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); - moh_release(NULL, res); - res = NULL; - } - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); - } - return res; -} - -static int moh_generate(struct ast_channel *chan, void *data, int len, int samples) -{ - struct ast_frame f; - struct mohdata *moh = data; - short buf[1280 + AST_FRIENDLY_OFFSET / 2]; - int res; - - if (!moh->parent->pid) - return -1; - - len = ast_codec_get_len(moh->parent->format, samples); - - if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { - ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); - len = sizeof(buf) - AST_FRIENDLY_OFFSET; - } - res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); -#if 0 - if (res != len) { - ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno)); - } -#endif - if (res <= 0) - return 0; - - memset(&f, 0, sizeof(f)); - - f.frametype = AST_FRAME_VOICE; - f.subclass = moh->parent->format; - f.mallocd = 0; - f.datalen = res; - f.data = buf + AST_FRIENDLY_OFFSET / 2; - f.offset = AST_FRIENDLY_OFFSET; - f.samples = ast_codec_get_samples(&f); - - if (ast_write(chan, &f) < 0) { - ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); - return -1; - } - - return 0; -} - -static struct ast_generator mohgen = -{ - alloc: moh_alloc, - release: moh_release, - generate: moh_generate, -}; - -static int moh_scan_files(struct mohclass *class) { - - DIR *files_DIR; - struct dirent *files_dirent; - char path[512]; - char filepath[MAX_MOHFILE_LEN]; - char *ext; - struct stat statbuf; - int dirnamelen; - int i; - - files_DIR = opendir(class->dir); - if (!files_DIR) { - ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir); - return -1; - } - - class->total_files = 0; - dirnamelen = strlen(class->dir) + 2; - getcwd(path, 512); - chdir(class->dir); - memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN); - while ((files_dirent = readdir(files_DIR))) { - if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN)) - continue; - - snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name); - - if (stat(filepath, &statbuf)) - continue; - - if (!S_ISREG(statbuf.st_mode)) - continue; - - if ((ext = strrchr(filepath, '.'))) { - *ext = '\0'; - ext++; - } - - /* if the file is present in multiple formats, ensure we only put it into the list once */ - for (i = 0; i < class->total_files; i++) - if (!strcmp(filepath, class->filearray[i])) - break; - - if (i == class->total_files) - strcpy(class->filearray[class->total_files++], filepath); - } - - closedir(files_DIR); - chdir(path); - return class->total_files; -} - -static int moh_register(struct mohclass *moh, int reload) -{ -#ifdef ZAPATA_MOH - int x; -#endif - ast_mutex_lock(&moh_lock); - if (get_mohbyname(moh->name)) { - if (reload) { - ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name); - } else { - ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); - } - free(moh); - ast_mutex_unlock(&moh_lock); - return -1; - } - ast_mutex_unlock(&moh_lock); - - time(&moh->start); - moh->start -= respawn_time; - - if (!strcasecmp(moh->mode, "files")) { - if (!moh_scan_files(moh)) { - ast_moh_free_class(&moh); - return -1; - } - if (strchr(moh->args, 'r')) - ast_set_flag(moh, MOH_RANDOMIZE); - } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { - - if (!strcasecmp(moh->mode, "custom")) - ast_set_flag(moh, MOH_CUSTOM); - else if (!strcasecmp(moh->mode, "mp3nb")) - ast_set_flag(moh, MOH_SINGLE); - else if (!strcasecmp(moh->mode, "quietmp3nb")) - ast_set_flag(moh, MOH_SINGLE | MOH_QUIET); - else if (!strcasecmp(moh->mode, "quietmp3")) - ast_set_flag(moh, MOH_QUIET); - - moh->srcfd = -1; -#ifdef ZAPATA_MOH - /* Open /dev/zap/pseudo for timing... Is - there a better, yet reliable way to do this? */ - moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); - if (moh->pseudofd < 0) { - ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); - } else { - x = 320; - ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x); - } -#else - moh->pseudofd = -1; -#endif - if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) { - ast_log(LOG_WARNING, "Unable to create moh...\n"); - if (moh->pseudofd > -1) - close(moh->pseudofd); - ast_moh_free_class(&moh); - return -1; - } - } else { - ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); - ast_moh_free_class(&moh); - return -1; - } - ast_mutex_lock(&moh_lock); - moh->next = mohclasses; - mohclasses = moh; - ast_mutex_unlock(&moh_lock); - return 0; -} - -static void local_ast_moh_cleanup(struct ast_channel *chan) -{ - if (chan->music_state) { - free(chan->music_state); - chan->music_state = NULL; - } -} - -static int local_ast_moh_start(struct ast_channel *chan, char *class) -{ - struct mohclass *mohclass; - - if (ast_strlen_zero(class)) - class = chan->musicclass; - if (ast_strlen_zero(class)) - class = "default"; - ast_mutex_lock(&moh_lock); - mohclass = get_mohbyname(class); - ast_mutex_unlock(&moh_lock); - - if (!mohclass) { - ast_log(LOG_WARNING, "No class: %s\n", (char *)class); - return -1; - } - - ast_set_flag(chan, AST_FLAG_MOH); - if (mohclass->total_files) { - return ast_activate_generator(chan, &moh_file_stream, mohclass); - } else - return ast_activate_generator(chan, &mohgen, mohclass); -} - -static void local_ast_moh_stop(struct ast_channel *chan) -{ - ast_clear_flag(chan, AST_FLAG_MOH); - ast_deactivate_generator(chan); - - if (chan->music_state) { - if (chan->stream) { - ast_closestream(chan->stream); - chan->stream = NULL; - } - } -} - -static struct mohclass *moh_class_malloc(void) -{ - struct mohclass *class; - - class = malloc(sizeof(struct mohclass)); - - if (!class) - return NULL; - - memset(class, 0, sizeof(struct mohclass)); - - class->format = AST_FORMAT_SLINEAR; - - return class; -} - -static int load_moh_classes(int reload) -{ - struct ast_config *cfg; - struct ast_variable *var; - struct mohclass *class; - char *data; - char *args; - char *cat; - int numclasses = 0; - static int dep_warning = 0; - - cfg = ast_config_load("musiconhold.conf"); - - if (!cfg) - return 0; - - cat = ast_category_browse(cfg, NULL); - for (; cat; cat = ast_category_browse(cfg, cat)) { - if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) { - class = moh_class_malloc(); - if (!class) { - ast_log(LOG_WARNING, "Out of memory!\n"); - break; - } - ast_copy_string(class->name, cat, sizeof(class->name)); - var = ast_variable_browse(cfg, cat); - while (var) { - if (!strcasecmp(var->name, "mode")) - ast_copy_string(class->mode, var->value, sizeof(class->mode)); - else if (!strcasecmp(var->name, "directory")) - ast_copy_string(class->dir, var->value, sizeof(class->dir)); - else if (!strcasecmp(var->name, "application")) - ast_copy_string(class->args, var->value, sizeof(class->args)); - else if (!strcasecmp(var->name, "random")) - ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); - else if (!strcasecmp(var->name, "format")) { - class->format = ast_getformatbyname(var->value); - if (!class->format) { - ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); - class->format = AST_FORMAT_SLINEAR; - } - } - var = var->next; - } - - if (ast_strlen_zero(class->dir)) { - if (!strcasecmp(class->mode, "custom")) { - strcpy(class->dir, "nodir"); - } else { - ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); - free(class); - continue; - } - } - if (ast_strlen_zero(class->mode)) { - ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); - free(class); - continue; - } - if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { - ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); - free(class); - continue; - } - - /* Don't leak a class when it's already registered */ - moh_register(class, reload); - - numclasses++; - } - } - - - /* Deprecated Old-School Configuration */ - var = ast_variable_browse(cfg, "classes"); - while (var) { - if (!dep_warning) { - ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n"); - dep_warning = 1; - } - data = strchr(var->value, ':'); - if (data) { - *data++ = '\0'; - args = strchr(data, ','); - if (args) - *args++ = '\0'; - if (!(get_mohbyname(var->name))) { - class = moh_class_malloc(); - if (!class) { - ast_log(LOG_WARNING, "Out of memory!\n"); - return numclasses; - } - - ast_copy_string(class->name, var->name, sizeof(class->name)); - ast_copy_string(class->dir, data, sizeof(class->dir)); - ast_copy_string(class->mode, var->value, sizeof(class->mode)); - if (args) - ast_copy_string(class->args, args, sizeof(class->args)); - - moh_register(class, reload); - numclasses++; - } - } - var = var->next; - } - var = ast_variable_browse(cfg, "moh_files"); - while (var) { - if (!dep_warning) { - ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n"); - dep_warning = 1; - } - if (!(get_mohbyname(var->name))) { - args = strchr(var->value, ','); - if (args) - *args++ = '\0'; - class = moh_class_malloc(); - if (!class) { - ast_log(LOG_WARNING, "Out of memory!\n"); - return numclasses; - } - - ast_copy_string(class->name, var->name, sizeof(class->name)); - ast_copy_string(class->dir, var->value, sizeof(class->dir)); - strcpy(class->mode, "files"); - if (args) - ast_copy_string(class->args, args, sizeof(class->args)); - - moh_register(class, reload); - numclasses++; - } - var = var->next; - } - - ast_config_destroy(cfg); - - return numclasses; -} - -static void ast_moh_destroy(void) -{ - struct mohclass *moh, *tmp; - char buff[8192]; - int bytes, tbytes=0, stime = 0, pid = 0; - - if (option_verbose > 1) - ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); - ast_mutex_lock(&moh_lock); - moh = mohclasses; - - while (moh) { - if (moh->pid) { - ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); - stime = time(NULL) + 2; - pid = moh->pid; - moh->pid = 0; - kill(pid, SIGKILL); - while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) { - tbytes = tbytes + bytes; - } - ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); - close(moh->srcfd); - } - tmp = moh; - moh = moh->next; - ast_moh_free_class(&tmp); - } - mohclasses = NULL; - ast_mutex_unlock(&moh_lock); -} - -static void moh_on_off(int on) -{ - struct ast_channel *chan = NULL; - - while ( (chan = ast_channel_walk_locked(chan)) != NULL) { - if (ast_test_flag(chan, AST_FLAG_MOH)) { - if (on) - local_ast_moh_start(chan, NULL); - else - ast_deactivate_generator(chan); - } - ast_mutex_unlock(&chan->lock); - } -} - -static int moh_cli(int fd, int argc, char *argv[]) -{ - int x; - - moh_on_off(0); - ast_moh_destroy(); - x = load_moh_classes(1); - moh_on_off(1); - ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es"); - return 0; -} - -static int cli_files_show(int fd, int argc, char *argv[]) -{ - int i; - struct mohclass *class; - - ast_mutex_lock(&moh_lock); - for (class = mohclasses; class; class = class->next) { - if (!class->total_files) - continue; - - ast_cli(fd, "Class: %s\n", class->name); - for (i = 0; i < class->total_files; i++) - ast_cli(fd, "\tFile: %s\n", class->filearray[i]); - } - ast_mutex_unlock(&moh_lock); - - return 0; -} - -static int moh_classes_show(int fd, int argc, char *argv[]) -{ - struct mohclass *class; - - ast_mutex_lock(&moh_lock); - for (class = mohclasses; class; class = class->next) { - ast_cli(fd, "Class: %s\n", class->name); - ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode); - ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir); - if (ast_test_flag(class, MOH_CUSTOM)) - ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args); - ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); - } - ast_mutex_unlock(&moh_lock); - - return 0; -} - -static struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}; - -static struct ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}; - -static struct ast_cli_entry cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL}; - -static int init_classes(int reload) -{ - struct mohclass *moh; - - if (!load_moh_classes(reload)) /* Load classes from config */ - return 0; /* Return if nothing is found */ - moh = mohclasses; - while (moh) { - if (moh->total_files) - moh_scan_files(moh); - moh = moh->next; - } - return 1; -} - -int load_module(void) -{ - int res; - - res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); - ast_register_atexit(ast_moh_destroy); - ast_cli_register(&cli_moh); - ast_cli_register(&cli_moh_files_show); - ast_cli_register(&cli_moh_classes_show); - if (!res) - res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); - if (!res) - res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); - if (!res) - res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); - if (!res) - res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); - - if (!init_classes(0)) { /* No music classes configured, so skip it */ - ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold."); - } else { - ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); - } - - return 0; -} - -int reload(void) -{ - if (init_classes(1)) - ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); - - return 0; -} - -int unload_module(void) -{ - return -1; -} - -char *description(void) -{ - return "Music On Hold Resource"; -} - -int usecount(void) -{ - /* Never allow Music On Hold to be unloaded - unresolve needed symbols in the dialer */ -#if 0 - int res; - STANDARD_USECOUNT(res); - return res; -#else - return 1; -#endif -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_odbc.c b/1.2-netsec/res/res_odbc.c deleted file mode 100644 index cc4b61f2d..000000000 --- a/1.2-netsec/res/res_odbc.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * res_odbc.c <ODBC resource manager> - * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct@yahoo.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - - -/*! \file - * - * \brief ODBC resource manager - * - * \arg See also: \ref cdr_odbc - * - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/logger.h" -#include "asterisk/channel.h" -#include "asterisk/config.h" -#include "asterisk/options.h" -#include "asterisk/pbx.h" -#include "asterisk/module.h" -#include "asterisk/cli.h" -#include "asterisk/lock.h" -#include "asterisk/res_odbc.h" -#define MAX_ODBC_HANDLES 25 - -struct odbc_list -{ - char name[80]; - odbc_obj *obj; - int used; -}; - -static struct odbc_list ODBC_REGISTRY[MAX_ODBC_HANDLES]; - - -static void odbc_destroy(void) -{ - int x = 0; - - for (x = 0; x < MAX_ODBC_HANDLES; x++) { - if (ODBC_REGISTRY[x].obj) { - destroy_odbc_obj(&ODBC_REGISTRY[x].obj); - ODBC_REGISTRY[x].obj = NULL; - } - } -} - -static odbc_obj *odbc_read(struct odbc_list *registry, const char *name) -{ - int x = 0; - for (x = 0; x < MAX_ODBC_HANDLES; x++) { - if (registry[x].used && !strcmp(registry[x].name, name)) { - return registry[x].obj; - } - } - return NULL; -} - -static int odbc_write(struct odbc_list *registry, char *name, odbc_obj *obj) -{ - int x = 0; - for (x = 0; x < MAX_ODBC_HANDLES; x++) { - if (!registry[x].used) { - ast_copy_string(registry[x].name, name, sizeof(registry[x].name)); - registry[x].obj = obj; - registry[x].used = 1; - return 1; - } - } - return 0; -} - -static void odbc_init(void) -{ - int x = 0; - for (x = 0; x < MAX_ODBC_HANDLES; x++) { - memset(&ODBC_REGISTRY[x], 0, sizeof(struct odbc_list)); - } -} - -static char *tdesc = "ODBC Resource"; -/* internal stuff */ - -SQLHSTMT odbc_prepare_and_execute(odbc_obj *obj, SQLHSTMT (*prepare_cb)(odbc_obj *obj, void *data), void *data) -{ - int res = 0, i, attempt; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0; - unsigned char state[10], diagnostic[256]; - SQLHSTMT stmt; - - for (attempt = 0; attempt < 2; attempt++) { - /* This prepare callback may do more than just prepare -- it may also - * bind parameters, bind results, etc. The real key, here, is that - * when we disconnect, all handles become invalid for most databases. - * We must therefore redo everything when we establish a new - * connection. */ - stmt = prepare_cb(obj, data); - - if (stmt) { - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { - if (res == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i=0; i< numfields + 1; i++) { - SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } - - ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); - SQLFreeHandle(SQL_HANDLE_STMT, stmt); - - ast_mutex_lock(&obj->lock); - obj->up = 0; - ast_mutex_unlock(&obj->lock); - odbc_obj_disconnect(obj); - odbc_obj_connect(obj); - continue; - } - break; - } - } - - return stmt; -} - -int odbc_smart_execute(odbc_obj *obj, SQLHSTMT stmt) -{ - int res = 0, i; - SQLINTEGER nativeerror=0, numfields=0; - SQLSMALLINT diagbytes=0; - unsigned char state[10], diagnostic[256]; - - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO) && (res != SQL_NO_DATA)) { - if (res == SQL_ERROR) { - SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes); - for (i=0; i< numfields + 1; i++) { - SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes); - ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes); - if (i > 10) { - ast_log(LOG_WARNING, "Oh, that was good. There are really %d diagnostics?\n", (int)numfields); - break; - } - } - } -/* - ast_log(LOG_WARNING, "SQL Execute error %d! Attempting a reconnect...\n", res); - ast_mutex_lock(&obj->lock); - obj->up = 0; - ast_mutex_unlock(&obj->lock); - odbc_obj_disconnect(obj); - odbc_obj_connect(obj); - res = SQLExecute(stmt); -*/ - } - - return res; -} - - -int odbc_smart_direct_execute(odbc_obj *obj, SQLHSTMT stmt, char *sql) -{ - int res = 0; - - res = SQLExecDirect (stmt, (unsigned char *)sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - ast_log(LOG_WARNING, "SQL Execute error! Attempting a reconnect...\n"); - ast_mutex_lock(&obj->lock); - obj->up = 0; - ast_mutex_unlock(&obj->lock); - odbc_obj_disconnect(obj); - odbc_obj_connect(obj); - res = SQLExecDirect (stmt, (unsigned char *)sql, SQL_NTS); - } - - return res; -} - -int odbc_sanity_check(odbc_obj *obj) -{ - char *test_sql = "select 1"; - SQLHSTMT stmt; - int res = 0; - - ast_mutex_lock(&obj->lock); - if(obj->up) { /* so you say... let's make sure */ - res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; /* Liar!*/ - } else { - res = SQLPrepare(stmt, (unsigned char *)test_sql, SQL_NTS); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; /* Liar!*/ - } else { - res = SQLExecute(stmt); - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - obj->up = 0; /* Liar!*/ - } - } - } - SQLFreeHandle (SQL_HANDLE_STMT, stmt); - } - ast_mutex_unlock(&obj->lock); - - if(!obj->up) { /* Try to reconnect! */ - ast_log(LOG_WARNING, "Connection is down attempting to reconnect...\n"); - odbc_obj_disconnect(obj); - odbc_obj_connect(obj); - } - return obj->up; -} - -static int load_odbc_config(void) -{ - static char *cfg = "res_odbc.conf"; - struct ast_config *config; - struct ast_variable *v; - char *cat, *dsn, *username, *password; - int enabled; - int connect = 0; - char *env_var; - - odbc_obj *obj; - - config = ast_config_load(cfg); - if (config) { - for (cat = ast_category_browse(config, NULL); cat; cat=ast_category_browse(config, cat)) { - if (!strcmp(cat, "ENV")) { - for (v = ast_variable_browse(config, cat); v; v = v->next) { - env_var = malloc(strlen(v->name) + strlen(v->value) + 2); - if (env_var) { - sprintf(env_var, "%s=%s", v->name, v->value); - ast_log(LOG_NOTICE, "Adding ENV var: %s=%s\n", v->name, v->value); - putenv(env_var); - free(env_var); - } - } - - cat = ast_category_browse(config, cat); - } - - dsn = username = password = NULL; - enabled = 1; - connect = 0; - for (v = ast_variable_browse(config, cat); v; v = v->next) { - if (!strcmp(v->name, "enabled")) - enabled = ast_true(v->value); - if (!strcmp(v->name, "pre-connect")) - connect = ast_true(v->value); - if (!strcmp(v->name, "dsn")) - dsn = v->value; - if (!strcmp(v->name, "username")) - username = v->value; - if (!strcmp(v->name, "password")) - password = v->value; - } - - if (enabled && dsn) { - obj = new_odbc_obj(cat, dsn, username, password); - if (obj) { - register_odbc_obj(cat, obj); - ast_log(LOG_NOTICE, "registered database handle '%s' dsn->[%s]\n", cat, obj->dsn); - if (connect) { - odbc_obj_connect(obj); - } - } else { - ast_log(LOG_WARNING, "Addition of obj %s failed.\n", cat); - } - - } - } - ast_config_destroy(config); - } - return 0; -} - -int odbc_dump_fd(int fd, odbc_obj *obj) -{ - /* make sure the connection is up before we lie to our master.*/ - odbc_sanity_check(obj); - ast_cli(fd, "Name: %s\nDSN: %s\nConnected: %s\n\n", obj->name, obj->dsn, obj->up ? "yes" : "no"); - return 0; -} - -static int odbc_connect_usage(int fd) -{ - ast_cli(fd, "usage odbc connect <DSN>\n"); - return 0; -} - -static int odbc_disconnect_usage(int fd) -{ - ast_cli(fd, "usage odbc disconnect <DSN>\n"); - return 0; -} - -static int odbc_show_command(int fd, int argc, char **argv) -{ - odbc_obj *obj; - int x = 0; - - if (!strcmp(argv[1], "show")) { - if (!argv[2] || (argv[2] && !strcmp(argv[2], "all"))) { - for (x = 0; x < MAX_ODBC_HANDLES; x++) { - if (!ODBC_REGISTRY[x].used) - break; - if (ODBC_REGISTRY[x].obj) - odbc_dump_fd(fd, ODBC_REGISTRY[x].obj); - } - } else { - obj = odbc_read(ODBC_REGISTRY, argv[2]); - if (obj) - odbc_dump_fd(fd, obj); - } - } - return 0; -} - -static int odbc_disconnect_command(int fd, int argc, char **argv) -{ - odbc_obj *obj; - if (!strcmp(argv[1], "disconnect")) { - if (!argv[2]) - return odbc_disconnect_usage(fd); - - obj = odbc_read(ODBC_REGISTRY, argv[2]); - if (obj) { - odbc_obj_disconnect(obj); - } - } - return 0; -} - -static int odbc_connect_command(int fd, int argc, char **argv) -{ - odbc_obj *obj; - if (!argv[1]) - return odbc_connect_usage(fd); - - if (!strcmp(argv[1], "connect") || !strcmp(argv[1], "disconnect")) { - if (!argv[2]) - return odbc_connect_usage(fd); - - obj = odbc_read(ODBC_REGISTRY, argv[2]); - if (obj) { - odbc_obj_connect(obj); - } - } - return 0; -} - - -static char connect_usage[] = -"Usage: odbc connect <DSN>\n" -" Connect to ODBC DSN\n"; - -static char disconnect_usage[] = -"Usage: odbc connect <DSN>\n" -" Disconnect from ODBC DSN\n"; - -static char show_usage[] = -"Usage: odbc show {DSN}\n" -" Show ODBC {DSN}\n" -" Specifying DSN will show that DSN else, all DSNs are shown\n"; - -static struct ast_cli_entry odbc_connect_struct = - { { "odbc", "connect", NULL }, odbc_connect_command, "Connect to ODBC DSN", connect_usage }; - - -static struct ast_cli_entry odbc_disconnect_struct = - { { "odbc", "disconnect", NULL }, odbc_disconnect_command, "Disconnect from ODBC DSN", disconnect_usage }; - -static struct ast_cli_entry odbc_show_struct = - { { "odbc", "show", NULL }, odbc_show_command, "Show ODBC DSN(s)", show_usage }; - -/* api calls */ - -int register_odbc_obj(char *name, odbc_obj *obj) -{ - if (obj != NULL) - return odbc_write(ODBC_REGISTRY, name, obj); - return 0; -} - -odbc_obj *fetch_odbc_obj(const char *name, int check) -{ - odbc_obj *obj = NULL; - if((obj = (odbc_obj *) odbc_read(ODBC_REGISTRY, name))) { - if(check) - odbc_sanity_check(obj); - } - return obj; -} - -odbc_obj *new_odbc_obj(char *name, char *dsn, char *username, char *password) -{ - static odbc_obj *new; - - if (!(new = calloc(1, sizeof(*new))) || - !(new->name = malloc(strlen(name) + 1)) || - !(new->dsn = malloc(strlen(dsn) + 1))) - goto cleanup; - - if (username) { - if (!(new->username = malloc(strlen(username) + 1))) - goto cleanup; - strcpy(new->username, username); - } - - if (password) { - if (!(new->password = malloc(strlen(password) + 1))) - goto cleanup; - strcpy(new->password, password); - } - - strcpy(new->name, name); - strcpy(new->dsn, dsn); - new->env = SQL_NULL_HANDLE; - new->up = 0; - ast_mutex_init(&new->lock); - return new; - -cleanup: - if (new) { - free(new->name); - free(new->dsn); - free(new->username); - free(new->password); - - free(new); - } - - return NULL; -} - -void destroy_odbc_obj(odbc_obj **obj) -{ - odbc_obj_disconnect(*obj); - - ast_mutex_lock(&(*obj)->lock); - SQLFreeHandle(SQL_HANDLE_STMT, (*obj)->stmt); - SQLFreeHandle(SQL_HANDLE_DBC, (*obj)->con); - SQLFreeHandle(SQL_HANDLE_ENV, (*obj)->env); - - free((*obj)->name); - free((*obj)->dsn); - if ((*obj)->username) - free((*obj)->username); - if ((*obj)->password) - free((*obj)->password); - ast_mutex_unlock(&(*obj)->lock); - ast_mutex_destroy(&(*obj)->lock); - free(*obj); -} - -odbc_status odbc_obj_disconnect(odbc_obj *obj) -{ - int res; - ast_mutex_lock(&obj->lock); - - res = SQLDisconnect(obj->con); - - - if (res == ODBC_SUCCESS) { - ast_log(LOG_WARNING, "res_odbc: disconnected %d from %s [%s]\n", res, obj->name, obj->dsn); - } else { - ast_log(LOG_WARNING, "res_odbc: %s [%s] already disconnected\n", - obj->name, obj->dsn); - } - obj->up = 0; - ast_mutex_unlock(&obj->lock); - return ODBC_SUCCESS; -} - -odbc_status odbc_obj_connect(odbc_obj *obj) -{ - int res; - SQLINTEGER err; - short int mlen; - unsigned char msg[200], stat[10]; - - ast_mutex_lock(&obj->lock); - - if (obj->env == SQL_NULL_HANDLE) { - res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &obj->env); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 3) - ast_log(LOG_WARNING, "res_odbc: Error AllocHandle\n"); - ast_mutex_unlock(&obj->lock); - return ODBC_FAIL; - } - - res = SQLSetEnvAttr(obj->env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - if (option_verbose > 3) - ast_log(LOG_WARNING, "res_odbc: Error SetEnv\n"); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - ast_mutex_unlock(&obj->lock); - return ODBC_FAIL; - } - - res = SQLAllocHandle(SQL_HANDLE_DBC, obj->env, &obj->con); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - - if (option_verbose > 3) - ast_log(LOG_WARNING, "res_odbc: Error AllocHDB %d\n", res); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - - ast_mutex_unlock(&obj->lock); - return ODBC_FAIL; - } - SQLSetConnectAttr(obj->con, SQL_LOGIN_TIMEOUT, (SQLPOINTER *) 10, 0); - } - if(obj->up) { - odbc_obj_disconnect(obj); - ast_log(LOG_NOTICE,"Re-connecting %s\n", obj->name); - } - - ast_log(LOG_NOTICE, "Connecting %s\n", obj->name); - - res = SQLConnect(obj->con, - (SQLCHAR *) obj->dsn, SQL_NTS, - (SQLCHAR *) obj->username, SQL_NTS, - (SQLCHAR *) obj->password, SQL_NTS); - - if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { - SQLGetDiagRec(SQL_HANDLE_DBC, obj->con, 1, stat, &err, msg, 100, &mlen); - SQLFreeHandle(SQL_HANDLE_ENV, obj->env); - ast_mutex_unlock(&obj->lock); - ast_log(LOG_WARNING, "res_odbc: Error SQLConnect=%d errno=%d %s\n", res, (int)err, msg); - return ODBC_FAIL; - } else { - - ast_log(LOG_NOTICE, "res_odbc: Connected to %s [%s]\n", obj->name, obj->dsn); - obj->up = 1; - } - - ast_mutex_unlock(&obj->lock); - return ODBC_SUCCESS; -} - -STANDARD_LOCAL_USER; - -LOCAL_USER_DECL; - -int unload_module(void) -{ - STANDARD_HANGUP_LOCALUSERS; - odbc_destroy(); - ast_cli_unregister(&odbc_disconnect_struct); - ast_cli_unregister(&odbc_connect_struct); - ast_cli_unregister(&odbc_show_struct); - ast_log(LOG_NOTICE, "res_odbc unloaded.\n"); - return 0; -} - -int load_module(void) -{ - odbc_init(); - load_odbc_config(); - ast_cli_register(&odbc_disconnect_struct); - ast_cli_register(&odbc_connect_struct); - ast_cli_register(&odbc_show_struct); - ast_log(LOG_NOTICE, "res_odbc loaded.\n"); - return 0; -} - -char *description(void) -{ - return tdesc; -} - -int usecount(void) -{ - int res; - STANDARD_USECOUNT(res); - return res; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} diff --git a/1.2-netsec/res/res_osp.c b/1.2-netsec/res/res_osp.c deleted file mode 100644 index 41ca8c0cf..000000000 --- a/1.2-netsec/res/res_osp.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2005, Digium, Inc. - * - * Mark Spencer <markster@digium.com> - * - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - */ - -/*! \file - * - * \brief Provide Open Settlement Protocol capability - * - * \arg See also: \ref chan_sip.c - */ - -#include <sys/types.h> -#include <osp.h> -#include <openssl/err.h> -#include <stdio.h> -#include <dirent.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <openssl/bio.h> -#include <openssl/pem.h> -#include <openssl/evp.h> - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include "asterisk/file.h" -#include "asterisk/channel.h" -#include "asterisk/logger.h" -#include "asterisk/say.h" -#include "asterisk/module.h" -#include "asterisk/options.h" -#include "asterisk/crypto.h" -#include "asterisk/md5.h" -#include "asterisk/cli.h" -#include "asterisk/io.h" -#include "asterisk/lock.h" -#include "asterisk/astosp.h" -#include "asterisk/config.h" -#include "asterisk/utils.h" -#include "asterisk/lock.h" -#include "asterisk/causes.h" -#include "asterisk/callerid.h" -#include "asterisk/pbx.h" - -#define MAX_CERTS 10 -#define MAX_SERVICEPOINTS 10 -#define OSP_MAX 256 - -#define OSP_DEFAULT_MAX_CONNECTIONS 20 -#define OSP_DEFAULT_RETRY_DELAY 0 -#define OSP_DEFAULT_RETRY_LIMIT 2 -#define OSP_DEFAULT_TIMEOUT 500 - -static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len); -static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len); - -AST_MUTEX_DEFINE_STATIC(osplock); - -static int initialized = 0; -static int hardware = 0; -static unsigned tokenformat = TOKEN_ALGO_SIGNED; - -struct osp_provider { - char name[OSP_MAX]; - char localpvtkey[OSP_MAX]; - char localcert[OSP_MAX]; - char cacerts[MAX_CERTS][OSP_MAX]; - int cacount; - char servicepoints[MAX_SERVICEPOINTS][OSP_MAX]; - char source[OSP_MAX]; - int spcount; - int dead; - int maxconnections; - int retrydelay; - int retrylimit; - int timeout; - OSPTPROVHANDLE handle; - struct osp_provider *next; -}; -static struct osp_provider *providers; - -static int osp_build(struct ast_config *cfg, char *cat) -{ - OSPTCERT TheAuthCert[MAX_CERTS]; - unsigned char Reqbuf[4096],LocalBuf[4096],AuthBuf[MAX_CERTS][4096]; - struct ast_variable *v; - struct osp_provider *osp; - int x,length,errorcode=0; - int mallocd=0,i; - char *cacerts[MAX_CERTS]; - const char *servicepoints[MAX_SERVICEPOINTS]; - OSPTPRIVATEKEY privatekey; - OSPTCERT localcert; - OSPTCERT *authCerts[MAX_CERTS]; - - - - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - if (!strcasecmp(osp->name, cat)) - break; - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (!osp) { - mallocd = 1; - osp = malloc(sizeof(struct osp_provider)); - if (!osp) { - ast_log(LOG_WARNING, "Out of memory!\n"); - return -1; - } - memset(osp, 0, sizeof(struct osp_provider)); - osp->handle = -1; - } - ast_copy_string(osp->name, cat, sizeof(osp->name)); - snprintf(osp->localpvtkey, sizeof(osp->localpvtkey) ,"%s/%s-privatekey.pem", ast_config_AST_KEY_DIR, cat); - snprintf(osp->localcert, sizeof(osp->localpvtkey), "%s/%s-localcert.pem", ast_config_AST_KEY_DIR, cat); - osp->maxconnections=OSP_DEFAULT_MAX_CONNECTIONS; - osp->retrydelay = OSP_DEFAULT_RETRY_DELAY; - osp->retrylimit = OSP_DEFAULT_RETRY_LIMIT; - osp->timeout = OSP_DEFAULT_TIMEOUT; - osp->source[0] = '\0'; - ast_log(LOG_DEBUG, "Building OSP Provider '%s'\n", cat); - v = ast_variable_browse(cfg, cat); - while(v) { - if (!strcasecmp(v->name, "privatekey")) { - if (v->value[0] == '/') - ast_copy_string(osp->localpvtkey, v->value, sizeof(osp->localpvtkey)); - else - snprintf(osp->localpvtkey, sizeof(osp->localpvtkey), "%s/%s", ast_config_AST_KEY_DIR , v->value); - } else if (!strcasecmp(v->name, "localcert")) { - if (v->value[0] == '/') - ast_copy_string(osp->localcert, v->value, sizeof(osp->localcert)); - else - snprintf(osp->localcert, sizeof(osp->localcert), "%s/%s", ast_config_AST_KEY_DIR, v->value); - } else if (!strcasecmp(v->name, "cacert")) { - if (osp->cacount < MAX_CERTS) { - if (v->value[0] == '/') - ast_copy_string(osp->cacerts[osp->cacount], v->value, sizeof(osp->cacerts[0])); - else - snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s", ast_config_AST_KEY_DIR, v->value); - osp->cacount++; - } else - ast_log(LOG_WARNING, "Too many CA Certificates at line %d\n", v->lineno); - } else if (!strcasecmp(v->name, "servicepoint")) { - if (osp->spcount < MAX_SERVICEPOINTS) { - ast_copy_string(osp->servicepoints[osp->spcount], v->value, sizeof(osp->servicepoints[0])); - osp->spcount++; - } else - ast_log(LOG_WARNING, "Too many Service points at line %d\n", v->lineno); - } else if (!strcasecmp(v->name, "maxconnections")) { - if ((sscanf(v->value, "%d", &x) == 1) && (x > 0) && (x <= 1000)) { - osp->maxconnections = x; - } else - ast_log(LOG_WARNING, "maxconnections should be an integer from 1 to 1000, not '%s' at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "retrydelay")) { - if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 10)) { - osp->retrydelay = x; - } else - ast_log(LOG_WARNING, "retrydelay should be an integer from 0 to 10, not '%s' at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "retrylimit")) { - if ((sscanf(v->value, "%d", &x) == 1) && (x >= 0) && (x <= 100)) { - osp->retrylimit = x; - } else - ast_log(LOG_WARNING, "retrylimit should be an integer from 0 to 100, not '%s' at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "timeout")) { - if ((sscanf(v->value, "%d", &x) == 1) && (x >= 200) && (x <= 10000)) { - osp->timeout = x; - } else - ast_log(LOG_WARNING, "timeout should be an integer from 200 to 10000, not '%s' at line %d\n", v->value, v->lineno); - } else if (!strcasecmp(v->name, "source")) { - ast_copy_string(osp->source, v->value, sizeof(osp->source)); - } - v = v->next; - } - if (osp->cacount < 1) { - snprintf(osp->cacerts[osp->cacount], sizeof(osp->cacerts[0]), "%s/%s-cacert.pem", ast_config_AST_KEY_DIR, cat); - osp->cacount++; - } - for (x=0;x<osp->cacount;x++) - cacerts[x] = osp->cacerts[x]; - for (x=0;x<osp->spcount;x++) - servicepoints[x] = osp->servicepoints[x]; - - ast_mutex_lock(&osplock); - osp->dead = 0; - if (osp->handle > -1) { - ast_log(LOG_DEBUG, "Deleting old handle for '%s'\n", osp->name); - OSPPProviderDelete(osp->handle, 0); - } - - - length = 0; - ast_log(LOG_DEBUG, "Loading private key for '%s' (%s)\n", osp->name, osp->localpvtkey); - errorcode = loadPemPrivateKey(osp->localpvtkey,Reqbuf,&length); - if (errorcode == 0) - { - privatekey.PrivateKeyData = Reqbuf; - privatekey.PrivateKeyLength = length; - } - else - { - return -1; - } - - length = 0; - ast_log(LOG_DEBUG, "Loading local cert for '%s' (%s)\n", osp->name, osp->localcert); - errorcode = loadPemCert(osp->localcert,LocalBuf,&length); - if (errorcode == 0) - { - localcert.CertData = LocalBuf; - localcert.CertDataLength = length; - } - else - { - return -1; - } - - for (i=0;i<osp->cacount;i++) - { - length = 0; - ast_log(LOG_DEBUG, "Loading CA cert %d for '%s' (%s)\n", i + 1, osp->name, osp->cacerts[i]); - errorcode = loadPemCert(osp->cacerts[i],AuthBuf[i],&length); - if (errorcode == 0) - { - TheAuthCert[i].CertData = AuthBuf[i]; - TheAuthCert[i].CertDataLength = length; - authCerts[i] = &(TheAuthCert[i]); - } - else - { - return -1; - } - } - - ast_log(LOG_DEBUG, "Creating provider handle for '%s'\n", osp->name); - - ast_log(LOG_DEBUG, "Service point '%s %d'\n", servicepoints[0], osp->spcount); - - if (OSPPProviderNew(osp->spcount, - servicepoints, - NULL, - "localhost", - &privatekey, - &localcert, - osp->cacount, - (const OSPTCERT **)authCerts, - 1, - 300, - osp->maxconnections, - 1, - osp->retrydelay, - osp->retrylimit, - osp->timeout, - "", - "", - &osp->handle)) { - ast_log(LOG_WARNING, "Unable to initialize provider '%s'\n", cat); - osp->dead = 1; - } - - if (mallocd) { - osp->next = providers; - providers = osp; - } - ast_mutex_unlock(&osplock); - return 0; -} - -static int show_osp(int fd, int argc, char *argv[]) -{ - struct osp_provider *osp; - char *search = NULL; - int x; - int found = 0; - char *tokenalgo; - - if ((argc < 2) || (argc > 3)) - return RESULT_SHOWUSAGE; - if (argc > 2) - search = argv[2]; - if (!search) { - switch (tokenformat) { - case TOKEN_ALGO_BOTH: - tokenalgo = "Both"; - break; - case TOKEN_ALGO_UNSIGNED: - tokenalgo = "Unsigned"; - break; - case TOKEN_ALGO_SIGNED: - default: - tokenalgo = "Signed"; - break; - } - ast_cli(fd, "OSP: %s %s %s\n", initialized ? "Initialized" : "Uninitialized", hardware ? "Accelerated" : "Normal", tokenalgo); - } - - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - if (!search || !strcasecmp(osp->name, search)) { - if (found) - ast_cli(fd, "\n"); - ast_cli(fd, " == OSP Provider '%s' ==\n", osp->name); - ast_cli(fd, "Local Private Key: %s\n", osp->localpvtkey); - ast_cli(fd, "Local Certificate: %s\n", osp->localcert); - for (x=0;x<osp->cacount;x++) - ast_cli(fd, "CA Certificate %d: %s\n", x + 1, osp->cacerts[x]); - for (x=0;x<osp->spcount;x++) - ast_cli(fd, "Service Point %d: %s\n", x + 1, osp->servicepoints[x]); - ast_cli(fd, "Max Connections: %d\n", osp->maxconnections); - ast_cli(fd, "Retry Delay: %d seconds\n", osp->retrydelay); - ast_cli(fd, "Retry Limit: %d\n", osp->retrylimit); - ast_cli(fd, "Timeout: %d milliseconds\n", osp->timeout); - ast_cli(fd, "Source: %s\n", strlen(osp->source) ? osp->source : "<unspecified>"); - ast_cli(fd, "OSP Handle: %d\n", osp->handle); - found++; - } - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (!found) { - if (search) - ast_cli(fd, "Unable to find OSP provider '%s'\n", search); - else - ast_cli(fd, "No OSP providers configured\n"); - } - return RESULT_SUCCESS; -} - - -/*----------------------------------------------* - * Loads the Certificate * - *----------------------------------------------*/ -static int loadPemCert(unsigned char *FileName, unsigned char *buffer, int *len) -{ - int length = 0; - unsigned char *temp; - BIO *bioIn = NULL; - X509 *cert=NULL; - int retVal = OSPC_ERR_NO_ERROR; - - temp = buffer; - bioIn = BIO_new_file((const char*)FileName,"r"); - if (bioIn == NULL) - { - ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName); - return -1; - } - else - { - cert = PEM_read_bio_X509(bioIn,NULL,NULL,NULL); - if (cert == NULL) - { - ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s \n",FileName); - return -1; - } - else - { - length = i2d_X509(cert,&temp); - if (cert == 0) - { - ast_log(LOG_WARNING,"Failed to parse the Certificate from the File - %s, Length=0 \n",FileName); - return -1; - } - else - { - *len = length; - } - } - } - - if (bioIn != NULL) - { - BIO_free(bioIn); - } - - if (cert != NULL) - { - X509_free(cert); - } - return retVal; -} - -/*----------------------------------------------* - * Loads the Private Key * - *----------------------------------------------*/ -static int loadPemPrivateKey(unsigned char *FileName, unsigned char *buffer, int *len) -{ - int length = 0; - unsigned char *temp; - BIO *bioIn = NULL; - RSA *pKey = NULL; - int retVal = OSPC_ERR_NO_ERROR; - - temp = buffer; - - bioIn = BIO_new_file((const char*)FileName,"r"); - if (bioIn == NULL) - { - ast_log(LOG_WARNING,"Failed to find the File - %s \n",FileName); - return -1; - } - else - { - pKey = PEM_read_bio_RSAPrivateKey(bioIn,NULL,NULL,NULL); - if (pKey == NULL) - { - ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s \n",FileName); - return -1; - } - else - { - length = i2d_RSAPrivateKey(pKey,&temp); - if (length == 0) - { - ast_log(LOG_WARNING,"Failed to parse the Private Key from the File - %s, Length=0 \n",FileName); - return -1; - } - else - { - *len = length; - } - } - } - if (bioIn != NULL) - { - BIO_free(bioIn); - } - - if (pKey != NULL) - { - RSA_free(pKey); - } - return retVal; -} - -int ast_osp_validate(char *provider, char *token, int *handle, unsigned int *timelimit, char *callerid, struct in_addr addr, char *extension) -{ - char tmp[256]="", *l, *n; - char iabuf[INET_ADDRSTRLEN]; - char source[OSP_MAX] = ""; /* Same length as osp->source */ - char *token2; - int tokenlen; - struct osp_provider *osp; - int res = 0; - unsigned int authorised, dummy; - - if (!provider || !strlen(provider)) - provider = "default"; - - token2 = ast_strdupa(token); - if (!token2) - return -1; - tokenlen = ast_base64decode(token2, token, strlen(token)); - *handle = -1; - if (!callerid) - callerid = ""; - ast_copy_string(tmp, callerid, sizeof(tmp)); - ast_callerid_parse(tmp, &n, &l); - if (!l) - l = ""; - else { - ast_shrink_phone_number(l); - if (!ast_isphonenumber(l)) - l = ""; - } - callerid = l; - ast_mutex_lock(&osplock); - ast_inet_ntoa(iabuf, sizeof(iabuf), addr); - osp = providers; - while(osp) { - if (!strcasecmp(osp->name, provider)) { - if (OSPPTransactionNew(osp->handle, handle)) { - ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n"); - } else { - ast_copy_string(source, osp->source, sizeof(source)); - res = 1; - } - break; - } - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (res) { - res = 0; - dummy = 0; - if (!OSPPTransactionValidateAuthorisation(*handle, iabuf, source, NULL, NULL, - callerid, OSPC_E164, extension, OSPC_E164, 0, "", tokenlen, token2, &authorised, timelimit, &dummy, NULL, tokenformat)) { - if (authorised) { - ast_log(LOG_DEBUG, "Validated token for '%s' from '%s@%s'\n", extension, callerid, iabuf); - res = 1; - } - } - } - return res; -} - -int ast_osp_lookup(struct ast_channel *chan, char *provider, char *extension, char *callerid, struct ast_osp_result *result) -{ - int cres; - int res = 0; - int counts; - int tokenlen; - unsigned int dummy=0; - unsigned int timelimit; - unsigned int callidlen; - char callidstr[OSPC_CALLID_MAXSIZE] = ""; - struct osp_provider *osp; - char source[OSP_MAX] = ""; /* Same length as osp->source */ - char callednum[2048]=""; - char callingnum[2048]=""; - char destination[2048]=""; - char token[2000]; - char tmp[256]="", *l, *n; - OSPE_DEST_PROT prot; - OSPE_DEST_OSP_ENABLED ospenabled; - char *devinfo = NULL; - - result->handle = -1; - result->numresults = 0; - result->tech[0] = '\0'; - result->dest[0] = '\0'; - result->token[0] = '\0'; - - if (!provider || !strlen(provider)) - provider = "default"; - - if (!callerid) - callerid = ""; - ast_copy_string(tmp, callerid, sizeof(tmp)); - ast_callerid_parse(tmp, &n, &l); - if (!l) - l = ""; - else { - ast_shrink_phone_number(l); - if (!ast_isphonenumber(l)) - l = ""; - } - callerid = l; - - if (chan) { - cres = ast_autoservice_start(chan); - if (cres < 0) - return cres; - } - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - if (!strcasecmp(osp->name, provider)) { - if (OSPPTransactionNew(osp->handle, &result->handle)) { - ast_log(LOG_WARNING, "Unable to create OSP Transaction handle!\n"); - } else { - ast_copy_string(source, osp->source, sizeof(source)); - res = 1; - } - break; - } - osp = osp->next; - } - ast_mutex_unlock(&osplock); - if (res) { - res = 0; - /* No more than 10 back */ - counts = 10; - dummy = 0; - devinfo = pbx_builtin_getvar_helper (chan, "OSPPEER"); - if (!devinfo) { - devinfo = ""; - } - if (!OSPPTransactionRequestAuthorisation(result->handle, source, devinfo, - callerid,OSPC_E164, extension, OSPC_E164, NULL, 0, NULL, NULL, &counts, &dummy, NULL)) { - if (counts) { - tokenlen = sizeof(token); - result->numresults = counts - 1; - callidlen = sizeof(callidstr); - if (!OSPPTransactionGetFirstDestination(result->handle, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - ast_log(LOG_DEBUG, "Got destination '%s' and called: '%s' calling: '%s' for '%s' (provider '%s')\n", - destination, callednum, callingnum, extension, provider); - /* Only support OSP server with only one duration limit */ - if (ast_channel_cmpwhentohangup (chan, timelimit) < 0) { - ast_channel_setwhentohangup (chan, timelimit); - } - do { - if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { - result->token[0] = 0; - } - else { - ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); - } - if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { - res = 1; - /* Strip leading and trailing brackets */ - destination[strlen(destination) - 1] = '\0'; - switch(prot) { - case OSPE_DEST_PROT_H323_SETUP: - ast_copy_string(result->tech, "H323", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_SIP: - ast_copy_string(result->tech, "SIP", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_IAX: - ast_copy_string(result->tech, "IAX", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - default: - ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); - res = 0; - } - if (!res && result->numresults) { - result->numresults--; - callidlen = sizeof(callidstr); - if (OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - break; - } - } - } else { - ast_log(LOG_DEBUG, "Missing destination protocol\n"); - break; - } - } while(!res && result->numresults); - } - } - - } - if (!res) { - OSPPTransactionDelete(result->handle); - result->handle = -1; - } - - } - if (!osp) - ast_log(LOG_NOTICE, "OSP Provider '%s' does not exist!\n", provider); - if (chan) { - cres = ast_autoservice_stop(chan); - if (cres < 0) - return cres; - } - return res; -} - -int ast_osp_next(struct ast_osp_result *result, int cause) -{ - int res = 0; - int tokenlen; - unsigned int dummy=0; - unsigned int timelimit; - unsigned int callidlen; - char callidstr[OSPC_CALLID_MAXSIZE] = ""; - char callednum[2048]=""; - char callingnum[2048]=""; - char destination[2048]=""; - char token[2000]; - OSPE_DEST_PROT prot; - OSPE_DEST_OSP_ENABLED ospenabled; - - result->tech[0] = '\0'; - result->dest[0] = '\0'; - result->token[0] = '\0'; - - if (result->handle > -1) { - dummy = 0; - if (result->numresults) { - tokenlen = sizeof(token); - while(!res && result->numresults) { - result->numresults--; - callidlen = sizeof(callidstr); - if (!OSPPTransactionGetNextDestination(result->handle, OSPC_FAIL_INCOMPATIBLE_DEST, 0, NULL, NULL, &timelimit, &callidlen, callidstr, - sizeof(callednum), callednum, sizeof(callingnum), callingnum, sizeof(destination), destination, 0, NULL, &tokenlen, token)) { - if (!OSPPTransactionIsDestOSPEnabled (result->handle, &ospenabled) && (ospenabled == OSPE_OSP_FALSE)) { - result->token[0] = 0; - } - else { - ast_base64encode(result->token, token, tokenlen, sizeof(result->token) - 1); - } - if ((strlen(destination) > 2) && !OSPPTransactionGetDestProtocol(result->handle, &prot)) { - res = 1; - /* Strip leading and trailing brackets */ - destination[strlen(destination) - 1] = '\0'; - switch(prot) { - case OSPE_DEST_PROT_H323_SETUP: - ast_copy_string(result->tech, "H323", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_SIP: - ast_copy_string(result->tech, "SIP", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - case OSPE_DEST_PROT_IAX: - ast_copy_string(result->tech, "IAX", sizeof(result->tech)); - snprintf(result->dest, sizeof(result->dest), "%s@%s", callednum, destination + 1); - break; - default: - ast_log(LOG_DEBUG, "Unknown destination protocol '%d', skipping...\n", prot); - res = 0; - } - } else { - ast_log(LOG_DEBUG, "Missing destination protocol\n"); - break; - } - } - } - - } - if (!res) { - OSPPTransactionDelete(result->handle); - result->handle = -1; - } - - } - return res; -} - -static enum OSPEFAILREASON cause2reason(int cause) -{ - switch(cause) { - case AST_CAUSE_BUSY: - return OSPC_FAIL_USER_BUSY; - case AST_CAUSE_CONGESTION: - return OSPC_FAIL_SWITCHING_EQUIPMENT_CONGESTION; - case AST_CAUSE_UNALLOCATED: - return OSPC_FAIL_UNALLOC_NUMBER; - case AST_CAUSE_NOTDEFINED: - return OSPC_FAIL_NORMAL_UNSPECIFIED; - case AST_CAUSE_NOANSWER: - return OSPC_FAIL_NO_ANSWER_FROM_USER; - case AST_CAUSE_NORMAL: - default: - return OSPC_FAIL_NORMAL_CALL_CLEARING; - } -} - -int ast_osp_terminate(int handle, int cause, time_t start, time_t duration) -{ - unsigned int dummy = 0; - int res = -1; - enum OSPEFAILREASON reason; - - time_t endTime = 0; - time_t alertTime = 0; - time_t connectTime = 0; - unsigned isPddInfoPresent = 0; - unsigned pdd = 0; - unsigned releaseSource = 0; - unsigned char *confId = ""; - - reason = cause2reason(cause); - if (OSPPTransactionRecordFailure(handle, reason)) - ast_log(LOG_WARNING, "Failed to record call termination for handle %d\n", handle); - else if (OSPPTransactionReportUsage(handle, duration, start, - endTime,alertTime,connectTime,isPddInfoPresent,pdd,releaseSource,confId, - 0, 0, 0, 0, &dummy, NULL)) - ast_log(LOG_WARNING, "Failed to report duration for handle %d\n", handle); - else { - ast_log(LOG_DEBUG, "Completed recording handle %d\n", handle); - OSPPTransactionDelete(handle); - res = 0; - } - return res; -} - -static int config_load(void) -{ - struct ast_config *cfg; - char *cat; - struct osp_provider *osp, *prev = NULL, *next; - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - osp->dead = 1; - osp = osp->next; - } - ast_mutex_unlock(&osplock); - cfg = ast_config_load("osp.conf"); - if (cfg) { - if (!initialized) { - cat = ast_variable_retrieve(cfg, "general", "accelerate"); - if (cat && ast_true(cat)) - if (OSPPInit(1)) { - ast_log(LOG_WARNING, "Failed to enable hardware accelleration, falling back to software mode\n"); - OSPPInit(0); - } else - hardware = 1; - else - OSPPInit(0); - initialized = 1; - } - cat = ast_variable_retrieve(cfg, "general", "tokenformat"); - if (cat) { - if ((sscanf(cat, "%d", &tokenformat) != 1) || (tokenformat < TOKEN_ALGO_SIGNED) || (tokenformat > TOKEN_ALGO_BOTH)) { - tokenformat = TOKEN_ALGO_SIGNED; - ast_log(LOG_WARNING, "tokenformat should be an integer from 0 to 2, not '%s'\n", cat); - } - } - cat = ast_category_browse(cfg, NULL); - while(cat) { - if (strcasecmp(cat, "general")) - osp_build(cfg, cat); - cat = ast_category_browse(cfg, cat); - } - ast_config_destroy(cfg); - } else - ast_log(LOG_NOTICE, "No OSP configuration found. OSP support disabled\n"); - ast_mutex_lock(&osplock); - osp = providers; - while(osp) { - next = osp->next; - if (osp->dead) { - if (prev) - prev->next = next; - else - providers = next; - /* XXX Cleanup OSP structure first XXX */ - free(osp); - } else - prev = osp; - osp = next; - } - ast_mutex_unlock(&osplock); - return 0; -} - -static char show_osp_usage[] = -"Usage: show osp\n" -" Displays information on Open Settlement Protocol\n"; - -static struct ast_cli_entry cli_show_osp = -{ { "show", "osp", NULL }, show_osp, "Displays OSP information", show_osp_usage }; - -int reload(void) -{ - config_load(); - ast_log(LOG_NOTICE, "XXX Should reload OSP config XXX\n"); - return 0; -} - -int load_module(void) -{ - config_load(); - ast_cli_register(&cli_show_osp); - return 0; -} - -int unload_module(void) -{ - /* Can't unload this once we're loaded */ - return -1; -} - -char *description(void) -{ - return "Open Settlement Protocol Support"; -} - -int usecount(void) -{ - /* We should never be unloaded */ - return 1; -} - -char *key() -{ - return ASTERISK_GPL_KEY; -} |