Thu Sep 7 01:03:07 2017

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

 AST_APP_OPTIONS (spy_opts,{AST_APP_OPTION('b', OPTION_BRIDGED), AST_APP_OPTION('B', OPTION_BARGE), AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE), AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES), AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED), AST_APP_OPTION('E', OPTION_EXITONHANGUP), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME), AST_APP_OPTION('o', OPTION_READONLY), AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD), AST_APP_OPTION('s', OPTION_NOTECH), AST_APP_OPTION('S', OPTION_STOP), AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION('w', OPTION_WHISPER), AST_APP_OPTION('W', OPTION_PRIVATE), AST_APP_OPTION_ARG('x', OPTION_DTMF_EXIT, OPT_ARG_EXIT), AST_APP_OPTION('X', OPTION_EXIT),})
 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Listen to the audio of an active channel")
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 const char app_chan [] = "ChanSpy"
static const char app_dahdiscan [] = "DAHDIScan"
static const char app_ext [] = "ExtenSpy"
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 354 of file app_chanspy.c.

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

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

00376      {
00377    OPT_ARG_VOLUME = 0,
00378    OPT_ARG_GROUP,
00379    OPT_ARG_RECORD,
00380    OPT_ARG_ENFORCED,
00381    OPT_ARG_NAME,
00382    OPT_ARG_EXIT,
00383    OPT_ARG_CYCLE,
00384    OPT_ARG_ARRAY_SIZE,
00385 };


Function Documentation

AST_APP_OPTIONS ( spy_opts   ) 
AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Listen to the audio of an active channel"   
)
static void change_spy_mode ( const char  digit,
struct ast_flags flags 
) [static]

Definition at line 499 of file app_chanspy.c.

References ast_clear_flag, ast_set_flag, OPTION_BARGE, and OPTION_WHISPER.

Referenced by channel_spy().

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

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 513 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(), 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().

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

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

Definition at line 1050 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, 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(), and ast_channel::writeformat.

Referenced by load_module().

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

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 766 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(), 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(), and S_OR.

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

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

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

Definition at line 1290 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, LOG_ERROR, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, and ast_channel::writeformat.

Referenced by load_module().

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

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

Definition at line 1169 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, 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(), and ast_channel::writeformat.

Referenced by load_module().

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

static int load_module ( void   )  [static]

Definition at line 1338 of file app_chanspy.c.

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

01339 {
01340    int res = 0;
01341 
01342    res |= ast_register_application_xml(app_chan, chanspy_exec);
01343    res |= ast_register_application_xml(app_ext, extenspy_exec);
01344    res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
01345 
01346    return res;
01347 }

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

Definition at line 736 of file app_chanspy.c.

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

Referenced by common_exec().

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

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

Definition at line 424 of file app_chanspy.c.

00425 {
00426    /* just store the data pointer in the channel structure */
00427    return data;
00428 }

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

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

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

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

Definition at line 430 of file app_chanspy.c.

00431 {
00432    /* nothing to do */
00433 }

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

Definition at line 483 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, and LOG_NOTICE.

Referenced by channel_spy().

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

static int unload_module ( void   )  [static]

Definition at line 1327 of file app_chanspy.c.

References ast_unregister_application().

01328 {
01329    int res = 0;
01330 
01331    res |= ast_unregister_application(app_chan);
01332    res |= ast_unregister_application(app_ext);
01333    res |= ast_unregister_application(app_dahdiscan);
01334 
01335    return res;
01336 }


Variable Documentation

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

Definition at line 348 of file app_chanspy.c.

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

Definition at line 352 of file app_chanspy.c.

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

Definition at line 350 of file app_chanspy.c.

struct ast_generator spygen [static]
Initial value:
 {
   .alloc = spy_alloc,
   .release = spy_release,
   .generate = spy_generate,
}

Definition at line 477 of file app_chanspy.c.


Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1