Asterisk - The Open Source Telephony Project GIT-master-0a46be9
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) , OPTION_NOANSWER = (1 << 22)
}
 
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 }, [ 'N' ] = { .flag = OPTION_NOANSWER }, [ '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 
OPTION_NOANSWER 

Definition at line 394 of file app_chanspy.c.

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

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

420 {
421 OPT_ARG_VOLUME = 0,
429};
@ OPT_ARG_CYCLE
Definition: app_chanspy.c:427
@ OPT_ARG_RECORD
Definition: app_chanspy.c:423
@ OPT_ARG_EXIT
Definition: app_chanspy.c:426
@ OPT_ARG_NAME
Definition: app_chanspy.c:425
@ OPT_ARG_VOLUME
Definition: app_chanspy.c:421
@ OPT_ARG_ENFORCED
Definition: app_chanspy.c:424
@ OPT_ARG_ARRAY_SIZE
Definition: app_chanspy.c:428
@ OPT_ARG_GROUP
Definition: app_chanspy.c:422

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1597 of file app_chanspy.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1597 of file app_chanspy.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

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

702{
703 int retval = 0;
704 struct ast_autochan *internal_bridge_autochan;
705 struct ast_channel *spyee_chan;
706 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
707
708 ast_autochan_channel_lock(spyee_autochan);
709 spyee_chan = ast_channel_ref(spyee_autochan->chan);
710 ast_autochan_channel_unlock(spyee_autochan);
711 bridged = ast_channel_bridge_peer(spyee_chan);
712 ast_channel_unref(spyee_chan);
713 if (!bridged) {
714 return -1;
715 }
716
717 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
718
719 internal_bridge_autochan = ast_autochan_setup(bridged);
720 if (!internal_bridge_autochan) {
721 return -1;
722 }
723
724 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
725 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
726 retval = -1;
727 }
728
729 *spyee_bridge_autochan = internal_bridge_autochan;
730
731 return retval;
732}
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:605
#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:10578
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3008
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Definition: channel.h:3019
static const char name[]
Definition: format_mp3.c:68
#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:978

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

625{
626 if (digit == '4') {
629 } else if (digit == '5') {
632 } else if (digit == '6') {
635 }
636}
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 734 of file app_chanspy.c.

737{
738 struct chanspy_translation_helper csth;
739 int running = 0, bridge_connected = 0, res, x = 0;
740 char inp[24] = {0};
741 char *name;
742 struct ast_frame *f;
743 struct ast_silence_generator *silgen = NULL;
744 struct ast_autochan *spyee_bridge_autochan = NULL;
745 const char *spyer_name;
746
748 if (ast_check_hangup(chan)) {
750 return 0;
751 }
752 spyer_name = ast_strdupa(ast_channel_name(chan));
754
755 ast_autochan_channel_lock(spyee_autochan);
756 if (ast_check_hangup(spyee_autochan->chan)
757 || ast_test_flag(ast_channel_flags(spyee_autochan->chan), AST_FLAG_ZOMBIE)) {
758 ast_autochan_channel_unlock(spyee_autochan);
759 return 0;
760 }
761 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
762
763 ast_verb(2, "Spying on channel %s\n", name);
764 publish_chanspy_message(chan, spyee_autochan->chan, 1);
765 ast_autochan_channel_unlock(spyee_autochan);
766
767 memset(&csth, 0, sizeof(csth));
768 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
769
770 /* This is the audiohook which gives us the audio off the channel we are
771 spying on.
772 */
773 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
774
775 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook, flags)) {
776 ast_audiohook_destroy(&csth.spy_audiohook);
777 return 0;
778 }
779
781 /* This audiohook will let us inject audio from our channel into the
782 channel we are currently spying on.
783 */
784 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
785
786 if (start_whispering(spyee_autochan, spyer_name, &csth.whisper_audiohook, flags)) {
787 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
788 }
789 }
790
792
793 csth.volfactor = *volfactor;
794
795 if (csth.volfactor) {
796 csth.spy_audiohook.options.read_volume = csth.volfactor;
797 csth.spy_audiohook.options.write_volume = csth.volfactor;
798 }
799
800 csth.fd = fd;
801
802 if (ast_test_flag(flags, OPTION_PRIVATE))
804 else
806
807 /* We can no longer rely on 'spyee' being an actual channel;
808 it can be hung up and freed out from under us. However, the
809 channel destructor will put NULL into our csth.spy.chan
810 field when that happens, so that is our signal that the spyee
811 channel has gone away.
812 */
813
814 /* Note: it is very important that the ast_waitfor() be the first
815 condition in this expression, so that if we wait for some period
816 of time before receiving a frame from our spying channel, we check
817 for hangup on the spied-on channel _after_ knowing that a frame
818 has arrived, since the spied-on channel could have gone away while
819 we were waiting
820 */
821 while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
822 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
823 running = -1;
824 if (f) {
825 ast_frfree(f);
826 }
827 break;
828 }
829
831 /* This hook lets us inject audio into the channel that the spyee is currently
832 * bridged with. If the spyee isn't bridged with anything yet, nothing will
833 * be attached and we'll need to continue attempting to attach the barge
834 * audio hook. */
835 if (!bridge_connected && attach_barge(spyee_autochan, &spyee_bridge_autochan,
836 &csth.bridge_whisper_audiohook, spyer_name, name, flags) == 0) {
837 bridge_connected = 1;
838 }
839
840 ast_audiohook_lock(&csth.whisper_audiohook);
841 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
842 ast_audiohook_unlock(&csth.whisper_audiohook);
843
844 if (bridge_connected) {
845 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
846 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
847 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
848 }
849
850 ast_frfree(f);
851 continue;
852 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
853 ast_audiohook_lock(&csth.whisper_audiohook);
854 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
855 ast_audiohook_unlock(&csth.whisper_audiohook);
856 ast_frfree(f);
857 continue;
858 }
859
860 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
861 ast_frfree(f);
862 if (!res)
863 continue;
864
865 if (x == sizeof(inp))
866 x = 0;
867
868 if (res < 0) {
869 running = -1;
870 break;
871 }
872
873 if (ast_test_flag(flags, OPTION_EXIT)) {
874 char tmp[2];
875 tmp[0] = res;
876 tmp[1] = '\0';
877 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
878 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
879 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
880 running = -2;
881 break;
882 } else {
883 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
884 }
885 } else if (res >= '0' && res <= '9') {
887 change_spy_mode(res, flags);
888 } else {
889 inp[x++] = res;
890 }
891 }
892
893 if (res == user_options->cycle) {
894 running = 0;
895 break;
896 } else if (res == user_options->exit) {
897 running = -2;
898 break;
899 } else if (res == user_options->volume) {
900 if (!ast_strlen_zero(inp)) {
901 running = atoi(inp);
902 break;
903 }
904
905 (*volfactor)++;
906 if (*volfactor > 4)
907 *volfactor = -4;
908 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
909
910 csth.volfactor = *volfactor;
911 csth.spy_audiohook.options.read_volume = csth.volfactor;
912 csth.spy_audiohook.options.write_volume = csth.volfactor;
913 }
914 }
915
916 if (ast_test_flag(flags, OPTION_PRIVATE))
918 else
920
922
924 ast_audiohook_lock(&csth.whisper_audiohook);
925 ast_audiohook_detach(&csth.whisper_audiohook);
926 ast_audiohook_unlock(&csth.whisper_audiohook);
927 ast_audiohook_destroy(&csth.whisper_audiohook);
928 }
929
931 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
932 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
933 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
934 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
935 }
936
937 ast_audiohook_lock(&csth.spy_audiohook);
938 ast_audiohook_detach(&csth.spy_audiohook);
939 ast_audiohook_unlock(&csth.spy_audiohook);
940 ast_audiohook_destroy(&csth.spy_audiohook);
941
942 ast_verb(2, "Done Spying on channel %s\n", name);
943 publish_chanspy_message(chan, spyee_autochan->chan, 0);
944
945 if (spyee_bridge_autochan) {
946 ast_autochan_destroy(spyee_bridge_autochan);
947 }
948
949 return running;
950}
static void publish_chanspy_message(struct ast_channel *spyer, struct ast_channel *spyee, int start)
Definition: app_chanspy.c:659
static void change_spy_mode(const char digit, struct ast_flags *flags)
Definition: app_chanspy.c:624
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:581
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:699
static struct ast_generator spygen
Definition: app_chanspy.c:575
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:587
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
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:2921
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition: channel.c:11048
#define ast_channel_lock(chan)
Definition: channel.h:2972
struct ast_silence_generator * ast_channel_start_silence_generator(struct ast_channel *chan)
Starts a silence generator on the given channel.
Definition: channel.c:8178
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3132
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:8224
@ AST_FLAG_ZOMBIE
Definition: channel.h:1007
@ AST_FLAG_END_DTMF_ONLY
Definition: channel.h:1027
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2863
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4223
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:11041
#define ast_channel_unlock(chan)
Definition: channel.h:2973
#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:8806
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:214

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

1297{
1298 char *myenforced = NULL;
1299 char *mygroup = NULL;
1300 char *recbase = NULL;
1301 int fd = 0;
1302 struct ast_flags flags;
1303 struct spy_dtmf_options user_options = {
1304 .cycle = '*',
1305 .volume = '#',
1306 .exit = '\0',
1307 };
1308 RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
1309 int volfactor = 0;
1310 int res;
1311 char *mailbox = NULL;
1312 char *name_context = NULL;
1314 AST_APP_ARG(spec);
1316 );
1317 char *opts[OPT_ARG_ARRAY_SIZE];
1318 char *parse = ast_strdupa(data);
1319
1321
1322 if (args.spec && !strcmp(args.spec, "all"))
1323 args.spec = NULL;
1324
1325 if (args.options) {
1326 char tmp;
1327 ast_app_parse_options(spy_opts, &flags, opts, args.options);
1328 if (ast_test_flag(&flags, OPTION_GROUP))
1329 mygroup = opts[OPT_ARG_GROUP];
1330
1331 if (ast_test_flag(&flags, OPTION_RECORD) &&
1332 !(recbase = opts[OPT_ARG_RECORD]))
1333 recbase = "chanspy";
1334
1335 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
1336 tmp = opts[OPT_ARG_EXIT][0];
1337 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1338 user_options.exit = tmp;
1339 } else {
1340 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n");
1341 }
1342 }
1343
1344 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
1345 tmp = opts[OPT_ARG_CYCLE][0];
1346 if (strchr("0123456789*#", tmp) && tmp != '\0') {
1347 user_options.cycle = tmp;
1348 } else {
1349 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n");
1350 }
1351 }
1352
1353 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
1354 int vol;
1355
1356 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
1357 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
1358 else
1359 volfactor = vol;
1360 }
1361
1362 if (ast_test_flag(&flags, OPTION_PRIVATE))
1364
1365 if (ast_test_flag(&flags, OPTION_ENFORCED))
1366 myenforced = opts[OPT_ARG_ENFORCED];
1367
1368 if (ast_test_flag(&flags, OPTION_NAME)) {
1369 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
1370 char *delimiter;
1371 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
1372 mailbox = opts[OPT_ARG_NAME];
1373 *delimiter++ = '\0';
1374 name_context = delimiter;
1375 } else {
1376 mailbox = opts[OPT_ARG_NAME];
1377 }
1378 }
1379 }
1380 } else {
1382 }
1383
1384 oldwf = ao2_bump(ast_channel_writeformat(chan));
1385 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1386 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1387 return -1;
1388 }
1389
1390 if (recbase) {
1391 char filename[PATH_MAX];
1392
1393 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
1394 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
1395 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
1396 fd = 0;
1397 }
1398 }
1399
1400 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
1401
1402 if (fd)
1403 close(fd);
1404
1405 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1406 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1407
1408 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
1409 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
1410 }
1411
1412 return res;
1413}
static const struct ast_app_option spy_opts[128]
Definition: app_chanspy.c:454
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:986
#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:5771
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:156
Structure used to handle boolean flags.
Definition: utils.h:217
unsigned int flags
Definition: utils.h:218
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, and spy_opts.

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

990{
991 char nameprefix[AST_NAME_STRLEN];
992 char exitcontext[AST_MAX_CONTEXT] = "";
993 signed char zero_volume = 0;
994 int waitms;
995 int res;
996 int num_spied_upon = 1;
997 struct ast_channel_iterator *iter = NULL;
998
999 if (ast_test_flag(flags, OPTION_EXIT)) {
1000 const char *c;
1001 ast_channel_lock(chan);
1002 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
1004 } else {
1006 }
1007 ast_channel_unlock(chan);
1008 }
1009
1011 ast_answer(chan);
1012 }
1013
1015
1016 waitms = 100;
1017
1018 for (;;) {
1019 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
1020 struct ast_channel *prev = NULL;
1021
1022 if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
1023 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
1024 if (!res)
1025 res = ast_waitstream(chan, "");
1026 else if (res < 0) {
1028 break;
1029 }
1031 char tmp[2];
1032 tmp[0] = res;
1033 tmp[1] = '\0';
1034 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
1035 goto exit;
1036 else
1037 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1038 }
1039 }
1040
1041 /* Set up the iterator we'll be using during this call */
1042 if (!ast_strlen_zero(spec)) {
1044 struct ast_channel *unique_chan;
1045
1046 unique_chan = ast_channel_get_by_name(spec);
1047 if (!unique_chan) {
1048 res = -1;
1049 goto exit;
1050 }
1051 iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
1052 ast_channel_unref(unique_chan);
1053 } else {
1054 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
1055 }
1056 } else if (!ast_strlen_zero(exten)) {
1058 } else {
1060 }
1061
1062 if (!iter) {
1063 res = -1;
1064 goto exit;
1065 }
1066
1067 res = ast_waitfordigit(chan, waitms);
1068 if (res < 0) {
1069 iter = ast_channel_iterator_destroy(iter);
1071 break;
1072 }
1074 char tmp[2];
1075 tmp[0] = res;
1076 tmp[1] = '\0';
1077 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
1078 iter = ast_channel_iterator_destroy(iter);
1079 goto exit;
1080 } else {
1081 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
1082 }
1083 }
1084
1085 /* reset for the next loop around, unless overridden later */
1086 waitms = 100;
1087 num_spied_upon = 0;
1088
1089 for (autochan = next_channel(iter, chan);
1090 autochan;
1091 prev = autochan->chan,
1092 ast_autochan_destroy(autochan),
1093 autochan = next_autochan ?: next_channel(iter, chan),
1094 next_autochan = NULL) {
1095 int igrp = !mygroup;
1096 int ienf = !myenforced;
1097
1098 if (autochan->chan == prev) {
1099 ast_autochan_destroy(autochan);
1100 break;
1101 }
1102
1103 if (ast_check_hangup(chan)) {
1104 ast_autochan_destroy(autochan);
1105 break;
1106 }
1107
1108 ast_autochan_channel_lock(autochan);
1110 && !ast_channel_is_bridged(autochan->chan)) {
1112 continue;
1113 }
1114
1115 if (ast_check_hangup(autochan->chan)
1118 continue;
1119 }
1121
1122 if (mygroup) {
1123 int num_groups = 0;
1124 int num_mygroups = 0;
1125 char dup_group[512];
1126 char dup_mygroup[512];
1127 char *groups[NUM_SPYGROUPS];
1128 char *mygroups[NUM_SPYGROUPS];
1129 const char *group = NULL;
1130 int x;
1131 int y;
1132 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
1133 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
1134 ARRAY_LEN(mygroups));
1135
1136 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
1137 * rather than "SPYGROUP", this check is done to preserve expected behavior */
1138 ast_autochan_channel_lock(autochan);
1140 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
1141 } else {
1142 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
1143 }
1145
1146 if (!ast_strlen_zero(group)) {
1147 ast_copy_string(dup_group, group, sizeof(dup_group));
1148 num_groups = ast_app_separate_args(dup_group, ':', groups,
1149 ARRAY_LEN(groups));
1150 }
1151
1152 for (y = 0; y < num_mygroups; y++) {
1153 for (x = 0; x < num_groups; x++) {
1154 if (!strcmp(mygroups[y], groups[x])) {
1155 igrp = 1;
1156 break;
1157 }
1158 }
1159 }
1160 }
1161
1162 if (!igrp) {
1163 continue;
1164 }
1165 if (myenforced) {
1166 char ext[AST_CHANNEL_NAME + 3];
1167 char buffer[512];
1168 char *end;
1169
1170 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
1171
1172 ast_autochan_channel_lock(autochan);
1173 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
1175 if ((end = strchr(ext, '-'))) {
1176 *end++ = ':';
1177 *end = '\0';
1178 }
1179
1180 ext[0] = ':';
1181
1182 if (strcasestr(buffer, ext)) {
1183 ienf = 1;
1184 }
1185 }
1186
1187 if (!ienf) {
1188 continue;
1189 }
1190
1192 char peer_name[AST_NAME_STRLEN + 5];
1193 char *ptr, *s;
1194
1195 strcpy(peer_name, "spy-");
1196 ast_autochan_channel_lock(autochan);
1197 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
1199 if ((ptr = strchr(peer_name, '/'))) {
1200 *ptr++ = '\0';
1201 for (s = peer_name; s < ptr; s++) {
1202 *s = tolower(*s);
1203 }
1204 if ((s = strchr(ptr, '-'))) {
1205 *s = '\0';
1206 }
1207 }
1208
1210 const char *local_context = S_OR(name_context, "default");
1211 const char *local_mailbox = S_OR(mailbox, ptr);
1212
1213 if (local_mailbox) {
1214 res = spy_sayname(chan, local_mailbox, local_context);
1215 } else {
1216 res = -1;
1217 }
1218 }
1219 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
1220 int num;
1222 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
1223 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
1224 if (!res) {
1225 res = ast_waitstream(chan, "");
1226 }
1227 if (res) {
1228 ast_autochan_destroy(autochan);
1229 break;
1230 }
1231 } else {
1232 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
1233 }
1234 }
1235 if (ptr && (num = atoi(ptr))) {
1236 ast_say_digits(chan, num, "", ast_channel_language(chan));
1237 }
1238 }
1239 }
1240
1241 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
1242 num_spied_upon++;
1243
1244 if (res == -1) {
1245 ast_autochan_destroy(autochan);
1246 iter = ast_channel_iterator_destroy(iter);
1247 goto exit;
1248 } else if (res == -2) {
1249 res = 0;
1250 ast_autochan_destroy(autochan);
1251 iter = ast_channel_iterator_destroy(iter);
1252 goto exit;
1253 } else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
1254 struct ast_channel *next;
1255
1256 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
1257
1258 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
1259 next_autochan = ast_autochan_setup(next);
1260 next = ast_channel_unref(next);
1261 } else {
1262 /* stay on this channel, if it is still valid */
1263 ast_autochan_channel_lock(autochan);
1264 if (!ast_check_hangup(autochan->chan)) {
1265 next_autochan = ast_autochan_setup(autochan->chan);
1266 } else {
1267 /* the channel is gone */
1268 next_autochan = NULL;
1269 }
1271 }
1272 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
1273 ast_autochan_destroy(autochan);
1274 iter = ast_channel_iterator_destroy(iter);
1275 goto exit;
1276 }
1277 }
1278
1279 iter = ast_channel_iterator_destroy(iter);
1280
1281 if (res == -1 || ast_check_hangup(chan))
1282 break;
1283 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
1284 break;
1285 }
1286 }
1287exit:
1288
1290
1291 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
1292
1293 return res;
1294}
static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
Definition: app_chanspy.c:977
#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:734
static struct ast_autochan * next_channel(struct ast_channel_iterator *iter, struct ast_channel *chan)
Definition: app_chanspy.c:952
#define AST_NAME_STRLEN
Definition: app_chanspy.c:60
char * strcasestr(const char *, const char *)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3145
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:1349
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1330
@ AST_FLAG_SPYING
Definition: channel.h:1013
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:1338
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:1381
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
int ast_channel_is_bridged(const struct ast_channel *chan)
Determine if a channel is in a bridge.
Definition: channel.c:10559
#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)
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:7404
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2776
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1361
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:1312
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1148
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1874
const char * ext
Definition: http.c:150
#define ast_app_separate_args(a, b, c, d)
#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:8285
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
Definition: channel.c:8267
@ 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:703

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_NOANSWER, OPTION_NOTECH, OPTION_QUIET, OPTION_STOP, OPTION_UNIQUEID, pbx_builtin_getvar_helper(), S_OR, spy_sayname(), strcasestr(), 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 1536 of file app_chanspy.c.

1537{
1538 const char *spec = "DAHDI";
1539 struct ast_flags flags = {0};
1540 struct spy_dtmf_options user_options = {
1541 .cycle = '#',
1542 .volume = '\0',
1543 .exit = '*',
1544 };
1545 struct ast_format *oldwf;
1546 int res;
1547 char *mygroup = NULL;
1548
1549 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1551
1552 if (!ast_strlen_zero(data)) {
1553 mygroup = ast_strdupa(data);
1554 }
1558
1559 oldwf = ao2_bump(ast_channel_writeformat(chan));
1560 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1561 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1562 ao2_cleanup(oldwf);
1563 return -1;
1564 }
1565
1566 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1567
1568 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1569 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1570 ao2_cleanup(oldwf);
1571
1572 return res;
1573}

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

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

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, and spy_opts.

Referenced by load_module().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1586 of file app_chanspy.c.

1587{
1588 int res = 0;
1589
1593
1594 return res;
1595}
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1296
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1536
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1415
static const char app_dahdiscan[]
Definition: app_chanspy.c:392
static const char app_ext[]
Definition: app_chanspy.c:390
static const char app_chan[]
Definition: app_chanspy.c:388
#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 952 of file app_chanspy.c.

954{
955 struct ast_channel *next;
956 struct ast_autochan *autochan_store;
957 const size_t pseudo_len = strlen("DAHDI/pseudo");
958
959 if (!iter) {
960 return NULL;
961 }
962
964 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
965 || next == chan) {
966 continue;
967 }
968
969 autochan_store = ast_autochan_setup(next);
971
972 return autochan_store;
973 }
974 return NULL;
975}
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1369
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 638 of file app_chanspy.c.

640{
641 RAII_VAR(struct ast_channel_snapshot *, snapshot,
644
645 if (!snapshot) {
646 return -1;
647 }
648 ast_multi_channel_blob_add_channel(payload, role, snapshot);
649 return 0;
650}
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 659 of file app_chanspy.c.

662{
663 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
664 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
667
668 if (!spyer) {
669 ast_log(AST_LOG_WARNING, "Attempt to publish ChanSpy message for NULL spyer channel\n");
670 return;
671 }
672 blob = ast_json_null();
673 if (!blob || !type) {
674 return;
675 }
676
677 payload = ast_multi_channel_blob_create(blob);
678 if (!payload) {
679 return;
680 }
681
682 if (pack_channel_into_message(spyer, "spyer_channel", payload)) {
683 return;
684 }
685
686 if (spyee) {
687 if (pack_channel_into_message(spyee, "spyee_channel", payload)) {
688 return;
689 }
690 }
691
693 if (!message) {
694 return;
695 }
697}
static int pack_channel_into_message(struct ast_channel *chan, const char *role, struct ast_multi_channel_blob *payload)
Definition: app_chanspy.c:638
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:1538
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 472 of file app_chanspy.c.

473{
474 /* just store the data pointer in the channel structure */
475 return data;
476}

◆ spy_generate()

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

Definition at line 483 of file app_chanspy.c.

484{
485 struct chanspy_translation_helper *csth = data;
486 struct ast_frame *f, *cur;
487
490 /* Channel is already gone more than likely */
492 return -1;
493 }
494
495 if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
496 /* Option 'o' was set, so don't mix channel audio */
498 } else if (ast_test_flag(&csth->flags, OPTION_INTERLEAVED)) {
499 /* Option 'D' was set, so mix the spy frame as an interleaved dual channel frame. */
500 int i;
501 struct ast_frame *fr_read = NULL;
502 struct ast_frame *fr_write = NULL;
503 short read_buf[samples];
504 short write_buf[samples];
505 short stereo_buf[samples * 2];
506 struct ast_frame stereo_frame = {
508 .datalen = sizeof(stereo_buf),
509 .samples = samples,
510 };
511
512 f = ast_audiohook_read_frame_all(&csth->spy_audiohook, samples, ast_format_slin, &fr_read, &fr_write);
513 if (f) {
514 ast_frame_free(f, 0);
515 f = NULL;
516 }
517
518 if (fr_read) {
519 memcpy(read_buf, fr_read->data.ptr, sizeof(read_buf));
520 } else {
521 /* silent out the output frame if we can't read the input */
522 memset(read_buf, 0, sizeof(read_buf));
523 }
524
525 if (fr_write) {
526 memcpy(write_buf, fr_write->data.ptr, sizeof(write_buf));
527 } else {
528 memset(write_buf, 0, sizeof(write_buf));
529 }
530
531 for (i = 0; i < samples; i++) {
532 stereo_buf[i*2] = read_buf[i];
533 stereo_buf[i*2+1] = write_buf[i];
534 }
535
536 stereo_frame.data.ptr = stereo_buf;
538
539 f = ast_frdup(&stereo_frame);
540
541 if (fr_read) {
542 ast_frame_free(fr_read, 0);
543 }
544 if (fr_write) {
545 ast_frame_free(fr_write, 0);
546 }
547
548 } else {
550 }
551
553
554 if (!f)
555 return 0;
556
557 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
558 if (ast_write(chan, cur)) {
559 ast_frfree(f);
560 return -1;
561 }
562
563 if (csth->fd) {
564 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
565 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
566 }
567 }
568 }
569
570 ast_frfree(f);
571
572 return 0;
573}
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:488
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:483
@ 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:5112
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::@231 data
struct ast_audiohook spy_audiohook
Definition: app_chanspy.c:458
struct ast_flags flags
Definition: app_chanspy.c:463

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

479{
480 /* nothing to do */
481}

◆ spy_sayname()

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

Definition at line 977 of file app_chanspy.c.

978{
979 char *mailbox_id;
980
981 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
982 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
983 return ast_app_sayname(chan, mailbox_id);
984}
#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 581 of file app_chanspy.c.

582{
583 int res;
584
586 ast_verb(3, "Attaching spy channel %s to %s\n",
587 spychan_name, ast_channel_name(autochan->chan));
588
589 if (ast_test_flag(flags, OPTION_READONLY)) {
592 } else {
594 }
595 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
596 ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
597 } else {
599 }
600 res = ast_audiohook_attach(autochan->chan, audiohook);
602 return res;
603}
@ 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:521
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 605 of file app_chanspy.c.

606{
607 int res;
608
610 ast_verb(3, "Attaching spy channel %s to %s\n",
611 spychan_name, ast_channel_name(autochan->chan));
612
614 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
615 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
616 } else {
618 }
619 res = ast_audiohook_attach(autochan->chan, audiohook);
621 return res;
622}

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

1576{
1577 int res = 0;
1578
1582
1583 return res;
1584}
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 1597 of file app_chanspy.c.

◆ app_chan

const char app_chan[] = "ChanSpy"
static

Definition at line 388 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_dahdiscan

const char app_dahdiscan[] = "DAHDIScan"
static

Definition at line 392 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_ext

const char app_ext[] = "ExtenSpy"
static

Definition at line 390 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 1597 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 }, [ 'N' ] = { .flag = OPTION_NOANSWER }, [ '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 454 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:472
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:478
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:483

Definition at line 575 of file app_chanspy.c.

Referenced by channel_spy().