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