Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 388 of file app_chanspy.c.

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

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

413 {
414 OPT_ARG_VOLUME = 0,
422};
@ OPT_ARG_CYCLE
Definition: app_chanspy.c:420
@ OPT_ARG_RECORD
Definition: app_chanspy.c:416
@ OPT_ARG_EXIT
Definition: app_chanspy.c:419
@ OPT_ARG_NAME
Definition: app_chanspy.c:418
@ OPT_ARG_VOLUME
Definition: app_chanspy.c:414
@ OPT_ARG_ENFORCED
Definition: app_chanspy.c:417
@ OPT_ARG_ARRAY_SIZE
Definition: app_chanspy.c:421
@ OPT_ARG_GROUP
Definition: app_chanspy.c:415

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1588 of file app_chanspy.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1588 of file app_chanspy.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

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

694{
695 int retval = 0;
696 struct ast_autochan *internal_bridge_autochan;
697 struct ast_channel *spyee_chan;
698 RAII_VAR(struct ast_channel *, bridged, NULL, ast_channel_cleanup);
699
700 ast_autochan_channel_lock(spyee_autochan);
701 spyee_chan = ast_channel_ref(spyee_autochan->chan);
702 ast_autochan_channel_unlock(spyee_autochan);
703 bridged = ast_channel_bridge_peer(spyee_chan);
704 ast_channel_unref(spyee_chan);
705 if (!bridged) {
706 return -1;
707 }
708
709 ast_audiohook_init(bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
710
711 internal_bridge_autochan = ast_autochan_setup(bridged);
712 if (!internal_bridge_autochan) {
713 return -1;
714 }
715
716 if (start_whispering(internal_bridge_autochan, spyer_name, bridge_whisper_audiohook, flags)) {
717 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee '%s'. Barge mode disabled.\n", name);
718 retval = -1;
719 }
720
721 *spyee_bridge_autochan = internal_bridge_autochan;
722
723 return retval;
724}
static int start_whispering(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
Definition: app_chanspy.c:597
#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:10569
#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: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, 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 616 of file app_chanspy.c.

617{
618 if (digit == '4') {
621 } else if (digit == '5') {
624 } else if (digit == '6') {
627 }
628}
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 726 of file app_chanspy.c.

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

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

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

1528{
1529 const char *spec = "DAHDI";
1530 struct ast_flags flags = {0};
1531 struct spy_dtmf_options user_options = {
1532 .cycle = '#',
1533 .volume = '\0',
1534 .exit = '*',
1535 };
1536 struct ast_format *oldwf;
1537 int res;
1538 char *mygroup = NULL;
1539
1540 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */
1542
1543 if (!ast_strlen_zero(data)) {
1544 mygroup = ast_strdupa(data);
1545 }
1549
1550 oldwf = ao2_bump(ast_channel_writeformat(chan));
1551 if (ast_set_write_format(chan, ast_format_slin) < 0) {
1552 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1553 ao2_cleanup(oldwf);
1554 return -1;
1555 }
1556
1557 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
1558
1559 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
1560 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
1561 ao2_cleanup(oldwf);
1562
1563 return res;
1564}

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

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

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

1578{
1579 int res = 0;
1580
1584
1585 return res;
1586}
static int chanspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1287
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1527
static int extenspy_exec(struct ast_channel *chan, const char *data)
Definition: app_chanspy.c:1406
static const char app_dahdiscan[]
Definition: app_chanspy.c:386
static const char app_ext[]
Definition: app_chanspy.c:384
static const char app_chan[]
Definition: app_chanspy.c:382
#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 944 of file app_chanspy.c.

946{
947 struct ast_channel *next;
948 struct ast_autochan *autochan_store;
949 const size_t pseudo_len = strlen("DAHDI/pseudo");
950
951 if (!iter) {
952 return NULL;
953 }
954
956 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
957 || next == chan) {
958 continue;
959 }
960
961 autochan_store = ast_autochan_setup(next);
963
964 return autochan_store;
965 }
966 return NULL;
967}
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1368
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 630 of file app_chanspy.c.

632{
633 RAII_VAR(struct ast_channel_snapshot *, snapshot,
636
637 if (!snapshot) {
638 return -1;
639 }
640 ast_multi_channel_blob_add_channel(payload, role, snapshot);
641 return 0;
642}
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 651 of file app_chanspy.c.

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

465{
466 /* just store the data pointer in the channel structure */
467 return data;
468}

◆ spy_generate()

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

Definition at line 475 of file app_chanspy.c.

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

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

471{
472 /* nothing to do */
473}

◆ spy_sayname()

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

Definition at line 969 of file app_chanspy.c.

970{
971 char *mailbox_id;
972
973 mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
974 sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
975 return ast_app_sayname(chan, mailbox_id);
976}
#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 573 of file app_chanspy.c.

574{
575 int res;
576
578 ast_verb(3, "Attaching spy channel %s to %s\n",
579 spychan_name, ast_channel_name(autochan->chan));
580
581 if (ast_test_flag(flags, OPTION_READONLY)) {
584 } else {
586 }
587 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
588 ast_debug(9, "Using a long queue to store audio frames in spy audiohook\n");
589 } else {
591 }
592 res = ast_audiohook_attach(autochan->chan, audiohook);
594 return res;
595}
@ 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 597 of file app_chanspy.c.

598{
599 int res;
600
602 ast_verb(3, "Attaching spy channel %s to %s\n",
603 spychan_name, ast_channel_name(autochan->chan));
604
606 if (ast_test_flag(flags, OPTION_LONG_QUEUE)) {
607 ast_debug(9, "Using a long queue to store audio frames in whisper audiohook\n");
608 } else {
610 }
611 res = ast_audiohook_attach(autochan->chan, audiohook);
613 return res;
614}

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

1567{
1568 int res = 0;
1569
1573
1574 return res;
1575}
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 1588 of file app_chanspy.c.

◆ app_chan

const char app_chan[] = "ChanSpy"
static

Definition at line 382 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_dahdiscan

const char app_dahdiscan[] = "DAHDIScan"
static

Definition at line 386 of file app_chanspy.c.

Referenced by load_module(), and unload_module().

◆ app_ext

const char app_ext[] = "ExtenSpy"
static

Definition at line 384 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 1588 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 446 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:464
static void spy_release(struct ast_channel *chan, void *data)
Definition: app_chanspy.c:470
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
Definition: app_chanspy.c:475

Definition at line 567 of file app_chanspy.c.

Referenced by channel_spy().