Sat Aug 6 00:39:19 2011

Asterisk developer's documentation


app_dahdiscan.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Modified from app_zapbarge by David Troy <dave@toad.net>
00009  *
00010  * Special thanks to comphealth.com for sponsoring this
00011  * GPL application.
00012  *
00013  * See http://www.asterisk.org for more information about
00014  * the Asterisk project. Please do not directly contact
00015  * any of the maintainers of this project for assistance;
00016  * the project provides a web site, mailing lists and IRC
00017  * channels for your use.
00018  *
00019  * This program is free software, distributed under the terms of
00020  * the GNU General Public License Version 2. See the LICENSE file
00021  * at the top of the source tree.
00022  */
00023 
00024 /*! \file
00025  *
00026  * \brief Zap Scanner
00027  *
00028  * \author Mark Spencer <markster@digium.com>
00029  *
00030  * \ingroup applications
00031  */
00032 
00033 /*** MODULEINFO
00034    <depend>dahdi</depend>
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    /* Set it into U-law mode (write) */
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    /* Set it into U-law mode (read) */
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       /* Make non-blocking */
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       /* Setup buffering information */
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       /* XXX Make sure we're not running on a pseudo channel XXX */
00169       fd = chan->fds[0];
00170       nfds = 0;
00171    }
00172    memset(&ztc, 0, sizeof(ztc));
00173    /* Check to see if we're in a conference... */
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          /* Whoa, already in a conference...  Retry... */
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         /* Add us to the conference */
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                   /* Kill old pseudo */
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                      /* Carefully write */
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                   /* break; */
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          /* Take out of conference */
00274          /* Add us to the conference */
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 

Generated on Sat Aug 6 00:39:19 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7