Sat Mar 10 01:54:31 2012

Asterisk developer's documentation


app_chanspy.c File Reference

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

#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"

Go to the source code of this file.

Data Structures

struct  chanspy_translation_helper
struct  spy_dtmf_options

Defines

#define AST_NAME_STRLEN   256
#define NUM_SPYGROUPS   128

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), OPTION_READONLY = (1 << 7),
  OPTION_EXIT = (1 << 8), OPTION_ENFORCED = (1 << 9), OPTION_NOTECH = (1 << 10), OPTION_BARGE = (1 << 11),
  OPTION_NAME = (1 << 12), OPTION_DTMF_SWITCH_MODES = (1 << 13), OPTION_DTMF_EXIT = (1 << 14), OPTION_DTMF_CYCLE = (1 << 15),
  OPTION_DAHDI_SCAN = (1 << 16), OPTION_STOP = (1 << 17), OPTION_EXITONHANGUP = (1 << 18)
}
enum  {
  OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ENFORCED,
  OPT_ARG_NAME, OPT_ARG_EXIT, OPT_ARG_CYCLE, OPT_ARG_ARRAY_SIZE
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void change_spy_mode (const char digit, struct ast_flags *flags)
static int channel_spy (struct ast_channel *chan, struct ast_autochan *spyee_autochan, int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags, char *exitcontext)
static int chanspy_exec (struct ast_channel *chan, const char *data)
static int common_exec (struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context)
static int dahdiscan_exec (struct ast_channel *chan, const char *data)
static int extenspy_exec (struct ast_channel *chan, const char *data)
static int load_module (void)
static struct ast_autochannext_channel (struct ast_channel_iterator *iter, struct ast_autochan *autochan, struct ast_channel *chan)
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_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static const char app_chan [] = "ChanSpy"
static const char app_dahdiscan [] = "DAHDIScan"
static const char app_ext [] = "ExtenSpy"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_app_option spy_opts [128] = { [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'c' ] = { .flag = OPTION_DTMF_CYCLE , .arg_index = OPT_ARG_CYCLE + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'E' ] = { .flag = OPTION_EXITONHANGUP }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'S' ] = { .flag = OPTION_STOP }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'x' ] = { .flag = OPTION_DTMF_EXIT , .arg_index = OPT_ARG_EXIT + 1 }, [ 'X' ] = { .flag = OPTION_EXIT },}
static struct ast_generator spygen


Detailed Description

ChanSpy: Listen in on any channel.

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

Joshua Colp <jcolp@digium.com>

Russell Bryant <russell@digium.com>

Definition in file app_chanspy.c.


Define Documentation

#define AST_NAME_STRLEN   256

Definition at line 59 of file app_chanspy.c.

Referenced by common_exec().

#define NUM_SPYGROUPS   128

Definition at line 60 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 
OPTION_READONLY 
OPTION_EXIT 
OPTION_ENFORCED 
OPTION_NOTECH 
OPTION_BARGE 
OPTION_NAME 
OPTION_DTMF_SWITCH_MODES 
OPTION_DTMF_EXIT 
OPTION_DTMF_CYCLE 
OPTION_DAHDI_SCAN 
OPTION_STOP 
OPTION_EXITONHANGUP 

Definition at line 350 of file app_chanspy.c.

00350      {
00351    OPTION_QUIET             = (1 << 0),    /* Quiet, no announcement */
00352    OPTION_BRIDGED           = (1 << 1),    /* Only look at bridged calls */
00353    OPTION_VOLUME            = (1 << 2),    /* Specify initial volume */
00354    OPTION_GROUP             = (1 << 3),    /* Only look at channels in group */
00355    OPTION_RECORD            = (1 << 4),
00356    OPTION_WHISPER           = (1 << 5),
00357    OPTION_PRIVATE           = (1 << 6),    /* Private Whisper mode */
00358    OPTION_READONLY          = (1 << 7),    /* Don't mix the two channels */
00359    OPTION_EXIT              = (1 << 8),    /* Exit to a valid single digit extension */
00360    OPTION_ENFORCED          = (1 << 9),    /* Enforced mode */
00361    OPTION_NOTECH            = (1 << 10),   /* Skip technology name playback */
00362    OPTION_BARGE             = (1 << 11),   /* Barge mode (whisper to both channels) */
00363    OPTION_NAME              = (1 << 12),   /* Say the name of the person on whom we will spy */
00364    OPTION_DTMF_SWITCH_MODES = (1 << 13),   /* Allow numeric DTMF to switch between chanspy modes */
00365    OPTION_DTMF_EXIT         = (1 << 14),  /* Set DTMF to exit, added for DAHDIScan integration */
00366    OPTION_DTMF_CYCLE        = (1 << 15),  /* Custom DTMF for cycling next avaliable channel, (default is '*') */
00367    OPTION_DAHDI_SCAN        = (1 << 16),  /* Scan groups in DAHDIScan mode */
00368    OPTION_STOP              = (1 << 17),
00369    OPTION_EXITONHANGUP      = (1 << 18),   /* Hang up when the spied-on channel hangs up. */
00370 };

anonymous enum

Enumerator:
OPT_ARG_VOLUME 
OPT_ARG_GROUP 
OPT_ARG_RECORD 
OPT_ARG_ENFORCED 
OPT_ARG_NAME 
OPT_ARG_EXIT 
OPT_ARG_CYCLE 
OPT_ARG_ARRAY_SIZE 

Definition at line 372 of file app_chanspy.c.

00372      {
00373    OPT_ARG_VOLUME = 0,
00374    OPT_ARG_GROUP,
00375    OPT_ARG_RECORD,
00376    OPT_ARG_ENFORCED,
00377    OPT_ARG_NAME,
00378    OPT_ARG_EXIT,
00379    OPT_ARG_CYCLE,
00380    OPT_ARG_ARRAY_SIZE,
00381 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1330 of file app_chanspy.c.

static void __unreg_module ( void   )  [static]

Definition at line 1330 of file app_chanspy.c.

static void change_spy_mode ( const char  digit,
struct ast_flags flags 
) [static]

Definition at line 495 of file app_chanspy.c.

References ast_clear_flag, ast_set_flag, ast_channel::flags, OPTION_BARGE, and OPTION_WHISPER.

Referenced by channel_spy().

00496 {
00497    if (digit == '4') {
00498       ast_clear_flag(flags, OPTION_WHISPER);
00499       ast_clear_flag(flags, OPTION_BARGE);
00500    } else if (digit == '5') {
00501       ast_clear_flag(flags, OPTION_BARGE);
00502       ast_set_flag(flags, OPTION_WHISPER);
00503    } else if (digit == '6') {
00504       ast_clear_flag(flags, OPTION_WHISPER);
00505       ast_set_flag(flags, OPTION_BARGE);
00506    }
00507 }

static int channel_spy ( struct ast_channel chan,
struct ast_autochan spyee_autochan,
int *  volfactor,
int  fd,
struct spy_dtmf_options user_options,
struct ast_flags flags,
char *  exitcontext 
) [static]

Definition at line 509 of file app_chanspy.c.

References ast_activate_generator(), ast_audiohook_destroy(), ast_audiohook_detach(), AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_init(), ast_audiohook_lock, AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_unlock, ast_audiohook_write_frame(), ast_autochan_destroy(), ast_autochan_setup(), ast_bridged_channel(), ast_channel_lock, ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_flags, ast_deactivate_generator(), ast_debug, AST_FLAG_END_DTMF_ONLY, AST_FLAGS_ALL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor(), ast_autochan::chan, change_spy_mode(), spy_dtmf_options::cycle, EVENT_FLAG_CALL, spy_dtmf_options::exit, f, ast_channel::flags, LOG_WARNING, ast_channel::name, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, pbx_builtin_setvar_helper(), spygen, start_spying(), and spy_dtmf_options::volume.

Referenced by common_exec().

00512 {
00513    struct chanspy_translation_helper csth;
00514    int running = 0, res, x = 0;
00515    char inp[24] = {0};
00516    char *name;
00517    struct ast_frame *f;
00518    struct ast_silence_generator *silgen = NULL;
00519    struct ast_autochan *spyee_bridge_autochan = NULL;
00520    const char *spyer_name;
00521    struct ast_channel *chans[] = { chan, spyee_autochan->chan };
00522 
00523    ast_channel_lock(chan);
00524    spyer_name = ast_strdupa(chan->name);
00525    ast_channel_unlock(chan);
00526 
00527    /* We now hold the channel lock on spyee */
00528 
00529    if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
00530       return 0;
00531    }
00532 
00533    ast_channel_lock(spyee_autochan->chan);
00534    name = ast_strdupa(spyee_autochan->chan->name);
00535    ast_channel_unlock(spyee_autochan->chan);
00536 
00537    ast_verb(2, "Spying on channel %s\n", name);
00538    ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
00539          "SpyerChannel: %s\r\n"
00540          "SpyeeChannel: %s\r\n",
00541          spyer_name, name);
00542 
00543    memset(&csth, 0, sizeof(csth));
00544    ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
00545 
00546    /* This is the audiohook which gives us the audio off the channel we are
00547       spying on.
00548    */
00549    ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00550 
00551    if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
00552       ast_audiohook_destroy(&csth.spy_audiohook);
00553       return 0;
00554    }
00555 
00556    if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00557       /* This audiohook will let us inject audio from our channel into the
00558          channel we are currently spying on.
00559       */
00560       ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00561 
00562       if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
00563          ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
00564       }
00565    }
00566 
00567    if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00568       /* And this hook lets us inject audio into the channel that the spied on
00569          channel is currently bridged with.
00570       */
00571       ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
00572 
00573       if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
00574          ast_channel_lock(spyee_bridge_autochan->chan);
00575          if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
00576             ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
00577          }
00578          ast_channel_unlock(spyee_bridge_autochan->chan);
00579       }
00580    }
00581 
00582    ast_channel_lock(chan);
00583    ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00584    ast_channel_unlock(chan);
00585 
00586    csth.volfactor = *volfactor;
00587 
00588    if (csth.volfactor) {
00589       csth.spy_audiohook.options.read_volume = csth.volfactor;
00590       csth.spy_audiohook.options.write_volume = csth.volfactor;
00591    }
00592 
00593    csth.fd = fd;
00594 
00595    if (ast_test_flag(flags, OPTION_PRIVATE))
00596       silgen = ast_channel_start_silence_generator(chan);
00597    else
00598       ast_activate_generator(chan, &spygen, &csth);
00599 
00600    /* We can no longer rely on 'spyee' being an actual channel;
00601       it can be hung up and freed out from under us. However, the
00602       channel destructor will put NULL into our csth.spy.chan
00603       field when that happens, so that is our signal that the spyee
00604       channel has gone away.
00605    */
00606 
00607    /* Note: it is very important that the ast_waitfor() be the first
00608       condition in this expression, so that if we wait for some period
00609       of time before receiving a frame from our spying channel, we check
00610       for hangup on the spied-on channel _after_ knowing that a frame
00611       has arrived, since the spied-on channel could have gone away while
00612       we were waiting
00613    */
00614    while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00615       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00616          running = -1;
00617          break;
00618       }
00619 
00620       if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
00621          ast_audiohook_lock(&csth.whisper_audiohook);
00622          ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00623          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00624          ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00625          ast_audiohook_unlock(&csth.whisper_audiohook);
00626          ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00627          ast_frfree(f);
00628          continue;
00629       } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
00630          ast_audiohook_lock(&csth.whisper_audiohook);
00631          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00632          ast_audiohook_unlock(&csth.whisper_audiohook);
00633          ast_frfree(f);
00634          continue;
00635       }
00636       
00637       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
00638       ast_frfree(f);
00639       if (!res)
00640          continue;
00641 
00642       if (x == sizeof(inp))
00643          x = 0;
00644 
00645       if (res < 0) {
00646          running = -1;
00647          break;
00648       }
00649 
00650       if (ast_test_flag(flags, OPTION_EXIT)) {
00651          char tmp[2];
00652          tmp[0] = res;
00653          tmp[1] = '\0';
00654          if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00655             ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
00656             pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
00657             running = -2;
00658             break;
00659          } else {
00660             ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00661          }
00662       } else if (res >= '0' && res <= '9') {
00663          if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
00664             change_spy_mode(res, flags);
00665          } else {
00666             inp[x++] = res;
00667          }
00668       }
00669 
00670       if (res == user_options->cycle) {
00671          running = 0;
00672          break;
00673       } else if (res == user_options->exit) {
00674          running = -2;
00675          break;
00676       } else if (res == user_options->volume) {
00677          if (!ast_strlen_zero(inp)) {
00678             running = atoi(inp);
00679             break;
00680          }
00681 
00682          (*volfactor)++;
00683          if (*volfactor > 4)
00684             *volfactor = -4;
00685          ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00686 
00687          csth.volfactor = *volfactor;
00688          csth.spy_audiohook.options.read_volume = csth.volfactor;
00689          csth.spy_audiohook.options.write_volume = csth.volfactor;
00690       }
00691    }
00692 
00693    if (ast_test_flag(flags, OPTION_PRIVATE))
00694       ast_channel_stop_silence_generator(chan, silgen);
00695    else
00696       ast_deactivate_generator(chan);
00697 
00698    ast_channel_lock(chan);
00699    ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00700    ast_channel_unlock(chan);
00701 
00702    if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00703       ast_audiohook_lock(&csth.whisper_audiohook);
00704       ast_audiohook_detach(&csth.whisper_audiohook);
00705       ast_audiohook_unlock(&csth.whisper_audiohook);
00706       ast_audiohook_destroy(&csth.whisper_audiohook);
00707    }
00708 
00709    if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00710       ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00711       ast_audiohook_detach(&csth.bridge_whisper_audiohook);
00712       ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00713       ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
00714    }
00715 
00716    ast_audiohook_lock(&csth.spy_audiohook);
00717    ast_audiohook_detach(&csth.spy_audiohook);
00718    ast_audiohook_unlock(&csth.spy_audiohook);
00719    ast_audiohook_destroy(&csth.spy_audiohook);
00720 
00721    if (spyee_bridge_autochan) {
00722       ast_autochan_destroy(spyee_bridge_autochan);
00723    }
00724 
00725    ast_verb(2, "Done Spying on channel %s\n", name);
00726    ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
00727 
00728    return running;
00729 }

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

Definition at line 1033 of file app_chanspy.c.

References args, AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, common_exec(), spy_dtmf_options::cycle, spy_dtmf_options::exit, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_CYCLE, OPT_ARG_ENFORCED, OPT_ARG_EXIT, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, OPTION_ENFORCED, OPTION_EXITONHANGUP, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, parse(), spy_opts, and ast_channel::writeformat.

Referenced by load_module().

01034 {
01035    char *myenforced = NULL;
01036    char *mygroup = NULL;
01037    char *recbase = NULL;
01038    int fd = 0;
01039    struct ast_flags flags;
01040    struct spy_dtmf_options user_options = {
01041       .cycle = '*',
01042       .volume = '#',
01043       .exit = '\0',
01044    };
01045    int oldwf = 0;
01046    int volfactor = 0;
01047    int res;
01048    char *mailbox = NULL;
01049    char *name_context = NULL;
01050    AST_DECLARE_APP_ARGS(args,
01051       AST_APP_ARG(spec);
01052       AST_APP_ARG(options);
01053    );
01054    char *opts[OPT_ARG_ARRAY_SIZE];
01055    char *parse = ast_strdupa(data);
01056 
01057    AST_STANDARD_APP_ARGS(args, parse);
01058 
01059    if (args.spec && !strcmp(args.spec, "all"))
01060       args.spec = NULL;
01061 
01062    if (args.options) {
01063       char tmp;
01064       ast_app_parse_options(spy_opts, &flags, opts, args.options);
01065       if (ast_test_flag(&flags, OPTION_GROUP))
01066          mygroup = opts[OPT_ARG_GROUP];
01067 
01068       if (ast_test_flag(&flags, OPTION_RECORD) &&
01069          !(recbase = opts[OPT_ARG_RECORD]))
01070          recbase = "chanspy";
01071 
01072       if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
01073          tmp = opts[OPT_ARG_EXIT][0];
01074          if (strchr("0123456789*#", tmp) && tmp != '\0') {
01075             user_options.exit = tmp;
01076          } else {
01077             ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
01078          }
01079       }
01080 
01081       if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
01082          tmp = opts[OPT_ARG_CYCLE][0];
01083          if (strchr("0123456789*#", tmp) && tmp != '\0') {
01084             user_options.cycle = tmp;
01085          } else {
01086             ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
01087          }
01088       }
01089 
01090       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
01091          int vol;
01092 
01093          if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
01094             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
01095          else
01096             volfactor = vol;
01097       }
01098 
01099       if (ast_test_flag(&flags, OPTION_PRIVATE))
01100          ast_set_flag(&flags, OPTION_WHISPER);
01101 
01102       if (ast_test_flag(&flags, OPTION_ENFORCED))
01103          myenforced = opts[OPT_ARG_ENFORCED];
01104 
01105       if (ast_test_flag(&flags, OPTION_NAME)) {
01106          if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
01107             char *delimiter;
01108             if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
01109                mailbox = opts[OPT_ARG_NAME];
01110                *delimiter++ = '\0';
01111                name_context = delimiter;
01112             } else {
01113                mailbox = opts[OPT_ARG_NAME];
01114             }
01115          }
01116       }
01117    } else {
01118       ast_clear_flag(&flags, AST_FLAGS_ALL);
01119    }
01120 
01121    oldwf = chan->writeformat;
01122    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01123       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01124       return -1;
01125    }
01126 
01127    if (recbase) {
01128       char filename[PATH_MAX];
01129 
01130       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
01131       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
01132          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
01133          fd = 0;
01134       }
01135    }
01136 
01137    res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
01138 
01139    if (fd)
01140       close(fd);
01141 
01142    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
01143       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01144 
01145    if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
01146       ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
01147    }
01148 
01149    return res;
01150 }

static int common_exec ( struct ast_channel chan,
struct ast_flags flags,
int  volfactor,
const int  fd,
struct spy_dtmf_options user_options,
const char *  mygroup,
const char *  myenforced,
const char *  spec,
const char *  exten,
const char *  context,
const char *  mailbox,
const char *  name_context 
) [static]

Definition at line 759 of file app_chanspy.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_sayname(), ast_app_separate_args, ast_autochan_destroy(), ast_autochan_setup(), ast_bridged_channel(), ast_channel_get_by_name_prefix(), ast_channel_iterator_all_new(), ast_channel_iterator_by_exten_new(), ast_channel_iterator_by_name_new(), ast_channel_iterator_destroy(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_fileexists(), AST_FLAG_SPYING, ast_goto_if_exists(), AST_MAX_CONTEXT, AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), ast_channel::context, exitcontext, ext, ast_channel::flags, ast_channel::macrocontext, next_channel(), NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_DAHDI_SCAN, OPTION_EXIT, OPTION_EXITONHANGUP, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, OPTION_STOP, pbx_builtin_getvar_helper(), S_OR, strcasestr(), and strsep().

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

00763 {
00764    char nameprefix[AST_NAME_STRLEN];
00765    char peer_name[AST_NAME_STRLEN + 5];
00766    char exitcontext[AST_MAX_CONTEXT] = "";
00767    signed char zero_volume = 0;
00768    int waitms;
00769    int res;
00770    char *ptr;
00771    int num;
00772    int num_spyed_upon = 1;
00773    struct ast_channel_iterator *iter = NULL;
00774 
00775    if (ast_test_flag(flags, OPTION_EXIT)) {
00776       const char *c;
00777       ast_channel_lock(chan);
00778       if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
00779          ast_copy_string(exitcontext, c, sizeof(exitcontext));
00780       } else if (!ast_strlen_zero(chan->macrocontext)) {
00781          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00782       } else {
00783          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00784       }
00785       ast_channel_unlock(chan);
00786    }
00787 
00788    if (chan->_state != AST_STATE_UP)
00789       ast_answer(chan);
00790 
00791    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00792 
00793    waitms = 100;
00794 
00795    for (;;) {
00796       struct ast_autochan *autochan = NULL, *next_autochan = NULL;
00797       struct ast_channel *prev = NULL;
00798 
00799       if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00800          res = ast_streamfile(chan, "beep", chan->language);
00801          if (!res)
00802             res = ast_waitstream(chan, "");
00803          else if (res < 0) {
00804             ast_clear_flag(chan, AST_FLAG_SPYING);
00805             break;
00806          }
00807          if (!ast_strlen_zero(exitcontext)) {
00808             char tmp[2];
00809             tmp[0] = res;
00810             tmp[1] = '\0';
00811             if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00812                goto exit;
00813             else
00814                ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00815          }
00816       }
00817 
00818       /* Set up the iterator we'll be using during this call */
00819       if (!ast_strlen_zero(spec)) {
00820          iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
00821       } else if (!ast_strlen_zero(exten)) {
00822          iter = ast_channel_iterator_by_exten_new(exten, context);
00823       } else {
00824          iter = ast_channel_iterator_all_new();
00825       }
00826 
00827       if (!iter) {
00828          res = -1;
00829          goto exit;
00830       }
00831 
00832       res = ast_waitfordigit(chan, waitms);
00833       if (res < 0) {
00834          iter = ast_channel_iterator_destroy(iter);
00835          ast_clear_flag(chan, AST_FLAG_SPYING);
00836          break;
00837       }
00838       if (!ast_strlen_zero(exitcontext)) {
00839          char tmp[2];
00840          tmp[0] = res;
00841          tmp[1] = '\0';
00842          if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00843             iter = ast_channel_iterator_destroy(iter);
00844             goto exit;
00845          } else {
00846             ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00847          }
00848       }
00849 
00850       /* reset for the next loop around, unless overridden later */
00851       waitms = 100;
00852       num_spyed_upon = 0;
00853 
00854       for (autochan = next_channel(iter, autochan, chan);
00855            autochan;
00856           prev = autochan->chan, ast_autochan_destroy(autochan),
00857            autochan = next_autochan ? next_autochan : 
00858             next_channel(iter, autochan, chan), next_autochan = NULL) {
00859          int igrp = !mygroup;
00860          int ienf = !myenforced;
00861          char *s;
00862 
00863          if (autochan->chan == prev) {
00864             ast_autochan_destroy(autochan);
00865             break;
00866          }
00867 
00868          if (ast_check_hangup(chan)) {
00869             ast_autochan_destroy(autochan);
00870             break;
00871          }
00872 
00873          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
00874             continue;
00875          }
00876 
00877          if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
00878             continue;
00879          }
00880 
00881          if (mygroup) {
00882             int num_groups = 0;
00883             int num_mygroups = 0;
00884             char dup_group[512];
00885             char dup_mygroup[512];
00886             char *groups[NUM_SPYGROUPS];
00887             char *mygroups[NUM_SPYGROUPS];
00888             const char *group = NULL;
00889             int x;
00890             int y;
00891             ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
00892             num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
00893                ARRAY_LEN(mygroups));
00894 
00895             /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
00896              * rather than "SPYGROUP", this check is done to preserve expected behavior */
00897             if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
00898                group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
00899             } else {
00900                group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
00901             }
00902 
00903             if (!ast_strlen_zero(group)) {
00904                ast_copy_string(dup_group, group, sizeof(dup_group));
00905                num_groups = ast_app_separate_args(dup_group, ':', groups,
00906                   ARRAY_LEN(groups));
00907             }
00908 
00909             for (y = 0; y < num_mygroups; y++) {
00910                for (x = 0; x < num_groups; x++) {
00911                   if (!strcmp(mygroups[y], groups[x])) {
00912                      igrp = 1;
00913                      break;
00914                   }
00915                }
00916             }
00917          }
00918 
00919          if (!igrp) {
00920             continue;
00921          }
00922          if (myenforced) {
00923             char ext[AST_CHANNEL_NAME + 3];
00924             char buffer[512];
00925             char *end;
00926 
00927             snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
00928 
00929             ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
00930             if ((end = strchr(ext, '-'))) {
00931                *end++ = ':';
00932                *end = '\0';
00933             }
00934 
00935             ext[0] = ':';
00936 
00937             if (strcasestr(buffer, ext)) {
00938                ienf = 1;
00939             }
00940          }
00941 
00942          if (!ienf) {
00943             continue;
00944          }
00945 
00946          strcpy(peer_name, "spy-");
00947          strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
00948          ptr = strchr(peer_name, '/');
00949          *ptr++ = '\0';
00950          ptr = strsep(&ptr, "-");
00951 
00952          for (s = peer_name; s < ptr; s++)
00953             *s = tolower(*s);
00954 
00955          if (!ast_test_flag(flags, OPTION_QUIET)) {
00956             if (ast_test_flag(flags, OPTION_NAME)) {
00957                const char *local_context = S_OR(name_context, "default");
00958                const char *local_mailbox = S_OR(mailbox, ptr);
00959                res = ast_app_sayname(chan, local_mailbox, local_context);
00960             }
00961             if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
00962                if (!ast_test_flag(flags, OPTION_NOTECH)) {
00963                   if (ast_fileexists(peer_name, NULL, NULL) > 0) {
00964                      res = ast_streamfile(chan, peer_name, chan->language);
00965                      if (!res) {
00966                         res = ast_waitstream(chan, "");
00967                      }
00968                      if (res) {
00969                         ast_autochan_destroy(autochan);
00970                         break;
00971                      }
00972                   } else {
00973                      res = ast_say_character_str(chan, peer_name, "", chan->language);
00974                   }
00975                }
00976                if ((num = atoi(ptr)))
00977                   ast_say_digits(chan, atoi(ptr), "", chan->language);
00978             }
00979          }
00980 
00981          res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
00982          num_spyed_upon++;
00983 
00984          if (res == -1) {
00985             ast_autochan_destroy(autochan);
00986             iter = ast_channel_iterator_destroy(iter);
00987             goto exit;
00988          } else if (res == -2) {
00989             res = 0;
00990             ast_autochan_destroy(autochan);
00991             iter = ast_channel_iterator_destroy(iter);
00992             goto exit;
00993          } else if (res > 1 && spec) {
00994             struct ast_channel *next;
00995 
00996             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00997 
00998             if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
00999                next_autochan = ast_autochan_setup(next);
01000                next = ast_channel_unref(next);
01001             } else {
01002                /* stay on this channel, if it is still valid */
01003                if (!ast_check_hangup(autochan->chan)) {
01004                   next_autochan = ast_autochan_setup(autochan->chan);
01005                } else {
01006                   /* the channel is gone */
01007                   next_autochan = NULL;
01008                }
01009             }
01010          } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
01011             iter = ast_channel_iterator_destroy(iter);
01012             goto exit;
01013          }
01014       }
01015 
01016       iter = ast_channel_iterator_destroy(iter);
01017 
01018       if (res == -1 || ast_check_hangup(chan))
01019          break;
01020       if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
01021          break;
01022       }
01023    }
01024 exit:
01025 
01026    ast_clear_flag(chan, AST_FLAG_SPYING);
01027 
01028    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01029 
01030    return res;
01031 }

static int dahdiscan_exec ( struct ast_channel chan,
const char *  data 
) [static]

Definition at line 1272 of file app_chanspy.c.

References ast_clear_flag, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), common_exec(), spy_dtmf_options::cycle, ast_flags::flags, LOG_ERROR, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, and ast_channel::writeformat.

Referenced by load_module().

01273 {
01274    const char *spec = "DAHDI";
01275    struct ast_flags flags;
01276    struct spy_dtmf_options user_options = {
01277       .cycle = '#',
01278       .volume = '\0',
01279       .exit = '*',
01280    };
01281    int oldwf = 0;
01282    int res;
01283    char *mygroup = NULL;
01284 
01285    ast_clear_flag(&flags, AST_FLAGS_ALL);
01286 
01287    if (!ast_strlen_zero(data)) {
01288       mygroup = ast_strdupa(data);
01289    }
01290    ast_set_flag(&flags, OPTION_DTMF_EXIT);
01291    ast_set_flag(&flags, OPTION_DTMF_CYCLE);
01292    ast_set_flag(&flags, OPTION_DAHDI_SCAN);
01293 
01294    oldwf = chan->writeformat;
01295    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01296       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01297       return -1;
01298    }
01299 
01300    res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
01301 
01302    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
01303       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01304 
01305    return res;
01306 }

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

Definition at line 1152 of file app_chanspy.c.

References args, AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_channel::context, context, spy_dtmf_options::cycle, spy_dtmf_options::exit, exten, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_CYCLE, OPT_ARG_EXIT, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, parse(), spy_opts, and ast_channel::writeformat.

Referenced by load_module().

01153 {
01154    char *ptr, *exten = NULL;
01155    char *mygroup = NULL;
01156    char *recbase = NULL;
01157    int fd = 0;
01158    struct ast_flags flags;
01159    struct spy_dtmf_options user_options = {
01160       .cycle = '*',
01161       .volume = '#',
01162       .exit = '\0',
01163    };
01164    int oldwf = 0;
01165    int volfactor = 0;
01166    int res;
01167    char *mailbox = NULL;
01168    char *name_context = NULL;
01169    AST_DECLARE_APP_ARGS(args,
01170       AST_APP_ARG(context);
01171       AST_APP_ARG(options);
01172    );
01173    char *parse = ast_strdupa(data);
01174 
01175    AST_STANDARD_APP_ARGS(args, parse);
01176    if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
01177       exten = args.context;
01178       *ptr++ = '\0';
01179       args.context = ptr;
01180    }
01181 
01182    if (ast_strlen_zero(args.context))
01183       args.context = ast_strdupa(chan->context);
01184 
01185    if (args.options) {
01186       char *opts[OPT_ARG_ARRAY_SIZE];
01187       char tmp;
01188 
01189       ast_app_parse_options(spy_opts, &flags, opts, args.options);
01190       if (ast_test_flag(&flags, OPTION_GROUP))
01191          mygroup = opts[OPT_ARG_GROUP];
01192 
01193       if (ast_test_flag(&flags, OPTION_RECORD) &&
01194          !(recbase = opts[OPT_ARG_RECORD]))
01195          recbase = "chanspy";
01196 
01197       if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
01198          tmp = opts[OPT_ARG_EXIT][0];
01199          if (strchr("0123456789*#", tmp) && tmp != '\0') {
01200             user_options.exit = tmp;
01201          } else {
01202             ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
01203          }
01204       }
01205 
01206       if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
01207          tmp = opts[OPT_ARG_CYCLE][0];
01208          if (strchr("0123456789*#", tmp) && tmp != '\0') {
01209             user_options.cycle = tmp;
01210          } else {
01211             ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
01212          }
01213       }
01214 
01215       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
01216          int vol;
01217 
01218          if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
01219             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
01220          else
01221             volfactor = vol;
01222       }
01223 
01224       if (ast_test_flag(&flags, OPTION_PRIVATE))
01225          ast_set_flag(&flags, OPTION_WHISPER);
01226 
01227       if (ast_test_flag(&flags, OPTION_NAME)) {
01228          if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
01229             char *delimiter;
01230             if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
01231                mailbox = opts[OPT_ARG_NAME];
01232                *delimiter++ = '\0';
01233                name_context = delimiter;
01234             } else {
01235                mailbox = opts[OPT_ARG_NAME];
01236             }
01237          }
01238       }
01239 
01240    } else {
01241       ast_clear_flag(&flags, AST_FLAGS_ALL);
01242    }
01243 
01244    oldwf = chan->writeformat;
01245    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01246       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01247       return -1;
01248    }
01249 
01250    if (recbase) {
01251       char filename[PATH_MAX];
01252 
01253       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
01254       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
01255          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
01256          fd = 0;
01257       }
01258    }
01259 
01260 
01261    res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
01262 
01263    if (fd)
01264       close(fd);
01265 
01266    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
01267       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01268 
01269    return res;
01270 }

static int load_module ( void   )  [static]

Definition at line 1319 of file app_chanspy.c.

References ast_register_application_xml, chanspy_exec(), dahdiscan_exec(), and extenspy_exec().

01320 {
01321    int res = 0;
01322 
01323    res |= ast_register_application_xml(app_chan, chanspy_exec);
01324    res |= ast_register_application_xml(app_ext, extenspy_exec);
01325    res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
01326 
01327    return res;
01328 }

static struct ast_autochan* next_channel ( struct ast_channel_iterator iter,
struct ast_autochan autochan,
struct ast_channel chan 
) [static]

Definition at line 731 of file app_chanspy.c.

References ast_autochan_setup(), ast_channel_iterator_next(), ast_channel_unref, ast_autochan::chan, and ast_autochan::next.

Referenced by common_exec().

00733 {
00734    struct ast_channel *next;
00735    struct ast_autochan *autochan_store;
00736    const size_t pseudo_len = strlen("DAHDI/pseudo");
00737 
00738    if (!iter) {
00739       return NULL;
00740    }
00741 
00742 redo:
00743    if (!(next = ast_channel_iterator_next(iter))) {
00744       return NULL;
00745    }
00746 
00747    if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
00748       goto redo;
00749    } else if (next == chan) {
00750       goto redo;
00751    }
00752 
00753    autochan_store = ast_autochan_setup(next);
00754    ast_channel_unref(next);
00755 
00756    return autochan_store;
00757 }

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

Definition at line 420 of file app_chanspy.c.

00421 {
00422    /* just store the data pointer in the channel structure */
00423    return data;
00424 }

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

Definition at line 431 of file app_chanspy.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, AST_LIST_NEXT, ast_log(), ast_test_flag, ast_write(), ast_frame::data, ast_frame::datalen, errno, f, chanspy_translation_helper::fd, chanspy_translation_helper::flags, LOG_WARNING, OPTION_READONLY, ast_frame::ptr, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.

00432 {
00433    struct chanspy_translation_helper *csth = data;
00434    struct ast_frame *f, *cur;
00435 
00436    ast_audiohook_lock(&csth->spy_audiohook);
00437    if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00438       /* Channel is already gone more than likely */
00439       ast_audiohook_unlock(&csth->spy_audiohook);
00440       return -1;
00441    }
00442 
00443    if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
00444       /* Option 'o' was set, so don't mix channel audio */
00445       f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR);
00446    } else {
00447       f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
00448    }
00449 
00450    ast_audiohook_unlock(&csth->spy_audiohook);
00451 
00452    if (!f)
00453       return 0;
00454 
00455    for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00456       if (ast_write(chan, cur)) {
00457          ast_frfree(f);
00458          return -1;
00459       }
00460 
00461       if (csth->fd) {
00462          if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
00463             ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00464          }
00465       }
00466    }
00467 
00468    ast_frfree(f);
00469 
00470    return 0;
00471 }

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

Definition at line 426 of file app_chanspy.c.

00427 {
00428    /* nothing to do */
00429 }

static int start_spying ( struct ast_autochan autochan,
const char *  spychan_name,
struct ast_audiohook audiohook 
) [static]

Definition at line 479 of file app_chanspy.c.

References ast_audiohook_attach(), AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_log(), ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, ast_autochan::chan, LOG_NOTICE, and ast_channel::name.

Referenced by channel_spy().

00480 {
00481    int res = 0;
00482    struct ast_channel *peer = NULL;
00483 
00484    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
00485 
00486    ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
00487    res = ast_audiohook_attach(autochan->chan, audiohook);
00488 
00489    if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
00490       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00491    }
00492    return res;
00493 }

static int unload_module ( void   )  [static]

Definition at line 1308 of file app_chanspy.c.

References ast_unregister_application().

01309 {
01310    int res = 0;
01311 
01312    res |= ast_unregister_application(app_chan);
01313    res |= ast_unregister_application(app_ext);
01314    res |= ast_unregister_application(app_dahdiscan);
01315 
01316    return res;
01317 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 1330 of file app_chanspy.c.

const char app_chan[] = "ChanSpy" [static]

Definition at line 344 of file app_chanspy.c.

const char app_dahdiscan[] = "DAHDIScan" [static]

Definition at line 348 of file app_chanspy.c.

const char app_ext[] = "ExtenSpy" [static]

Definition at line 346 of file app_chanspy.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1330 of file app_chanspy.c.

struct ast_app_option spy_opts[128] = { [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'c' ] = { .flag = OPTION_DTMF_CYCLE , .arg_index = OPT_ARG_CYCLE + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'E' ] = { .flag = OPTION_EXITONHANGUP }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'S' ] = { .flag = OPTION_STOP }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'x' ] = { .flag = OPTION_DTMF_EXIT , .arg_index = OPT_ARG_EXIT + 1 }, [ 'X' ] = { .flag = OPTION_EXIT },} [static]

Definition at line 402 of file app_chanspy.c.

Referenced by chanspy_exec(), and extenspy_exec().

struct ast_generator spygen [static]

Initial value:

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

Definition at line 473 of file app_chanspy.c.

Referenced by channel_spy().


Generated on Sat Mar 10 01:54:31 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7