Sat Apr 12 07:12:29 2008

Asterisk developer's documentation


app_chanspy.c File Reference

ChanSpy: Listen in on any channel. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/chanspy.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"

Include dependency graph for app_chanspy.c:

Go to the source code of this file.

Data Structures

struct  chanspy_translation_helper

Defines

#define AST_NAME_STRLEN   256

Enumerations

enum  {
  OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3),
  OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6)
}
enum  { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ARRAY_SIZE }

Functions

 AST_APP_OPTIONS (spy_opts,{AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('b', OPTION_BRIDGED), AST_APP_OPTION('w', OPTION_WHISPER), AST_APP_OPTION('W', OPTION_PRIVATE), AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),})
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Listen to the audio of an active channel")
static int channel_spy (struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd, const struct ast_flags *flags)
static int chanspy_exec (struct ast_channel *chan, void *data)
static int chanspychan_exec (struct ast_channel *chan, void *data)
static int common_exec (struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context, const char *uniqueid)
static int extenspy_exec (struct ast_channel *chan, void *data)
static int load_module (void)
static struct ast_channelnext_channel (const struct ast_channel *last, const char *spec, const char *exten, const char *context, const char *uniqueid)
static void set_volume (struct ast_channel *chan, struct chanspy_translation_helper *csth)
static void * spy_alloc (struct ast_channel *chan, void *data)
static int spy_generate (struct ast_channel *chan, void *data, int len, int samples)
static void spy_release (struct ast_channel *chan, void *data)
static int start_spying (struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy)
static int unload_module (void)

Variables

static const char * app_chan = "ChanSpy"
static const char * app_chan2 = "ChanSpyChan"
static const char * app_ext = "ExtenSpy"
enum { ... }  chanspy_opt_args
enum { ... }  chanspy_opt_flags
static const char * desc_chan
static const char * desc_ext
static const char * desc_uniqueid
static struct ast_generator spygen
static const char * tdesc = "Listen to a channel, and optionally whisper into it"
static signed char volfactor_map []


Detailed Description

ChanSpy: Listen in on any channel.

Author:
Anthony Minessale II <anthmct@yahoo.com>

Definition in file app_chanspy.c.


Define Documentation

#define AST_NAME_STRLEN   256

Definition at line 54 of file app_chanspy.c.

Referenced by common_exec().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPTION_QUIET 
OPTION_BRIDGED 
OPTION_VOLUME 
OPTION_GROUP 
OPTION_RECORD 
OPTION_WHISPER 
OPTION_PRIVATE 

Definition at line 138 of file app_chanspy.c.

00138      {
00139    OPTION_QUIET    = (1 << 0),   /* Quiet, no announcement */
00140    OPTION_BRIDGED   = (1 << 1),  /* Only look at bridged calls */
00141    OPTION_VOLUME    = (1 << 2),  /* Specify initial volume */
00142    OPTION_GROUP     = (1 << 3),  /* Only look at channels in group */
00143    OPTION_RECORD    = (1 << 4),
00144    OPTION_WHISPER  = (1 << 5),
00145    OPTION_PRIVATE   = (1 << 6),  /* Private Whisper mode */
00146 } chanspy_opt_flags;

anonymous enum

Enumerator:
OPT_ARG_VOLUME 
OPT_ARG_GROUP 
OPT_ARG_RECORD 
OPT_ARG_ARRAY_SIZE 

Definition at line 148 of file app_chanspy.c.

00148      {
00149    OPT_ARG_VOLUME = 0,
00150    OPT_ARG_GROUP,
00151    OPT_ARG_RECORD,
00152    OPT_ARG_ARRAY_SIZE,
00153 } chanspy_opt_args;


Function Documentation

AST_APP_OPTIONS ( spy_opts   ) 

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Listen to the audio of an active channel"   
)

static int channel_spy ( struct ast_channel chan,
struct ast_channel spyee,
int *  volfactor,
int  fd,
const struct ast_flags flags 
) [static]

Definition at line 265 of file app_chanspy.c.

References ast_activate_generator(), ast_channel_lock, ast_channel_spy_free(), ast_channel_spy_remove(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_channel_whisper_feed(), ast_channel_whisper_start(), ast_channel_whisper_stop(), ast_check_hangup(), ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_mutex_destroy(), ast_mutex_init(), ast_openstream_full(), ast_read(), ast_readframe(), ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor(), ast_channel_spy::chan, CHANSPY_DONE, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_RUNNING, CHANSPY_TRIGGER_NONE, CHANSPY_WRITE_VOLADJUST, f, chanspy_translation_helper::fd, ast_channel_spy_queue::format, ast_frame::frametype, ast_channel_spy::lock, name, OPTION_PRIVATE, option_verbose, OPTION_WHISPER, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, set_volume(), chanspy_translation_helper::spy, start_spying(), ast_channel_spy::status, ast_channel::stream, ast_frame::subclass, ast_channel_spy::type, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, chanspy_translation_helper::volfactor, ast_channel_spy::write_queue, ast_channel_spy::write_vol_adjustment, and ast_channel::writeformat.

Referenced by common_exec().

00267 {
00268    struct chanspy_translation_helper csth;
00269    int running = 0, res, x = 0;
00270    char inp[24] = {0};
00271    char *name;
00272    struct ast_frame *f;
00273    struct ast_silence_generator *silgen = NULL;
00274 
00275    if (ast_check_hangup(chan) || ast_check_hangup(spyee))
00276       return 0;
00277 
00278    name = ast_strdupa(spyee->name);
00279    if (option_verbose >= 2)
00280       ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00281 
00282    memset(&csth, 0, sizeof(csth));
00283    ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
00284    ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
00285    ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
00286    csth.spy.type = "ChanSpy";
00287    csth.spy.status = CHANSPY_RUNNING;
00288    csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
00289    csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
00290    ast_mutex_init(&csth.spy.lock);
00291    csth.volfactor = *volfactor;
00292    set_volume(chan, &csth);
00293    if (csth.volfactor) {
00294       ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00295       csth.spy.read_vol_adjustment = csth.volfactor;
00296       ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00297       csth.spy.write_vol_adjustment = csth.volfactor;
00298    }
00299    csth.fd = fd;
00300    
00301    if (start_spying(spyee, chan, &csth.spy)) {
00302       ast_mutex_destroy(&csth.spy.lock);
00303       return 0;
00304    }
00305 
00306    if (ast_test_flag(flags, OPTION_WHISPER)) {
00307       struct ast_filestream *beepstream;
00308       int old_write_format = 0;
00309 
00310       ast_channel_whisper_start(csth.spy.chan);
00311       old_write_format = chan->writeformat;
00312       if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
00313          struct ast_frame *f;
00314 
00315          while ((f = ast_readframe(beepstream))) {
00316             ast_channel_whisper_feed(csth.spy.chan, f);
00317             ast_frfree(f);
00318          }
00319 
00320          ast_closestream(beepstream);
00321          chan->stream = NULL;
00322       }
00323       if (old_write_format)
00324          ast_set_write_format(chan, old_write_format);
00325    }
00326 
00327    if (ast_test_flag(flags, OPTION_PRIVATE))
00328       silgen = ast_channel_start_silence_generator(chan);
00329    else
00330       ast_activate_generator(chan, &spygen, &csth);
00331 
00332    /* We can no longer rely on 'spyee' being an actual channel;
00333       it can be hung up and freed out from under us. However, the
00334       channel destructor will put NULL into our csth.spy.chan
00335       field when that happens, so that is our signal that the spyee
00336       channel has gone away.
00337    */
00338 
00339    /* Note: it is very important that the ast_waitfor() be the first
00340       condition in this expression, so that if we wait for some period
00341       of time before receiving a frame from our spying channel, we check
00342       for hangup on the spied-on channel _after_ knowing that a frame
00343       has arrived, since the spied-on channel could have gone away while
00344       we were waiting
00345    */
00346    while ((res = ast_waitfor(chan, -1) > -1) &&
00347           csth.spy.status == CHANSPY_RUNNING &&
00348           csth.spy.chan) {
00349       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00350          running = -1;
00351          break;
00352       }
00353 
00354       if (ast_test_flag(flags, OPTION_WHISPER) &&
00355           (f->frametype == AST_FRAME_VOICE)) {
00356          ast_channel_whisper_feed(csth.spy.chan, f);
00357          ast_frfree(f);
00358          continue;
00359       }
00360 
00361       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00362       ast_frfree(f);
00363       if (!res)
00364          continue;
00365 
00366       if (x == sizeof(inp))
00367          x = 0;
00368 
00369       if (res < 0) {
00370          running = -1;
00371          break;
00372       }
00373 
00374       if (res == '*') {
00375          running = 0;
00376          break;
00377       } else if (res == '#') {
00378          if (!ast_strlen_zero(inp)) {
00379             running = atoi(inp);
00380             break;
00381          }
00382 
00383          (*volfactor)++;
00384          if (*volfactor > 4)
00385             *volfactor = -4;
00386          if (option_verbose > 2)
00387             ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00388          csth.volfactor = *volfactor;
00389          set_volume(chan, &csth);
00390          if (csth.volfactor) {
00391             ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00392             csth.spy.read_vol_adjustment = csth.volfactor;
00393             ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00394             csth.spy.write_vol_adjustment = csth.volfactor;
00395          } else {
00396             ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00397             ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00398          }
00399       } else if (res >= '0' && res <= '9') {
00400          inp[x++] = res;
00401       }
00402    }
00403 
00404    if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
00405       ast_channel_whisper_stop(csth.spy.chan);
00406 
00407    if (ast_test_flag(flags, OPTION_PRIVATE))
00408       ast_channel_stop_silence_generator(chan, silgen);
00409    else
00410       ast_deactivate_generator(chan);
00411 
00412    csth.spy.status = CHANSPY_DONE;
00413 
00414    /* If a channel still exists on our spy structure then we need to remove ourselves */
00415    if (csth.spy.chan) {
00416       ast_channel_lock(csth.spy.chan);
00417       ast_channel_spy_remove(csth.spy.chan, &csth.spy);
00418       ast_channel_unlock(csth.spy.chan);
00419    }
00420    ast_channel_spy_free(&csth.spy);
00421    
00422    if (option_verbose >= 2)
00423       ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00424    
00425    return running;
00426 }

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

Definition at line 582 of file app_chanspy.c.

References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, and ast_channel::writeformat.

Referenced by load_module().

00583 {
00584    struct ast_module_user *u;
00585    char *options = NULL;
00586    char *spec = NULL;
00587    char *argv[2];
00588    char *mygroup = NULL;
00589    char *recbase = NULL;
00590    int fd = 0;
00591    struct ast_flags flags;
00592    int oldwf = 0;
00593    int argc = 0;
00594    int volfactor = 0;
00595    int res;
00596 
00597    data = ast_strdupa(data);
00598 
00599    u = ast_module_user_add(chan);
00600 
00601    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00602       spec = argv[0];
00603       if (argc > 1)
00604          options = argv[1];
00605 
00606       if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00607          spec = NULL;
00608    }
00609 
00610    if (options) {
00611       char *opts[OPT_ARG_ARRAY_SIZE];
00612       
00613       ast_app_parse_options(spy_opts, &flags, opts, options);
00614       if (ast_test_flag(&flags, OPTION_GROUP))
00615          mygroup = opts[OPT_ARG_GROUP];
00616 
00617       if (ast_test_flag(&flags, OPTION_RECORD) &&
00618           !(recbase = opts[OPT_ARG_RECORD]))
00619          recbase = "chanspy";
00620 
00621       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00622          int vol;
00623 
00624          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00625             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00626          else
00627             volfactor = vol;
00628       }
00629 
00630       if (ast_test_flag(&flags, OPTION_PRIVATE))
00631          ast_set_flag(&flags, OPTION_WHISPER);
00632    } else
00633       ast_clear_flag(&flags, AST_FLAGS_ALL);
00634 
00635    oldwf = chan->writeformat;
00636    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00637       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00638       ast_module_user_remove(u);
00639       return -1;
00640    }
00641 
00642    if (recbase) {
00643       char filename[512];
00644 
00645       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00646       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00647          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00648          fd = 0;
00649       }
00650    }
00651 
00652    res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL, NULL);
00653 
00654    if (fd)
00655       close(fd);
00656 
00657    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00658       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00659 
00660    ast_module_user_remove(u);
00661 
00662    return res;
00663 }

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

Definition at line 750 of file app_chanspy.c.

References ast_app_parse_options(), ast_app_separate_args(), ast_config_AST_MONITOR_DIR, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, and ast_channel::writeformat.

Referenced by load_module().

00751 {
00752    struct ast_module_user *u;
00753    char *options = NULL;
00754    char *uniqueid = NULL;
00755    char *argv[2];
00756    char *mygroup = NULL;
00757    char *recbase = NULL;
00758    int fd = 0;
00759    struct ast_flags flags;
00760    int oldwf = 0;
00761    int argc = 0;
00762    int volfactor = 0;
00763    int res;
00764 
00765    data = ast_strdupa(data);
00766 
00767    u = ast_module_user_add(chan);
00768 
00769    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00770       uniqueid = argv[0];
00771       if (argc > 1)
00772          options = argv[1];
00773 
00774       if (ast_strlen_zero(uniqueid)) {
00775          ast_log(LOG_ERROR, "no uniqueid specified.\n");
00776          ast_module_user_remove(u);
00777          return -1;
00778       }
00779    }
00780 
00781    if (options) {
00782       char *opts[OPT_ARG_ARRAY_SIZE];
00783       
00784       ast_app_parse_options(spy_opts, &flags, opts, options);
00785       if (ast_test_flag(&flags, OPTION_GROUP))
00786          mygroup = opts[OPT_ARG_GROUP];
00787 
00788       if (ast_test_flag(&flags, OPTION_RECORD) &&
00789           !(recbase = opts[OPT_ARG_RECORD]))
00790          recbase = "chanspy";
00791 
00792       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00793          int vol;
00794 
00795          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00796             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00797          else
00798             volfactor = vol;
00799       }
00800 
00801       if (ast_test_flag(&flags, OPTION_PRIVATE))
00802          ast_set_flag(&flags, OPTION_WHISPER);
00803    }
00804 
00805    oldwf = chan->writeformat;
00806    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00807       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00808       ast_module_user_remove(u);
00809       return -1;
00810    }
00811 
00812    if (recbase) {
00813       char filename[512];
00814 
00815       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00816       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00817          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00818          fd = 0;
00819       }
00820    }
00821 
00822    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, NULL, uniqueid);
00823 
00824    if (fd)
00825       close(fd);
00826 
00827    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00828       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00829 
00830    ast_module_user_remove(u);
00831 
00832    return res;
00833 }

static int common_exec ( struct ast_channel chan,
const struct ast_flags flags,
int  volfactor,
const int  fd,
const char *  mygroup,
const char *  spec,
const char *  exten,
const char *  context,
const char *  uniqueid 
) [static]

Definition at line 452 of file app_chanspy.c.

References ast_channel::_state, ast_answer(), ast_app_separate_args(), ast_bridged_channel(), ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_fileexists(), AST_FLAG_SPYING, ast_get_channel_by_name_prefix_locked(), AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), group, next_channel(), OPTION_BRIDGED, OPTION_QUIET, pbx_builtin_getvar_helper(), and s.

Referenced by chanspy_exec(), chanspychan_exec(), and extenspy_exec().

00455 {
00456    struct ast_channel *peer, *prev, *next;
00457    char nameprefix[AST_NAME_STRLEN];
00458    char peer_name[AST_NAME_STRLEN + 5];
00459    signed char zero_volume = 0;
00460    int waitms;
00461    int res;
00462    char *ptr;
00463    int num;
00464 
00465    if (chan->_state != AST_STATE_UP)
00466       ast_answer(chan);
00467 
00468    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00469 
00470    waitms = 100;
00471 
00472    for (;;) {
00473       if (!ast_test_flag(flags, OPTION_QUIET)) {
00474          res = ast_streamfile(chan, "beep", chan->language);
00475          if (!res)
00476             res = ast_waitstream(chan, "");
00477          else if (res < 0) {
00478             ast_clear_flag(chan, AST_FLAG_SPYING);
00479             break;
00480          }
00481       }
00482 
00483       res = ast_waitfordigit(chan, waitms);
00484       if (res < 0) {
00485          ast_clear_flag(chan, AST_FLAG_SPYING);
00486          break;
00487       }
00488             
00489       /* reset for the next loop around, unless overridden later */
00490       waitms = 100;
00491       peer = prev = next = NULL;
00492 
00493       for (peer = next_channel(peer, spec, exten, context, NULL);
00494            peer;
00495            prev = peer, peer = next ? next : next_channel(peer, spec, exten, context, NULL), next = NULL) {
00496          const char *group;
00497          int igrp = !mygroup;
00498          char *groups[25];
00499          int num_groups = 0;
00500          char *dup_group;
00501          int x;
00502          char *s;
00503             
00504          if (peer == prev)
00505             break;
00506 
00507          if (peer == chan)
00508             continue;
00509 
00510          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
00511             continue;
00512 
00513          if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
00514             continue;
00515 
00516          if (mygroup) {
00517             if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00518                dup_group = ast_strdupa(group);
00519                num_groups = ast_app_separate_args(dup_group, ':', groups,
00520                               sizeof(groups) / sizeof(groups[0]));
00521             }
00522             
00523             for (x = 0; x < num_groups; x++) {
00524                if (!strcmp(mygroup, groups[x])) {
00525                   igrp = 1;
00526                   break;
00527                }
00528             }
00529          }
00530          
00531          if (!igrp)
00532             continue;
00533 
00534          strcpy(peer_name, "spy-");
00535          strncat(peer_name, peer->name, AST_NAME_STRLEN);
00536          ptr = strchr(peer_name, '/');
00537          *ptr++ = '\0';
00538          
00539          for (s = peer_name; s < ptr; s++)
00540             *s = tolower(*s);
00541          
00542          if (!ast_test_flag(flags, OPTION_QUIET)) {
00543             if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00544                res = ast_streamfile(chan, peer_name, chan->language);
00545                if (!res)
00546                   res = ast_waitstream(chan, "");
00547                if (res)
00548                   break;
00549             } else
00550                res = ast_say_character_str(chan, peer_name, "", chan->language);
00551             if ((num = atoi(ptr))) 
00552                ast_say_digits(chan, atoi(ptr), "", chan->language);
00553          }
00554          
00555          waitms = 5000;
00556          res = channel_spy(chan, peer, &volfactor, fd, flags);
00557          
00558          if (res == -1) {
00559             break;
00560          } else if (res > 1 && spec) {
00561             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00562             if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00563                ast_channel_unlock(next);
00564             } else {
00565                /* stay on this channel */
00566                next = peer;
00567             }
00568             peer = NULL;
00569          }
00570       }
00571       if (res == -1)
00572          break;
00573    }
00574    
00575    ast_clear_flag(chan, AST_FLAG_SPYING);
00576 
00577    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00578 
00579    return res;
00580 }

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

Definition at line 665 of file app_chanspy.c.

References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_channel::context, context, exten, LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, strsep(), and ast_channel::writeformat.

Referenced by load_module().

00666 {
00667    struct ast_module_user *u;
00668    char *options = NULL;
00669    char *exten = NULL;
00670    char *context = NULL;
00671    char *argv[2];
00672    char *mygroup = NULL;
00673    char *recbase = NULL;
00674    int fd = 0;
00675    struct ast_flags flags;
00676    int oldwf = 0;
00677    int argc = 0;
00678    int volfactor = 0;
00679    int res;
00680 
00681    data = ast_strdupa(data);
00682 
00683    u = ast_module_user_add(chan);
00684 
00685    if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00686       context = argv[0];
00687       if (!ast_strlen_zero(argv[0]))
00688          exten = strsep(&context, "@");
00689       if (ast_strlen_zero(context))
00690          context = ast_strdupa(chan->context);
00691       if (argc > 1)
00692          options = argv[1];
00693    }
00694 
00695    if (options) {
00696       char *opts[OPT_ARG_ARRAY_SIZE];
00697       
00698       ast_app_parse_options(spy_opts, &flags, opts, options);
00699       if (ast_test_flag(&flags, OPTION_GROUP))
00700          mygroup = opts[OPT_ARG_GROUP];
00701 
00702       if (ast_test_flag(&flags, OPTION_RECORD) &&
00703           !(recbase = opts[OPT_ARG_RECORD]))
00704          recbase = "chanspy";
00705 
00706       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00707          int vol;
00708 
00709          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00710             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00711          else
00712             volfactor = vol;
00713       }
00714 
00715       if (ast_test_flag(&flags, OPTION_PRIVATE))
00716          ast_set_flag(&flags, OPTION_WHISPER);
00717    } else
00718       ast_clear_flag(&flags, AST_FLAGS_ALL);
00719 
00720    oldwf = chan->writeformat;
00721    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00722       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00723       ast_module_user_remove(u);
00724       return -1;
00725    }
00726 
00727    if (recbase) {
00728       char filename[512];
00729 
00730       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00731       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00732          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00733          fd = 0;
00734       }
00735    }
00736 
00737    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context, NULL);
00738 
00739    if (fd)
00740       close(fd);
00741 
00742    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00743       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00744 
00745    ast_module_user_remove(u);
00746 
00747    return res;
00748 }

static int load_module ( void   )  [static]

Definition at line 848 of file app_chanspy.c.

References ast_register_application(), chanspy_exec(), chanspychan_exec(), and extenspy_exec().

00849 {
00850    int res = 0;
00851 
00852    res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00853    res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00854    res |= ast_register_application(app_chan2, chanspychan_exec, tdesc, desc_uniqueid);
00855 
00856    return res;
00857 }

static struct ast_channel* next_channel ( const struct ast_channel last,
const char *  spec,
const char *  exten,
const char *  context,
const char *  uniqueid 
) [static, read]

Definition at line 428 of file app_chanspy.c.

References ast_channel_unlock, ast_channel_walk_locked(), ast_get_channel_by_uniqueid_locked(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), and name.

Referenced by common_exec().

00430 {
00431    struct ast_channel *this;
00432 
00433    redo:
00434    if (spec)
00435       this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00436    else if (exten)
00437       this = ast_walk_channel_by_exten_locked(last, exten, context);
00438    else if (uniqueid)
00439       this = ast_get_channel_by_uniqueid_locked(uniqueid);
00440    else
00441       this = ast_channel_walk_locked(last);
00442 
00443    if (this) {
00444       ast_channel_unlock(this);
00445       if (!strncmp(this->name, "Zap/pseudo", 10))
00446          goto redo;
00447    }
00448 
00449    return this;
00450 }

static void set_volume ( struct ast_channel chan,
struct chanspy_translation_helper csth 
) [static]

Definition at line 255 of file app_chanspy.c.

References ast_channel_setoption(), AST_OPTION_TXGAIN, ast_channel_spy::read_vol_adjustment, chanspy_translation_helper::spy, chanspy_translation_helper::volfactor, and ast_channel_spy::write_vol_adjustment.

Referenced by channel_spy().

00256 {
00257    signed char volume_adjust = volfactor_map[csth->volfactor + 4];
00258 
00259    if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
00260       csth->volfactor = 0;
00261    csth->spy.read_vol_adjustment = csth->volfactor;
00262    csth->spy.write_vol_adjustment = csth->volfactor;
00263 }

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

Definition at line 173 of file app_chanspy.c.

00174 {
00175    /* just store the data pointer in the channel structure */
00176    return data;
00177 }

static int spy_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
) [static]

Definition at line 184 of file app_chanspy.c.

References ast_channel_spy_read_frame(), ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_write(), CHANSPY_RUNNING, ast_frame::data, ast_frame::datalen, f, chanspy_translation_helper::fd, ast_channel_spy::lock, chanspy_translation_helper::spy, and ast_channel_spy::status.

00185 {
00186    struct chanspy_translation_helper *csth = data;
00187    struct ast_frame *f;
00188       
00189    if (csth->spy.status != CHANSPY_RUNNING)
00190       /* Channel is already gone more than likely */
00191       return -1;
00192 
00193    ast_mutex_lock(&csth->spy.lock);
00194    f = ast_channel_spy_read_frame(&csth->spy, samples);
00195    ast_mutex_unlock(&csth->spy.lock);
00196       
00197    if (!f)
00198       return 0;
00199       
00200    if (ast_write(chan, f)) {
00201       ast_frfree(f);
00202       return -1;
00203    }
00204 
00205    if (csth->fd)
00206       write(csth->fd, f->data, f->datalen);
00207 
00208    ast_frfree(f);
00209 
00210    return 0;
00211 }

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

Definition at line 179 of file app_chanspy.c.

00180 {
00181    /* nothing to do */
00182 }

static int start_spying ( struct ast_channel chan,
struct ast_channel spychan,
struct ast_channel_spy spy 
) [static]

Definition at line 219 of file app_chanspy.c.

References ast_bridged_channel(), ast_channel_lock, ast_channel_spy_add(), ast_channel_unlock, AST_FLAG_NBRIDGE, ast_log(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and LOG_NOTICE.

Referenced by channel_spy().

00220 {
00221    int res;
00222    struct ast_channel *peer;
00223 
00224    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
00225 
00226    ast_channel_lock(chan);
00227    res = ast_channel_spy_add(chan, spy);
00228    ast_channel_unlock(chan);
00229 
00230    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00231       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00232 
00233    return res;
00234 }

static int unload_module ( void   )  [static]

Definition at line 836 of file app_chanspy.c.

References ast_unregister_application().

00837 {
00838    int res = 0;
00839 
00840    res |= ast_unregister_application(app_chan);
00841    res |= ast_unregister_application(app_chan2);
00842    res |= ast_unregister_application(app_ext);
00843 
00844 
00845    return res;
00846 }


Variable Documentation

const char* app_chan = "ChanSpy" [static]

Definition at line 57 of file app_chanspy.c.

const char* app_chan2 = "ChanSpyChan" [static]

Definition at line 58 of file app_chanspy.c.

const char* app_ext = "ExtenSpy" [static]

Definition at line 110 of file app_chanspy.c.

enum { ... } chanspy_opt_args

enum { ... } chanspy_opt_flags

const char* desc_chan [static]

Definition at line 59 of file app_chanspy.c.

const char* desc_ext [static]

Definition at line 111 of file app_chanspy.c.

const char* desc_uniqueid [static]

Definition at line 89 of file app_chanspy.c.

struct ast_generator spygen [static]

Initial value:

 {
   .alloc = spy_alloc,
   .release = spy_release,
   .generate = spy_generate, 
}

Definition at line 213 of file app_chanspy.c.

const char* tdesc = "Listen to a channel, and optionally whisper into it" [static]

Definition at line 56 of file app_chanspy.c.

signed char volfactor_map[] [static]

Definition at line 239 of file app_chanspy.c.


Generated on Sat Apr 12 07:12:29 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5