Mon Oct 8 12:39:07 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 = "ac1f6a56484a8820659555499174e588" , .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 1344 of file app_chanspy.c.

static void __unreg_module ( void   )  [static]

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

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

Definition at line 1045 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().

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

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 762 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, and strcasestr().

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

00766 {
00767    char nameprefix[AST_NAME_STRLEN];
00768    char exitcontext[AST_MAX_CONTEXT] = "";
00769    signed char zero_volume = 0;
00770    int waitms;
00771    int res;
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 
00862          if (autochan->chan == prev) {
00863             ast_autochan_destroy(autochan);
00864             break;
00865          }
00866 
00867          if (ast_check_hangup(chan)) {
00868             ast_autochan_destroy(autochan);
00869             break;
00870          }
00871 
00872          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
00873             continue;
00874          }
00875 
00876          if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
00877             continue;
00878          }
00879 
00880          if (mygroup) {
00881             int num_groups = 0;
00882             int num_mygroups = 0;
00883             char dup_group[512];
00884             char dup_mygroup[512];
00885             char *groups[NUM_SPYGROUPS];
00886             char *mygroups[NUM_SPYGROUPS];
00887             const char *group = NULL;
00888             int x;
00889             int y;
00890             ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
00891             num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
00892                ARRAY_LEN(mygroups));
00893 
00894             /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
00895              * rather than "SPYGROUP", this check is done to preserve expected behavior */
00896             if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
00897                group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
00898             } else {
00899                group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
00900             }
00901 
00902             if (!ast_strlen_zero(group)) {
00903                ast_copy_string(dup_group, group, sizeof(dup_group));
00904                num_groups = ast_app_separate_args(dup_group, ':', groups,
00905                   ARRAY_LEN(groups));
00906             }
00907 
00908             for (y = 0; y < num_mygroups; y++) {
00909                for (x = 0; x < num_groups; x++) {
00910                   if (!strcmp(mygroups[y], groups[x])) {
00911                      igrp = 1;
00912                      break;
00913                   }
00914                }
00915             }
00916          }
00917 
00918          if (!igrp) {
00919             continue;
00920          }
00921          if (myenforced) {
00922             char ext[AST_CHANNEL_NAME + 3];
00923             char buffer[512];
00924             char *end;
00925 
00926             snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
00927 
00928             ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
00929             if ((end = strchr(ext, '-'))) {
00930                *end++ = ':';
00931                *end = '\0';
00932             }
00933 
00934             ext[0] = ':';
00935 
00936             if (strcasestr(buffer, ext)) {
00937                ienf = 1;
00938             }
00939          }
00940 
00941          if (!ienf) {
00942             continue;
00943          }
00944 
00945 
00946          if (!ast_test_flag(flags, OPTION_QUIET)) {
00947             char peer_name[AST_NAME_STRLEN + 5];
00948             char *ptr, *s;
00949 
00950             strcpy(peer_name, "spy-");
00951             strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
00952             if ((ptr = strchr(peer_name, '/'))) {
00953                *ptr++ = '\0';
00954                for (s = peer_name; s < ptr; s++) {
00955                   *s = tolower(*s);
00956                }
00957                if ((s = strchr(ptr, '-'))) {
00958                   *s = '\0';
00959                }
00960             }
00961 
00962             if (ast_test_flag(flags, OPTION_NAME)) {
00963                const char *local_context = S_OR(name_context, "default");
00964                const char *local_mailbox = S_OR(mailbox, ptr);
00965                if (local_mailbox) {
00966                   res = ast_app_sayname(chan, local_mailbox, local_context);
00967                } else {
00968                   res = -1;
00969                }
00970             }
00971             if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
00972                int num;
00973                if (!ast_test_flag(flags, OPTION_NOTECH)) {
00974                   if (ast_fileexists(peer_name, NULL, NULL) > 0) {
00975                      res = ast_streamfile(chan, peer_name, chan->language);
00976                      if (!res) {
00977                         res = ast_waitstream(chan, "");
00978                      }
00979                      if (res) {
00980                         ast_autochan_destroy(autochan);
00981                         break;
00982                      }
00983                   } else {
00984                      res = ast_say_character_str(chan, peer_name, "", chan->language);
00985                   }
00986                }
00987                if (ptr && (num = atoi(ptr))) {
00988                   ast_say_digits(chan, num, "", chan->language);
00989                }
00990             }
00991          }
00992 
00993          res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
00994          num_spyed_upon++;
00995 
00996          if (res == -1) {
00997             ast_autochan_destroy(autochan);
00998             iter = ast_channel_iterator_destroy(iter);
00999             goto exit;
01000          } else if (res == -2) {
01001             res = 0;
01002             ast_autochan_destroy(autochan);
01003             iter = ast_channel_iterator_destroy(iter);
01004             goto exit;
01005          } else if (res > 1 && spec) {
01006             struct ast_channel *next;
01007 
01008             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
01009 
01010             if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
01011                next_autochan = ast_autochan_setup(next);
01012                next = ast_channel_unref(next);
01013             } else {
01014                /* stay on this channel, if it is still valid */
01015                if (!ast_check_hangup(autochan->chan)) {
01016                   next_autochan = ast_autochan_setup(autochan->chan);
01017                } else {
01018                   /* the channel is gone */
01019                   next_autochan = NULL;
01020                }
01021             }
01022          } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
01023             iter = ast_channel_iterator_destroy(iter);
01024             goto exit;
01025          }
01026       }
01027 
01028       iter = ast_channel_iterator_destroy(iter);
01029 
01030       if (res == -1 || ast_check_hangup(chan))
01031          break;
01032       if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
01033          break;
01034       }
01035    }
01036 exit:
01037 
01038    ast_clear_flag(chan, AST_FLAG_SPYING);
01039 
01040    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01041 
01042    return res;
01043 }

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

Definition at line 1285 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().

01286 {
01287    const char *spec = "DAHDI";
01288    struct ast_flags flags;
01289    struct spy_dtmf_options user_options = {
01290       .cycle = '#',
01291       .volume = '\0',
01292       .exit = '*',
01293    };
01294    int oldwf = 0;
01295    int res;
01296    char *mygroup = NULL;
01297 
01298    /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
01299    ast_clear_flag(&flags, AST_FLAGS_ALL);
01300 
01301    if (!ast_strlen_zero(data)) {
01302       mygroup = ast_strdupa(data);
01303    }
01304    ast_set_flag(&flags, OPTION_DTMF_EXIT);
01305    ast_set_flag(&flags, OPTION_DTMF_CYCLE);
01306    ast_set_flag(&flags, OPTION_DAHDI_SCAN);
01307 
01308    oldwf = chan->writeformat;
01309    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01310       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01311       return -1;
01312    }
01313 
01314    res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
01315 
01316    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
01317       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01318 
01319    return res;
01320 }

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

Definition at line 1164 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().

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

static int load_module ( void   )  [static]

Definition at line 1333 of file app_chanspy.c.

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

01334 {
01335    int res = 0;
01336 
01337    res |= ast_register_application_xml(app_chan, chanspy_exec);
01338    res |= ast_register_application_xml(app_ext, extenspy_exec);
01339    res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
01340 
01341    return res;
01342 }

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

Definition at line 732 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().

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

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 1322 of file app_chanspy.c.

References ast_unregister_application().

01323 {
01324    int res = 0;
01325 
01326    res |= ast_unregister_application(app_chan);
01327    res |= ast_unregister_application(app_ext);
01328    res |= ast_unregister_application(app_dahdiscan);
01329 
01330    return res;
01331 }


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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 1344 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 1344 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 Mon Oct 8 12:39:07 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7