Asterisk - The Open Source Telephony Project GIT-master-2070bb5
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) , OPTION_INTERLEAVED = (1 << 21)
}
 
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 = AST_BUILDOPT_SUM, .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 }, [ 'D' ] = { .flag = OPTION_INTERLEAVED }, [ '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.

◆ NUM_SPYGROUPS

#define NUM_SPYGROUPS   128

Definition at line 61 of file app_chanspy.c.

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 
OPTION_INTERLEAVED 

Definition at line 379 of file app_chanspy.c.

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

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

404 {
405 OPT_ARG_VOLUME = 0,
413};
@ OPT_ARG_CYCLE
Definition: app_chanspy.c:411
@ OPT_ARG_RECORD
Definition: app_chanspy.c:407
@ OPT_ARG_EXIT
Definition: app_chanspy.c:410
@ OPT_ARG_NAME
Definition: app_chanspy.c:409
@ OPT_ARG_VOLUME
Definition: app_chanspy.c:405
@ OPT_ARG_ENFORCED
Definition: app_chanspy.c:408
@ OPT_ARG_ARRAY_SIZE
Definition: app_chanspy.c:412
@ OPT_ARG_GROUP
Definition: app_chanspy.c:406

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1560 of file app_chanspy.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1560 of file app_chanspy.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

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

666{
667 int retval = 0;
668 struct ast_autochan *internal_bridge_autochan;
669 struct ast_channel *spyee_chan;
670 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
671
672 ast_autochan_channel_lock(spyee_autochan);
673 spyee_chan = ast_channel_ref(spyee_autochan->chan);
674 ast_autochan_channel_unlock(spyee_autochan);
675 bridged = ast_channel_bridge_peer(spyee_chan);
676 ast_channel_unref(spyee_chan);
677 if (!bridged) {
678 return -1;
679 }
680
681 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
682
683 internal_bridge_autochan = ast_autochan_setup(bridged);
684 if (!internal_bridge_autochan) {
685 return -1;
686 }
687
688 if (start_spying(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
689 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
690 retval = -1;
691 }
692
693 *spyee_bridge_autochan = internal_bridge_autochan;
694
695 return retval;
696}
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:564
#define ast_log
Definition: astobj2.c:42
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:100
@ AST_AUDIOHOOK_TYPE_WHISPER
Definition: audiohook.h:37
struct ast_autochan * ast_autochan_setup(struct ast_channel *chan)
set up a new ast_autochan structure
Definition: autochan.c:38
#define ast_autochan_channel_lock(autochan)
Lock the autochan's channel lock.
Definition: autochan.h:75
#define ast_autochan_channel_unlock(autochan)
Definition: autochan.h:84
struct ast_channel * ast_channel_bridge_peer(struct ast_channel *chan)
Get the channel's bridge peer only if the bridge is two-party.
Definition: channel.c:10583
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3015
static const char name[]
Definition: format_mp3.c:68
static ENTRY retval
Definition: hsearch.c:50
#define LOG_WARNING
#define NULL
Definition: resample.c:96
struct ast_channel * chan
Definition: autochan.h:33
Main Channel structure associated with a channel.
struct ast_flags flags
#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:941

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, ast_channel::flags, LOG_WARNING, name, NULL, RAII_VAR, retval, and start_spying().

Referenced by channel_spy().

◆ change_spy_mode()

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

Definition at line 588 of file app_chanspy.c.

589{
590 if (digit == '4') {
593 } else if (digit == '5') {
596 } else if (digit == '6') {
599 }
600}
char digit
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70

References ast_clear_flag, ast_set_flag, digit, OPTION_BARGE, and OPTION_WHISPER.

Referenced by channel_spy().

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

701{
702 struct chanspy_translation_helper csth;
703 int running = 0, bridge_connected = 0, res, x = 0;
704 char inp[24] = {0};
705 char *name;
706 struct ast_frame *f;
707 struct ast_silence_generator *silgen = NULL;
708 struct ast_autochan *spyee_bridge_autochan = NULL;
709 const char *spyer_name;
710
712 if (ast_check_hangup(chan)) {
714 return 0;
715 }
716 spyer_name = ast_strdupa(ast_channel_name(chan));
718
719 ast_autochan_channel_lock(spyee_autochan);
720 if (ast_check_hangup(spyee_autochan->chan)
721 || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
722 ast_autochan_channel_unlock(spyee_autochan);
723 return 0;
724 }
725 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
726
727 ast_verb(2, "Spying on channel %s\n", name);
728 publish_chanspy_message(chan, spyee_autochan->chan, 1);
729 ast_autochan_channel_unlock(spyee_autochan);
730
731 memset(&csth, 0, sizeof(csth));
732 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
733
734 /* This is the audiohook which gives us the audio off the channel we are
735 spying on.
736 */
737 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
738
739 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
740 ast_audiohook_destroy(&csth.spy_audiohook);
741 return 0;
742 }
743
745 /* This audiohook will let us inject audio from our channel into the
746 channel we are currently spying on.
747 */
748 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
749
750 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
751 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
752 }
753 }
754
756
757 csth.volfactor = *volfactor;
758
759 if (csth.volfactor) {
760 csth.spy_audiohook.options.read_volume = csth.volfactor;
761 csth.spy_audiohook.options.write_volume = csth.volfactor;
762 }
763
764 csth.fd = fd;
765
766 if (ast_test_flag(flags, OPTION_PRIVATE))
768 else
770
771 /* We can no longer rely on 'spyee' being an actual channel;
772 it can be hung up and freed out from under us. However, the
773 channel destructor will put NULL into our csth.spy.chan
774 field when that happens, so that is our signal that the spyee
775 channel has gone away.
776 */
777
778 /* Note: it is very important that the ast_waitfor() be the first
779 condition in this expression, so that if we wait for some period
780 of time before receiving a frame from our spying channel, we check
781 for hangup on the spied-on channel _after_ knowing that a frame
782 has arrived, since the spied-on channel could have gone away while
783 we were waiting
784 */
785 while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
786 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
787 running = -1;
788 if (f) {
789 ast_frfree(f);
790 }
791 break;
792 }
793
795 /* This hook lets us inject audio into the channel that the spyee is currently
796 * bridged with. If the spyee isn't bridged with anything yet, nothing will
797 * be attached and we'll need to continue attempting to attach the barge
798 * audio hook. */
799 if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
800 &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
801 bridge_connected = 1;
802 }
803
804 ast_audiohook_lock(&csth.whisper_audiohook);
805 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
806 ast_audiohook_unlock(&csth.whisper_audiohook);
807
808 if (bridge_connected) {
809 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
810 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
811 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
812 }
813
814 ast_frfree(f);
815 continue;
816 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
817 ast_audiohook_lock(&csth.whisper_audiohook);
818 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
819 ast_audiohook_unlock(&csth.whisper_audiohook);
820 ast_frfree(f);
821 continue;
822 }
823
824 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
825 ast_frfree(f);
826 if (!res)
827 continue;
828
829 if (x == sizeof(inp))
830 x = 0;
831
832 if (res < 0) {
833 running = -1;
834 break;
835 }
836
837 if (ast_test_flag(flags, OPTION_EXIT)) {
838 char tmp[2];
839 tmp[0] = res;
840 tmp[1] = '\0';
842 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
843 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
844 running = -2;
845 break;
846 } else {
847 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
848 }
849 } else if (res >= '0' && res <= '9') {
851 change_spy_mode(res, flags);
852 } else {
853 inp[x++] = res;
854 }
855 }
856
857 if (res == user_options->cycle) {
858 running = 0;
859 break;
860 } else if (res == user_options->exit) {
861 running = -2;
862 break;
863 } else if (res == user_options->volume) {
864 if (!ast_strlen_zero(inp)) {
865 running = atoi(inp);
866 break;
867 }
868
869 (*volfactor)++;
870 if (*volfactor > 4)
871 *volfactor = -4;
872 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
873
874 csth.volfactor = *volfactor;
875 csth.spy_audiohook.options.read_volume = csth.volfactor;
876 csth.spy_audiohook.options.write_volume = csth.volfactor;
877 }
878 }
879
880 if (ast_test_flag(flags, OPTION_PRIVATE))
882 else
884
886
888 ast_audiohook_lock(&csth.whisper_audiohook);
889 ast_audiohook_detach(&csth.whisper_audiohook);
890 ast_audiohook_unlock(&csth.whisper_audiohook);
891 ast_audiohook_destroy(&csth.whisper_audiohook);
892 }
893
895 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
896 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
897 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
898 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
899 }
900
901 ast_audiohook_lock(&csth.spy_audiohook);
902 ast_audiohook_detach(&csth.spy_audiohook);
903 ast_audiohook_unlock(&csth.spy_audiohook);
904 ast_audiohook_destroy(&csth.spy_audiohook);
905
906 ast_verb(2, "Done Spying on channel %s\n", name);
907 publish_chanspy_message(chan, spyee_autochan->chan, 0);
908
909 if (spyee_bridge_autochan) {
910 ast_autochan_destroy(spyee_bridge_autochan);
911 }
912
913 return running;
914}
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:623
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:588
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:663
static struct ast_generator spygen
Definition: app_chanspy.c:558
static char exitcontext[AST_MAX_CONTEXT]
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
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:167
@ AST_AUDIOHOOK_DIRECTION_WRITE
Definition: audiohook.h:50
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:313
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:550
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:124
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:318
@ AST_AUDIOHOOK_TYPE_SPY
Definition: audiohook.h:36
@ AST_AUDIOHOOK_STATUS_RUNNING
Definition: audiohook.h:43
void ast_autochan_destroy(struct ast_autochan *autochan)
destroy an ast_autochan structure
Definition: autochan.c:64
static int tmp()
Definition: bt_open.c:389
const char * ast_channel_name(const struct ast_channel *chan)
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:2970
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11053
#define ast_channel_lock(chan)
Definition: channel.h:2968
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8183
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3181
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
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:8229
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2912
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4276
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:11046
@ AST_FLAG_ZOMBIE
Definition: channel.h:1007
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1027
#define ast_channel_unlock(chan)
Definition: channel.h:2969
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_VOICE
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
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.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196

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

◆ chanspy_exec()

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

Definition at line 1259 of file app_chanspy.c.

1260{
1261 char *myenforced = NULL;
1262 char *mygroup = NULL;
1263 char *recbase = NULL;
1264 int fd = 0;
1265 struct ast_flags flags;
1266 struct spy_dtmf_options user_options = {
1267 .cycle = '*',
1268 .volume = '#',
1269 .exit = '\0',
1270 };
1271 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1272 int volfactor = 0;
1273 int res;
1274 char *mailbox = NULL;
1275 char *name_context = NULL;
1277 AST_APP_ARG(spec);
1279 );
1280 char *opts[OPT_ARG_ARRAY_SIZE];
1281 char *parse = ast_strdupa(data);
1282
1284
1285 if (args.spec && !strcmp(args.spec, "all"))
1286 args.spec = NULL;
1287
1288 if (args.options) {
1289 char tmp;
1290 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1291 if (ast_test_flag(&flags, OPTION_GROUP))
1292 mygroup = opts[OPT_ARG_GROUP];
1293
1294 if (ast_test_flag(&flags, OPTION_RECORD) &&
1295 !(recbase = opts[OPT_ARG_RECORD]))
1296 recbase = "chanspy";
1297
1298 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1299 tmp = opts[OPT_ARG_EXIT][0];
1300 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1301 user_options.exit = tmp;
1302 } else {
1303 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1304 }
1305 }
1306
1307 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1308 tmp = opts[OPT_ARG_CYCLE][0];
1309 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1310 user_options.cycle = tmp;
1311 } else {
1312 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1313 }
1314 }
1315
1316 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1317 int vol;
1318
1319 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1320 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1321 else
1322 volfactor = vol;
1323 }
1324
1325 if (ast_test_flag(&flags, OPTION_PRIVATE))
1327
1328 if (ast_test_flag(&flags, OPTION_ENFORCED))
1329 myenforced = opts[OPT_ARG_ENFORCED];
1330
1331 if (ast_test_flag(&flags, OPTION_NAME)) {
1332 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1333 char *delimiter;
1334 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1335 mailbox = opts[OPT_ARG_NAME];
1336 *delimiter++ = '\0';
1337 name_context = delimiter;
1338 } else {
1339 mailbox = opts[OPT_ARG_NAME];
1340 }
1341 }
1342 }
1343 } else {
1345 }
1346
1347 oldwf = ao2_bump(ast_channel_writeformat(chan));
1348 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1349 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1350 return -1;
1351 }
1352
1353 if (recbase) {
1354 char filename[PATH_MAX];
1355
1356 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1357 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1358 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1359 fd = 0;
1360 }
1361 }
1362
1363 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1364
1365 if (fd)
1366 close(fd);
1367
1368 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1369 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1370
1371 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1372 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1373 }
1374
1375 return res;
1376}
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:437
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:950
#define AST_FILE_MODE
Definition: asterisk.h:32
#define PATH_MAX
Definition: asterisk.h:40
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5822
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
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:3066
#define LOG_ERROR
#define LOG_NOTICE
const char * ast_config_AST_MONITOR_DIR
Definition: options.c:155
Structure used to handle boolean flags.
Definition: utils.h:199
unsigned int flags
Definition: utils.h:200
Definition of a media format.
Definition: format.c:43
const char * args
static struct test_options options

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, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, voicemailpwcheck::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, PATH_MAX, RAII_VAR, spy_opts, and tmp().

Referenced by load_module().

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

954{
955 char nameprefix[AST_NAME_STRLEN];
956 char exitcontext[AST_MAX_CONTEXT] = "";
957 signed char zero_volume = 0;
958 int waitms;
959 int res;
960 int num_spied_upon = 1;
961 struct ast_channel_iterator *iter = NULL;
962
963 if (ast_test_flag(flags, OPTION_EXIT)) {
964 const char *c;
965 ast_channel_lock(chan);
966 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
968 } else {
970 }
971 ast_channel_unlock(chan);
972 }
973
974 if (ast_channel_state(chan) != AST_STATE_UP)
975 ast_answer(chan);
976
978
979 waitms = 100;
980
981 for (;;) {
982 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
983 struct ast_channel *prev = NULL;
984
985 if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
986 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
987 if (!res)
988 res = ast_waitstream(chan, "");
989 else if (res < 0) {
991 break;
992 }
994 char tmp[2];
995 tmp[0] = res;
996 tmp[1] = '\0';
997 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
998 goto exit;
999 else
1000 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1001 }
1002 }
1003
1004 /* Set up the iterator we'll be using during this call */
1005 if (!ast_strlen_zero(spec)) {
1007 struct ast_channel *unique_chan;
1008
1009 unique_chan = ast_channel_get_by_name(spec);
1010 if (!unique_chan) {
1011 res = -1;
1012 goto exit;
1013 }
1014 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
1015 ast_channel_unref(unique_chan);
1016 } else {
1017 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
1018 }
1019 } else if (!ast_strlen_zero(exten)) {
1021 } else {
1023 }
1024
1025 if (!iter) {
1026 res = -1;
1027 goto exit;
1028 }
1029
1030 res = ast_waitfordigit(chan, waitms);
1031 if (res < 0) {
1032 iter = ast_channel_iterator_destroy(iter);
1034 break;
1035 }
1037 char tmp[2];
1038 tmp[0] = res;
1039 tmp[1] = '\0';
1040 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1041 iter = ast_channel_iterator_destroy(iter);
1042 goto exit;
1043 } else {
1044 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1045 }
1046 }
1047
1048 /* reset for the next loop around, unless overridden later */
1049 waitms = 100;
1050 num_spied_upon = 0;
1051
1052 for (autochan = next_channel(iter, chan);
1053 autochan;
1054 prev = autochan->chan,
1055 ast_autochan_destroy(autochan),
1056 autochan = next_autochan ?: next_channel(iter, chan),
1057 next_autochan = NULL) {
1058 int igrp = !mygroup;
1059 int ienf = !myenforced;
1060
1061 if (autochan->chan == prev) {
1062 ast_autochan_destroy(autochan);
1063 break;
1064 }
1065
1066 if (ast_check_hangup(chan)) {
1067 ast_autochan_destroy(autochan);
1068 break;
1069 }
1070
1071 ast_autochan_channel_lock(autochan);
1073 && !ast_channel_is_bridged(autochan->chan)) {
1075 continue;
1076 }
1077
1078 if (ast_check_hangup(autochan->chan)
1081 continue;
1082 }
1084
1085 if (mygroup) {
1086 int num_groups = 0;
1087 int num_mygroups = 0;
1088 char dup_group[512];
1089 char dup_mygroup[512];
1090 char *groups[NUM_SPYGROUPS];
1091 char *mygroups[NUM_SPYGROUPS];
1092 const char *group = NULL;
1093 int x;
1094 int y;
1095 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1096 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1097 ARRAY_LEN(mygroups));
1098
1099 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1100 * rather than "SPYGROUP", this check is done to preserve expected behavior */
1101 ast_autochan_channel_lock(autochan);
1103 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1104 } else {
1105 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1106 }
1108
1109 if (!ast_strlen_zero(group)) {
1110 ast_copy_string(dup_group, group, sizeof(dup_group));
1111 num_groups = ast_app_separate_args(dup_group, ':', groups,
1112 ARRAY_LEN(groups));
1113 }
1114
1115 for (y = 0; y < num_mygroups; y++) {
1116 for (x = 0; x < num_groups; x++) {
1117 if (!strcmp(mygroups[y], groups[x])) {
1118 igrp = 1;
1119 break;
1120 }
1121 }
1122 }
1123 }
1124
1125 if (!igrp) {
1126 continue;
1127 }
1128 if (myenforced) {
1129 char ext[AST_CHANNEL_NAME + 3];
1130 char buffer[512];
1131 char *end;
1132
1133 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1134
1135 ast_autochan_channel_lock(autochan);
1136 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1138 if ((end = strchr(ext, '-'))) {
1139 *end++ = ':';
1140 *end = '\0';
1141 }
1142
1143 ext[0] = ':';
1144
1145 if (strcasestr(buffer, ext)) {
1146 ienf = 1;
1147 }
1148 }
1149
1150 if (!ienf) {
1151 continue;
1152 }
1153
1155 char peer_name[AST_NAME_STRLEN + 5];
1156 char *ptr, *s;
1157
1158 strcpy(peer_name, "spy-");
1159 ast_autochan_channel_lock(autochan);
1160 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1162 if ((ptr = strchr(peer_name, '/'))) {
1163 *ptr++ = '\0';
1164 for (s = peer_name; s < ptr; s++) {
1165 *s = tolower(*s);
1166 }
1167 if ((s = strchr(ptr, '-'))) {
1168 *s = '\0';
1169 }
1170 }
1171
1173 const char *local_context = S_OR(name_context, "default");
1174 const char *local_mailbox = S_OR(mailbox, ptr);
1175
1176 if (local_mailbox) {
1177 res = spy_sayname(chan, local_mailbox, local_context);
1178 } else {
1179 res = -1;
1180 }
1181 }
1182 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1183 int num;
1185 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1186 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1187 if (!res) {
1188 res = ast_waitstream(chan, "");
1189 }
1190 if (res) {
1191 ast_autochan_destroy(autochan);
1192 break;
1193 }
1194 } else {
1195 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1196 }
1197 }
1198 if (ptr && (num = atoi(ptr))) {
1199 ast_say_digits(chan, num, "", ast_channel_language(chan));
1200 }
1201 }
1202 }
1203
1204 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1205 num_spied_upon++;
1206
1207 if (res == -1) {
1208 ast_autochan_destroy(autochan);
1209 iter = ast_channel_iterator_destroy(iter);
1210 goto exit;
1211 } else if (res == -2) {
1212 res = 0;
1213 ast_autochan_destroy(autochan);
1214 iter = ast_channel_iterator_destroy(iter);
1215 goto exit;
1216 } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1217 struct ast_channel *next;
1218
1219 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1220
1221 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1222 next_autochan = ast_autochan_setup(next);
1223 next = ast_channel_unref(next);
1224 } else {
1225 /* stay on this channel, if it is still valid */
1226 ast_autochan_channel_lock(autochan);
1227 if (!ast_check_hangup(autochan->chan)) {
1228 next_autochan = ast_autochan_setup(autochan->chan);
1229 } else {
1230 /* the channel is gone */
1231 next_autochan = NULL;
1232 }
1234 }
1235 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1236 ast_autochan_destroy(autochan);
1237 iter = ast_channel_iterator_destroy(iter);
1238 goto exit;
1239 }
1240 }
1241
1242 iter = ast_channel_iterator_destroy(iter);
1243
1244 if (res == -1 || ast_check_hangup(chan))
1245 break;
1246 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1247 break;
1248 }
1249 }
1250exit:
1251
1253
1254 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1255
1256 return res;
1257}
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Definition: app_chanspy.c:941
#define NUM_SPYGROUPS
Definition: app_chanspy.c:61
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:698
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:916
#define AST_NAME_STRLEN
Definition: app_chanspy.c:60
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3194
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:1407
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1379
const char * ast_channel_context(const struct ast_channel *chan)
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:1387
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:1453
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10564
#define AST_CHANNEL_NAME
Definition: channel.h:173
#define AST_MAX_CONTEXT
Definition: channel.h:135
const char * ast_channel_language(const struct ast_channel *chan)
@ AST_FLAG_SPYING
Definition: channel.h:1013
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:7441
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2824
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1427
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
char * end
Definition: eagi_proxy.c:73
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1840
const char * ext
Definition: http.c:150
#define ast_app_separate_args(a, b, c, d)
char * strcasestr(const char *, const char *)
#define AST_OPTION_TXGAIN
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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:8290
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8272
@ AST_SAY_CASE_NONE
Definition: say.h:182
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char exten[AST_MAX_EXTENSION]
char x
Definition: extconf.c:81
static struct test_val c
#define ARRAY_LEN(a)
Definition: utils.h:666

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_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(), voicemailpwcheck::context, end, exitcontext, ext, ast_channel::exten, ast_channel::flags, voicemailpwcheck::mailbox, 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().

◆ dahdiscan_exec()

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

Definition at line 1499 of file app_chanspy.c.

1500{
1501 const char *spec = "DAHDI";
1502 struct ast_flags flags = {0};
1503 struct spy_dtmf_options user_options = {
1504 .cycle = '#',
1505 .volume = '\0',
1506 .exit = '*',
1507 };
1508 struct ast_format *oldwf;
1509 int res;
1510 char *mygroup = NULL;
1511
1512 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1514
1515 if (!ast_strlen_zero(data)) {
1516 mygroup = ast_strdupa(data);
1517 }
1521
1522 oldwf = ao2_bump(ast_channel_writeformat(chan));
1523 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1524 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1525 ao2_cleanup(oldwf);
1526 return -1;
1527 }
1528
1529 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1530
1531 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1532 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1533 ao2_cleanup(oldwf);
1534
1535 return res;
1536}

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, ast_flags::flags, LOG_ERROR, NULL, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, and OPTION_DTMF_EXIT.

Referenced by load_module().

◆ extenspy_exec()

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

Definition at line 1378 of file app_chanspy.c.

1379{
1380 char *ptr, *exten = NULL;
1381 char *mygroup = NULL;
1382 char *recbase = NULL;
1383 int fd = 0;
1384 struct ast_flags flags;
1385 struct spy_dtmf_options user_options = {
1386 .cycle = '*',
1387 .volume = '#',
1388 .exit = '\0',
1389 };
1390 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1391 int volfactor = 0;
1392 int res;
1393 char *mailbox = NULL;
1394 char *name_context = NULL;
1398 );
1399 char *parse = ast_strdupa(data);
1400
1402
1403 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
1404 exten = args.context;
1405 *ptr++ = '\0';
1406 args.context = ptr;
1407 }
1408 if (ast_strlen_zero(args.context))
1409 args.context = ast_strdupa(ast_channel_context(chan));
1410
1411 if (args.options) {
1412 char *opts[OPT_ARG_ARRAY_SIZE];
1413 char tmp;
1414
1415 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1416 if (ast_test_flag(&flags, OPTION_GROUP))
1417 mygroup = opts[OPT_ARG_GROUP];
1418
1419 if (ast_test_flag(&flags, OPTION_RECORD) &&
1420 !(recbase = opts[OPT_ARG_RECORD]))
1421 recbase = "chanspy";
1422
1423 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1424 tmp = opts[OPT_ARG_EXIT][0];
1425 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1426 user_options.exit = tmp;
1427 } else {
1428 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1429 }
1430 }
1431
1432 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1433 tmp = opts[OPT_ARG_CYCLE][0];
1434 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1435 user_options.cycle = tmp;
1436 } else {
1437 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1438 }
1439 }
1440
1441 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1442 int vol;
1443
1444 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1445 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1446 else
1447 volfactor = vol;
1448 }
1449
1450 if (ast_test_flag(&flags, OPTION_PRIVATE))
1452
1453 if (ast_test_flag(&flags, OPTION_NAME)) {
1454 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1455 char *delimiter;
1456 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1457 mailbox = opts[OPT_ARG_NAME];
1458 *delimiter++ = '\0';
1459 name_context = delimiter;
1460 } else {
1461 mailbox = opts[OPT_ARG_NAME];
1462 }
1463 }
1464 }
1465
1466 } else {
1467 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1469 }
1470
1471 oldwf = ao2_bump(ast_channel_writeformat(chan));
1472 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1473 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1474 return -1;
1475 }
1476
1477 if (recbase) {
1478 char filename[PATH_MAX];
1479
1480 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1481 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1482 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1483 fd = 0;
1484 }
1485 }
1486
1487
1488 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
1489
1490 if (fd)
1491 close(fd);
1492
1493 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1494 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1495
1496 return res;
1497}

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(), voicemailpwcheck::context, spy_dtmf_options::cycle, spy_dtmf_options::exit, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, voicemailpwcheck::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, PATH_MAX, RAII_VAR, spy_opts, and tmp().

Referenced by load_module().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1549 of file app_chanspy.c.

1550{
1551 int res = 0;
1552
1556
1557 return res;
1558}
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1259
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1499
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1378
static const char app_dahdiscan[]
Definition: app_chanspy.c:377
static const char app_ext[]
Definition: app_chanspy.c:375
static const char app_chan[]
Definition: app_chanspy.c:373
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640

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

◆ next_channel()

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

Definition at line 916 of file app_chanspy.c.

918{
919 struct ast_channel *next;
920 struct ast_autochan *autochan_store;
921 const size_t pseudo_len = strlen("DAHDI/pseudo");
922
923 if (!iter) {
924 return NULL;
925 }
926
928 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
929 || next == chan) {
930 continue;
931 }
932
933 autochan_store = ast_autochan_setup(next);
935
936 return autochan_store;
937 }
938 return NULL;
939}
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1441
struct ast_autochan * next
Definition: autochan.h:34

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

Referenced by common_exec().

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

604{
605 RAII_VAR(struct ast_channel_snapshot *, snapshot,
608
609 if (!snapshot) {
610 return -1;
611 }
612 ast_multi_channel_blob_add_channel(payload, role, snapshot);
613 return 0;
614}
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,...
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.
Structure representing a snapshot of channel state.

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

◆ publish_chanspy_message()

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

Definition at line 623 of file app_chanspy.c.

626{
627 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
628 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
631
632 if (!spyer) {
633 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
634 return;
635 }
636 blob = ast_json_null();
637 if (!blob || !type) {
638 return;
639 }
640
641 payload = ast_multi_channel_blob_create(blob);
642 if (!payload) {
643 return;
644 }
645
646 if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
647 return;
648 }
649
650 if (spyee) {
651 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
652 return;
653 }
654 }
655
657 if (!message) {
658 return;
659 }
661}
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:602
static const char type[]
Definition: chan_ooh323.c:109
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
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_start_type(void)
Message type for when a channel starts spying on another channel.
struct stasis_message_type * ast_channel_chanspy_stop_type(void)
Message type for when a channel stops spying on another channel.
#define AST_LOG_WARNING
struct ast_json * ast_json_null(void)
Get the JSON null value.
Definition: json.c:248
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
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's subscribers.
Definition: stasis.c:1512
Abstract JSON element (object, array, string, int, ...).
A multi channel blob data structure for multi_channel_blob stasis messages.

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

◆ spy_alloc()

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

Definition at line 455 of file app_chanspy.c.

456{
457 /* just store the data pointer in the channel structure */
458 return data;
459}

◆ spy_generate()

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

Definition at line 466 of file app_chanspy.c.

467{
468 struct chanspy_translation_helper *csth = data;
469 struct ast_frame *f, *cur;
470
473 /* Channel is already gone more than likely */
475 return -1;
476 }
477
478 if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
479 /* Option 'o' was set, so don't mix channel audio */
481 } else if (ast_test_flag(&csth->flags, OPTION_INTERLEAVED)) {
482 /* Option 'D' was set, so mix the spy frame as an interleaved dual channel frame. */
483 int i;
484 struct ast_frame *fr_read = NULL;
485 struct ast_frame *fr_write = NULL;
486 short read_buf[samples];
487 short write_buf[samples];
488 short stereo_buf[samples * 2];
489 struct ast_frame stereo_frame = {
491 .datalen = sizeof(stereo_buf),
492 .samples = samples,
493 };
494
495 f = ast_audiohook_read_frame_all(&csth->spy_audiohook, samples, ast_format_slin, &fr_read, &fr_write);
496 if (f) {
497 ast_frame_free(f, 0);
498 f = NULL;
499 }
500
501 if (fr_read) {
502 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
503 } else {
504 /* silent out the output frame if we can't read the input */
505 memset(read_buf, 0, sizeof(read_buf));
506 }
507
508 if (fr_write) {
509 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
510 } else {
511 memset(write_buf, 0, sizeof(write_buf));
512 }
513
514 for (i = 0; i < samples; i++) {
515 stereo_buf[i*2] = read_buf[i];
516 stereo_buf[i*2+1] = write_buf[i];
517 }
518
519 stereo_frame.data.ptr = stereo_buf;
521
522 f = ast_frdup(&stereo_frame);
523
524 if (fr_read) {
525 ast_frame_free(fr_read, 0);
526 }
527 if (fr_write) {
528 ast_frame_free(fr_write, 0);
529 }
530
531 } else {
533 }
534
536
537 if (!f)
538 return 0;
539
540 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
541 if (ast_write(chan, cur)) {
542 ast_frfree(f);
543 return -1;
544 }
545
546 if (csth->fd) {
547 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
548 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
549 }
550 }
551 }
552
553 ast_frfree(f);
554
555 return 0;
556}
struct ast_frame * ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame dat...
Definition: audiohook.c:451
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:446
@ AST_AUDIOHOOK_DIRECTION_READ
Definition: audiohook.h:49
@ AST_AUDIOHOOK_DIRECTION_BOTH
Definition: audiohook.h:51
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:5163
void write_buf(int file, char *buffer, int num)
Definition: eagi_proxy.c:312
struct ast_format * ast_format_cache_get_slin_by_rate(unsigned int rate)
Retrieve the best signed linear format given a sample rate.
Definition: format_cache.c:512
void ast_frame_free(struct ast_frame *frame, int cache)
Frees a frame or list of frames.
Definition: main/frame.c:176
#define ast_frdup(fr)
Copies a frame.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
int errno
enum ast_audiohook_status status
Definition: audiohook.h:108
struct ast_format * format
union ast_frame::@226 data
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:441
struct ast_flags flags
Definition: app_chanspy.c:446

References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), ast_audiohook_read_frame_all(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, ast_format_cache_get_slin_by_rate(), ast_format_slin, ast_frame_free(), AST_FRAME_VOICE, ast_frdup, 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, ast_frame_subclass::format, ast_frame::frametype, LOG_WARNING, NULL, OPTION_INTERLEAVED, OPTION_READONLY, ast_frame::ptr, ast_frame::samples, chanspy_translation_helper::spy_audiohook, ast_audiohook::status, ast_frame::subclass, and write_buf().

◆ spy_release()

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

Definition at line 461 of file app_chanspy.c.

462{
463 /* nothing to do */
464}

◆ spy_sayname()

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

Definition at line 941 of file app_chanspy.c.

942{
943 char *mailbox_id;
944
945 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
946 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
947 return ast_app_sayname(chan, mailbox_id);
948}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
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:637

References ast_alloca, ast_app_sayname(), ast_autochan::chan, voicemailpwcheck::context, and voicemailpwcheck::mailbox.

Referenced by common_exec().

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

565{
566 int res;
567
569 ast_verb(3, "Attaching spy channel %s to %s\n",
570 spychan_name, ast_channel_name(autochan->chan));
571
572 if (ast_test_flag(flags, OPTION_READONLY)) {
575 } else {
577 }
578 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
579 ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
580 } else {
582 }
583 res = ast_audiohook_attach(autochan->chan, audiohook);
585 return res;
586}
@ AST_AUDIOHOOK_MUTE_WRITE
Definition: audiohook.h:65
@ AST_AUDIOHOOK_SMALL_QUEUE
Definition: audiohook.h:63
@ AST_AUDIOHOOK_TRIGGER_SYNC
Definition: audiohook.h:59
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:484
int ast_audiohook_set_frame_feed_direction(struct ast_audiohook *audiohook, enum ast_audiohook_direction direction)
Sets direction on audiohook.
Definition: audiohook.c:150

References ast_audiohook_attach(), AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_frame_feed_direction(), 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().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1538 of file app_chanspy.c.

1539{
1540 int res = 0;
1541
1545
1546 return res;
1547}
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392

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

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

Definition at line 1560 of file app_chanspy.c.

◆ app_chan

const char app_chan[] = "ChanSpy"
static

Definition at line 373 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_dahdiscan

const char app_dahdiscan[] = "DAHDIScan"
static

Definition at line 377 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_ext

const char app_ext[] = "ExtenSpy"
static

Definition at line 375 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 1560 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 }, [ 'D' ] = { .flag = OPTION_INTERLEAVED }, [ '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 437 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:455
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:461
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:466

Definition at line 558 of file app_chanspy.c.

Referenced by channel_spy().