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