various cleanups:

use API call for finding channel by name prefix
  code formatting to match guidelines (lost about half the of the indenting)
  remove useless automatic variable initializations
  don't set the spying channel's read format to SLINEAR when we don't do anything with the voice frames we read from it anyway
  use proper option argument checking for volume argument



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@38368 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Kevin P. Fleming 19 years ago
parent 01e006c33c
commit 22d37976f2

@ -54,8 +54,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
AST_MUTEX_DEFINE_STATIC(modlock);
#define AST_NAME_STRLEN 256
#define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
static const char *tdesc = "Listen to the audio of an active channel";
static const char *app = "ChanSpy";
@ -120,28 +118,28 @@ struct chanspy_translation_helper {
static struct ast_channel *local_channel_walk(struct ast_channel *chan)
{
struct ast_channel *ret;
ast_mutex_lock(&modlock);
if ((ret = ast_channel_walk_locked(chan))) {
if ((ret = ast_channel_walk_locked(chan)))
ast_mutex_unlock(&ret->lock);
}
ast_mutex_unlock(&modlock);
return ret;
}
static struct ast_channel *local_get_channel_begin_name(char *name)
{
struct ast_channel *chan, *ret = NULL;
ast_mutex_lock(&modlock);
chan = local_channel_walk(NULL);
while (chan) {
if (!strncmp(chan->name, name, strlen(name))) {
ret = chan;
break;
}
chan = local_channel_walk(chan);
}
ast_mutex_unlock(&modlock);
struct ast_channel *ret;
ast_mutex_lock(&modlock);
if ((ret = ast_get_channel_by_name_prefix_locked(name, strlen(name))))
ast_mutex_unlock(&ret->lock);
ast_mutex_unlock(&modlock);
return ret;
}
@ -185,7 +183,6 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
return 0;
}
static struct ast_generator spygen = {
.alloc = spy_alloc,
.release = spy_release,
@ -203,9 +200,8 @@ static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, s
res = ast_channel_spy_add(chan, spy);
ast_channel_unlock(chan);
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
}
return res;
}
@ -250,106 +246,99 @@ static void set_volume(struct ast_channel *chan, struct chanspy_translation_help
if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
csth->volfactor = 0;
csth->spy.read_vol_adjustment = csth->volfactor;
csth->spy.write_vol_adjustment = csth->volfactor;
}
static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
{
struct chanspy_translation_helper csth;
int running, res = 0, x = 0;
char inp[24];
char *name=NULL;
int running, res, x = 0;
char inp[24] = {0};
char *name;
struct ast_frame *f;
running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
if (running) {
memset(inp, 0, sizeof(inp));
name = ast_strdupa(spyee->name);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
memset(&csth, 0, sizeof(csth));
ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
csth.spy.type = chanspy_spy_type;
csth.spy.status = CHANSPY_RUNNING;
csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
ast_mutex_init(&csth.spy.lock);
csth.volfactor = *volfactor;
set_volume(chan, &csth);
csth.spy.read_vol_adjustment = csth.volfactor;
csth.spy.write_vol_adjustment = csth.volfactor;
csth.fd = fd;
if (start_spying(spyee, chan, &csth.spy))
running = 0;
if (!(chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)))
return 0;
name = ast_strdupa(spyee->name);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
memset(&csth, 0, sizeof(csth));
ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
csth.spy.type = chanspy_spy_type;
csth.spy.status = CHANSPY_RUNNING;
csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
ast_mutex_init(&csth.spy.lock);
csth.volfactor = *volfactor;
set_volume(chan, &csth);
csth.fd = fd;
if (start_spying(spyee, chan, &csth.spy)) {
ast_mutex_destroy(&csth.spy.lock);
return 0;
}
if (running) {
running = 1;
ast_activate_generator(chan, &spygen, &csth);
while (csth.spy.status == CHANSPY_RUNNING &&
chan && !ast_check_hangup(chan) &&
spyee &&
!ast_check_hangup(spyee) &&
running == 1 &&
(res = ast_waitfor(chan, -1) > -1)) {
if ((f = ast_read(chan))) {
res = 0;
if (f->frametype == AST_FRAME_DTMF) {
res = f->subclass;
}
ast_frfree(f);
if (!res) {
continue;
}
} else {
ast_activate_generator(chan, &spygen, &csth);
/* Note: it is very important that the ast_waitfor() be the first
condition in this expression, so that if we wait for some period
of time before receiving a frame from our spying channel, we check
for hangup on the spied-on channel _after_ knowing that frame
has arrived, since the spied-on channel could have gone away while
we were waiting
*/
while ((res = ast_waitfor(chan, 500) > -1) &&
csth.spy.status == CHANSPY_RUNNING &&
!ast_check_hangup(chan) &&
!ast_check_hangup(spyee)) {
if (!(f = ast_read(chan)))
break;
res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
ast_frfree(f);
if (!res)
continue;
if (x == sizeof(inp))
x = 0;
if (res < 0) {
running = -1;
break;
}
if (res == '*') {
running = 0;
break;
} else if (res == '#') {
if (!ast_strlen_zero(inp)) {
running = atoi(inp);
break;
}
if (x == sizeof(inp)) {
x = 0;
}
if (res < 0) {
running = -1;
}
if (res == 0) {
continue;
} else if (res == '*') {
running = 0;
} else if (res == '#') {
if (!ast_strlen_zero(inp)) {
running = x ? atoi(inp) : -1;
break;
} else {
(*volfactor)++;
if (*volfactor > 4) {
*volfactor = -4;
}
if (option_verbose > 2) {
ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
}
csth.volfactor = *volfactor;
set_volume(chan, &csth);
csth.spy.read_vol_adjustment = csth.volfactor;
csth.spy.write_vol_adjustment = csth.volfactor;
}
} else if (res >= 48 && res <= 57) {
inp[x++] = res;
}
}
ast_deactivate_generator(chan);
stop_spying(spyee, &csth.spy);
if (option_verbose >= 2) {
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
(*volfactor)++;
if (*volfactor > 4)
*volfactor = -4;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
csth.volfactor = *volfactor;
set_volume(chan, &csth);
} else if (res >= '0' && res <= '9') {
inp[x++] = res;
}
} else {
running = 0;
}
ast_deactivate_generator(chan);
stop_spying(spyee, &csth.spy);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
ast_mutex_destroy(&csth.spy.lock);
return running;
@ -358,44 +347,32 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
static int chanspy_exec(struct ast_channel *chan, void *data)
{
struct localuser *u;
struct ast_channel *peer=NULL, *prev=NULL;
struct ast_channel *peer, *prev;
char name[AST_NAME_STRLEN],
peer_name[AST_NAME_STRLEN + 5],
*args,
*ptr = NULL,
*ptr,
*options = NULL,
*spec = NULL,
*argv[5],
*mygroup = NULL,
*recbase = NULL;
int res = -1,
volfactor = 0,
volfactor,
silent = 0,
argc = 0,
argc,
bronly = 0,
chosen = 0,
count=0,
waitms = 100,
num = 0,
oldrf = 0,
oldwf = 0,
waitms,
num,
oldwf,
fd = 0;
struct ast_flags flags;
signed char zero_volume = 0;
if (!(args = ast_strdupa(data)))
return -1;
data = ast_strdupa(data);
LOCAL_USER_ADD(u);
oldrf = chan->readformat;
oldwf = chan->writeformat;
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
LOCAL_USER_REMOVE(u);
return -1;
}
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
LOCAL_USER_REMOVE(u);
@ -406,9 +383,9 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
spec = argv[0];
if ( argc > 1) {
if (argc > 1) {
options = argv[1];
}
if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
@ -418,157 +395,156 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
if (options) {
char *opts[OPT_ARG_ARRAY_SIZE];
ast_app_parse_options(chanspy_opts, &flags, opts, options);
if (ast_test_flag(&flags, OPTION_GROUP)) {
mygroup = opts[1];
}
if (ast_test_flag(&flags, OPTION_RECORD)) {
if (!(recbase = opts[2])) {
recbase = "chanspy";
}
}
if (ast_test_flag(&flags, OPTION_GROUP))
mygroup = opts[OPT_ARG_GROUP];
if (ast_test_flag(&flags, OPTION_RECORD) &&
!(recbase = opts[OPT_ARG_RECORD]))
recbase = "chanspy";
silent = ast_test_flag(&flags, OPTION_QUIET);
bronly = ast_test_flag(&flags, OPTION_BRIDGED);
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
int vol;
if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
else
volfactor = vol;
}
}
}
if (recbase) {
char filename[512];
snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
fd = 0;
}
}
for(;;) {
waitms = 100;
for (;;) {
if (!silent) {
res = ast_streamfile(chan, "beep", chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (res < 0) {
else if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING);
break;
}
}
count = 0;
res = ast_waitfordigit(chan, waitms);
if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING);
break;
}
peer = local_channel_walk(NULL);
prev=NULL;
while(peer) {
if (peer != chan) {
const char *group = NULL;
int igrp = 1;
char *groups[25] = {0};
int num_groups = 0;
char *dup_group;
/* reset for the next loop around, unless overridden later */
waitms = 100;
for (peer = local_channel_walk(NULL), prev = NULL;
peer;
peer = local_channel_walk(peer)) {
const char *group;
int igrp = 0;
char *groups[25];
int num_groups = 0;
char *dup_group;
int x;
char *s;
if (peer == prev && !chosen) {
break;
}
chosen = 0;
if (mygroup) {
int x;
if (peer == chan)
continue;
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
dup_group = ast_strdupa(group);
num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0]));
}
if (peer == prev)
break;
igrp = 0;
if (num_groups) {
for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroup, groups[x])) {
igrp = 1;
break;
}
}
}
if (mygroup) {
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
dup_group = ast_strdupa(group);
num_groups = ast_app_separate_args(dup_group, ':', groups,
sizeof(groups) / sizeof(groups[0]));
}
if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
!strncasecmp(peer->name, spec, strlen(spec)))))) {
if (peer && (!bronly || ast_bridged_channel(peer)) &&
!ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
int x = 0;
strncpy(peer_name, "spy-", 5);
strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
ptr = strchr(peer_name, '/');
*ptr = '\0';
ptr++;
for (x = 0 ; x < strlen(peer_name) ; x++) {
if (peer_name[x] == '/') {
break;
}
peer_name[x] = tolower(peer_name[x]);
}
if (!silent) {
if (ast_fileexists(peer_name, NULL, NULL) != -1) {
res = ast_streamfile(chan, peer_name, chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (res)
break;
} else
res = ast_say_character_str(chan, peer_name, "", chan->language);
if ((num=atoi(ptr)))
ast_say_digits(chan, atoi(ptr), "", chan->language);
}
count++;
prev = peer;
res = channel_spy(chan, peer, &volfactor, fd);
if (res == -1) {
if (num_groups) {
for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroup, groups[x])) {
igrp = 1;
break;
} else if (res > 1 && spec) {
snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((peer = local_get_channel_begin_name(name))) {
chosen = 1;
}
continue;
}
}
}
}
}
if ((peer = local_channel_walk(peer)) == NULL) {
if (!igrp)
continue;
if (spec && strncasecmp(peer->name, spec, strlen(spec)))
continue;
if (bronly && !ast_bridged_channel(peer))
continue;
if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
continue;
strcpy(peer_name, "spy-");
strncat(peer_name, peer->name, AST_NAME_STRLEN);
ptr = strchr(peer_name, '/');
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++)
*s = tolower(*s);
if (!silent) {
if (ast_fileexists(peer_name, NULL, NULL) != -1) {
res = ast_streamfile(chan, peer_name, chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (res)
break;
} else
res = ast_say_character_str(chan, peer_name, "", chan->language);
if ((num = atoi(ptr)))
ast_say_digits(chan, atoi(ptr), "", chan->language);
}
waitms = 5000;
prev = peer;
res = channel_spy(chan, peer, &volfactor, fd);
if (res == -1) {
break;
} else if (res > 1 && spec) {
snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((peer = local_get_channel_begin_name(name)))
prev = NULL;
continue;
}
}
waitms = count ? 100 : 5000;
}
if (fd > 0) {
if (fd)
close(fd);
}
if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
}
if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
}
ast_clear_flag(chan, AST_FLAG_SPYING);
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
ALL_DONE(u, res);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void *mod)
@ -585,6 +561,7 @@ static int unload_module(void *mod)
static int load_module(void *mod)
{
__mod_desc = mod;
return ast_register_application(app, chanspy_exec, tdesc, desc);
}

Loading…
Cancel
Save