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: 7221 $")
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 (fd != chan->fds[0])
00273 close(fd);
00274 else {
00275
00276
00277 ztc.chan = 0;
00278 ztc.confno = 0;
00279 ztc.confmode = 0;
00280 if (ioctl(fd, ZT_SETCONF, &ztc)) {
00281 ast_log(LOG_WARNING, "Error setting conference\n");
00282 }
00283 }
00284
00285 outrun:
00286
00287 return ret;
00288 }
00289
00290 static int conf_exec(struct ast_channel *chan, void *data)
00291 {
00292 int res=-1;
00293 struct localuser *u;
00294 int confflags = 0;
00295 int confno = 0;
00296 char confstr[80] = "", *tmp = NULL;
00297 struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
00298 struct ast_frame *f;
00299 char *mygroup;
00300 char *desired_group;
00301 int input=0,search_group=0;
00302
00303 LOCAL_USER_ADD(u);
00304
00305 if (chan->_state != AST_STATE_UP)
00306 ast_answer(chan);
00307
00308 desired_group = ast_strdupa((char *) data);
00309 if(!ast_strlen_zero(desired_group)) {
00310 ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
00311 search_group = 1;
00312 }
00313
00314 for (;;) {
00315 if (ast_waitfor(chan, 100) < 0)
00316 break;
00317
00318 f = ast_read(chan);
00319 if (!f)
00320 break;
00321 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
00322 ast_frfree(f);
00323 break;
00324 }
00325 ast_frfree(f);
00326 ichan = NULL;
00327 if(input) {
00328 ichan = get_zap_channel_locked(input);
00329 input = 0;
00330 }
00331
00332 tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
00333
00334 if ( !tempchan && !lastchan )
00335 break;
00336
00337 if (tempchan && search_group) {
00338 if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
00339 ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
00340 } else {
00341 ast_mutex_unlock(&tempchan->lock);
00342 lastchan = tempchan;
00343 continue;
00344 }
00345 }
00346 if ( tempchan && tempchan->type && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) {
00347 ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
00348 ast_copy_string(confstr, tempchan->name, sizeof(confstr));
00349 ast_mutex_unlock(&tempchan->lock);
00350 if ((tmp = strchr(confstr,'-'))) {
00351 *tmp = '\0';
00352 }
00353 confno = atoi(strchr(confstr,'/') + 1);
00354 ast_stopstream(chan);
00355 ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
00356 res = conf_run(chan, confno, confflags);
00357 if (res<0) break;
00358 input = res;
00359 } else if (tempchan)
00360 ast_mutex_unlock(&tempchan->lock);
00361 lastchan = tempchan;
00362 }
00363 LOCAL_USER_REMOVE(u);
00364 return res;
00365 }
00366
00367 int unload_module(void)
00368 {
00369 int res;
00370
00371 res = ast_unregister_application(app);
00372
00373 STANDARD_HANGUP_LOCALUSERS;
00374
00375 return res;
00376 }
00377
00378 int load_module(void)
00379 {
00380 return ast_register_application(app, conf_exec, synopsis, descrip);
00381 }
00382
00383 char *description(void)
00384 {
00385 return tdesc;
00386 }
00387
00388 int usecount(void)
00389 {
00390 int res;
00391 STANDARD_USECOUNT(res);
00392 return res;
00393 }
00394
00395 char *key()
00396 {
00397 return ASTERISK_GPL_KEY;
00398 }
00399