Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:20 2009

## Asterisk developer's documentation

# 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"`

Include dependency graph for app_zapscan.c:

Go to the source code of this file.

## Defines

#define | CONF_SIZE 160

## Functions

static int | careful_write (int fd, unsigned char *data, int len)
static int | conf_exec (struct ast_channel *chan, void *data)
static int | conf_run (struct ast_channel *chan, int confno, int confflags)
char * | description (void)
| Provides a description of the module.
static struct ast_channel * | get_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

static char * | app = "ZapScan"
static char * | descrip
| LOCAL_USER_DECL
| STANDARD_LOCAL_USER
static char * | synopsis = "Scan Zap channels to monitor calls"
static 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

static 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.

    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 }

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

Definition at line 292 of file app_zapscan.c.

References ast_channel::_state, ast_answer(), ast_channel_walk_locked(), AST_DIGIT_ANY, AST_FRAME_DTMF, ast_frfree(), ast_mutex_unlock(), ast_read(), ast_say_number(), AST_STATE_UP, ast_stopstream(), ast_strdupa, ast_strlen_zero(), ast_verbose(), ast_waitfor(), conf_run(), ast_frame::frametype, get_zap_channel_locked(), input(), 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.

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

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

    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 (f)
    00273       ast_frfree(f);
    00274         if (fd != chan->fds[0])
    00275          close(fd);
    00276         else {
    00277          /* Take out of conference */
    00278          /* Add us to the conference */
    00279          ztc.chan = 0;
    00280          ztc.confno = 0;
    00281          ztc.confmode = 0;
    00282          if (ioctl(fd, ZT_SETCONF, &ztc)) {
    00283             ast_log(LOG_WARNING, "Error setting conference\n");
    00284                 }
    00285         }
    00286
    00287  outrun:
    00288
    00289         return ret;
    00290 }

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 385 of file app_zapscan.c.

    00386 {
    00387    return tdesc;
    00388 }

static struct ast_channel* get_zap_channel_locked | ( | int | num | ) | `[static, read]`

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

References ASTERISK_GPL_KEY.

    00398 {
    00399    return ASTERISK_GPL_KEY;
    00400 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

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.

TE STUFF END

Definition at line 380 of file app_zapscan.c.

References ast_register_application(), and conf_exec().

    00381 {
    00382    return ast_register_application(app, conf_exec, synopsis, descrip);
    00383 }

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

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

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

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

References STANDARD_USECOUNT.

    00391 {
    00392    int res;
    00393    STANDARD_USECOUNT(res);
    00394    return res;
    00395 }

## Variable Documentation

char* app = "ZapScan"`[static]`

Definition at line 63 of file app_zapscan.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 67 of file app_zapscan.c.

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.

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

Definition at line 61 of file app_zapscan.c.