Sat Feb 11 06:33:34 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"

Include dependency graph for app_chanspy.c:

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 = AST_BUILDOPT_SUM, .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 1336 of file app_chanspy.c.

static void __unreg_module ( void   )  [static]

Definition at line 1336 of file app_chanspy.c.

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

Definition at line 498 of file app_chanspy.c.

References ast_clear_flag, ast_set_flag, OPTION_BARGE, and OPTION_WHISPER.

Referenced by channel_spy().

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

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 512 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_name(), 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(), chanspy_translation_helper::bridge_whisper_audiohook, ast_autochan::chan, change_spy_mode(), spy_dtmf_options::cycle, EVENT_FLAG_CALL, spy_dtmf_options::exit, f, chanspy_translation_helper::fd, chanspy_translation_helper::flags, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, ast_audiohook::options, pbx_builtin_setvar_helper(), ast_audiohook_options::read_volume, chanspy_translation_helper::spy_audiohook, start_spying(), ast_audiohook::status, ast_frame::subclass, chanspy_translation_helper::volfactor, spy_dtmf_options::volume, chanspy_translation_helper::whisper_audiohook, and ast_audiohook_options::write_volume.

Referenced by common_exec().

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

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

Definition at line 1037 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_clear(), ast_format_copy(), AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), ast_set_write_format_by_id(), 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_format::id, 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().

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

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_language(), ast_channel_lock, ast_channel_name(), 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(), ast_autochan::chan, channel_spy(), ast_channel::context, exitcontext, ext, 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().

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

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

Definition at line 1278 of file app_chanspy.c.

References ast_clear_flag, AST_FLAGS_ALL, ast_format_clear(), ast_format_copy(), AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), ast_set_write_format_by_id(), ast_strdupa, ast_strlen_zero(), common_exec(), spy_dtmf_options::cycle, ast_format::id, LOG_ERROR, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, and ast_channel::writeformat.

Referenced by load_module().

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

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

Definition at line 1157 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_clear(), AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), ast_set_write_format_by_id(), 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_format::id, 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().

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

static int load_module ( void   )  [static]

Definition at line 1325 of file app_chanspy.c.

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

01326 {
01327    int res = 0;
01328 
01329    res |= ast_register_application_xml(app_chan, chanspy_exec);
01330    res |= ast_register_application_xml(app_ext, extenspy_exec);
01331    res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
01332 
01333    return res;
01334 }

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

Definition at line 734 of file app_chanspy.c.

References ast_autochan_setup(), ast_channel_iterator_next(), ast_channel_name(), and ast_channel_unref.

Referenced by common_exec().

00736 {
00737    struct ast_channel *next;
00738    struct ast_autochan *autochan_store;
00739    const size_t pseudo_len = strlen("DAHDI/pseudo");
00740 
00741    if (!iter) {
00742       return NULL;
00743    }
00744 
00745 redo:
00746    if (!(next = ast_channel_iterator_next(iter))) {
00747       return NULL;
00748    }
00749 
00750    if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)) {
00751       goto redo;
00752    } else if (next == chan) {
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_set(), 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    struct ast_format format_slin;
00436 
00437    ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0);
00438 
00439    ast_audiohook_lock(&csth->spy_audiohook);
00440    if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00441       /* Channel is already gone more than likely */
00442       ast_audiohook_unlock(&csth->spy_audiohook);
00443       return -1;
00444    }
00445 
00446    if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
00447       /* Option 'o' was set, so don't mix channel audio */
00448       f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
00449    } else {
00450       f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin);
00451    }
00452 
00453    ast_audiohook_unlock(&csth->spy_audiohook);
00454 
00455    if (!f)
00456       return 0;
00457 
00458    for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00459       if (ast_write(chan, cur)) {
00460          ast_frfree(f);
00461          return -1;
00462       }
00463 
00464       if (csth->fd) {
00465          if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
00466             ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00467          }
00468       }
00469    }
00470 
00471    ast_frfree(f);
00472 
00473    return 0;
00474 }

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

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

Referenced by channel_spy().

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

static int unload_module ( void   )  [static]

Definition at line 1314 of file app_chanspy.c.

References ast_unregister_application().

01315 {
01316    int res = 0;
01317 
01318    res |= ast_unregister_application(app_chan);
01319    res |= ast_unregister_application(app_ext);
01320    res |= ast_unregister_application(app_dahdiscan);
01321 
01322    return res;
01323 }


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

Definition at line 1336 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.

Definition at line 1336 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 476 of file app_chanspy.c.


Generated on Sat Feb 11 06:33:35 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6