00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035 #include <errno.h>
00036 #include <sys/ioctl.h>
00037
00038 #ifdef __linux__
00039 #include <linux/zaptel.h>
00040 #else
00041 #include <zaptel.h>
00042 #endif
00043
00044 #include "asterisk.h"
00045
00046 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 33449 $")
00047
00048 #include "asterisk/lock.h"
00049 #include "asterisk/file.h"
00050 #include "asterisk/logger.h"
00051 #include "asterisk/channel.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/module.h"
00054 #include "asterisk/config.h"
00055 #include "asterisk/app.h"
00056 #include "asterisk/options.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/cli.h"
00059 #include "asterisk/say.h"
00060
00061 static char *tdesc = "Scan Zap channels application";
00062
00063 static char *app = "ZapScan";
00064
00065 static char *synopsis = "Scan Zap channels to monitor calls";
00066
00067 static char *descrip =
00068 " ZapScan([group]) allows a call center manager to monitor Zap channels in\n"
00069 "a convenient way. Use '#' to select the next channel and use '*' to exit\n"
00070 "Limit scanning to a channel GROUP by setting the option group argument.\n";
00071
00072 STANDARD_LOCAL_USER;
00073
00074 LOCAL_USER_DECL;
00075
00076
00077 #define CONF_SIZE 160
00078
00079 static struct ast_channel *get_zap_channel_locked(int num) {
00080 char name[80];
00081
00082 snprintf(name,sizeof(name),"Zap/%d-1",num);
00083 return ast_get_channel_by_name_locked(name);
00084 }
00085
00086 static int careful_write(int fd, unsigned char *data, int len)
00087 {
00088 int res;
00089 while(len) {
00090 res = write(fd, data, len);
00091 if (res < 1) {
00092 if (errno != EAGAIN) {
00093 ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00094 return -1;
00095 } else
00096 return 0;
00097 }
00098 len -= res;
00099 data += res;
00100 }
00101 return 0;
00102 }
00103
00104 static int conf_run(struct ast_channel *chan, int confno, int confflags)
00105 {
00106 int fd;
00107 struct zt_confinfo ztc;
00108 struct ast_frame *f;
00109 struct ast_channel *c;
00110 struct ast_frame fr;
00111 int outfd;
00112 int ms;
00113 int nfds;
00114 int res;
00115 int flags;
00116 int retryzap;
00117 int origfd;
00118 int ret = -1;
00119 char input[4];
00120 int ic=0;
00121
00122 ZT_BUFFERINFO bi;
00123 char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00124 char *buf = __buf + AST_FRIENDLY_OFFSET;
00125
00126
00127 if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00128 ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00129 goto outrun;
00130 }
00131
00132
00133 if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00134 ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00135 goto outrun;
00136 }
00137 ast_indicate(chan, -1);
00138 retryzap = strcasecmp(chan->type, "Zap");
00139 zapretry:
00140 origfd = chan->fds[0];
00141 if (retryzap) {
00142 fd = open("/dev/zap/pseudo", O_RDWR);
00143 if (fd < 0) {
00144 ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00145 goto outrun;
00146 }
00147
00148 flags = fcntl(fd, F_GETFL);
00149 if (flags < 0) {
00150 ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00151 close(fd);
00152 goto outrun;
00153 }
00154 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00155 ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00156 close(fd);
00157 goto outrun;
00158 }
00159
00160 memset(&bi, 0, sizeof(bi));
00161 bi.bufsize = CONF_SIZE;
00162 bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
00163 bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
00164 bi.numbufs = 4;
00165 if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
00166 ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00167 close(fd);
00168 goto outrun;
00169 }
00170 nfds = 1;
00171 } else {
00172
00173 fd = chan->fds[0];
00174 nfds = 0;
00175 }
00176 memset(&ztc, 0, sizeof(ztc));
00177
00178 ztc.chan = 0;
00179 if (ioctl(fd, ZT_GETCONF, &ztc)) {
00180 ast_log(LOG_WARNING, "Error getting conference\n");
00181 close(fd);
00182 goto outrun;
00183 }
00184 if (ztc.confmode) {
00185
00186 if (!retryzap) {
00187 ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
00188 retryzap = 1;
00189 goto zapretry;
00190 }
00191 }
00192 memset(&ztc, 0, sizeof(ztc));
00193
00194 ztc.chan = 0;
00195 ztc.confno = confno;
00196 ztc.confmode = ZT_CONF_MONITORBOTH;
00197
00198 if (ioctl(fd, ZT_SETCONF, &ztc)) {
00199 ast_log(LOG_WARNING, "Error setting conference\n");
00200 close(fd);
00201 goto outrun;
00202 }
00203 ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
00204
00205 for(;;) {
00206 outfd = -1;
00207 ms = -1;
00208 c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00209 if (c) {
00210 if (c->fds[0] != origfd) {
00211 if (retryzap) {
00212
00213 close(fd);
00214 }
00215 ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
00216 retryzap = 0;
00217 goto zapretry;
00218 }
00219 f = ast_read(c);
00220 if (!f)
00221 break;
00222 if(f->frametype == AST_FRAME_DTMF) {
00223 if(f->subclass == '#') {
00224 ret = 0;
00225 break;
00226 }
00227 else if (f->subclass == '*') {
00228 ret = -1;
00229 break;
00230
00231 }
00232 else {
00233 input[ic++] = f->subclass;
00234 }
00235 if(ic == 3) {
00236 input[ic++] = '\0';
00237 ic=0;
00238 ret = atoi(input);
00239 ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret);
00240 break;
00241 }
00242 }
00243
00244 if (fd != chan->fds[0]) {
00245 if (f->frametype == AST_FRAME_VOICE) {
00246 if (f->subclass == AST_FORMAT_ULAW) {
00247
00248 careful_write(fd, f->data, f->datalen);
00249 } else
00250 ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00251 }
00252 }
00253 ast_frfree(f);
00254 } else if (outfd > -1) {
00255 res = read(outfd, buf, CONF_SIZE);
00256 if (res > 0) {
00257 memset(&fr, 0, sizeof(fr));
00258 fr.frametype = AST_FRAME_VOICE;
00259 fr.subclass = AST_FORMAT_ULAW;
00260 fr.datalen = res;
00261 fr.samples = res;
00262 fr.data = buf;
00263 fr.offset = AST_FRIENDLY_OFFSET;
00264 if (ast_write(chan, &fr) < 0) {
00265 ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00266
00267 }
00268 } else
00269 ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00270 }
00271 }
00272 if (f)
00273 ast_frfree(f);
00274 if (fd != chan->fds[0])
00275 close(fd);
00276 else {
00277
00278
00279 ztc.chan = 0;
00280 ztc.confno = 0;
00281 ztc.confmode = 0;
00282 if (ioctl(fd, ZT_SETCONF, &ztc)) {
00283 ast_log(LOG_WARNING, "Error setting conference\n");
00284 }
00285 }
00286
00287 outrun:
00288
00289 return ret;
00290 }
00291
00292 static int conf_exec(struct ast_channel *chan, void *data)
00293 {
00294 int res=-1;
00295 struct localuser *u;
00296 int confflags = 0;
00297 int confno = 0;
00298 char confstr[80] = "", *tmp = NULL;
00299 struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
00300 struct ast_frame *f;
00301 char *mygroup;
00302 char *desired_group;
00303 int input=0,search_group=0;
00304
00305 LOCAL_USER_ADD(u);
00306
00307 if (chan->_state != AST_STATE_UP)
00308 ast_answer(chan);
00309
00310 desired_group = ast_strdupa((char *) data);
00311 if(!ast_strlen_zero(desired_group)) {
00312 ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
00313 search_group = 1;
00314 }
00315
00316 for (;;) {
00317 if (ast_waitfor(chan, 100) < 0)
00318 break;
00319
00320 f = ast_read(chan);
00321 if (!f)
00322 break;
00323 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
00324 ast_frfree(f);
00325 break;
00326 }
00327 ast_frfree(f);
00328 ichan = NULL;
00329 if(input) {
00330 ichan = get_zap_channel_locked(input);
00331 input = 0;
00332 }
00333
00334 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
00335
00336 if ( !tempchan && !lastchan )
00337 break;
00338
00339 if (tempchan && search_group) {
00340 if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
00341 ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
00342 } else {
00343 ast_mutex_unlock(&tempchan->lock);
00344 lastchan = tempchan;
00345 continue;
00346 }
00347 }
00348 if ( tempchan && tempchan->type && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) {
00349 ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
00350 ast_copy_string(confstr, tempchan->name, sizeof(confstr));
00351 ast_mutex_unlock(&tempchan->lock);
00352 if ((tmp = strchr(confstr,'-'))) {
00353 *tmp = '\0';
00354 }
00355 confno = atoi(strchr(confstr,'/') + 1);
00356 ast_stopstream(chan);
00357 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
00358 res = conf_run(chan, confno, confflags);
00359 if (res<0) break;
00360 input = res;
00361 } else if (tempchan)
00362 ast_mutex_unlock(&tempchan->lock);
00363 lastchan = tempchan;
00364 }
00365 LOCAL_USER_REMOVE(u);
00366 return res;
00367 }
00368
00369 int unload_module(void)
00370 {
00371 int res;
00372
00373 res = ast_unregister_application(app);
00374
00375 STANDARD_HANGUP_LOCALUSERS;
00376
00377 return res;
00378 }
00379
00380 int load_module(void)
00381 {
00382 return ast_register_application(app, conf_exec, synopsis, descrip);
00383 }
00384
00385 char *description(void)
00386 {
00387 return tdesc;
00388 }
00389
00390 int usecount(void)
00391 {
00392 int res;
00393 STANDARD_USECOUNT(res);
00394 return res;
00395 }
00396
00397 char *key()
00398 {
00399 return ASTERISK_GPL_KEY;
00400 }
00401