Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Enumerations | Functions | Variables
app_chanspy.c File Reference

ChanSpy: Listen in on any channel. More...

#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/json.h"
#include "asterisk/format_cache.h"
Include dependency graph for app_chanspy.c:

Go to the source code of this file.

Data Structures

struct  chanspy_translation_helper
 
struct  spy_dtmf_options
 

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), OPTION_UNIQUEID = (1 << 19),
  OPTION_LONG_QUEUE = (1 << 20)
}
 
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)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int attach_barge (struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
 
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_channel *chan)
 
static int pack_channel_into_message (struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
 
static void publish_chanspy_message (struct ast_channel *spyer, struct ast_channel *spyee, int start)
 
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 spy_sayname (struct ast_channel *chan, const char *mailbox, const char *context)
 
static int start_spying (struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
 
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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
 
static const char app_chan [] = "ChanSpy"
 
static const char app_dahdiscan [] = "DAHDIScan"
 
static const char app_ext [] = "ExtenSpy"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static const 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 }, [ 'l' ] = { .flag = OPTION_LONG_QUEUE }, [ '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 }, [ 'u' ] = { .flag = OPTION_UNIQUEID }, [ '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

◆ AST_NAME_STRLEN

#define AST_NAME_STRLEN   256

Definition at line 60 of file app_chanspy.c.

Referenced by common_exec().

◆ NUM_SPYGROUPS

#define NUM_SPYGROUPS   128

Definition at line 61 of file app_chanspy.c.

Referenced by common_exec().

Enumeration Type Documentation

◆ anonymous enum

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 
OPTION_UNIQUEID 
OPTION_LONG_QUEUE 

Definition at line 374 of file app_chanspy.c.

374  {
375  OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
376  OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
377  OPTION_VOLUME = (1 << 2), /* Specify initial volume */
378  OPTION_GROUP = (1 << 3), /* Only look at channels in group */
379  OPTION_RECORD = (1 << 4),
380  OPTION_WHISPER = (1 << 5),
381  OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
382  OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
383  OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
384  OPTION_ENFORCED = (1 << 9), /* Enforced mode */
385  OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
386  OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
387  OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
388  OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
389  OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
390  OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next available channel, (default is '*') */
391  OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
392  OPTION_STOP = (1 << 17),
393  OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */
394  OPTION_UNIQUEID = (1 << 19), /* The chanprefix is a channel uniqueid or fully specified channel name. */
395  OPTION_LONG_QUEUE = (1 << 20), /* Allow usage of a long queue to store audio frames. */
396 };

◆ anonymous enum

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

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1504 of file app_chanspy.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1504 of file app_chanspy.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1504 of file app_chanspy.c.

◆ attach_barge()

static int attach_barge ( struct ast_autochan spyee_autochan,
struct ast_autochan **  spyee_bridge_autochan,
struct ast_audiohook bridge_whisper_audiohook,
const char *  spyer_name,
const char *  name,
struct ast_flags flags 
)
static

Definition at line 605 of file app_chanspy.c.

References ast_audiohook_init(), AST_AUDIOHOOK_TYPE_WHISPER, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_autochan_setup(), ast_channel_bridge_peer(), ast_channel_cleanup, ast_channel_ref, ast_channel_unref, ast_log, ast_autochan::chan, LOG_WARNING, NULL, RAII_VAR, retval, and start_spying().

Referenced by channel_spy().

608 {
609  int retval = 0;
610  struct ast_autochan *internal_bridge_autochan;
611  struct ast_channel *spyee_chan;
612  RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
613 
614  ast_autochan_channel_lock(spyee_autochan);
615  spyee_chan = ast_channel_ref(spyee_autochan->chan);
616  ast_autochan_channel_unlock(spyee_autochan);
617  bridged = ast_channel_bridge_peer(spyee_chan);
618  ast_channel_unref(spyee_chan);
619  if (!bridged) {
620  return -1;
621  }
622 
623  ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
624 
625  internal_bridge_autochan = ast_autochan_setup(bridged);
626  if (!internal_bridge_autochan) {
627  return -1;
628  }
629 
630  if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
631  ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
632  retval = -1;
633  }
634 
635  *spyee_bridge_autochan = internal_bridge_autochan;
636 
637  return retval;
638 }
Main Channel structure associated with a channel.
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define LOG_WARNING
Definition: logger.h:274
struct ast_channel * chan
Definition: autochan.h:33
#define NULL
Definition: resample.c:96
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:108
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:2992
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:507
static const char name[]
Definition: cdr_mysql.c:74
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2970
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel&#39;s bridge peer only if the bridge is two-party.
Definition: channel.c:10765
static ENTRY retval
Definition: hsearch.c:50
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84

◆ change_spy_mode()

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

Definition at line 530 of file app_chanspy.c.

References ast_clear_flag, ast_set_flag, OPTION_BARGE, and OPTION_WHISPER.

Referenced by channel_spy().

531 {
532  if (digit == '4') {
535  } else if (digit == '5') {
538  } else if (digit == '6') {
540  ast_set_flag(flags, OPTION_BARGE);
541  }
542 }
char digit
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_clear_flag(p, flag)
Definition: utils.h:77

◆ channel_spy()

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 640 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_channel_lock, ast_autochan_channel_unlock, ast_autochan_destroy(), ast_channel_clear_flag(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_set_flag(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_check_hangup(), 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_read(), ast_strdupa, ast_strlen_zero, ast_test_flag, ast_verb, ast_waitfor(), attach_barge(), chanspy_translation_helper::bridge_whisper_audiohook, ast_autochan::chan, change_spy_mode(), spy_dtmf_options::cycle, spy_dtmf_options::exit, chanspy_translation_helper::fd, chanspy_translation_helper::flags, ast_frame::frametype, ast_frame_subclass::integer, LOG_WARNING, name, NULL, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, ast_audiohook::options, pbx_builtin_setvar_helper(), publish_chanspy_message(), ast_audiohook_options::read_volume, chanspy_translation_helper::spy_audiohook, start_spying(), ast_audiohook::status, ast_frame::subclass, tmp(), chanspy_translation_helper::volfactor, spy_dtmf_options::volume, chanspy_translation_helper::whisper_audiohook, and ast_audiohook_options::write_volume.

Referenced by common_exec().

643 {
644  struct chanspy_translation_helper csth;
645  int running = 0, bridge_connected = 0, res, x = 0;
646  char inp[24] = {0};
647  char *name;
648  struct ast_frame *f;
649  struct ast_silence_generator *silgen = NULL;
650  struct ast_autochan *spyee_bridge_autochan = NULL;
651  const char *spyer_name;
652 
653  ast_channel_lock(chan);
654  if (ast_check_hangup(chan)) {
655  ast_channel_unlock(chan);
656  return 0;
657  }
658  spyer_name = ast_strdupa(ast_channel_name(chan));
659  ast_channel_unlock(chan);
660 
661  ast_autochan_channel_lock(spyee_autochan);
662  if (ast_check_hangup(spyee_autochan->chan)
663  || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
664  ast_autochan_channel_unlock(spyee_autochan);
665  return 0;
666  }
667  name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
668 
669  ast_verb(2, "Spying on channel %s\n", name);
670  publish_chanspy_message(chan, spyee_autochan->chan, 1);
671  ast_autochan_channel_unlock(spyee_autochan);
672 
673  memset(&csth, 0, sizeof(csth));
674  ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
675 
676  /* This is the audiohook which gives us the audio off the channel we are
677  spying on.
678  */
679  ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
680 
681  if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
682  ast_audiohook_destroy(&csth.spy_audiohook);
683  return 0;
684  }
685 
687  /* This audiohook will let us inject audio from our channel into the
688  channel we are currently spying on.
689  */
690  ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
691 
692  if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
693  ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
694  }
695  }
696 
698 
699  csth.volfactor = *volfactor;
700 
701  if (csth.volfactor) {
702  csth.spy_audiohook.options.read_volume = csth.volfactor;
703  csth.spy_audiohook.options.write_volume = csth.volfactor;
704  }
705 
706  csth.fd = fd;
707 
708  if (ast_test_flag(flags, OPTION_PRIVATE))
710  else
711  ast_activate_generator(chan, &spygen, &csth);
712 
713  /* We can no longer rely on 'spyee' being an actual channel;
714  it can be hung up and freed out from under us. However, the
715  channel destructor will put NULL into our csth.spy.chan
716  field when that happens, so that is our signal that the spyee
717  channel has gone away.
718  */
719 
720  /* Note: it is very important that the ast_waitfor() be the first
721  condition in this expression, so that if we wait for some period
722  of time before receiving a frame from our spying channel, we check
723  for hangup on the spied-on channel _after_ knowing that a frame
724  has arrived, since the spied-on channel could have gone away while
725  we were waiting
726  */
727  while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
728  if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
729  running = -1;
730  if (f) {
731  ast_frfree(f);
732  }
733  break;
734  }
735 
736  if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
737  /* This hook lets us inject audio into the channel that the spyee is currently
738  * bridged with. If the spyee isn't bridged with anything yet, nothing will
739  * be attached and we'll need to continue attempting to attach the barge
740  * audio hook. */
741  if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
742  &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
743  bridge_connected = 1;
744  }
745 
746  ast_audiohook_lock(&csth.whisper_audiohook);
747  ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
748  ast_audiohook_unlock(&csth.whisper_audiohook);
749 
750  if (bridge_connected) {
751  ast_audiohook_lock(&csth.bridge_whisper_audiohook);
752  ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
753  ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
754  }
755 
756  ast_frfree(f);
757  continue;
758  } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
759  ast_audiohook_lock(&csth.whisper_audiohook);
760  ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
761  ast_audiohook_unlock(&csth.whisper_audiohook);
762  ast_frfree(f);
763  continue;
764  }
765 
766  res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
767  ast_frfree(f);
768  if (!res)
769  continue;
770 
771  if (x == sizeof(inp))
772  x = 0;
773 
774  if (res < 0) {
775  running = -1;
776  break;
777  }
778 
779  if (ast_test_flag(flags, OPTION_EXIT)) {
780  char tmp[2];
781  tmp[0] = res;
782  tmp[1] = '\0';
783  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
784  ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
785  pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
786  running = -2;
787  break;
788  } else {
789  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
790  }
791  } else if (res >= '0' && res <= '9') {
793  change_spy_mode(res, flags);
794  } else {
795  inp[x++] = res;
796  }
797  }
798 
799  if (res == user_options->cycle) {
800  running = 0;
801  break;
802  } else if (res == user_options->exit) {
803  running = -2;
804  break;
805  } else if (res == user_options->volume) {
806  if (!ast_strlen_zero(inp)) {
807  running = atoi(inp);
808  break;
809  }
810 
811  (*volfactor)++;
812  if (*volfactor > 4)
813  *volfactor = -4;
814  ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
815 
816  csth.volfactor = *volfactor;
817  csth.spy_audiohook.options.read_volume = csth.volfactor;
818  csth.spy_audiohook.options.write_volume = csth.volfactor;
819  }
820  }
821 
822  if (ast_test_flag(flags, OPTION_PRIVATE))
824  else
826 
828 
830  ast_audiohook_lock(&csth.whisper_audiohook);
831  ast_audiohook_detach(&csth.whisper_audiohook);
832  ast_audiohook_unlock(&csth.whisper_audiohook);
833  ast_audiohook_destroy(&csth.whisper_audiohook);
834  }
835 
837  ast_audiohook_lock(&csth.bridge_whisper_audiohook);
838  ast_audiohook_detach(&csth.bridge_whisper_audiohook);
839  ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
840  ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
841  }
842 
843  ast_audiohook_lock(&csth.spy_audiohook);
844  ast_audiohook_detach(&csth.spy_audiohook);
845  ast_audiohook_unlock(&csth.spy_audiohook);
846  ast_audiohook_destroy(&csth.spy_audiohook);
847 
848  ast_verb(2, "Done Spying on channel %s\n", name);
849  publish_chanspy_message(chan, spyee_autochan->chan, 0);
850 
851  if (spyee_bridge_autochan) {
852  ast_autochan_destroy(spyee_bridge_autochan);
853  }
854 
855  return running;
856 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
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:170
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
#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:2960
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Definition: channel.c:11235
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4302
struct ast_channel * chan
Definition: autochan.h:33
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define NULL
Definition: resample.c:96
#define AST_FRAME_DTMF
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
#define ast_verb(level,...)
Definition: logger.h:463
struct ast_frame_subclass subclass
static int attach_barge(struct ast_autochan *spyee_autochan, struct ast_autochan **spyee_bridge_autochan, struct ast_audiohook *bridge_whisper_audiohook, const char *spyer_name, const char *name, struct ast_flags *flags)
Definition: app_chanspy.c:605
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:108
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8266
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
static struct ast_generator spygen
Definition: app_chanspy.c:501
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:565
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11228
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:507
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
#define ast_channel_unlock(chan)
Definition: channel.h:2946
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:8312
static const char name[]
Definition: cdr_mysql.c:74
#define AST_FLAGS_ALL
Definition: utils.h:196
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
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...
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2902
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:530
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3171
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_frfree(fr)
Data structure associated with a single frame of data.
enum ast_frame_type frametype
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295

◆ chanspy_exec()

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

Definition at line 1203 of file app_chanspy.c.

References ao2_bump, ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), ast_channel_writeformat(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, ast_format_slin, 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, chanspy_translation_helper::fd, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, NULL, 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, options, parse(), PATH_MAX, RAII_VAR, spy_opts, tmp(), and chanspy_translation_helper::volfactor.

Referenced by load_module().

1204 {
1205  char *myenforced = NULL;
1206  char *mygroup = NULL;
1207  char *recbase = NULL;
1208  int fd = 0;
1209  struct ast_flags flags;
1210  struct spy_dtmf_options user_options = {
1211  .cycle = '*',
1212  .volume = '#',
1213  .exit = '\0',
1214  };
1215  RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1216  int volfactor = 0;
1217  int res;
1218  char *mailbox = NULL;
1219  char *name_context = NULL;
1221  AST_APP_ARG(spec);
1223  );
1224  char *opts[OPT_ARG_ARRAY_SIZE];
1225  char *parse = ast_strdupa(data);
1226 
1227  AST_STANDARD_APP_ARGS(args, parse);
1228 
1229  if (args.spec && !strcmp(args.spec, "all"))
1230  args.spec = NULL;
1231 
1232  if (args.options) {
1233  char tmp;
1234  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1235  if (ast_test_flag(&flags, OPTION_GROUP))
1236  mygroup = opts[OPT_ARG_GROUP];
1237 
1238  if (ast_test_flag(&flags, OPTION_RECORD) &&
1239  !(recbase = opts[OPT_ARG_RECORD]))
1240  recbase = "chanspy";
1241 
1242  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1243  tmp = opts[OPT_ARG_EXIT][0];
1244  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1245  user_options.exit = tmp;
1246  } else {
1247  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1248  }
1249  }
1250 
1251  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1252  tmp = opts[OPT_ARG_CYCLE][0];
1253  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1254  user_options.cycle = tmp;
1255  } else {
1256  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1257  }
1258  }
1259 
1260  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1261  int vol;
1262 
1263  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1264  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1265  else
1266  volfactor = vol;
1267  }
1268 
1269  if (ast_test_flag(&flags, OPTION_PRIVATE))
1270  ast_set_flag(&flags, OPTION_WHISPER);
1271 
1272  if (ast_test_flag(&flags, OPTION_ENFORCED))
1273  myenforced = opts[OPT_ARG_ENFORCED];
1274 
1275  if (ast_test_flag(&flags, OPTION_NAME)) {
1276  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1277  char *delimiter;
1278  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1279  mailbox = opts[OPT_ARG_NAME];
1280  *delimiter++ = '\0';
1281  name_context = delimiter;
1282  } else {
1283  mailbox = opts[OPT_ARG_NAME];
1284  }
1285  }
1286  }
1287  } else {
1288  ast_clear_flag(&flags, AST_FLAGS_ALL);
1289  }
1290 
1291  oldwf = ao2_bump(ast_channel_writeformat(chan));
1292  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1293  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1294  return -1;
1295  }
1296 
1297  if (recbase) {
1298  char filename[PATH_MAX];
1299 
1300  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1301  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1302  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1303  fd = 0;
1304  }
1305  }
1306 
1307  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1308 
1309  if (fd)
1310  close(fd);
1311 
1312  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1313  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1314 
1315  if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1316  ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1317  }
1318 
1319  return res;
1320 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
const char * args
#define NULL
Definition: resample.c:96
#define AST_FILE_MODE
Definition: asterisk.h:32
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
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: main/app.c:2906
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:430
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:892
#define PATH_MAX
Definition: asterisk.h:40
static struct test_options options
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ common_exec()

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

References ARRAY_LEN, ast_answer(), ast_app_separate_args, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_autochan_destroy(), ast_autochan_setup(), ast_channel_clear_flag(), ast_channel_context(), ast_channel_flags(), ast_channel_get_by_name(), ast_channel_get_by_name_prefix(), ast_channel_is_bridged(), ast_channel_iterator_all_new(), ast_channel_iterator_by_exten_new(), ast_channel_iterator_by_name_new(), ast_channel_iterator_destroy(), ast_channel_language(), ast_channel_lock, ast_channel_macrocontext(), AST_CHANNEL_NAME, ast_channel_name(), ast_channel_set_flag(), ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), 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_CASE_NONE, ast_say_character_str(), ast_say_digits(), AST_STATE_UP, ast_streamfile(), ast_strlen_zero, ast_test_flag, ast_waitfordigit(), ast_waitstream(), c, ast_autochan::chan, channel_spy(), end, exitcontext, ext, next_channel(), NULL, NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_DAHDI_SCAN, OPTION_EXIT, OPTION_EXITONHANGUP, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, OPTION_STOP, OPTION_UNIQUEID, pbx_builtin_getvar_helper(), S_OR, spy_sayname(), strcasestr(), tmp(), and ast_channel::x.

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

896 {
897  char nameprefix[AST_NAME_STRLEN];
898  char exitcontext[AST_MAX_CONTEXT] = "";
899  signed char zero_volume = 0;
900  int waitms;
901  int res;
902  int num_spyed_upon = 1;
903  struct ast_channel_iterator *iter = NULL;
904 
905  if (ast_test_flag(flags, OPTION_EXIT)) {
906  const char *c;
907  ast_channel_lock(chan);
908  if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
909  ast_copy_string(exitcontext, c, sizeof(exitcontext));
910  } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
911  ast_copy_string(exitcontext, ast_channel_macrocontext(chan), sizeof(exitcontext));
912  } else {
913  ast_copy_string(exitcontext, ast_channel_context(chan), sizeof(exitcontext));
914  }
915  ast_channel_unlock(chan);
916  }
917 
918  if (ast_channel_state(chan) != AST_STATE_UP)
919  ast_answer(chan);
920 
922 
923  waitms = 100;
924 
925  for (;;) {
926  struct ast_autochan *autochan = NULL, *next_autochan = NULL;
927  struct ast_channel *prev = NULL;
928 
929  if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
930  res = ast_streamfile(chan, "beep", ast_channel_language(chan));
931  if (!res)
932  res = ast_waitstream(chan, "");
933  else if (res < 0) {
935  break;
936  }
937  if (!ast_strlen_zero(exitcontext)) {
938  char tmp[2];
939  tmp[0] = res;
940  tmp[1] = '\0';
941  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
942  goto exit;
943  else
944  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
945  }
946  }
947 
948  /* Set up the iterator we'll be using during this call */
949  if (!ast_strlen_zero(spec)) {
950  if (ast_test_flag(flags, OPTION_UNIQUEID)) {
951  struct ast_channel *unique_chan;
952 
953  unique_chan = ast_channel_get_by_name(spec);
954  if (!unique_chan) {
955  res = -1;
956  goto exit;
957  }
958  iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
959  ast_channel_unref(unique_chan);
960  } else {
961  iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
962  }
963  } else if (!ast_strlen_zero(exten)) {
965  } else {
967  }
968 
969  if (!iter) {
970  res = -1;
971  goto exit;
972  }
973 
974  res = ast_waitfordigit(chan, waitms);
975  if (res < 0) {
976  iter = ast_channel_iterator_destroy(iter);
978  break;
979  }
980  if (!ast_strlen_zero(exitcontext)) {
981  char tmp[2];
982  tmp[0] = res;
983  tmp[1] = '\0';
984  if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
985  iter = ast_channel_iterator_destroy(iter);
986  goto exit;
987  } else {
988  ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
989  }
990  }
991 
992  /* reset for the next loop around, unless overridden later */
993  waitms = 100;
994  num_spyed_upon = 0;
995 
996  for (autochan = next_channel(iter, chan);
997  autochan;
998  prev = autochan->chan,
999  ast_autochan_destroy(autochan),
1000  autochan = next_autochan ?: next_channel(iter, chan),
1001  next_autochan = NULL) {
1002  int igrp = !mygroup;
1003  int ienf = !myenforced;
1004 
1005  if (autochan->chan == prev) {
1006  ast_autochan_destroy(autochan);
1007  break;
1008  }
1009 
1010  if (ast_check_hangup(chan)) {
1011  ast_autochan_destroy(autochan);
1012  break;
1013  }
1014 
1015  ast_autochan_channel_lock(autochan);
1016  if (ast_test_flag(flags, OPTION_BRIDGED)
1017  && !ast_channel_is_bridged(autochan->chan)) {
1018  ast_autochan_channel_unlock(autochan);
1019  continue;
1020  }
1021 
1022  if (ast_check_hangup(autochan->chan)
1024  ast_autochan_channel_unlock(autochan);
1025  continue;
1026  }
1027  ast_autochan_channel_unlock(autochan);
1028 
1029  if (mygroup) {
1030  int num_groups = 0;
1031  int num_mygroups = 0;
1032  char dup_group[512];
1033  char dup_mygroup[512];
1034  char *groups[NUM_SPYGROUPS];
1035  char *mygroups[NUM_SPYGROUPS];
1036  const char *group = NULL;
1037  int x;
1038  int y;
1039  ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1040  num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1041  ARRAY_LEN(mygroups));
1042 
1043  /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1044  * rather than "SPYGROUP", this check is done to preserve expected behavior */
1045  ast_autochan_channel_lock(autochan);
1046  if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
1047  group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1048  } else {
1049  group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1050  }
1051  ast_autochan_channel_unlock(autochan);
1052 
1053  if (!ast_strlen_zero(group)) {
1054  ast_copy_string(dup_group, group, sizeof(dup_group));
1055  num_groups = ast_app_separate_args(dup_group, ':', groups,
1056  ARRAY_LEN(groups));
1057  }
1058 
1059  for (y = 0; y < num_mygroups; y++) {
1060  for (x = 0; x < num_groups; x++) {
1061  if (!strcmp(mygroups[y], groups[x])) {
1062  igrp = 1;
1063  break;
1064  }
1065  }
1066  }
1067  }
1068 
1069  if (!igrp) {
1070  continue;
1071  }
1072  if (myenforced) {
1073  char ext[AST_CHANNEL_NAME + 3];
1074  char buffer[512];
1075  char *end;
1076 
1077  snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1078 
1079  ast_autochan_channel_lock(autochan);
1080  ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1081  ast_autochan_channel_unlock(autochan);
1082  if ((end = strchr(ext, '-'))) {
1083  *end++ = ':';
1084  *end = '\0';
1085  }
1086 
1087  ext[0] = ':';
1088 
1089  if (strcasestr(buffer, ext)) {
1090  ienf = 1;
1091  }
1092  }
1093 
1094  if (!ienf) {
1095  continue;
1096  }
1097 
1098  if (!ast_test_flag(flags, OPTION_QUIET)) {
1099  char peer_name[AST_NAME_STRLEN + 5];
1100  char *ptr, *s;
1101 
1102  strcpy(peer_name, "spy-");
1103  ast_autochan_channel_lock(autochan);
1104  strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1105  ast_autochan_channel_unlock(autochan);
1106  if ((ptr = strchr(peer_name, '/'))) {
1107  *ptr++ = '\0';
1108  for (s = peer_name; s < ptr; s++) {
1109  *s = tolower(*s);
1110  }
1111  if ((s = strchr(ptr, '-'))) {
1112  *s = '\0';
1113  }
1114  }
1115 
1116  if (ast_test_flag(flags, OPTION_NAME)) {
1117  const char *local_context = S_OR(name_context, "default");
1118  const char *local_mailbox = S_OR(mailbox, ptr);
1119 
1120  if (local_mailbox) {
1121  res = spy_sayname(chan, local_mailbox, local_context);
1122  } else {
1123  res = -1;
1124  }
1125  }
1126  if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1127  int num;
1128  if (!ast_test_flag(flags, OPTION_NOTECH)) {
1129  if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1130  res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1131  if (!res) {
1132  res = ast_waitstream(chan, "");
1133  }
1134  if (res) {
1135  ast_autochan_destroy(autochan);
1136  break;
1137  }
1138  } else {
1139  res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1140  }
1141  }
1142  if (ptr && (num = atoi(ptr))) {
1143  ast_say_digits(chan, num, "", ast_channel_language(chan));
1144  }
1145  }
1146  }
1147 
1148  res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1149  num_spyed_upon++;
1150 
1151  if (res == -1) {
1152  ast_autochan_destroy(autochan);
1153  iter = ast_channel_iterator_destroy(iter);
1154  goto exit;
1155  } else if (res == -2) {
1156  res = 0;
1157  ast_autochan_destroy(autochan);
1158  iter = ast_channel_iterator_destroy(iter);
1159  goto exit;
1160  } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1161  struct ast_channel *next;
1162 
1163  snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1164 
1165  if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1166  next_autochan = ast_autochan_setup(next);
1167  next = ast_channel_unref(next);
1168  } else {
1169  /* stay on this channel, if it is still valid */
1170  ast_autochan_channel_lock(autochan);
1171  if (!ast_check_hangup(autochan->chan)) {
1172  next_autochan = ast_autochan_setup(autochan->chan);
1173  } else {
1174  /* the channel is gone */
1175  next_autochan = NULL;
1176  }
1177  ast_autochan_channel_unlock(autochan);
1178  }
1179  } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1180  ast_autochan_destroy(autochan);
1181  iter = ast_channel_iterator_destroy(iter);
1182  goto exit;
1183  }
1184  }
1185 
1186  iter = ast_channel_iterator_destroy(iter);
1187 
1188  if (res == -1 || ast_check_hangup(chan))
1189  break;
1190  if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1191  break;
1192  }
1193  }
1194 exit:
1195 
1197 
1198  ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1199 
1200  return res;
1201 }
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:858
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
#define NUM_SPYGROUPS
Definition: app_chanspy.c:61
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1250
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define AST_OPTION_TXGAIN
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
#define ast_test_flag(p, flag)
Definition: utils.h:63
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:640
static int tmp()
Definition: bt_open.c:389
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Definition: channel.c:11235
ast_channel_state
ast_channel states
Definition: channelstate.h:35
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8349
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Definition: app_chanspy.c:883
struct ast_channel * chan
Definition: autochan.h:33
static struct test_val c
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
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:7522
const char * ext
Definition: http.c:147
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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:1434
#define ast_strlen_zero(foo)
Definition: strings.h:52
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
static char exitcontext[AST_MAX_CONTEXT]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_NAME_STRLEN
Definition: app_chanspy.c:60
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
Definition: channel.c:8367
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition: channel.c:11228
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:1368
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8793
char * strcasestr(const char *, const char *)
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10746
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define AST_CHANNEL_NAME
Definition: channel.h:172
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:1388
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3184
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1776
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1360
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2814
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
char x
Definition: extconf.c:81
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1408
const char * ast_channel_macrocontext(const struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1454
#define ast_app_separate_args(a, b, c, d)

◆ dahdiscan_exec()

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

Definition at line 1443 of file app_chanspy.c.

References ao2_bump, ao2_cleanup, ast_channel_writeformat(), ast_clear_flag, AST_FLAGS_ALL, ast_format_slin, ast_log, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero, common_exec(), spy_dtmf_options::cycle, LOG_ERROR, NULL, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, and OPTION_DTMF_EXIT.

Referenced by load_module().

1444 {
1445  const char *spec = "DAHDI";
1446  struct ast_flags flags = {0};
1447  struct spy_dtmf_options user_options = {
1448  .cycle = '#',
1449  .volume = '\0',
1450  .exit = '*',
1451  };
1452  struct ast_format *oldwf;
1453  int res;
1454  char *mygroup = NULL;
1455 
1456  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1457  ast_clear_flag(&flags, AST_FLAGS_ALL);
1458 
1459  if (!ast_strlen_zero(data)) {
1460  mygroup = ast_strdupa(data);
1461  }
1462  ast_set_flag(&flags, OPTION_DTMF_EXIT);
1465 
1466  oldwf = ao2_bump(ast_channel_writeformat(chan));
1467  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1468  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1469  ao2_cleanup(oldwf);
1470  return -1;
1471  }
1472 
1473  res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1474 
1475  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1476  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1477  ao2_cleanup(oldwf);
1478 
1479  return res;
1480 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
#define LOG_ERROR
Definition: logger.h:285
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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:892
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)

◆ extenspy_exec()

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

Definition at line 1322 of file app_chanspy.c.

References ao2_bump, ao2_cleanup, args, AST_APP_ARG, ast_app_parse_options(), ast_channel_context(), ast_channel_writeformat(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, ast_format_slin, ast_log, ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, common_exec(), context, spy_dtmf_options::cycle, spy_dtmf_options::exit, exten, chanspy_translation_helper::fd, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, NULL, 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, options, parse(), PATH_MAX, RAII_VAR, spy_opts, tmp(), and chanspy_translation_helper::volfactor.

Referenced by load_module().

1323 {
1324  char *ptr, *exten = NULL;
1325  char *mygroup = NULL;
1326  char *recbase = NULL;
1327  int fd = 0;
1328  struct ast_flags flags;
1329  struct spy_dtmf_options user_options = {
1330  .cycle = '*',
1331  .volume = '#',
1332  .exit = '\0',
1333  };
1334  RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1335  int volfactor = 0;
1336  int res;
1337  char *mailbox = NULL;
1338  char *name_context = NULL;
1342  );
1343  char *parse = ast_strdupa(data);
1344 
1345  AST_STANDARD_APP_ARGS(args, parse);
1346 
1347  if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1348  exten = args.context;
1349  *ptr++ = '\0';
1350  args.context = ptr;
1351  }
1352  if (ast_strlen_zero(args.context))
1353  args.context = ast_strdupa(ast_channel_context(chan));
1354 
1355  if (args.options) {
1356  char *opts[OPT_ARG_ARRAY_SIZE];
1357  char tmp;
1358 
1359  ast_app_parse_options(spy_opts, &flags, opts, args.options);
1360  if (ast_test_flag(&flags, OPTION_GROUP))
1361  mygroup = opts[OPT_ARG_GROUP];
1362 
1363  if (ast_test_flag(&flags, OPTION_RECORD) &&
1364  !(recbase = opts[OPT_ARG_RECORD]))
1365  recbase = "chanspy";
1366 
1367  if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1368  tmp = opts[OPT_ARG_EXIT][0];
1369  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1370  user_options.exit = tmp;
1371  } else {
1372  ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1373  }
1374  }
1375 
1376  if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1377  tmp = opts[OPT_ARG_CYCLE][0];
1378  if (strchr("0123456789*#", tmp) && tmp != '\0') {
1379  user_options.cycle = tmp;
1380  } else {
1381  ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1382  }
1383  }
1384 
1385  if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1386  int vol;
1387 
1388  if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1389  ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1390  else
1391  volfactor = vol;
1392  }
1393 
1394  if (ast_test_flag(&flags, OPTION_PRIVATE))
1395  ast_set_flag(&flags, OPTION_WHISPER);
1396 
1397  if (ast_test_flag(&flags, OPTION_NAME)) {
1398  if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1399  char *delimiter;
1400  if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1401  mailbox = opts[OPT_ARG_NAME];
1402  *delimiter++ = '\0';
1403  name_context = delimiter;
1404  } else {
1405  mailbox = opts[OPT_ARG_NAME];
1406  }
1407  }
1408  }
1409 
1410  } else {
1411  /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1412  ast_clear_flag(&flags, AST_FLAGS_ALL);
1413  }
1414 
1415  oldwf = ao2_bump(ast_channel_writeformat(chan));
1416  if (ast_set_write_format(chan, ast_format_slin) < 0) {
1417  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1418  return -1;
1419  }
1420 
1421  if (recbase) {
1422  char filename[PATH_MAX];
1423 
1424  snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1425  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1426  ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1427  fd = 0;
1428  }
1429  }
1430 
1431 
1432  res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1433 
1434  if (fd)
1435  close(fd);
1436 
1437  if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1438  ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1439 
1440  return res;
1441 }
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int tmp()
Definition: bt_open.c:389
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
const char * args
#define NULL
Definition: resample.c:96
#define AST_FILE_MODE
Definition: asterisk.h:32
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ao2_bump(obj)
Definition: astobj2.h:491
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5890
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: main/app.c:2906
#define LOG_ERROR
Definition: logger.h:285
#define LOG_NOTICE
Definition: logger.h:263
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:430
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_context(const struct ast_channel *chan)
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:892
#define PATH_MAX
Definition: asterisk.h:40
static struct test_options options
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1493 of file app_chanspy.c.

References app_chan, app_dahdiscan, app_ext, ast_register_application_xml, chanspy_exec(), dahdiscan_exec(), and extenspy_exec().

1494 {
1495  int res = 0;
1496 
1500 
1501  return res;
1502 }
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1443
static const char app_chan[]
Definition: app_chanspy.c:368
static const char app_ext[]
Definition: app_chanspy.c:370
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1322
static const char app_dahdiscan[]
Definition: app_chanspy.c:372
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1203
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ next_channel()

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

Definition at line 858 of file app_chanspy.c.

References ast_autochan_setup(), ast_channel_iterator_next(), ast_channel_name(), ast_channel_unref, ast_autochan::chan, and NULL.

Referenced by common_exec().

860 {
861  struct ast_channel *next;
862  struct ast_autochan *autochan_store;
863  const size_t pseudo_len = strlen("DAHDI/pseudo");
864 
865  if (!iter) {
866  return NULL;
867  }
868 
869  for (; (next = ast_channel_iterator_next(iter)); ast_channel_unref(next)) {
870  if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
871  || next == chan) {
872  continue;
873  }
874 
875  autochan_store = ast_autochan_setup(next);
876  ast_channel_unref(next);
877 
878  return autochan_store;
879  }
880  return NULL;
881 }
Main Channel structure associated with a channel.
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1422
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2981
struct ast_channel * chan
Definition: autochan.h:33
#define NULL
Definition: resample.c:96
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
const char * ast_channel_name(const struct ast_channel *chan)

◆ pack_channel_into_message()

static int pack_channel_into_message ( struct ast_channel chan,
const char *  role,
struct ast_multi_channel_blob payload 
)
static

Definition at line 544 of file app_chanspy.c.

References ao2_cleanup, ast_channel_snapshot_get_latest(), ast_channel_uniqueid(), ast_multi_channel_blob_add_channel(), and RAII_VAR.

Referenced by publish_chanspy_message().

546 {
547  RAII_VAR(struct ast_channel_snapshot *, snapshot,
549  ao2_cleanup);
550 
551  if (!snapshot) {
552  return -1;
553  }
554  ast_multi_channel_blob_add_channel(payload, role, snapshot);
555  return 0;
556 }
Structure representing a snapshot of channel state.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ publish_chanspy_message()

static void publish_chanspy_message ( struct ast_channel spyer,
struct ast_channel spyee,
int  start 
)
static

Definition at line 565 of file app_chanspy.c.

References ao2_cleanup, ast_channel_chanspy_start_type(), ast_channel_chanspy_stop_type(), ast_channel_topic(), ast_json_null(), ast_json_unref(), ast_log, AST_LOG_WARNING, ast_multi_channel_blob_create(), NULL, pack_channel_into_message(), RAII_VAR, stasis_message_create(), stasis_publish(), and type.

Referenced by channel_spy().

568 {
569  RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
570  RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
573 
574  if (!spyer) {
575  ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
576  return;
577  }
578  blob = ast_json_null();
579  if (!blob || !type) {
580  return;
581  }
582 
583  payload = ast_multi_channel_blob_create(blob);
584  if (!payload) {
585  return;
586  }
587 
588  if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
589  return;
590  }
591 
592  if (spyee) {
593  if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
594  return;
595  }
596  }
597 
598  message = stasis_message_create(type, payload);
599  if (!message) {
600  return;
601  }
603 }
static const char type[]
Definition: chan_ooh323.c:109
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
#define AST_LOG_WARNING
Definition: logger.h:279
struct stasis_message_type * ast_channel_chanspy_start_type(void)
Message type for when a channel starts spying on another channel.
#define NULL
Definition: resample.c:96
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1511
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:544
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
A multi channel blob data structure for multi_channel_blob stasis messages.
Abstract JSON element (object, array, string, int, ...).
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.

◆ spy_alloc()

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

Definition at line 448 of file app_chanspy.c.

449 {
450  /* just store the data pointer in the channel structure */
451  return data;
452 }

◆ spy_generate()

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

Definition at line 459 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_slin, ast_frfree, AST_LIST_NEXT, ast_log, ast_test_flag, ast_write(), ast_frame::data, ast_frame::datalen, errno, chanspy_translation_helper::fd, chanspy_translation_helper::flags, LOG_WARNING, OPTION_READONLY, ast_frame::ptr, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.

460 {
461  struct chanspy_translation_helper *csth = data;
462  struct ast_frame *f, *cur;
463 
466  /* Channel is already gone more than likely */
468  return -1;
469  }
470 
471  if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
472  /* Option 'o' was set, so don't mix channel audio */
474  } else {
476  }
477 
479 
480  if (!f)
481  return 0;
482 
483  for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
484  if (ast_write(chan, cur)) {
485  ast_frfree(f);
486  return -1;
487  }
488 
489  if (csth->fd) {
490  if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
491  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
492  }
493  }
494  }
495 
496  ast_frfree(f);
497 
498  return 0;
499 }
struct ast_flags flags
Definition: app_chanspy.c:439
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:434
#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:300
#define ast_log
Definition: astobj2.c:42
int errno
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:5189
#define ast_frfree(fr)
Data structure associated with a single frame of data.
enum ast_audiohook_status status
Definition: audiohook.h:107
union ast_frame::@263 data
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
struct ast_frame * ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
Reads a frame in from the audiohook structure.
Definition: audiohook.c:449

◆ spy_release()

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

Definition at line 454 of file app_chanspy.c.

455 {
456  /* nothing to do */
457 }

◆ spy_sayname()

static int spy_sayname ( struct ast_channel chan,
const char *  mailbox,
const char *  context 
)
static

Definition at line 883 of file app_chanspy.c.

References ast_alloca, and ast_app_sayname().

Referenced by common_exec().

884 {
885  char *mailbox_id;
886 
887  mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
888  sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
889  return ast_app_sayname(chan, mailbox_id);
890 }
int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
Play a recorded user name for the mailbox to the specified channel.
Definition: main/app.c:710
static char mailbox[AST_MAX_MAILBOX_UNIQUEID]
Definition: chan_mgcp.c:204
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ start_spying()

static int start_spying ( struct ast_autochan autochan,
const char *  spychan_name,
struct ast_audiohook audiohook,
struct ast_flags flags 
)
static

Definition at line 507 of file app_chanspy.c.

References ast_audiohook_attach(), AST_AUDIOHOOK_MUTE_WRITE, AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_autochan_channel_lock, ast_autochan_channel_unlock, ast_channel_name(), ast_debug, ast_set_flag, ast_test_flag, ast_verb, ast_autochan::chan, OPTION_LONG_QUEUE, and OPTION_READONLY.

Referenced by attach_barge(), and channel_spy().

508 {
509  int res;
510 
511  ast_autochan_channel_lock(autochan);
512  ast_verb(3, "Attaching spy channel %s to %s\n",
513  spychan_name, ast_channel_name(autochan->chan));
514 
515  if (ast_test_flag(flags, OPTION_READONLY)) {
517  } else {
519  }
520  if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
521  ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
522  } else {
524  }
525  res = ast_audiohook_attach(autochan->chan, audiohook);
526  ast_autochan_channel_unlock(autochan);
527  return res;
528 }
#define ast_autochan_channel_lock(autochan)
Lock the autochan&#39;s channel lock.
Definition: autochan.h:75
#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:501
struct ast_channel * chan
Definition: autochan.h:33
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1482 of file app_chanspy.c.

References app_chan, app_dahdiscan, app_ext, and ast_unregister_application().

1483 {
1484  int res = 0;
1485 
1489 
1490  return res;
1491 }
static const char app_chan[]
Definition: app_chanspy.c:368
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static const char app_ext[]
Definition: app_chanspy.c:370
static const char app_dahdiscan[]
Definition: app_chanspy.c:372

Variable Documentation

◆ __mod_info

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, .support_level = AST_MODULE_SUPPORT_CORE, }
static

Definition at line 1504 of file app_chanspy.c.

◆ app_chan

const char app_chan[] = "ChanSpy"
static

Definition at line 368 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_dahdiscan

const char app_dahdiscan[] = "DAHDIScan"
static

Definition at line 372 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_ext

const char app_ext[] = "ExtenSpy"
static

Definition at line 370 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1504 of file app_chanspy.c.

◆ spy_opts

const 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 }, [ 'l' ] = { .flag = OPTION_LONG_QUEUE }, [ '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 }, [ 'u' ] = { .flag = OPTION_UNIQUEID }, [ '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 430 of file app_chanspy.c.

Referenced by chanspy_exec(), and extenspy_exec().

◆ spygen

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:448
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:459
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:454

Definition at line 501 of file app_chanspy.c.