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