Wed Jan 8 2020 09:49:53

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
 

Macros

#define AST_NAME_STRLEN   256
 
#define NUM_SPYGROUPS   128
 

Enumerations

enum  {
  OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3),
  OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6), OPTION_READONLY = (1 << 7),
  OPTION_EXIT = (1 << 8), OPTION_ENFORCED = (1 << 9), OPTION_NOTECH = (1 << 10), OPTION_BARGE = (1 << 11),
  OPTION_NAME = (1 << 12), OPTION_DTMF_SWITCH_MODES = (1 << 13), OPTION_DTMF_EXIT = (1 << 14), OPTION_DTMF_CYCLE = (1 << 15),
  OPTION_DAHDI_SCAN = (1 << 16), OPTION_STOP = (1 << 17), OPTION_EXITONHANGUP = (1 << 18)
}
 
enum  {
  OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ENFORCED,
  OPT_ARG_NAME, OPT_ARG_EXIT, OPT_ARG_CYCLE, OPT_ARG_ARRAY_SIZE
}
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void change_spy_mode (const char digit, struct ast_flags *flags)
 
static int channel_spy (struct ast_channel *chan, struct ast_autochan *spyee_autochan, int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags, char *exitcontext)
 
static int chanspy_exec (struct ast_channel *chan, const char *data)
 
static int common_exec (struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context)
 
static int dahdiscan_exec (struct ast_channel *chan, const char *data)
 
static int extenspy_exec (struct ast_channel *chan, const char *data)
 
static int load_module (void)
 
static struct ast_autochannext_channel (struct ast_channel_iterator *iter, struct ast_autochan *autochan, struct ast_channel *chan)
 
static void * spy_alloc (struct ast_channel *chan, void *data)
 
static int spy_generate (struct ast_channel *chan, void *data, int len, int samples)
 
static void spy_release (struct ast_channel *chan, void *data)
 
static int start_spying (struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
 
static const char app_chan [] = "ChanSpy"
 
static const char app_dahdiscan [] = "DAHDIScan"
 
static const char app_ext [] = "ExtenSpy"
 
static struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_app_option spy_opts [128] = { [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'c' ] = { .flag = OPTION_DTMF_CYCLE , .arg_index = OPT_ARG_CYCLE + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'E' ] = { .flag = OPTION_EXITONHANGUP }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'S' ] = { .flag = OPTION_STOP }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'x' ] = { .flag = OPTION_DTMF_EXIT , .arg_index = OPT_ARG_EXIT + 1 }, [ 'X' ] = { .flag = OPTION_EXIT }, }
 
static struct ast_generator spygen
 

Detailed Description

ChanSpy: Listen in on any channel.

Author
Anthony Minessale II anthm.nosp@m.ct@y.nosp@m.ahoo..nosp@m.com
Joshua Colp jcolp.nosp@m.@dig.nosp@m.ium.c.nosp@m.om
Russell Bryant russe.nosp@m.ll@d.nosp@m.igium.nosp@m..com

Definition in file app_chanspy.c.

Macro Definition 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.

354  {
355  OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
356  OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
357  OPTION_VOLUME = (1 << 2), /* Specify initial volume */
358  OPTION_GROUP = (1 << 3), /* Only look at channels in group */
359  OPTION_RECORD = (1 << 4),
360  OPTION_WHISPER = (1 << 5),
361  OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
362  OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
363  OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
364  OPTION_ENFORCED = (1 << 9), /* Enforced mode */
365  OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
366  OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
367  OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
368  OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
369  OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
370  OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
371  OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
372  OPTION_STOP = (1 << 17),
373  OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
374 };
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.

Function Documentation

static void __reg_module ( void  )
static

Definition at line 1349 of file app_chanspy.c.

static void __unreg_module ( void  )
static

Definition at line 1349 of file app_chanspy.c.

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

500 {
501  if (digit == '4') {
504  } else if (digit == '5') {
507  } else if (digit == '6') {
509  ast_set_flag(flags, OPTION_BARGE);
510  }
511 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_clear_flag(p, flag)
Definition: utils.h:77
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, ast_channel::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().

516 {
517  struct chanspy_translation_helper csth;
518  int running = 0, res, x = 0;
519  char inp[24] = {0};
520  char *name;
521  struct ast_frame *f;
522  struct ast_silence_generator *silgen = NULL;
523  struct ast_autochan *spyee_bridge_autochan = NULL;
524  const char *spyer_name;
525  struct ast_channel *chans[] = { chan, spyee_autochan->chan };
526 
527  ast_channel_lock(chan);
528  spyer_name = ast_strdupa(chan->name);
529  ast_channel_unlock(chan);
530 
531  /* We now hold the channel lock on spyee */
532 
533  if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan) ||
534  ast_test_flag(spyee_autochan->chan, AST_FLAG_ZOMBIE)) {
535  return 0;
536  }
537 
538  ast_channel_lock(spyee_autochan->chan);
539  name = ast_strdupa(spyee_autochan->chan->name);
540  ast_channel_unlock(spyee_autochan->chan);
541 
542  ast_verb(2, "Spying on channel %s\n", name);
543  ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
544  "SpyerChannel: %s\r\n"
545  "SpyeeChannel: %s\r\n",
546  spyer_name, name);
547 
548  memset(&csth, 0, sizeof(csth));
549  ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
550 
551  /* This is the audiohook which gives us the audio off the channel we are
552  spying on.
553  */
554  ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
555 
556  if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
557  ast_audiohook_destroy(&csth.spy_audiohook);
558  return 0;
559  }
560 
562  /* This audiohook will let us inject audio from our channel into the
563  channel we are currently spying on.
564  */
565  ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
566 
567  if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
568  ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
569  }
570  }
571 
573  /* And this hook lets us inject audio into the channel that the spied on
574  channel is currently bridged with.
575  */
576  ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
577 
578  if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
579  ast_channel_lock(spyee_bridge_autochan->chan);
580  if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
581  ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
582  }
583  ast_channel_unlock(spyee_bridge_autochan->chan);
584  }
585  }
586 
587  ast_channel_lock(chan);
589  ast_channel_unlock(chan);
590 
591  csth.volfactor = *volfactor;
592 
593  if (csth.volfactor) {
594  csth.spy_audiohook.options.read_volume = csth.volfactor;
595  csth.spy_audiohook.options.write_volume = csth.volfactor;
596  }
597 
598  csth.fd = fd;
599 
600  if (ast_test_flag(flags, OPTION_PRIVATE))
602  else
603  ast_activate_generator(chan, &spygen, &csth);
604 
605  /* We can no longer rely on 'spyee' being an actual channel;
606  it can be hung up and freed out from under us. However, the
607  channel destructor will put NULL into our csth.spy.chan
608  field when that happens, so that is our signal that the spyee
609  channel has gone away.
610  */
611 
612  /* Note: it is very important that the ast_waitfor() be the first
613  condition in this expression, so that if we wait for some period
614  of time before receiving a frame from our spying channel, we check
615  for hangup on the spied-on channel _after_ knowing that a frame
616  has arrived, since the spied-on channel could have gone away while
617  we were waiting
618  */
619  while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
620  if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
621  running = -1;
622  break;
623  }
624 
625  if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
626  ast_audiohook_lock(&csth.whisper_audiohook);
627  ast_audiohook_lock(&csth.bridge_whisper_audiohook);
628  ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
629  ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
630  ast_audiohook_unlock(&csth.whisper_audiohook);
631  ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
632  ast_frfree(f);
633  continue;
634  } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
635  ast_audiohook_lock(&csth.whisper_audiohook);
636  ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
637  ast_audiohook_unlock(&csth.whisper_audiohook);
638  ast_frfree(f);
639  continue;
640  }
641 
642  res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
643  ast_frfree(f);
644  if (!res)
645  continue;
646 
647  if (x == sizeof(inp))
648  x = 0;
649 
650  if (res < 0) {
651  running = -1;
652  break;
653  }
654 
655  if (ast_test_flag(flags, OPTION_EXIT)) {
656  char tmp[2];
657  tmp[0] = res;
658  tmp[1] = '\0';
659  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
660  ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
661  pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
662  running = -2;
663  break;
664  } else {
665  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
666  }
667  } else if (res >= '0' && res <= '9') {
669  change_spy_mode(res, flags);
670  } else {
671  inp[x++] = res;
672  }
673  }
674 
675  if (res == user_options->cycle) {
676  running = 0;
677  break;
678  } else if (res == user_options->exit) {
679  running = -2;
680  break;
681  } else if (res == user_options->volume) {
682  if (!ast_strlen_zero(inp)) {
683  running = atoi(inp);
684  break;
685  }
686 
687  (*volfactor)++;
688  if (*volfactor > 4)
689  *volfactor = -4;
690  ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
691 
692  csth.volfactor = *volfactor;
693  csth.spy_audiohook.options.read_volume = csth.volfactor;
694  csth.spy_audiohook.options.write_volume = csth.volfactor;
695  }
696  }
697 
698  if (ast_test_flag(flags, OPTION_PRIVATE))
700  else
702 
703  ast_channel_lock(chan);
705  ast_channel_unlock(chan);
706 
708  ast_audiohook_lock(&csth.whisper_audiohook);
709  ast_audiohook_detach(&csth.whisper_audiohook);
710  ast_audiohook_unlock(&csth.whisper_audiohook);
711  ast_audiohook_destroy(&csth.whisper_audiohook);
712  }
713 
715  ast_audiohook_lock(&csth.bridge_whisper_audiohook);
716  ast_audiohook_detach(&csth.bridge_whisper_audiohook);
717  ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
718  ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
719  }
720 
721  ast_audiohook_lock(&csth.spy_audiohook);
722  ast_audiohook_detach(&csth.spy_audiohook);
723  ast_audiohook_unlock(&csth.spy_audiohook);
724  ast_audiohook_destroy(&csth.spy_audiohook);
725 
726  if (spyee_bridge_autochan) {
727  ast_autochan_destroy(spyee_bridge_autochan);
728  }
729 
730  ast_verb(2, "Done Spying on channel %s\n", name);
731  ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
732 
733  return running;
734 }
union ast_frame_subclass subclass
Definition: frame.h:146
#define ast_channel_lock(chan)
Definition: channel.h:2466
Main Channel structure associated with a channel.
Definition: channel.h:742
int ast_audiohook_write_frame(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction, struct ast_frame *frame)
Writes a frame into the audiohook structure.
Definition: audiohook.c:127
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:3148
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source)
Initialize an audiohook structure.
Definition: audiohook.c:64
#define LOG_WARNING
Definition: logger.h:144
#define AST_FRAME_DTMF
Definition: frame.h:128
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
#define EVENT_FLAG_CALL
Definition: manager.h:72
struct ast_channel * chan
Definition: autochan.h:33
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:96
#define ast_verb(level,...)
Definition: logger.h:243
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:272
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8309
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:401
static struct ast_generator spygen
Definition: app_chanspy.c:477
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:11261
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void ast_channel_stop_silence_generator(struct ast_channel *chan, struct ast_silence_generator *state)
Stops a previously-started silence generator on the given channel.
Definition: channel.c:8355
static const char name[]
#define AST_FLAGS_ALL
Definition: utils.h:196
static struct ast_format f[]
Definition: format_g726.c:181
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:63
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
Definition: pbx.c:10546
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:40
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:499
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
Definition: app_chanspy.c:483
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
Data structure associated with a single frame of data.
Definition: frame.h:142
#define ast_manager_event_multichan(category, event, nchans, chans, contents,...)
Definition: manager.h:226
enum ast_frame_type frametype
Definition: frame.h:144
#define ast_frfree(fr)
Definition: frame.h:583
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:267
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(), spy_opts, and ast_channel::writeformat.

Referenced by load_module().

1051 {
1052  char *myenforced = NULL;
1053  char *mygroup = NULL;
1054  char *recbase = NULL;
1055  int fd = 0;
1056  struct ast_flags flags;
1057  struct spy_dtmf_options user_options = {
1058  .cycle = '*',
1059  .volume = '#',
1060  .exit = '\0',
1061  };
1062  int oldwf = 0;
1063  int volfactor = 0;
1064  int res;
1065  char *mailbox = NULL;
1066  char *name_context = NULL;
1068  AST_APP_ARG(spec);
1069  AST_APP_ARG(options);
1070  );
1071  char *opts[OPT_ARG_ARRAY_SIZE];
1072  char *parse = ast_strdupa(data);
1073 
1074  AST_STANDARD_APP_ARGS(args, parse);
1075 
1076  if (args.spec && !strcmp(args.spec, "all"))
1077  args.spec = NULL;
1078 
1079  if (args.options) {
1080  char tmp;
1081  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1082  if (ast_test_flag(&flags, OPTION_GROUP))
1083  mygroup = opts[OPT_ARG_GROUP];
1084 
1085  if (ast_test_flag(&flags, OPTION_RECORD) &&
1086  !(recbase = opts[OPT_ARG_RECORD]))
1087  recbase = "chanspy";
1088 
1089  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1090  tmp = opts[OPT_ARG_EXIT][0];
1091  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1092  user_options.exit = tmp;
1093  } else {
1094  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1095  }
1096  }
1097 
1098  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1099  tmp = opts[OPT_ARG_CYCLE][0];
1100  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1101  user_options.cycle = tmp;
1102  } else {
1103  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1104  }
1105  }
1106 
1107  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1108  int vol;
1109 
1110  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1111  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1112  else
1113  volfactor = vol;
1114  }
1115 
1116  if (ast_test_flag(&flags, OPTION_PRIVATE))
1117  ast_set_flag(&flags, OPTION_WHISPER);
1118 
1119  if (ast_test_flag(&flags, OPTION_ENFORCED))
1120  myenforced = opts[OPT_ARG_ENFORCED];
1121 
1122  if (ast_test_flag(&flags, OPTION_NAME)) {
1123  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1124  char *delimiter;
1125  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1126  mailbox = opts[OPT_ARG_NAME];
1127  *delimiter++ = '\0';
1128  name_context = delimiter;
1129  } else {
1130  mailbox = opts[OPT_ARG_NAME];
1131  }
1132  }
1133  }
1134  } else {
1135  ast_clear_flag(&flags, AST_FLAGS_ALL);
1136  }
1137 
1138  oldwf = chan->writeformat;
1139  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1140  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1141  return -1;
1142  }
1143 
1144  if (recbase) {
1145  char filename[PATH_MAX];
1146 
1147  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1148  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1149  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1150  fd = 0;
1151  }
1152  }
1153 
1154  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1155 
1156  if (fd)
1157  close(fd);
1158 
1159  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1160  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1161 
1162  if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1163  ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1164  }
1165 
1166  return res;
1167 }
format_t writeformat
Definition: channel.h:854
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
unsigned int flags
Definition: utils.h:201
#define AST_FILE_MODE
Definition: asterisk.h:36
#define ast_verb(level,...)
Definition: logger.h:243
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:406
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
const char * ast_config_AST_MONITOR_DIR
Definition: asterisk.c:260
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
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)
Definition: app_chanspy.c:766
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
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::language, ast_channel::macrocontext, ast_channel::name, next_channel(), NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_DAHDI_SCAN, OPTION_EXIT, OPTION_EXITONHANGUP, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, OPTION_STOP, pbx_builtin_getvar_helper(), S_OR, and strcasestr().

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

770 {
771  char nameprefix[AST_NAME_STRLEN];
772  char exitcontext[AST_MAX_CONTEXT] = "";
773  signed char zero_volume = 0;
774  int waitms;
775  int res;
776  int num_spyed_upon = 1;
777  struct ast_channel_iterator *iter = NULL;
778 
779  if (ast_test_flag(flags, OPTION_EXIT)) {
780  const char *c;
781  ast_channel_lock(chan);
782  if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
783  ast_copy_string(exitcontext, c, sizeof(exitcontext));
784  } else if (!ast_strlen_zero(chan->macrocontext)) {
785  ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
786  } else {
787  ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
788  }
789  ast_channel_unlock(chan);
790  }
791 
792  if (chan->_state != AST_STATE_UP)
793  ast_answer(chan);
794 
795  ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
796 
797  waitms = 100;
798 
799  for (;;) {
800  struct ast_autochan *autochan = NULL, *next_autochan = NULL;
801  struct ast_channel *prev = NULL;
802 
803  if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
804  res = ast_streamfile(chan, "beep", chan->language);
805  if (!res)
806  res = ast_waitstream(chan, "");
807  else if (res < 0) {
809  break;
810  }
811  if (!ast_strlen_zero(exitcontext)) {
812  char tmp[2];
813  tmp[0] = res;
814  tmp[1] = '\0';
815  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
816  goto exit;
817  else
818  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
819  }
820  }
821 
822  /* Set up the iterator we'll be using during this call */
823  if (!ast_strlen_zero(spec)) {
824  iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
825  } else if (!ast_strlen_zero(exten)) {
827  } else {
829  }
830 
831  if (!iter) {
832  res = -1;
833  goto exit;
834  }
835 
836  res = ast_waitfordigit(chan, waitms);
837  if (res < 0) {
838  iter = ast_channel_iterator_destroy(iter);
840  break;
841  }
842  if (!ast_strlen_zero(exitcontext)) {
843  char tmp[2];
844  tmp[0] = res;
845  tmp[1] = '\0';
846  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
847  iter = ast_channel_iterator_destroy(iter);
848  goto exit;
849  } else {
850  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
851  }
852  }
853 
854  /* reset for the next loop around, unless overridden later */
855  waitms = 100;
856  num_spyed_upon = 0;
857 
858  for (autochan = next_channel(iter, autochan, chan);
859  autochan;
860  prev = autochan->chan, ast_autochan_destroy(autochan),
861  autochan = next_autochan ? next_autochan :
862  next_channel(iter, autochan, chan), next_autochan = NULL) {
863  int igrp = !mygroup;
864  int ienf = !myenforced;
865 
866  if (autochan->chan == prev) {
867  ast_autochan_destroy(autochan);
868  break;
869  }
870 
871  if (ast_check_hangup(chan)) {
872  ast_autochan_destroy(autochan);
873  break;
874  }
875 
876  if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
877  continue;
878  }
879 
880  if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
881  continue;
882  }
883 
884  if (mygroup) {
885  int num_groups = 0;
886  int num_mygroups = 0;
887  char dup_group[512];
888  char dup_mygroup[512];
889  char *groups[NUM_SPYGROUPS];
890  char *mygroups[NUM_SPYGROUPS];
891  const char *group = NULL;
892  int x;
893  int y;
894  ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
895  num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
896  ARRAY_LEN(mygroups));
897 
898  /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
899  * rather than "SPYGROUP", this check is done to preserve expected behavior */
900  if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
901  group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
902  } else {
903  group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
904  }
905 
906  if (!ast_strlen_zero(group)) {
907  ast_copy_string(dup_group, group, sizeof(dup_group));
908  num_groups = ast_app_separate_args(dup_group, ':', groups,
909  ARRAY_LEN(groups));
910  }
911 
912  for (y = 0; y < num_mygroups; y++) {
913  for (x = 0; x < num_groups; x++) {
914  if (!strcmp(mygroups[y], groups[x])) {
915  igrp = 1;
916  break;
917  }
918  }
919  }
920  }
921 
922  if (!igrp) {
923  continue;
924  }
925  if (myenforced) {
926  char ext[AST_CHANNEL_NAME + 3];
927  char buffer[512];
928  char *end;
929 
930  snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
931 
932  ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
933  if ((end = strchr(ext, '-'))) {
934  *end++ = ':';
935  *end = '\0';
936  }
937 
938  ext[0] = ':';
939 
940  if (strcasestr(buffer, ext)) {
941  ienf = 1;
942  }
943  }
944 
945  if (!ienf) {
946  continue;
947  }
948 
949 
950  if (!ast_test_flag(flags, OPTION_QUIET)) {
951  char peer_name[AST_NAME_STRLEN + 5];
952  char *ptr, *s;
953 
954  strcpy(peer_name, "spy-");
955  strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
956  if ((ptr = strchr(peer_name, '/'))) {
957  *ptr++ = '\0';
958  for (s = peer_name; s < ptr; s++) {
959  *s = tolower(*s);
960  }
961  if ((s = strchr(ptr, '-'))) {
962  *s = '\0';
963  }
964  }
965 
966  if (ast_test_flag(flags, OPTION_NAME)) {
967  const char *local_context = S_OR(name_context, "default");
968  const char *local_mailbox = S_OR(mailbox, ptr);
969  if (local_mailbox) {
970  res = ast_app_sayname(chan, local_mailbox, local_context);
971  } else {
972  res = -1;
973  }
974  }
975  if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
976  int num;
977  if (!ast_test_flag(flags, OPTION_NOTECH)) {
978  if (ast_fileexists(peer_name, NULL, NULL) > 0) {
979  res = ast_streamfile(chan, peer_name, chan->language);
980  if (!res) {
981  res = ast_waitstream(chan, "");
982  }
983  if (res) {
984  ast_autochan_destroy(autochan);
985  break;
986  }
987  } else {
988  res = ast_say_character_str(chan, peer_name, "", chan->language);
989  }
990  }
991  if (ptr && (num = atoi(ptr))) {
992  ast_say_digits(chan, num, "", chan->language);
993  }
994  }
995  }
996 
997  res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
998  num_spyed_upon++;
999 
1000  if (res == -1) {
1001  ast_autochan_destroy(autochan);
1002  iter = ast_channel_iterator_destroy(iter);
1003  goto exit;
1004  } else if (res == -2) {
1005  res = 0;
1006  ast_autochan_destroy(autochan);
1007  iter = ast_channel_iterator_destroy(iter);
1008  goto exit;
1009  } else if (res > 1 && spec) {
1010  struct ast_channel *next;
1011 
1012  snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1013 
1014  if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1015  next_autochan = ast_autochan_setup(next);
1016  next = ast_channel_unref(next);
1017  } else {
1018  /* stay on this channel, if it is still valid */
1019  if (!ast_check_hangup(autochan->chan)) {
1020  next_autochan = ast_autochan_setup(autochan->chan);
1021  } else {
1022  /* the channel is gone */
1023  next_autochan = NULL;
1024  }
1025  }
1026  } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1027  ast_autochan_destroy(autochan);
1028  iter = ast_channel_iterator_destroy(iter);
1029  goto exit;
1030  }
1031  }
1032 
1033  iter = ast_channel_iterator_destroy(iter);
1034 
1035  if (res == -1 || ast_check_hangup(chan))
1036  break;
1037  if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1038  break;
1039  }
1040  }
1041 exit:
1042 
1044 
1045  ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1046 
1047  return res;
1048 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define NUM_SPYGROUPS
Definition: app_chanspy.c:60
Definition: app.c:104
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
#define ast_test_flag(p, flag)
Definition: utils.h:63
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
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)
Definition: app_chanspy.c:513
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8409
struct ast_channel * chan
Definition: autochan.h:33
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7795
const char * ext
Definition: http.c:112
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
struct ast_channel * ast_channel_get_by_name_prefix(const char *name, size_t name_len)
Find a channel by a name prefix.
Definition: channel.c:1808
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_NAME_STRLEN
Definition: app_chanspy.c:59
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Given a mailbox and context, play that mailbox owner&#39;s name to the channel specified.
Definition: app.c:478
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
enum ast_channel_state _state
Definition: channel.h:839
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
struct ast_channel_iterator * ast_channel_iterator_by_exten_new(const char *exten, const char *context)
Create a new channel iterator based on extension.
Definition: channel.c:1691
const ast_string_field name
Definition: channel.h:787
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:11261
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define AST_MAX_CONTEXT
Definition: channel.h:136
char macrocontext[AST_MAX_CONTEXT]
Definition: channel.h:870
#define AST_CHANNEL_NAME
Definition: channel.h:137
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
Definition: channel.c:8421
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition: channel.c:1696
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:63
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3552
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:40
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1649
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
Definition: app.c:1453
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1701
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_autochan *autochan, struct ast_channel *chan)
Definition: app_chanspy.c:736
char * strcasestr(const char *, const char *)
const ast_string_field language
Definition: channel.h:787
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
#define AST_OPTION_TXGAIN
Definition: frame.h:458
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().

1291 {
1292  const char *spec = "DAHDI";
1293  struct ast_flags flags;
1294  struct spy_dtmf_options user_options = {
1295  .cycle = '#',
1296  .volume = '\0',
1297  .exit = '*',
1298  };
1299  int oldwf = 0;
1300  int res;
1301  char *mygroup = NULL;
1302 
1303  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1304  ast_clear_flag(&flags, AST_FLAGS_ALL);
1305 
1306  if (!ast_strlen_zero(data)) {
1307  mygroup = ast_strdupa(data);
1308  }
1309  ast_set_flag(&flags, OPTION_DTMF_EXIT);
1312 
1313  oldwf = chan->writeformat;
1314  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1315  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1316  return -1;
1317  }
1318 
1319  res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1320 
1321  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1322  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1323 
1324  return res;
1325 }
format_t writeformat
Definition: channel.h:854
#define ast_set_flag(p, flag)
Definition: utils.h:70
unsigned int flags
Definition: utils.h:201
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
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)
Definition: app_chanspy.c:766
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(), context, ast_channel::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(), spy_opts, and ast_channel::writeformat.

Referenced by load_module().

1170 {
1171  char *ptr, *exten = NULL;
1172  char *mygroup = NULL;
1173  char *recbase = NULL;
1174  int fd = 0;
1175  struct ast_flags flags;
1176  struct spy_dtmf_options user_options = {
1177  .cycle = '*',
1178  .volume = '#',
1179  .exit = '\0',
1180  };
1181  int oldwf = 0;
1182  int volfactor = 0;
1183  int res;
1184  char *mailbox = NULL;
1185  char *name_context = NULL;
1188  AST_APP_ARG(options);
1189  );
1190  char *parse = ast_strdupa(data);
1191 
1192  AST_STANDARD_APP_ARGS(args, parse);
1193  if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1194  exten = args.context;
1195  *ptr++ = '\0';
1196  args.context = ptr;
1197  }
1198 
1199  if (ast_strlen_zero(args.context))
1200  args.context = ast_strdupa(chan->context);
1201 
1202  if (args.options) {
1203  char *opts[OPT_ARG_ARRAY_SIZE];
1204  char tmp;
1205 
1206  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1207  if (ast_test_flag(&flags, OPTION_GROUP))
1208  mygroup = opts[OPT_ARG_GROUP];
1209 
1210  if (ast_test_flag(&flags, OPTION_RECORD) &&
1211  !(recbase = opts[OPT_ARG_RECORD]))
1212  recbase = "chanspy";
1213 
1214  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1215  tmp = opts[OPT_ARG_EXIT][0];
1216  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1217  user_options.exit = tmp;
1218  } else {
1219  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1220  }
1221  }
1222 
1223  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1224  tmp = opts[OPT_ARG_CYCLE][0];
1225  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1226  user_options.cycle = tmp;
1227  } else {
1228  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1229  }
1230  }
1231 
1232  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1233  int vol;
1234 
1235  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1236  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1237  else
1238  volfactor = vol;
1239  }
1240 
1241  if (ast_test_flag(&flags, OPTION_PRIVATE))
1242  ast_set_flag(&flags, OPTION_WHISPER);
1243 
1244  if (ast_test_flag(&flags, OPTION_NAME)) {
1245  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1246  char *delimiter;
1247  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1248  mailbox = opts[OPT_ARG_NAME];
1249  *delimiter++ = '\0';
1250  name_context = delimiter;
1251  } else {
1252  mailbox = opts[OPT_ARG_NAME];
1253  }
1254  }
1255  }
1256 
1257  } else {
1258  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1259  ast_clear_flag(&flags, AST_FLAGS_ALL);
1260  }
1261 
1262  oldwf = chan->writeformat;
1263  if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
1264  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1265  return -1;
1266  }
1267 
1268  if (recbase) {
1269  char filename[PATH_MAX];
1270 
1271  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1272  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1273  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1274  fd = 0;
1275  }
1276  }
1277 
1278 
1279  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1280 
1281  if (fd)
1282  close(fd);
1283 
1284  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1285  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1286 
1287  return res;
1288 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
format_t writeformat
Definition: channel.h:854
#define ast_test_flag(p, flag)
Definition: utils.h:63
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: app.c:2101
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
unsigned int flags
Definition: utils.h:201
#define AST_FILE_MODE
Definition: asterisk.h:36
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
static struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:406
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
static struct @350 args
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
const char * ast_config_AST_MONITOR_DIR
Definition: asterisk.c:260
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
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)
Definition: app_chanspy.c:766
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
static char mailbox[AST_MAX_EXTENSION]
Definition: chan_mgcp.c:197
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().

1339 {
1340  int res = 0;
1341 
1345 
1346  return res;
1347 }
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1290
static const char app_chan[]
Definition: app_chanspy.c:348
static const char app_ext[]
Definition: app_chanspy.c:350
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1169
static const char app_dahdiscan[]
Definition: app_chanspy.c:352
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1050
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static struct ast_autochan* next_channel ( struct ast_channel_iterator iter,
struct ast_autochan autochan,
struct ast_channel chan 
)
static

Definition at line 736 of file app_chanspy.c.

References ast_autochan_setup(), ast_channel_iterator_next(), ast_channel_unref, and ast_channel::name.

Referenced by common_exec().

738 {
739  struct ast_channel *next;
740  struct ast_autochan *autochan_store;
741  const size_t pseudo_len = strlen("DAHDI/pseudo");
742 
743  if (!iter) {
744  return NULL;
745  }
746 
747 redo:
748  if (!(next = ast_channel_iterator_next(iter))) {
749  return NULL;
750  }
751 
752  if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
753  ast_channel_unref(next);
754  goto redo;
755  } else if (next == chan) {
756  ast_channel_unref(next);
757  goto redo;
758  }
759 
760  autochan_store = ast_autochan_setup(next);
761  ast_channel_unref(next);
762 
763  return autochan_store;
764 }
Main Channel structure associated with a channel.
Definition: channel.h:742
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1715
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
const ast_string_field name
Definition: channel.h:787
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:40
static void* spy_alloc ( struct ast_channel chan,
void *  data 
)
static

Definition at line 424 of file app_chanspy.c.

425 {
426  /* just store the data pointer in the channel structure */
427  return data;
428 }
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.

436 {
437  struct chanspy_translation_helper *csth = data;
438  struct ast_frame *f, *cur;
439 
442  /* Channel is already gone more than likely */
444  return -1;
445  }
446 
447  if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
448  /* Option 'o' was set, so don't mix channel audio */
450  } else {
452  }
453 
455 
456  if (!f)
457  return 0;
458 
459  for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
460  if (ast_write(chan, cur)) {
461  ast_frfree(f);
462  return -1;
463  }
464 
465  if (csth->fd) {
466  if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
467  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
468  }
469  }
470  }
471 
472  ast_frfree(f);
473 
474  return 0;
475 }
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, format_t format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:313
struct ast_flags flags
Definition: app_chanspy.c:415
#define ast_test_flag(p, flag)
Definition: utils.h:63
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:410
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:272
int datalen
Definition: frame.h:148
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
static struct ast_format f[]
Definition: format_g726.c:181
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
Data structure associated with a single frame of data.
Definition: frame.h:142
enum ast_audiohook_status status
Definition: audiohook.h:107
#define ast_frfree(fr)
Definition: frame.h:583
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:267
union ast_frame::@172 data
int samples
Definition: frame.h:150
static void spy_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 430 of file app_chanspy.c.

431 {
432  /* nothing to do */
433 }
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, LOG_NOTICE, and ast_channel::name.

Referenced by channel_spy().

484 {
485  int res = 0;
486  struct ast_channel *peer = NULL;
487 
488  ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
489 
491  res = ast_audiohook_attach(autochan->chan, audiohook);
492 
493  if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
495  }
496  return res;
497 }
Main Channel structure associated with a channel.
Definition: channel.h:742
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:348
struct ast_channel * chan
Definition: autochan.h:33
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
static int unload_module ( void  )
static

Definition at line 1327 of file app_chanspy.c.

References ast_unregister_application().

1328 {
1329  int res = 0;
1330 
1334 
1335  return res;
1336 }
static const char app_chan[]
Definition: app_chanspy.c:348
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
static const char app_ext[]
Definition: app_chanspy.c:350
static const char app_dahdiscan[]
Definition: app_chanspy.c:352

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static

Definition at line 1349 of file app_chanspy.c.

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.

Definition at line 1349 of file app_chanspy.c.

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

Definition at line 406 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,
}
static void * spy_alloc(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:424
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:435
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:430

Definition at line 477 of file app_chanspy.c.