Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 start_whispering (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 1579 of file app_chanspy.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1579 of file app_chanspy.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

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

685{
686 int retval = 0;
687 struct ast_autochan *internal_bridge_autochan;
688 struct ast_channel *spyee_chan;
689 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
690
691 ast_autochan_channel_lock(spyee_autochan);
692 spyee_chan = ast_channel_ref(spyee_autochan->chan);
693 ast_autochan_channel_unlock(spyee_autochan);
694 bridged = ast_channel_bridge_peer(spyee_chan);
695 ast_channel_unref(spyee_chan);
696 if (!bridged) {
697 return -1;
698 }
699
700 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
701
702 internal_bridge_autochan = ast_autochan_setup(bridged);
703 if (!internal_bridge_autochan) {
704 return -1;
705 }
706
707 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
708 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
709 retval = -1;
710 }
711
712 *spyee_bridge_autochan = internal_bridge_autochan;
713
714 return retval;
715}
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:588
#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:10586
#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_whispering().

Referenced by channel_spy().

◆ change_spy_mode()

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

Definition at line 607 of file app_chanspy.c.

608{
609 if (digit == '4') {
612 } else if (digit == '5') {
615 } else if (digit == '6') {
618 }
619}
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 717 of file app_chanspy.c.

720{
721 struct chanspy_translation_helper csth;
722 int running = 0, bridge_connected = 0, res, x = 0;
723 char inp[24] = {0};
724 char *name;
725 struct ast_frame *f;
726 struct ast_silence_generator *silgen = NULL;
727 struct ast_autochan *spyee_bridge_autochan = NULL;
728 const char *spyer_name;
729
731 if (ast_check_hangup(chan)) {
733 return 0;
734 }
735 spyer_name = ast_strdupa(ast_channel_name(chan));
737
738 ast_autochan_channel_lock(spyee_autochan);
739 if (ast_check_hangup(spyee_autochan->chan)
740 || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
741 ast_autochan_channel_unlock(spyee_autochan);
742 return 0;
743 }
744 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
745
746 ast_verb(2, "Spying on channel %s\n", name);
747 publish_chanspy_message(chan, spyee_autochan->chan, 1);
748 ast_autochan_channel_unlock(spyee_autochan);
749
750 memset(&csth, 0, sizeof(csth));
751 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
752
753 /* This is the audiohook which gives us the audio off the channel we are
754 spying on.
755 */
756 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
757
758 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
759 ast_audiohook_destroy(&csth.spy_audiohook);
760 return 0;
761 }
762
764 /* This audiohook will let us inject audio from our channel into the
765 channel we are currently spying on.
766 */
767 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
768
769 if (start_whispering(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
770 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
771 }
772 }
773
775
776 csth.volfactor = *volfactor;
777
778 if (csth.volfactor) {
779 csth.spy_audiohook.options.read_volume = csth.volfactor;
780 csth.spy_audiohook.options.write_volume = csth.volfactor;
781 }
782
783 csth.fd = fd;
784
785 if (ast_test_flag(flags, OPTION_PRIVATE))
787 else
789
790 /* We can no longer rely on 'spyee' being an actual channel;
791 it can be hung up and freed out from under us. However, the
792 channel destructor will put NULL into our csth.spy.chan
793 field when that happens, so that is our signal that the spyee
794 channel has gone away.
795 */
796
797 /* Note: it is very important that the ast_waitfor() be the first
798 condition in this expression, so that if we wait for some period
799 of time before receiving a frame from our spying channel, we check
800 for hangup on the spied-on channel _after_ knowing that a frame
801 has arrived, since the spied-on channel could have gone away while
802 we were waiting
803 */
804 while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
805 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
806 running = -1;
807 if (f) {
808 ast_frfree(f);
809 }
810 break;
811 }
812
814 /* This hook lets us inject audio into the channel that the spyee is currently
815 * bridged with. If the spyee isn't bridged with anything yet, nothing will
816 * be attached and we'll need to continue attempting to attach the barge
817 * audio hook. */
818 if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
819 &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
820 bridge_connected = 1;
821 }
822
823 ast_audiohook_lock(&csth.whisper_audiohook);
824 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
825 ast_audiohook_unlock(&csth.whisper_audiohook);
826
827 if (bridge_connected) {
828 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
829 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
830 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
831 }
832
833 ast_frfree(f);
834 continue;
835 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
836 ast_audiohook_lock(&csth.whisper_audiohook);
837 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
838 ast_audiohook_unlock(&csth.whisper_audiohook);
839 ast_frfree(f);
840 continue;
841 }
842
843 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
844 ast_frfree(f);
845 if (!res)
846 continue;
847
848 if (x == sizeof(inp))
849 x = 0;
850
851 if (res < 0) {
852 running = -1;
853 break;
854 }
855
856 if (ast_test_flag(flags, OPTION_EXIT)) {
857 char tmp[2];
858 tmp[0] = res;
859 tmp[1] = '\0';
861 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
862 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
863 running = -2;
864 break;
865 } else {
866 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
867 }
868 } else if (res >= '0' && res <= '9') {
870 change_spy_mode(res, flags);
871 } else {
872 inp[x++] = res;
873 }
874 }
875
876 if (res == user_options->cycle) {
877 running = 0;
878 break;
879 } else if (res == user_options->exit) {
880 running = -2;
881 break;
882 } else if (res == user_options->volume) {
883 if (!ast_strlen_zero(inp)) {
884 running = atoi(inp);
885 break;
886 }
887
888 (*volfactor)++;
889 if (*volfactor > 4)
890 *volfactor = -4;
891 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
892
893 csth.volfactor = *volfactor;
894 csth.spy_audiohook.options.read_volume = csth.volfactor;
895 csth.spy_audiohook.options.write_volume = csth.volfactor;
896 }
897 }
898
899 if (ast_test_flag(flags, OPTION_PRIVATE))
901 else
903
905
907 ast_audiohook_lock(&csth.whisper_audiohook);
908 ast_audiohook_detach(&csth.whisper_audiohook);
909 ast_audiohook_unlock(&csth.whisper_audiohook);
910 ast_audiohook_destroy(&csth.whisper_audiohook);
911 }
912
914 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
915 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
916 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
917 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
918 }
919
920 ast_audiohook_lock(&csth.spy_audiohook);
921 ast_audiohook_detach(&csth.spy_audiohook);
922 ast_audiohook_unlock(&csth.spy_audiohook);
923 ast_audiohook_destroy(&csth.spy_audiohook);
924
925 ast_verb(2, "Done Spying on channel %s\n", name);
926 publish_chanspy_message(chan, spyee_autochan->chan, 0);
927
928 if (spyee_bridge_autochan) {
929 ast_autochan_destroy(spyee_bridge_autochan);
930 }
931
932 return running;
933}
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:642
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:607
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
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:682
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:578
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:11056
#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:8186
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:8232
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:11049
@ 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(), start_whispering(), 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 1278 of file app_chanspy.c.

1279{
1280 char *myenforced = NULL;
1281 char *mygroup = NULL;
1282 char *recbase = NULL;
1283 int fd = 0;
1284 struct ast_flags flags;
1285 struct spy_dtmf_options user_options = {
1286 .cycle = '*',
1287 .volume = '#',
1288 .exit = '\0',
1289 };
1290 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1291 int volfactor = 0;
1292 int res;
1293 char *mailbox = NULL;
1294 char *name_context = NULL;
1296 AST_APP_ARG(spec);
1298 );
1299 char *opts[OPT_ARG_ARRAY_SIZE];
1300 char *parse = ast_strdupa(data);
1301
1303
1304 if (args.spec && !strcmp(args.spec, "all"))
1305 args.spec = NULL;
1306
1307 if (args.options) {
1308 char tmp;
1309 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1310 if (ast_test_flag(&flags, OPTION_GROUP))
1311 mygroup = opts[OPT_ARG_GROUP];
1312
1313 if (ast_test_flag(&flags, OPTION_RECORD) &&
1314 !(recbase = opts[OPT_ARG_RECORD]))
1315 recbase = "chanspy";
1316
1317 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1318 tmp = opts[OPT_ARG_EXIT][0];
1319 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1320 user_options.exit = tmp;
1321 } else {
1322 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1323 }
1324 }
1325
1326 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1327 tmp = opts[OPT_ARG_CYCLE][0];
1328 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1329 user_options.cycle = tmp;
1330 } else {
1331 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1332 }
1333 }
1334
1335 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1336 int vol;
1337
1338 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1339 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1340 else
1341 volfactor = vol;
1342 }
1343
1344 if (ast_test_flag(&flags, OPTION_PRIVATE))
1346
1347 if (ast_test_flag(&flags, OPTION_ENFORCED))
1348 myenforced = opts[OPT_ARG_ENFORCED];
1349
1350 if (ast_test_flag(&flags, OPTION_NAME)) {
1351 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1352 char *delimiter;
1353 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1354 mailbox = opts[OPT_ARG_NAME];
1355 *delimiter++ = '\0';
1356 name_context = delimiter;
1357 } else {
1358 mailbox = opts[OPT_ARG_NAME];
1359 }
1360 }
1361 }
1362 } else {
1364 }
1365
1366 oldwf = ao2_bump(ast_channel_writeformat(chan));
1367 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1368 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1369 return -1;
1370 }
1371
1372 if (recbase) {
1373 char filename[PATH_MAX];
1374
1375 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1376 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1377 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1378 fd = 0;
1379 }
1380 }
1381
1382 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1383
1384 if (fd)
1385 close(fd);
1386
1387 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1388 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1389
1390 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1391 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1392 }
1393
1394 return res;
1395}
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:969
#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 969 of file app_chanspy.c.

973{
974 char nameprefix[AST_NAME_STRLEN];
975 char exitcontext[AST_MAX_CONTEXT] = "";
976 signed char zero_volume = 0;
977 int waitms;
978 int res;
979 int num_spied_upon = 1;
980 struct ast_channel_iterator *iter = NULL;
981
982 if (ast_test_flag(flags, OPTION_EXIT)) {
983 const char *c;
984 ast_channel_lock(chan);
985 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
987 } else {
989 }
990 ast_channel_unlock(chan);
991 }
992
993 if (ast_channel_state(chan) != AST_STATE_UP)
994 ast_answer(chan);
995
997
998 waitms = 100;
999
1000 for (;;) {
1001 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
1002 struct ast_channel *prev = NULL;
1003
1004 if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
1005 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
1006 if (!res)
1007 res = ast_waitstream(chan, "");
1008 else if (res < 0) {
1010 break;
1011 }
1013 char tmp[2];
1014 tmp[0] = res;
1015 tmp[1] = '\0';
1016 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
1017 goto exit;
1018 else
1019 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1020 }
1021 }
1022
1023 /* Set up the iterator we'll be using during this call */
1024 if (!ast_strlen_zero(spec)) {
1026 struct ast_channel *unique_chan;
1027
1028 unique_chan = ast_channel_get_by_name(spec);
1029 if (!unique_chan) {
1030 res = -1;
1031 goto exit;
1032 }
1033 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
1034 ast_channel_unref(unique_chan);
1035 } else {
1036 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
1037 }
1038 } else if (!ast_strlen_zero(exten)) {
1040 } else {
1042 }
1043
1044 if (!iter) {
1045 res = -1;
1046 goto exit;
1047 }
1048
1049 res = ast_waitfordigit(chan, waitms);
1050 if (res < 0) {
1051 iter = ast_channel_iterator_destroy(iter);
1053 break;
1054 }
1056 char tmp[2];
1057 tmp[0] = res;
1058 tmp[1] = '\0';
1059 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1060 iter = ast_channel_iterator_destroy(iter);
1061 goto exit;
1062 } else {
1063 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1064 }
1065 }
1066
1067 /* reset for the next loop around, unless overridden later */
1068 waitms = 100;
1069 num_spied_upon = 0;
1070
1071 for (autochan = next_channel(iter, chan);
1072 autochan;
1073 prev = autochan->chan,
1074 ast_autochan_destroy(autochan),
1075 autochan = next_autochan ?: next_channel(iter, chan),
1076 next_autochan = NULL) {
1077 int igrp = !mygroup;
1078 int ienf = !myenforced;
1079
1080 if (autochan->chan == prev) {
1081 ast_autochan_destroy(autochan);
1082 break;
1083 }
1084
1085 if (ast_check_hangup(chan)) {
1086 ast_autochan_destroy(autochan);
1087 break;
1088 }
1089
1090 ast_autochan_channel_lock(autochan);
1092 && !ast_channel_is_bridged(autochan->chan)) {
1094 continue;
1095 }
1096
1097 if (ast_check_hangup(autochan->chan)
1100 continue;
1101 }
1103
1104 if (mygroup) {
1105 int num_groups = 0;
1106 int num_mygroups = 0;
1107 char dup_group[512];
1108 char dup_mygroup[512];
1109 char *groups[NUM_SPYGROUPS];
1110 char *mygroups[NUM_SPYGROUPS];
1111 const char *group = NULL;
1112 int x;
1113 int y;
1114 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1115 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1116 ARRAY_LEN(mygroups));
1117
1118 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1119 * rather than "SPYGROUP", this check is done to preserve expected behavior */
1120 ast_autochan_channel_lock(autochan);
1122 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1123 } else {
1124 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1125 }
1127
1128 if (!ast_strlen_zero(group)) {
1129 ast_copy_string(dup_group, group, sizeof(dup_group));
1130 num_groups = ast_app_separate_args(dup_group, ':', groups,
1131 ARRAY_LEN(groups));
1132 }
1133
1134 for (y = 0; y < num_mygroups; y++) {
1135 for (x = 0; x < num_groups; x++) {
1136 if (!strcmp(mygroups[y], groups[x])) {
1137 igrp = 1;
1138 break;
1139 }
1140 }
1141 }
1142 }
1143
1144 if (!igrp) {
1145 continue;
1146 }
1147 if (myenforced) {
1148 char ext[AST_CHANNEL_NAME + 3];
1149 char buffer[512];
1150 char *end;
1151
1152 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1153
1154 ast_autochan_channel_lock(autochan);
1155 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1157 if ((end = strchr(ext, '-'))) {
1158 *end++ = ':';
1159 *end = '\0';
1160 }
1161
1162 ext[0] = ':';
1163
1164 if (strcasestr(buffer, ext)) {
1165 ienf = 1;
1166 }
1167 }
1168
1169 if (!ienf) {
1170 continue;
1171 }
1172
1174 char peer_name[AST_NAME_STRLEN + 5];
1175 char *ptr, *s;
1176
1177 strcpy(peer_name, "spy-");
1178 ast_autochan_channel_lock(autochan);
1179 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1181 if ((ptr = strchr(peer_name, '/'))) {
1182 *ptr++ = '\0';
1183 for (s = peer_name; s < ptr; s++) {
1184 *s = tolower(*s);
1185 }
1186 if ((s = strchr(ptr, '-'))) {
1187 *s = '\0';
1188 }
1189 }
1190
1192 const char *local_context = S_OR(name_context, "default");
1193 const char *local_mailbox = S_OR(mailbox, ptr);
1194
1195 if (local_mailbox) {
1196 res = spy_sayname(chan, local_mailbox, local_context);
1197 } else {
1198 res = -1;
1199 }
1200 }
1201 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1202 int num;
1204 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1205 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1206 if (!res) {
1207 res = ast_waitstream(chan, "");
1208 }
1209 if (res) {
1210 ast_autochan_destroy(autochan);
1211 break;
1212 }
1213 } else {
1214 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1215 }
1216 }
1217 if (ptr && (num = atoi(ptr))) {
1218 ast_say_digits(chan, num, "", ast_channel_language(chan));
1219 }
1220 }
1221 }
1222
1223 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1224 num_spied_upon++;
1225
1226 if (res == -1) {
1227 ast_autochan_destroy(autochan);
1228 iter = ast_channel_iterator_destroy(iter);
1229 goto exit;
1230 } else if (res == -2) {
1231 res = 0;
1232 ast_autochan_destroy(autochan);
1233 iter = ast_channel_iterator_destroy(iter);
1234 goto exit;
1235 } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1236 struct ast_channel *next;
1237
1238 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1239
1240 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1241 next_autochan = ast_autochan_setup(next);
1242 next = ast_channel_unref(next);
1243 } else {
1244 /* stay on this channel, if it is still valid */
1245 ast_autochan_channel_lock(autochan);
1246 if (!ast_check_hangup(autochan->chan)) {
1247 next_autochan = ast_autochan_setup(autochan->chan);
1248 } else {
1249 /* the channel is gone */
1250 next_autochan = NULL;
1251 }
1253 }
1254 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1255 ast_autochan_destroy(autochan);
1256 iter = ast_channel_iterator_destroy(iter);
1257 goto exit;
1258 }
1259 }
1260
1261 iter = ast_channel_iterator_destroy(iter);
1262
1263 if (res == -1 || ast_check_hangup(chan))
1264 break;
1265 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1266 break;
1267 }
1268 }
1269exit:
1270
1272
1273 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1274
1275 return res;
1276}
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Definition: app_chanspy.c:960
#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:717
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:935
#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:10567
#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:7444
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:8293
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8275
@ 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 1518 of file app_chanspy.c.

1519{
1520 const char *spec = "DAHDI";
1521 struct ast_flags flags = {0};
1522 struct spy_dtmf_options user_options = {
1523 .cycle = '#',
1524 .volume = '\0',
1525 .exit = '*',
1526 };
1527 struct ast_format *oldwf;
1528 int res;
1529 char *mygroup = NULL;
1530
1531 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1533
1534 if (!ast_strlen_zero(data)) {
1535 mygroup = ast_strdupa(data);
1536 }
1540
1541 oldwf = ao2_bump(ast_channel_writeformat(chan));
1542 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1543 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1544 ao2_cleanup(oldwf);
1545 return -1;
1546 }
1547
1548 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1549
1550 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1551 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1552 ao2_cleanup(oldwf);
1553
1554 return res;
1555}

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

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

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

1569{
1570 int res = 0;
1571
1575
1576 return res;
1577}
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1278
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1518
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1397
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 935 of file app_chanspy.c.

937{
938 struct ast_channel *next;
939 struct ast_autochan *autochan_store;
940 const size_t pseudo_len = strlen("DAHDI/pseudo");
941
942 if (!iter) {
943 return NULL;
944 }
945
947 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
948 || next == chan) {
949 continue;
950 }
951
952 autochan_store = ast_autochan_setup(next);
954
955 return autochan_store;
956 }
957 return NULL;
958}
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 621 of file app_chanspy.c.

623{
624 RAII_VAR(struct ast_channel_snapshot *, snapshot,
627
628 if (!snapshot) {
629 return -1;
630 }
631 ast_multi_channel_blob_add_channel(payload, role, snapshot);
632 return 0;
633}
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 642 of file app_chanspy.c.

645{
646 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
647 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
650
651 if (!spyer) {
652 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
653 return;
654 }
655 blob = ast_json_null();
656 if (!blob || !type) {
657 return;
658 }
659
660 payload = ast_multi_channel_blob_create(blob);
661 if (!payload) {
662 return;
663 }
664
665 if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
666 return;
667 }
668
669 if (spyee) {
670 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
671 return;
672 }
673 }
674
676 if (!message) {
677 return;
678 }
680}
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:621
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:479
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:474
@ 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 960 of file app_chanspy.c.

961{
962 char *mailbox_id;
963
964 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
965 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
966 return ast_app_sayname(chan, mailbox_id);
967}
#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:512
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 channel_spy().

◆ start_whispering()

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

Definition at line 588 of file app_chanspy.c.

589{
590 int res;
591
593 ast_verb(3, "Attaching spy channel %s to %s\n",
594 spychan_name, ast_channel_name(autochan->chan));
595
597 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
598 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
599 } else {
601 }
602 res = ast_audiohook_attach(autochan->chan, audiohook);
604 return res;
605}

References ast_audiohook_attach(), 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, and OPTION_LONG_QUEUE.

Referenced by attach_barge(), and channel_spy().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1557 of file app_chanspy.c.

1558{
1559 int res = 0;
1560
1564
1565 return res;
1566}
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 1579 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 1579 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().