Mon Nov 24 15:34:22 2008

Asterisk developer's documentation


app_dahdiscan.c File Reference

Zap Scanner. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/dahdi_compat.h"

Go to the source code of this file.

Defines

#define CONF_SIZE   160

Functions

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Scan Zap channels application")
static int careful_write (int fd, unsigned char *data, int len)
static int conf_exec (struct ast_channel *chan, void *data)
static int conf_exec_warn (struct ast_channel *chan, void *data)
static int conf_run (struct ast_channel *chan, int confno, int confflags)
static struct ast_channelget_zap_channel_locked (int num)
static int load_module (void)
static int unload_module (void)

Variables

static char * app = "DAHDIScan"
static char * deprecated_app = "ZapScan"
static char * descrip
static char * synopsis = "Scan Zap channels to monitor calls"


Detailed Description

Zap Scanner.

Author:
Mark Spencer <markster@digium.com>

Definition in file app_dahdiscan.c.


Define Documentation

#define CONF_SIZE   160

Definition at line 74 of file app_dahdiscan.c.


Function Documentation

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Scan Zap channels application"   
)

static int careful_write ( int  fd,
unsigned char *  data,
int  len 
) [static]

Definition at line 83 of file app_dahdiscan.c.

References ast_log(), errno, and LOG_WARNING.

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 }

static int conf_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 288 of file app_dahdiscan.c.

References ast_channel::_state, ast_answer(), ast_channel_walk_locked(), AST_DIGIT_ANY, AST_FRAME_DTMF, ast_frfree, ast_module_user_add, ast_module_user_remove, ast_mutex_unlock(), ast_read(), ast_say_number(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), conf_run(), f, get_zap_channel_locked(), input(), ast_channel::lock, pbx_builtin_getvar_helper(), ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_3.

Referenced by conf_exec_warn(), and load_module().

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 }

static int conf_exec_warn ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 365 of file app_dahdiscan.c.

References ast_log(), conf_exec(), and LOG_WARNING.

Referenced by load_module().

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 }

static int conf_run ( struct ast_channel chan,
int  confno,
int  confflags 
) [static]

Definition at line 101 of file app_dahdiscan.c.

References AST_FORMAT_ULAW, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, AST_FRIENDLY_OFFSET, ast_indicate(), ast_log(), ast_read(), ast_set_read_format(), ast_set_write_format(), ast_verbose(), ast_waitfor_nandfds(), ast_write(), careful_write(), CONF_SIZE, errno, f, ast_channel::fds, ast_frame::flags, input(), LOG_DEBUG, LOG_WARNING, ast_channel::tech, ast_channel_tech::type, and VERBOSE_PREFIX_3.

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("/dev/zap/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 }

static struct ast_channel* get_zap_channel_locked ( int  num  )  [static]

Definition at line 76 of file app_dahdiscan.c.

References ast_get_channel_by_name_locked(), dahdi_chan_name, and name.

Referenced by conf_exec().

00076                                                            {
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 }

static int load_module ( void   )  [static]

Definition at line 382 of file app_dahdiscan.c.

References ast_register_application(), conf_exec(), and conf_exec_warn().

static int unload_module ( void   )  [static]

Definition at line 371 of file app_dahdiscan.c.

References ast_module_user_hangup_all, and ast_unregister_application().

00372 {
00373    int res;
00374 
00375    res = ast_unregister_application(app);
00376    
00377    ast_module_user_hangup_all();
00378 
00379    return res;
00380 }


Variable Documentation

char* app = "DAHDIScan" [static]

Definition at line 63 of file app_dahdiscan.c.

char* deprecated_app = "ZapScan" [static]

Definition at line 64 of file app_dahdiscan.c.

char* descrip [static]

Initial value:

"  ZapScan([group]) allows a call center manager to monitor Zap channels in\n"
"a convenient way.  Use '#' to select the next channel and use '*' to exit\n"
"Limit scanning to a channel GROUP by setting the option group argument.\n"

Definition at line 68 of file app_dahdiscan.c.

char* synopsis = "Scan Zap channels to monitor calls" [static]

Definition at line 66 of file app_dahdiscan.c.


Generated on Mon Nov 24 15:34:22 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7