Fri Jul 24 00:41:07 2009

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/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"

Go to the source code of this file.

Data Structures

struct  chanspy_ds
struct  chanspy_translation_helper

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)
}
enum  {
  OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ENFORCED,
  OPT_ARG_NAME, 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 chanspy_ds *spyee_chanspy_ds, int *volfactor, int fd, struct ast_flags *flags, char *exitcontext)
static void chanspy_ds_chan_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static void chanspy_ds_destroy (void *data)
static struct chanspy_dschanspy_ds_free (struct chanspy_ds *chanspy_ds)
static int chanspy_exec (struct ast_channel *chan, void *data)
static int common_exec (struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context)
static int extenspy_exec (struct ast_channel *chan, void *data)
static int load_module (void)
static struct chanspy_dsnext_channel (struct ast_channel *chan, const struct ast_channel *last, const char *spec, const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
static struct chanspy_dssetup_chanspy_ds (struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
static void * spy_alloc (struct ast_channel *chan, void *data)
static int spy_generate (struct ast_channel *chan, void *data, int len, int samples)
static void spy_release (struct ast_channel *chan, void *data)
static int start_spying (struct ast_channel *chan, 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_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static const char * app_chan = "ChanSpy"
static const char * app_ext = "ExtenSpy"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_datastore_info chanspy_ds_info
enum { ... }  chanspy_opt_args
enum { ... }  chanspy_opt_flags
static const char * desc_chan
static const char * desc_ext
static int next_unique_id_to_use = 0
static struct ast_app_option spy_opts [128] = { [ 'q' ] = { .flag = OPTION_QUIET }, [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'X' ] = { .flag = OPTION_EXIT }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES },}
static struct ast_generator spygen
static const char * tdesc = "Listen to a channel, and optionally whisper into it"


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

Referenced by common_exec().

#define NUM_SPYGROUPS   128

Definition at line 54 of file app_chanspy.c.

Referenced by common_exec().


Enumeration Type Documentation

anonymous enum

Enumerator:
OPTION_QUIET 
OPTION_BRIDGED 
OPTION_VOLUME 
OPTION_GROUP 
OPTION_RECORD 
OPTION_WHISPER 
OPTION_PRIVATE 
OPTION_READONLY 
OPTION_EXIT 
OPTION_ENFORCED 
OPTION_NOTECH 
OPTION_BARGE 
OPTION_NAME 
OPTION_DTMF_SWITCH_MODES 

Definition at line 179 of file app_chanspy.c.

00179      {
00180    OPTION_QUIET             = (1 << 0),    /* Quiet, no announcement */
00181    OPTION_BRIDGED           = (1 << 1),    /* Only look at bridged calls */
00182    OPTION_VOLUME            = (1 << 2),    /* Specify initial volume */
00183    OPTION_GROUP             = (1 << 3),    /* Only look at channels in group */
00184    OPTION_RECORD            = (1 << 4),
00185    OPTION_WHISPER           = (1 << 5),
00186    OPTION_PRIVATE           = (1 << 6),    /* Private Whisper mode */
00187    OPTION_READONLY          = (1 << 7),    /* Don't mix the two channels */
00188    OPTION_EXIT              = (1 << 8),    /* Exit to a valid single digit extension */
00189    OPTION_ENFORCED          = (1 << 9),    /* Enforced mode */
00190    OPTION_NOTECH            = (1 << 10),   /* Skip technology name playback */
00191    OPTION_BARGE             = (1 << 11),   /* Barge mode (whisper to both channels) */
00192    OPTION_NAME              = (1 << 12),   /* Say the name of the person on whom we will spy */
00193    OPTION_DTMF_SWITCH_MODES = (1 << 13),   /*Allow numeric DTMF to switch between chanspy modes */
00194 } chanspy_opt_flags;

anonymous enum

Enumerator:
OPT_ARG_VOLUME 
OPT_ARG_GROUP 
OPT_ARG_RECORD 
OPT_ARG_ENFORCED 
OPT_ARG_NAME 
OPT_ARG_ARRAY_SIZE 

Definition at line 196 of file app_chanspy.c.

00196      {
00197    OPT_ARG_VOLUME = 0,
00198    OPT_ARG_GROUP,
00199    OPT_ARG_RECORD,
00200    OPT_ARG_ENFORCED,
00201    OPT_ARG_NAME,
00202    OPT_ARG_ARRAY_SIZE,
00203 } chanspy_opt_args;


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1106 of file app_chanspy.c.

static void __unreg_module ( void   )  [static]

Definition at line 1106 of file app_chanspy.c.

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

Definition at line 306 of file app_chanspy.c.

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

Referenced by channel_spy().

00307 {
00308    if (digit == '4') {
00309       ast_clear_flag(flags, OPTION_WHISPER);
00310       ast_clear_flag(flags, OPTION_BARGE);
00311    } else if (digit == '5') {
00312       ast_clear_flag(flags, OPTION_BARGE);
00313       ast_set_flag(flags, OPTION_WHISPER);
00314    } else if (digit == '6') {
00315       ast_clear_flag(flags, OPTION_WHISPER);
00316       ast_set_flag(flags, OPTION_BARGE);
00317    }
00318 }

static int channel_spy ( struct ast_channel chan,
struct chanspy_ds spyee_chanspy_ds,
int *  volfactor,
int  fd,
struct ast_flags flags,
char *  exitcontext 
) [static]

Definition at line 320 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_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_deactivate_generator(), ast_debug, AST_FLAG_END_DTMF_ONLY, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor(), chanspy_ds::chan, chan, change_spy_mode(), f, ast_channel::flags, chanspy_ds::lock, LOG_WARNING, ast_channel::name, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, pbx_builtin_setvar_helper(), spygen, and start_spying().

Referenced by common_exec().

00322 {
00323    struct chanspy_translation_helper csth;
00324    int running = 0, res, x = 0;
00325    char inp[24] = {0};
00326    char *name;
00327    struct ast_frame *f;
00328    struct ast_silence_generator *silgen = NULL;
00329    struct ast_channel *spyee = NULL, *spyee_bridge = NULL;
00330    const char *spyer_name;
00331 
00332    ast_channel_lock(chan);
00333    spyer_name = ast_strdupa(chan->name);
00334    ast_channel_unlock(chan);
00335 
00336    ast_mutex_lock(&spyee_chanspy_ds->lock);
00337    if (spyee_chanspy_ds->chan) {
00338       spyee = spyee_chanspy_ds->chan;
00339       ast_channel_lock(spyee);
00340    }
00341    ast_mutex_unlock(&spyee_chanspy_ds->lock);
00342 
00343    if (!spyee)
00344       return 0;
00345 
00346    /* We now hold the channel lock on spyee */
00347 
00348    if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00349       ast_channel_unlock(spyee);
00350       return 0;
00351    }
00352 
00353    name = ast_strdupa(spyee->name);
00354    ast_verb(2, "Spying on channel %s\n", name);
00355 
00356    memset(&csth, 0, sizeof(csth));
00357 
00358    ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00359 
00360    if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
00361       ast_audiohook_destroy(&csth.spy_audiohook);
00362       ast_channel_unlock(spyee);
00363       return 0;
00364    }
00365 
00366    ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00367    ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
00368    if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) {
00369       ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name);
00370    }
00371    if ((spyee_bridge = ast_bridged_channel(spyee))) {
00372       ast_channel_lock(spyee_bridge);
00373       if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) {
00374          ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name);
00375       }
00376       ast_channel_unlock(spyee_bridge);
00377    }
00378    ast_channel_unlock(spyee);
00379    spyee = NULL;
00380 
00381    ast_channel_lock(chan);
00382    ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00383    ast_channel_unlock(chan);
00384 
00385    csth.volfactor = *volfactor;
00386 
00387    if (csth.volfactor) {
00388       csth.spy_audiohook.options.read_volume = csth.volfactor;
00389       csth.spy_audiohook.options.write_volume = csth.volfactor;
00390    }
00391 
00392    csth.fd = fd;
00393 
00394    if (ast_test_flag(flags, OPTION_PRIVATE))
00395       silgen = ast_channel_start_silence_generator(chan);
00396    else
00397       ast_activate_generator(chan, &spygen, &csth);
00398 
00399    /* We can no longer rely on 'spyee' being an actual channel;
00400       it can be hung up and freed out from under us. However, the
00401       channel destructor will put NULL into our csth.spy.chan
00402       field when that happens, so that is our signal that the spyee
00403       channel has gone away.
00404    */
00405 
00406    /* Note: it is very important that the ast_waitfor() be the first
00407       condition in this expression, so that if we wait for some period
00408       of time before receiving a frame from our spying channel, we check
00409       for hangup on the spied-on channel _after_ knowing that a frame
00410       has arrived, since the spied-on channel could have gone away while
00411       we were waiting
00412    */
00413    while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00414       if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00415          running = -1;
00416          break;
00417       }
00418 
00419       if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
00420          ast_audiohook_lock(&csth.whisper_audiohook);
00421          ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00422          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00423          ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00424          ast_audiohook_unlock(&csth.whisper_audiohook);
00425          ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00426          ast_frfree(f);
00427          continue;
00428       } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
00429          ast_audiohook_lock(&csth.whisper_audiohook);
00430          ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00431          ast_audiohook_unlock(&csth.whisper_audiohook);
00432          ast_frfree(f);
00433          continue;
00434       }
00435       
00436       res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00437       ast_frfree(f);
00438       if (!res)
00439          continue;
00440 
00441       if (x == sizeof(inp))
00442          x = 0;
00443 
00444       if (res < 0) {
00445          running = -1;
00446          break;
00447       }
00448 
00449       if (ast_test_flag(flags, OPTION_EXIT)) {
00450          char tmp[2];
00451          tmp[0] = res;
00452          tmp[1] = '\0';
00453          if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00454             ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
00455             pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
00456             running = -2;
00457             break;
00458          } else {
00459             ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00460          }
00461       } else if (res >= '0' && res <= '9') {
00462          if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
00463             change_spy_mode(res, flags);
00464          } else {
00465             inp[x++] = res;
00466          }
00467       }
00468 
00469       if (res == '*') {
00470          running = 0;
00471          break;
00472       } else if (res == '#') {
00473          if (!ast_strlen_zero(inp)) {
00474             running = atoi(inp);
00475             break;
00476          }
00477 
00478          (*volfactor)++;
00479          if (*volfactor > 4)
00480             *volfactor = -4;
00481          ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00482 
00483          csth.volfactor = *volfactor;
00484          csth.spy_audiohook.options.read_volume = csth.volfactor;
00485          csth.spy_audiohook.options.write_volume = csth.volfactor;
00486       }
00487    }
00488 
00489    if (ast_test_flag(flags, OPTION_PRIVATE))
00490       ast_channel_stop_silence_generator(chan, silgen);
00491    else
00492       ast_deactivate_generator(chan);
00493 
00494    ast_channel_lock(chan);
00495    ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00496    ast_channel_unlock(chan);
00497 
00498    ast_audiohook_lock(&csth.whisper_audiohook);
00499    ast_audiohook_detach(&csth.whisper_audiohook);
00500    ast_audiohook_unlock(&csth.whisper_audiohook);
00501    ast_audiohook_destroy(&csth.whisper_audiohook);
00502    
00503    ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00504    ast_audiohook_detach(&csth.bridge_whisper_audiohook);
00505    ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00506    ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
00507 
00508    ast_audiohook_lock(&csth.spy_audiohook);
00509    ast_audiohook_detach(&csth.spy_audiohook);
00510    ast_audiohook_unlock(&csth.spy_audiohook);
00511    ast_audiohook_destroy(&csth.spy_audiohook);
00512    
00513    ast_verb(2, "Done Spying on channel %s\n", name);
00514 
00515    return running;
00516 }

static void chanspy_ds_chan_fixup ( void *  data,
struct ast_channel old_chan,
struct ast_channel new_chan 
) [static]

Definition at line 535 of file app_chanspy.c.

References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.

00536 {
00537    struct chanspy_ds *chanspy_ds = data;
00538    
00539    ast_mutex_lock(&chanspy_ds->lock);
00540    chanspy_ds->chan = new_chan;
00541    ast_mutex_unlock(&chanspy_ds->lock);
00542 }

static void chanspy_ds_destroy ( void *  data  )  [static]

Note:
This relies on the embedded lock to be recursive, as it may be called due to a call to chanspy_ds_free with the lock held there.

Definition at line 522 of file app_chanspy.c.

References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.

Referenced by chanspy_ds_free().

00523 {
00524    struct chanspy_ds *chanspy_ds = data;
00525 
00526    /* Setting chan to be NULL is an atomic operation, but we don't want this
00527     * value to change while this lock is held.  The lock is held elsewhere
00528     * while it performs non-atomic operations with this channel pointer */
00529 
00530    ast_mutex_lock(&chanspy_ds->lock);
00531    chanspy_ds->chan = NULL;
00532    ast_mutex_unlock(&chanspy_ds->lock);
00533 }

static struct chanspy_ds* chanspy_ds_free ( struct chanspy_ds chanspy_ds  )  [static]

Definition at line 550 of file app_chanspy.c.

References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_free(), ast_mutex_lock(), ast_mutex_unlock(), chan, chanspy_ds::chan, chanspy_ds_destroy(), chanspy_ds_info, ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.

Referenced by common_exec(), and setup_chanspy_ds().

00551 {
00552    if (!chanspy_ds)
00553       return NULL;
00554 
00555    ast_mutex_lock(&chanspy_ds->lock);
00556    if (chanspy_ds->chan) {
00557       struct ast_datastore *datastore;
00558       struct ast_channel *chan;
00559 
00560       chan = chanspy_ds->chan;
00561 
00562       ast_channel_lock(chan);
00563       if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
00564          ast_channel_datastore_remove(chan, datastore);
00565          /* chanspy_ds->chan is NULL after this call */
00566          chanspy_ds_destroy(datastore->data);
00567          datastore->data = NULL;
00568          ast_datastore_free(datastore);
00569       }
00570       ast_channel_unlock(chan);
00571    }
00572    ast_mutex_unlock(&chanspy_ds->lock);
00573 
00574    return NULL;
00575 }

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

Definition at line 897 of file app_chanspy.c.

References 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, chan, common_exec(), ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_ENFORCED, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_ENFORCED, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, spy_opts, and ast_channel::writeformat.

Referenced by load_module().

00898 {
00899    char *myenforced = NULL;
00900    char *mygroup = NULL;
00901    char *recbase = NULL;
00902    int fd = 0;
00903    struct ast_flags flags;
00904    int oldwf = 0;
00905    int volfactor = 0;
00906    int res;
00907    char *mailbox = NULL;
00908    char *name_context = NULL;
00909    AST_DECLARE_APP_ARGS(args,
00910       AST_APP_ARG(spec);
00911       AST_APP_ARG(options);
00912    );
00913    char *opts[OPT_ARG_ARRAY_SIZE];
00914 
00915    data = ast_strdupa(data);
00916    AST_STANDARD_APP_ARGS(args, data);
00917 
00918    if (args.spec && !strcmp(args.spec, "all"))
00919       args.spec = NULL;
00920 
00921    if (args.options) {
00922       ast_app_parse_options(spy_opts, &flags, opts, args.options);
00923       if (ast_test_flag(&flags, OPTION_GROUP))
00924          mygroup = opts[OPT_ARG_GROUP];
00925 
00926       if (ast_test_flag(&flags, OPTION_RECORD) &&
00927          !(recbase = opts[OPT_ARG_RECORD]))
00928          recbase = "chanspy";
00929 
00930       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00931          int vol;
00932 
00933          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00934             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00935          else
00936             volfactor = vol;
00937       }
00938 
00939       if (ast_test_flag(&flags, OPTION_PRIVATE))
00940          ast_set_flag(&flags, OPTION_WHISPER);
00941 
00942       if (ast_test_flag(&flags, OPTION_ENFORCED))
00943          myenforced = opts[OPT_ARG_ENFORCED];
00944       
00945       if (ast_test_flag(&flags, OPTION_NAME)) {
00946          if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
00947             char *delimiter;
00948             if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
00949                mailbox = opts[OPT_ARG_NAME];
00950                *delimiter++ = '\0';
00951                name_context = delimiter;
00952             } else {
00953                mailbox = opts[OPT_ARG_NAME];
00954             }
00955          }
00956       }
00957 
00958 
00959    } else
00960       ast_clear_flag(&flags, AST_FLAGS_ALL);
00961 
00962    oldwf = chan->writeformat;
00963    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00964       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00965       return -1;
00966    }
00967 
00968    if (recbase) {
00969       char filename[PATH_MAX];
00970 
00971       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00972       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
00973          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00974          fd = 0;
00975       }
00976    }
00977 
00978    res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
00979 
00980    if (fd)
00981       close(fd);
00982 
00983    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00984       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00985 
00986    return res;
00987 }

static int common_exec ( struct ast_channel chan,
struct ast_flags flags,
int  volfactor,
const int  fd,
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 629 of file app_chanspy.c.

References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_sayname(), ast_app_separate_args(), ast_atomic_fetchadd_int(), ast_bridged_channel(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_fileexists(), AST_FLAG_SPYING, ast_get_channel_by_name_prefix_locked(), ast_goto_if_exists(), AST_MAX_CONTEXT, ast_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), 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(), chan, channel_spy(), chanspy_ds_free(), ast_channel::context, exitcontext, ext, ast_channel::flags, chanspy_ds::lock, ast_channel::macrocontext, ast_channel::next, next_channel(), num, NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_EXIT, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, pbx_builtin_getvar_helper(), s, S_OR, setup_chanspy_ds(), strcasestr(), strsep(), and chanspy_ds::unique_id.

Referenced by chanspy_exec(), and extenspy_exec().

00633 {
00634    char nameprefix[AST_NAME_STRLEN];
00635    char peer_name[AST_NAME_STRLEN + 5];
00636    char exitcontext[AST_MAX_CONTEXT] = "";
00637    signed char zero_volume = 0;
00638    int waitms;
00639    int res;
00640    char *ptr;
00641    int num;
00642    int num_spyed_upon = 1;
00643    struct chanspy_ds chanspy_ds = { 0, };
00644 
00645    if (ast_test_flag(flags, OPTION_EXIT)) {
00646       const char *c;
00647       ast_channel_lock(chan);
00648       if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
00649          ast_copy_string(exitcontext, c, sizeof(exitcontext));
00650       } else if (!ast_strlen_zero(chan->macrocontext)) {
00651          ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00652       } else {
00653          ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00654       }
00655       ast_channel_unlock(chan);
00656    }
00657 
00658    ast_mutex_init(&chanspy_ds.lock);
00659 
00660    snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
00661 
00662    if (chan->_state != AST_STATE_UP)
00663       ast_answer(chan);
00664 
00665    ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
00666 
00667    waitms = 100;
00668 
00669    for (;;) {
00670       struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00671       struct ast_channel *prev = NULL, *peer = NULL;
00672 
00673       if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00674          res = ast_streamfile(chan, "beep", chan->language);
00675          if (!res)
00676             res = ast_waitstream(chan, "");
00677          else if (res < 0) {
00678             ast_clear_flag(chan, AST_FLAG_SPYING);
00679             break;
00680          }
00681          if (!ast_strlen_zero(exitcontext)) {
00682             char tmp[2];
00683             tmp[0] = res;
00684             tmp[1] = '\0';
00685             if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00686                goto exit;
00687             else
00688                ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00689          }
00690       }
00691 
00692       res = ast_waitfordigit(chan, waitms);
00693       if (res < 0) {
00694          ast_clear_flag(chan, AST_FLAG_SPYING);
00695          break;
00696       }
00697       if (!ast_strlen_zero(exitcontext)) {
00698          char tmp[2];
00699          tmp[0] = res;
00700          tmp[1] = '\0';
00701          if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00702             goto exit;
00703          else
00704             ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00705       }
00706 
00707       /* reset for the next loop around, unless overridden later */
00708       waitms = 100;
00709       num_spyed_upon = 0;
00710 
00711       for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00712            peer_chanspy_ds;
00713           chanspy_ds_free(peer_chanspy_ds), prev = peer,
00714            peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 
00715             next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00716          int igrp = !mygroup;
00717          int ienf = !myenforced;
00718          char *s;
00719 
00720          peer = peer_chanspy_ds->chan;
00721 
00722          ast_mutex_unlock(&peer_chanspy_ds->lock);
00723 
00724          if (peer == prev) {
00725             ast_channel_unlock(peer);
00726             chanspy_ds_free(peer_chanspy_ds);
00727             break;
00728          }
00729 
00730          if (ast_check_hangup(chan)) {
00731             ast_channel_unlock(peer);
00732             chanspy_ds_free(peer_chanspy_ds);
00733             break;
00734          }
00735 
00736          if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00737             ast_channel_unlock(peer);
00738             continue;
00739          }
00740 
00741          if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00742             ast_channel_unlock(peer);
00743             continue;
00744          }
00745 
00746          if (mygroup) {
00747             int num_groups = 0;
00748             int num_mygroups = 0;
00749             char dup_group[512];
00750             char dup_mygroup[512];
00751             char *groups[NUM_SPYGROUPS];
00752             char *mygroups[NUM_SPYGROUPS];
00753             const char *group;
00754             int x;
00755             int y;
00756             ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
00757             num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
00758                ARRAY_LEN(mygroups));
00759 
00760             if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00761                ast_copy_string(dup_group, group, sizeof(dup_group));
00762                num_groups = ast_app_separate_args(dup_group, ':', groups,
00763                   ARRAY_LEN(groups));
00764             }
00765 
00766             for (y = 0; y < num_mygroups; y++) {
00767                for (x = 0; x < num_groups; x++) {
00768                   if (!strcmp(mygroups[y], groups[x])) {
00769                      igrp = 1;
00770                      break;
00771                   }
00772                }
00773             }
00774          }
00775 
00776          if (!igrp) {
00777             ast_channel_unlock(peer);
00778             continue;
00779          }
00780 
00781          if (myenforced) {
00782             char ext[AST_CHANNEL_NAME + 3];
00783             char buffer[512];
00784             char *end;
00785 
00786             snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
00787 
00788             ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
00789             if ((end = strchr(ext, '-'))) {
00790                *end++ = ':';
00791                *end = '\0';
00792             }
00793 
00794             ext[0] = ':';
00795 
00796             if (strcasestr(buffer, ext)) {
00797                ienf = 1;
00798             }
00799          }
00800 
00801          if (!ienf) {
00802             continue;
00803          }
00804 
00805          strcpy(peer_name, "spy-");
00806          strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00807          ptr = strchr(peer_name, '/');
00808          *ptr++ = '\0';
00809          ptr = strsep(&ptr, "-");
00810 
00811          for (s = peer_name; s < ptr; s++)
00812             *s = tolower(*s);
00813          /* We have to unlock the peer channel here to avoid a deadlock.
00814           * So, when we need to dereference it again, we have to lock the 
00815           * datastore and get the pointer from there to see if the channel 
00816           * is still valid. */
00817          ast_channel_unlock(peer);
00818 
00819          if (!ast_test_flag(flags, OPTION_QUIET)) {
00820             if (ast_test_flag(flags, OPTION_NAME)) {
00821                const char *local_context = S_OR(name_context, "default");
00822                const char *local_mailbox = S_OR(mailbox, ptr);
00823                res = ast_app_sayname(chan, local_mailbox, local_context);
00824             }
00825             if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
00826                if (!ast_test_flag(flags, OPTION_NOTECH)) {
00827                   if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00828                      res = ast_streamfile(chan, peer_name, chan->language);
00829                      if (!res) {
00830                         res = ast_waitstream(chan, "");
00831                      }
00832                      if (res) {
00833                         chanspy_ds_free(peer_chanspy_ds);
00834                         break;
00835                      }
00836                   } else {
00837                      res = ast_say_character_str(chan, peer_name, "", chan->language);
00838                   }
00839                }
00840                if ((num = atoi(ptr)))
00841                   ast_say_digits(chan, atoi(ptr), "", chan->language);
00842             }
00843          }
00844 
00845          res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
00846          num_spyed_upon++; 
00847 
00848          if (res == -1) {
00849             chanspy_ds_free(peer_chanspy_ds);
00850             goto exit;
00851          } else if (res == -2) {
00852             res = 0;
00853             chanspy_ds_free(peer_chanspy_ds);
00854             goto exit;
00855          } else if (res > 1 && spec) {
00856             struct ast_channel *next;
00857 
00858             snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00859 
00860             if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00861                peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
00862                next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
00863             } else {
00864                /* stay on this channel, if it is still valid */
00865 
00866                ast_mutex_lock(&peer_chanspy_ds->lock);
00867                if (peer_chanspy_ds->chan) {
00868                   ast_channel_lock(peer_chanspy_ds->chan);
00869                   next_chanspy_ds = peer_chanspy_ds;
00870                   peer_chanspy_ds = NULL;
00871                } else {
00872                   /* the channel is gone */
00873                   ast_mutex_unlock(&peer_chanspy_ds->lock);
00874                   next_chanspy_ds = NULL;
00875                }
00876             }
00877 
00878             peer = NULL;
00879          }
00880       }
00881       if (res == -1 || ast_check_hangup(chan))
00882          break;
00883    }
00884 exit:
00885 
00886    ast_clear_flag(chan, AST_FLAG_SPYING);
00887 
00888    ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00889 
00890    ast_mutex_lock(&chanspy_ds.lock);
00891    ast_mutex_unlock(&chanspy_ds.lock);
00892    ast_mutex_destroy(&chanspy_ds.lock);
00893 
00894    return res;
00895 }

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

Definition at line 989 of file app_chanspy.c.

References 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, chan, common_exec(), ast_channel::context, context, exten, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, spy_opts, and ast_channel::writeformat.

Referenced by load_module().

00990 {
00991    char *ptr, *exten = NULL;
00992    char *mygroup = NULL;
00993    char *recbase = NULL;
00994    int fd = 0;
00995    struct ast_flags flags;
00996    int oldwf = 0;
00997    int volfactor = 0;
00998    int res;
00999    char *mailbox = NULL;
01000    char *name_context = NULL;
01001    AST_DECLARE_APP_ARGS(args,
01002       AST_APP_ARG(context);
01003       AST_APP_ARG(options);
01004    );
01005 
01006    data = ast_strdupa(data);
01007 
01008    AST_STANDARD_APP_ARGS(args, data);
01009    if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
01010       exten = args.context;
01011       *ptr++ = '\0';
01012       args.context = ptr;
01013    }
01014 
01015    if (ast_strlen_zero(args.context))
01016       args.context = ast_strdupa(chan->context);
01017 
01018    if (args.options) {
01019       char *opts[OPT_ARG_ARRAY_SIZE];
01020 
01021       ast_app_parse_options(spy_opts, &flags, opts, args.options);
01022       if (ast_test_flag(&flags, OPTION_GROUP))
01023          mygroup = opts[OPT_ARG_GROUP];
01024 
01025       if (ast_test_flag(&flags, OPTION_RECORD) &&
01026          !(recbase = opts[OPT_ARG_RECORD]))
01027          recbase = "chanspy";
01028 
01029       if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
01030          int vol;
01031 
01032          if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
01033             ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
01034          else
01035             volfactor = vol;
01036       }
01037 
01038       if (ast_test_flag(&flags, OPTION_PRIVATE))
01039          ast_set_flag(&flags, OPTION_WHISPER);
01040 
01041       
01042       if (ast_test_flag(&flags, OPTION_NAME)) {
01043          if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
01044             char *delimiter;
01045             if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
01046                mailbox = opts[OPT_ARG_NAME];
01047                *delimiter++ = '\0';
01048                name_context = delimiter;
01049             } else {
01050                mailbox = opts[OPT_ARG_NAME];
01051             }
01052          }
01053       }
01054 
01055    } else
01056       ast_clear_flag(&flags, AST_FLAGS_ALL);
01057 
01058    oldwf = chan->writeformat;
01059    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
01060       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01061       return -1;
01062    }
01063 
01064    if (recbase) {
01065       char filename[PATH_MAX];
01066 
01067       snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
01068       if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
01069          ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
01070          fd = 0;
01071       }
01072    }
01073 
01074 
01075    res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
01076 
01077    if (fd)
01078       close(fd);
01079 
01080    if (oldwf && ast_set_write_format(chan, oldwf) < 0)
01081       ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01082 
01083    return res;
01084 }

static int load_module ( void   )  [static]

Definition at line 1096 of file app_chanspy.c.

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

01097 {
01098    int res = 0;
01099 
01100    res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
01101    res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
01102 
01103    return res;
01104 }

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

Definition at line 598 of file app_chanspy.c.

References ast_channel_unlock, ast_channel_walk_locked(), ast_strlen_zero(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), chan, last, ast_channel::name, ast_channel::next, and setup_chanspy_ds().

Referenced by common_exec().

00601 {
00602    struct ast_channel *next;
00603    const size_t pseudo_len = strlen("DAHDI/pseudo");
00604 
00605 redo:
00606    if (!ast_strlen_zero(spec))
00607       next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00608    else if (!ast_strlen_zero(exten))
00609       next = ast_walk_channel_by_exten_locked(last, exten, context);
00610    else
00611       next = ast_channel_walk_locked(last);
00612 
00613    if (!next)
00614       return NULL;
00615 
00616    if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
00617       last = next;
00618       ast_channel_unlock(next);
00619       goto redo;
00620    } else if (next == chan) {
00621       last = next;
00622       ast_channel_unlock(next);
00623       goto redo;
00624    }
00625 
00626    return setup_chanspy_ds(next, chanspy_ds);
00627 }

static struct chanspy_ds* setup_chanspy_ds ( struct ast_channel chan,
struct chanspy_ds chanspy_ds 
) [static]

Note:
Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked

Definition at line 578 of file app_chanspy.c.

References ast_channel_datastore_add(), ast_channel_unlock, ast_datastore_alloc(), ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, chan, chanspy_ds_free(), chanspy_ds_info, ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.

Referenced by common_exec(), and next_channel().

00579 {
00580    struct ast_datastore *datastore = NULL;
00581 
00582    ast_mutex_lock(&chanspy_ds->lock);
00583 
00584    if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
00585       ast_mutex_unlock(&chanspy_ds->lock);
00586       chanspy_ds = chanspy_ds_free(chanspy_ds);
00587       ast_channel_unlock(chan);
00588       return NULL;
00589    }
00590    
00591    chanspy_ds->chan = chan;
00592    datastore->data = chanspy_ds;
00593    ast_channel_datastore_add(chan, datastore);
00594 
00595    return chanspy_ds;
00596 }

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

Definition at line 233 of file app_chanspy.c.

00234 {
00235    /* just store the data pointer in the channel structure */
00236    return data;
00237 }

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

Definition at line 244 of file app_chanspy.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, ast_log(), ast_write(), chan, errno, f, chanspy_translation_helper::fd, LOG_WARNING, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.

00245 {
00246    struct chanspy_translation_helper *csth = data;
00247    struct ast_frame *f = NULL;
00248 
00249    ast_audiohook_lock(&csth->spy_audiohook);
00250    if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00251       /* Channel is already gone more than likely */
00252       ast_audiohook_unlock(&csth->spy_audiohook);
00253       return -1;
00254    }
00255 
00256    f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
00257 
00258    ast_audiohook_unlock(&csth->spy_audiohook);
00259 
00260    if (!f)
00261       return 0;
00262 
00263    if (ast_write(chan, f)) {
00264       ast_frfree(f);
00265       return -1;
00266    }
00267 
00268    if (csth->fd) {
00269       if (write(csth->fd, f->data.ptr, f->datalen) < 0) {
00270          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00271       }
00272    }
00273 
00274    ast_frfree(f);
00275 
00276    return 0;
00277 }

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

Definition at line 239 of file app_chanspy.c.

00240 {
00241    /* nothing to do */
00242 }

static int start_spying ( struct ast_channel chan,
const char *  spychan_name,
struct ast_audiohook audiohook 
) [static]

Definition at line 285 of file app_chanspy.c.

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

Referenced by channel_spy().

00286 {
00287    int res = 0;
00288    struct ast_channel *peer = NULL;
00289 
00290    ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
00291 
00292    res = ast_audiohook_attach(chan, audiohook);
00293 
00294    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 
00295       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00296    }
00297    return res;
00298 }

static int unload_module ( void   )  [static]

Definition at line 1086 of file app_chanspy.c.

References ast_unregister_application().

01087 {
01088    int res = 0;
01089 
01090    res |= ast_unregister_application(app_chan);
01091    res |= ast_unregister_application(app_ext);
01092 
01093    return res;
01094 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 1106 of file app_chanspy.c.

const char* app_chan = "ChanSpy" [static]

Definition at line 57 of file app_chanspy.c.

const char* app_ext = "ExtenSpy" [static]

Definition at line 122 of file app_chanspy.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1106 of file app_chanspy.c.

struct ast_datastore_info chanspy_ds_info [static]

Initial value:

 {
   .type = "chanspy",
   .destroy = chanspy_ds_destroy,
   .chan_fixup = chanspy_ds_chan_fixup,
}

Definition at line 544 of file app_chanspy.c.

Referenced by chanspy_ds_free(), and setup_chanspy_ds().

enum { ... } chanspy_opt_args

enum { ... } chanspy_opt_flags

const char* desc_chan [static]

Definition at line 58 of file app_chanspy.c.

const char* desc_ext [static]

Definition at line 123 of file app_chanspy.c.

int next_unique_id_to_use = 0 [static]

Definition at line 222 of file app_chanspy.c.

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

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

Referenced by channel_spy().

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

Definition at line 56 of file app_chanspy.c.


Generated on Fri Jul 24 00:41:08 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7