From 168242c841b9df35042ea02d63ae6ab49873bb1d Mon Sep 17 00:00:00 2001 From: Jeremy McNamara Date: Sun, 11 Jan 2004 07:37:47 +0000 Subject: add new application 'zapscan' Bug #250 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1935 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_zapscan.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100755 apps/app_zapscan.c (limited to 'apps/app_zapscan.c') diff --git a/apps/app_zapscan.c b/apps/app_zapscan.c new file mode 100755 index 000000000..54db27df0 --- /dev/null +++ b/apps/app_zapscan.c @@ -0,0 +1,304 @@ +/* + * Asterisk -- A telephony toolkit for Linux. + * + * Zap Scanner + * + * Copyright (C) 2003, Digium + * + * Modified from app_zapbarge by David Troy + * + * Mark Spencer + * + * This program is free software, distributed under the terms of + * the GNU General Public License + * + * Special thanks to comphealth.com for sponsoring this + * GPL application. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +static char *tdesc = "Scan Zap channels application"; + +static char *app = "ZapScan"; + +static char *synopsis = "Scan Zap channels to monitor calls"; + +static char *descrip = +" ZapScan allows a call center manager to monitor\n" +"phone conversations in a convenient way."; + + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + + +#define CONF_SIZE 160 + +static int careful_write(int fd, unsigned char *data, int len) +{ + int res; + while(len) { + res = write(fd, data, len); + if (res < 1) { + if (errno != EAGAIN) { + ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno)); + return -1; + } else + return 0; + } + len -= res; + data += res; + } + return 0; +} + +static int conf_run(struct ast_channel *chan, int confno, int confflags) +{ + int fd; + struct zt_confinfo ztc; + struct ast_frame *f; + struct ast_channel *c; + struct ast_frame fr; + int outfd; + int ms; + int nfds; + int res; + int flags; + int retryzap; + int origfd; + int ret = -1; + + ZT_BUFFERINFO bi; + char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET]; + char *buf = __buf + AST_FRIENDLY_OFFSET; + + /* Set it into U-law mode (write) */ + if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name); + goto outrun; + } + + /* Set it into U-law mode (read) */ + if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) { + ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name); + goto outrun; + } + ast_indicate(chan, -1); + retryzap = strcasecmp(chan->type, "Zap"); +zapretry: + origfd = chan->fds[0]; + if (retryzap) { + fd = open("/dev/zap/pseudo", O_RDWR); + if (fd < 0) { + ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno)); + goto outrun; + } + /* Make non-blocking */ + flags = fcntl(fd, F_GETFL); + if (flags < 0) { + ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno)); + close(fd); + goto outrun; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { + ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno)); + close(fd); + goto outrun; + } + /* Setup buffering information */ + memset(&bi, 0, sizeof(bi)); + bi.bufsize = CONF_SIZE; + bi.txbufpolicy = ZT_POLICY_IMMEDIATE; + bi.rxbufpolicy = ZT_POLICY_IMMEDIATE; + bi.numbufs = 4; + if (ioctl(fd, ZT_SET_BUFINFO, &bi)) { + ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno)); + close(fd); + goto outrun; + } + nfds = 1; + } else { + /* XXX Make sure we're not running on a pseudo channel XXX */ + fd = chan->fds[0]; + nfds = 0; + } + memset(&ztc, 0, sizeof(ztc)); + /* Check to see if we're in a conference... */ + ztc.chan = 0; + if (ioctl(fd, ZT_GETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error getting conference\n"); + close(fd); + goto outrun; + } + if (ztc.confmode) { + /* Whoa, already in a conference... Retry... */ + if (!retryzap) { + ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n"); + retryzap = 1; + goto zapretry; + } + } + memset(&ztc, 0, sizeof(ztc)); + /* Add us to the conference */ + ztc.chan = 0; + ztc.confno = confno; + ztc.confmode = ZT_CONF_MONITORBOTH; + + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + close(fd); + goto outrun; + } + ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno); + + for(;;) { + outfd = -1; + ms = -1; + c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms); + if (c) { + if (c->fds[0] != origfd) { + if (retryzap) { + /* Kill old pseudo */ + close(fd); + } + ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n"); + retryzap = 0; + goto zapretry; + } + f = ast_read(c); + if (!f) + break; + if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { + ret = 0; + break; + } else if (fd != chan->fds[0]) { + if (f->frametype == AST_FRAME_VOICE) { + if (f->subclass == AST_FORMAT_ULAW) { + /* Carefully write */ + careful_write(fd, f->data, f->datalen); + } else + ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass); + } + } + ast_frfree(f); + } else if (outfd > -1) { + res = read(outfd, buf, CONF_SIZE); + if (res > 0) { + memset(&fr, 0, sizeof(fr)); + fr.frametype = AST_FRAME_VOICE; + fr.subclass = AST_FORMAT_ULAW; + fr.datalen = res; + fr.samples = res; + fr.data = buf; + fr.offset = AST_FRIENDLY_OFFSET; + if (ast_write(chan, &fr) < 0) { + ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno)); + /* break; */ + } + } else + ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno)); + } + } + if (fd != chan->fds[0]) + close(fd); + else { + /* Take out of conference */ + /* Add us to the conference */ + ztc.chan = 0; + ztc.confno = 0; + ztc.confmode = 0; + if (ioctl(fd, ZT_SETCONF, &ztc)) { + ast_log(LOG_WARNING, "Error setting conference\n"); + } + } + +outrun: + + return ret; +} + +static int conf_exec(struct ast_channel *chan, void *data) +{ + int res=-1; + struct localuser *u; + int confflags = 0; + int confno = 0; + char confstr[80], *tmp; + struct ast_channel *tempchan = NULL, *lastchan = NULL; + + LOCAL_USER_ADD(u); + + if (chan->_state != AST_STATE_UP) + ast_answer(chan); + + for (;;) { + tempchan = ast_channel_walk(tempchan); + if ( !tempchan && !lastchan ) + break; + if ( tempchan && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) { + ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name); + strcpy(confstr, tempchan->name); + if ((tmp = strchr(confstr,'-'))) { + *tmp = '\0'; + } + confno = atoi(strchr(confstr,'/') + 1); + ast_stopstream(chan); + ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language); + res = conf_run(chan, confno, confflags); + if (res<0) break; + } + lastchan = tempchan; + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + STANDARD_HANGUP_LOCALUSERS; + return ast_unregister_application(app); +} + +int load_module(void) +{ + return ast_register_application(app, conf_exec, synopsis, descrip); +} + +char *description(void) +{ + return tdesc; +} + +int usecount(void) +{ + int res; + STANDARD_USECOUNT(res); + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} + -- cgit v1.2.3