Mon Mar 20 08:20:17 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app_zapscan.c File Reference

Zap Scanner. More...

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel.h>
#include "asterisk.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"

Go to the source code of this file.

Defines

#define CONF_SIZE   160

Functions

int careful_write (int fd, unsigned char *data, int len)
int conf_exec (struct ast_channel *chan, void *data)
int conf_run (struct ast_channel *chan, int confno, int confflags)
char * description (void)
 Provides a description of the module.
ast_channelget_zap_channel_locked (int num)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

char * app = "ZapScan"
char * descrip
 LOCAL_USER_DECL
 STANDARD_LOCAL_USER
char * synopsis = "Scan Zap channels to monitor calls"
char * tdesc = "Scan Zap channels application"


Detailed Description

Zap Scanner.

Definition in file app_zapscan.c.


Define Documentation

#define CONF_SIZE   160
 

Definition at line 77 of file app_zapscan.c.


Function Documentation

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

Definition at line 86 of file app_zapscan.c.

References ast_log(), and LOG_WARNING.

Referenced by conf_play(), and conf_run().

00087 {
00088    int res;
00089    while(len) {
00090       res = write(fd, data, len);
00091       if (res < 1) {
00092          if (errno != EAGAIN) {
00093             ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
00094             return -1;
00095          } else
00096             return 0;
00097       }
00098       len -= res;
00099       data += res;
00100    }
00101    return 0;
00102 }

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

Definition at line 290 of file app_zapscan.c.

References ast_channel::_state, ast_answer(), ast_channel_walk_locked(), AST_DIGIT_ANY, ast_frfree(), ast_mutex_unlock(), ast_read(), ast_say_number(), ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), conf_run(), ast_frame::frametype, get_zap_channel_locked(), ast_channel::language, LOCAL_USER_ADD, LOCAL_USER_REMOVE, ast_channel::lock, ast_channel::name, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::type, and VERBOSE_PREFIX_3.

Referenced by load_module().

00291 {
00292    int res=-1;
00293    struct localuser *u;
00294    int confflags = 0;
00295    int confno = 0;
00296    char confstr[80] = "", *tmp = NULL;
00297    struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
00298    struct ast_frame *f;
00299    char *mygroup;
00300    char *desired_group;
00301    int input=0,search_group=0;
00302    
00303    LOCAL_USER_ADD(u);
00304    
00305    if (chan->_state != AST_STATE_UP)
00306       ast_answer(chan);
00307    
00308    desired_group = ast_strdupa((char *) data);
00309    if(!ast_strlen_zero(desired_group)) {
00310       ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
00311       search_group = 1;
00312    }
00313 
00314    for (;;) {
00315       if (ast_waitfor(chan, 100) < 0)
00316          break;
00317       
00318       f = ast_read(chan);
00319       if (!f)
00320          break;
00321       if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
00322          ast_frfree(f);
00323          break;
00324       }
00325       ast_frfree(f);
00326       ichan = NULL;
00327       if(input) {
00328          ichan = get_zap_channel_locked(input);
00329          input = 0;
00330       }
00331       
00332       tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
00333       
00334       if ( !tempchan && !lastchan )
00335          break;
00336       
00337       if (tempchan && search_group) {
00338          if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
00339             ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
00340          } else {
00341             ast_mutex_unlock(&tempchan->lock);
00342             lastchan = tempchan;
00343             continue;
00344          }
00345       }
00346       if ( tempchan && tempchan->type && (!strcmp(tempchan->type, "Zap")) && (tempchan != chan) ) {
00347          ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
00348          ast_copy_string(confstr, tempchan->name, sizeof(confstr));
00349          ast_mutex_unlock(&tempchan->lock);
00350          if ((tmp = strchr(confstr,'-'))) {
00351             *tmp = '\0';
00352          }
00353          confno = atoi(strchr(confstr,'/') + 1);
00354          ast_stopstream(chan);
00355          ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
00356          res = conf_run(chan, confno, confflags);
00357          if (res<0) break;
00358          input = res;
00359       } else if (tempchan)
00360          ast_mutex_unlock(&tempchan->lock);
00361       lastchan = tempchan;
00362    }
00363    LOCAL_USER_REMOVE(u);
00364    return res;
00365 }

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

Definition at line 104 of file app_zapscan.c.

References AST_FORMAT_ULAW, ast_frfree(), 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, ast_frame::data, ast_frame::datalen, ast_channel::fds, ast_frame::frametype, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_frame::offset, ast_frame::samples, ast_frame::subclass, ast_channel::type, and VERBOSE_PREFIX_3.

Referenced by conf_exec().

00105 {
00106    int fd;
00107    struct zt_confinfo ztc;
00108    struct ast_frame *f;
00109    struct ast_channel *c;
00110    struct ast_frame fr;
00111    int outfd;
00112    int ms;
00113    int nfds;
00114    int res;
00115    int flags;
00116    int retryzap;
00117    int origfd;
00118    int ret = -1;
00119    char input[4];
00120    int ic=0;
00121    
00122    ZT_BUFFERINFO bi;
00123    char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
00124    char *buf = __buf + AST_FRIENDLY_OFFSET;
00125    
00126    /* Set it into U-law mode (write) */
00127    if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
00128       ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
00129       goto outrun;
00130    }
00131    
00132    /* Set it into U-law mode (read) */
00133    if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
00134       ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
00135       goto outrun;
00136    }
00137    ast_indicate(chan, -1);
00138    retryzap = strcasecmp(chan->type, "Zap");
00139  zapretry:
00140    origfd = chan->fds[0];
00141    if (retryzap) {
00142       fd = open("/dev/zap/pseudo", O_RDWR);
00143       if (fd < 0) {
00144          ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
00145          goto outrun;
00146       }
00147       /* Make non-blocking */
00148       flags = fcntl(fd, F_GETFL);
00149       if (flags < 0) {
00150          ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
00151          close(fd);
00152                         goto outrun;
00153       }
00154       if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
00155          ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
00156          close(fd);
00157          goto outrun;
00158       }
00159       /* Setup buffering information */
00160       memset(&bi, 0, sizeof(bi));
00161       bi.bufsize = CONF_SIZE;
00162       bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
00163       bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
00164       bi.numbufs = 4;
00165       if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
00166          ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
00167          close(fd);
00168          goto outrun;
00169       }
00170                 nfds = 1;
00171    } else {
00172       /* XXX Make sure we're not running on a pseudo channel XXX */
00173       fd = chan->fds[0];
00174       nfds = 0;
00175    }
00176    memset(&ztc, 0, sizeof(ztc));
00177    /* Check to see if we're in a conference... */
00178         ztc.chan = 0;
00179         if (ioctl(fd, ZT_GETCONF, &ztc)) {
00180          ast_log(LOG_WARNING, "Error getting conference\n");
00181          close(fd);
00182          goto outrun;
00183         }
00184         if (ztc.confmode) {
00185          /* Whoa, already in a conference...  Retry... */
00186          if (!retryzap) {
00187             ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
00188             retryzap = 1;
00189             goto zapretry;
00190          }
00191         }
00192         memset(&ztc, 0, sizeof(ztc));
00193         /* Add us to the conference */
00194         ztc.chan = 0;
00195         ztc.confno = confno;
00196         ztc.confmode = ZT_CONF_MONITORBOTH;
00197       
00198         if (ioctl(fd, ZT_SETCONF, &ztc)) {
00199                 ast_log(LOG_WARNING, "Error setting conference\n");
00200                 close(fd);
00201                 goto outrun;
00202         }
00203         ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
00204       
00205         for(;;) {
00206          outfd = -1;
00207          ms = -1;
00208          c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
00209          if (c) {
00210             if (c->fds[0] != origfd) {
00211                if (retryzap) {
00212                   /* Kill old pseudo */
00213                   close(fd);
00214                }
00215                ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
00216                retryzap = 0;
00217                                 goto zapretry;
00218             }
00219             f = ast_read(c);
00220             if (!f)
00221                break;
00222             if(f->frametype == AST_FRAME_DTMF) {
00223                if(f->subclass == '#') {
00224                   ret = 0;
00225                   break;
00226                }
00227                else if (f->subclass == '*') {
00228                   ret = -1;
00229                   break;
00230                   
00231                }
00232                else {
00233                   input[ic++] = f->subclass;
00234                }
00235                if(ic == 3) {
00236                   input[ic++] = '\0';
00237                   ic=0;
00238                   ret = atoi(input);
00239                   ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret);
00240                   break;
00241                }
00242             }
00243             
00244             if (fd != chan->fds[0]) {
00245                if (f->frametype == AST_FRAME_VOICE) {
00246                   if (f->subclass == AST_FORMAT_ULAW) {
00247                      /* Carefully write */
00248                                                 careful_write(fd, f->data, f->datalen);
00249                   } else
00250                      ast_log(LOG_WARNING, "Huh?  Got a non-ulaw (%d) frame in the conference\n", f->subclass);
00251                }
00252             }
00253             ast_frfree(f);
00254          } else if (outfd > -1) {
00255             res = read(outfd, buf, CONF_SIZE);
00256             if (res > 0) {
00257                memset(&fr, 0, sizeof(fr));
00258                fr.frametype = AST_FRAME_VOICE;
00259                fr.subclass = AST_FORMAT_ULAW;
00260                fr.datalen = res;
00261                fr.samples = res;
00262                fr.data = buf;
00263                fr.offset = AST_FRIENDLY_OFFSET;
00264                if (ast_write(chan, &fr) < 0) {
00265                   ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
00266                   /* break; */
00267                }
00268             } else
00269                ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
00270          }
00271         }
00272         if (fd != chan->fds[0])
00273          close(fd);
00274         else {
00275          /* Take out of conference */
00276          /* Add us to the conference */
00277          ztc.chan = 0;
00278          ztc.confno = 0;
00279          ztc.confmode = 0;
00280          if (ioctl(fd, ZT_SETCONF, &ztc)) {
00281             ast_log(LOG_WARNING, "Error setting conference\n");
00282                 }
00283         }
00284       
00285  outrun:
00286       
00287         return ret;
00288 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 383 of file app_zapscan.c.

00384 {
00385    return tdesc;
00386 }

struct ast_channel* get_zap_channel_locked int  num  )  [static]
 

Definition at line 79 of file app_zapscan.c.

References ast_get_channel_by_name_locked(), and name.

Referenced by conf_exec().

00079                                                            {
00080    char name[80];
00081    
00082    snprintf(name,sizeof(name),"Zap/%d-1",num);
00083    return ast_get_channel_by_name_locked(name);
00084 }

char* key void   ) 
 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 395 of file app_zapscan.c.

00396 {
00397    return ASTERISK_GPL_KEY;
00398 }

int load_module void   ) 
 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 378 of file app_zapscan.c.

References app, ast_register_application(), conf_exec(), descrip, and synopsis.

00379 {
00380    return ast_register_application(app, conf_exec, synopsis, descrip);
00381 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 367 of file app_zapscan.c.

References app, and ast_unregister_application().

00368 {
00369    int res;
00370 
00371    res = ast_unregister_application(app);
00372    
00373    STANDARD_HANGUP_LOCALUSERS;
00374 
00375    return res;
00376 }

int usecount void   ) 
 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 388 of file app_zapscan.c.

References STANDARD_USECOUNT.

00389 {
00390    int res;
00391    STANDARD_USECOUNT(res);
00392    return res;
00393 }


Variable Documentation

char* app = "ZapScan" [static]
 

Definition at line 63 of file app_zapscan.c.

Referenced by load_module(), and unload_module().

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 67 of file app_zapscan.c.

Referenced by load_module().

LOCAL_USER_DECL
 

Definition at line 74 of file app_zapscan.c.

STANDARD_LOCAL_USER
 

Definition at line 72 of file app_zapscan.c.

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

Definition at line 65 of file app_zapscan.c.

Referenced by load_module().

char* tdesc = "Scan Zap channels application" [static]
 

Definition at line 61 of file app_zapscan.c.


Generated on Mon Mar 20 08:20:17 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1