Sat Aug 6 00:39:34 2011

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

static void __reg_module (void)
static void __unreg_module (void)
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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Scan Zap channels application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, }
static char * app = "DAHDIScan"
static const struct ast_module_infoast_module_info = &__mod_info
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

static void __reg_module ( void   )  [static]

Definition at line 388 of file app_dahdiscan.c.

static void __unreg_module ( void   )  [static]

Definition at line 388 of file app_dahdiscan.c.

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_copy_string(), 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, ast_channel::name, 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, DAHDI_FILE_PSEUDO, errno, f, ast_channel::fds, ast_frame::flags, input(), LOG_DEBUG, LOG_WARNING, ast_channel::name, 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(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 }

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

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Scan Zap channels application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 388 of file app_dahdiscan.c.

char* app = "DAHDIScan" [static]

Definition at line 63 of file app_dahdiscan.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 388 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 Sat Aug 6 00:39:34 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7