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); AST_MUTEX_DEFINE_STATIC(modlock);
#define AST_NAME_STRLEN 256 #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 *tdesc = "Listen to the audio of an active channel";
static const char *app = "ChanSpy"; static const char *app = "ChanSpy";
@ -120,26 +118,26 @@ struct chanspy_translation_helper {
static struct ast_channel *local_channel_walk(struct ast_channel *chan) static struct ast_channel *local_channel_walk(struct ast_channel *chan)
{ {
struct ast_channel *ret; struct ast_channel *ret;
ast_mutex_lock(&modlock); 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(&ret->lock);
}
ast_mutex_unlock(&modlock); ast_mutex_unlock(&modlock);
return ret; return ret;
} }
static struct ast_channel *local_get_channel_begin_name(char *name) static struct ast_channel *local_get_channel_begin_name(char *name)
{ {
struct ast_channel *chan, *ret = NULL; struct ast_channel *ret;
ast_mutex_lock(&modlock); ast_mutex_lock(&modlock);
chan = local_channel_walk(NULL);
while (chan) { if ((ret = ast_get_channel_by_name_prefix_locked(name, strlen(name))))
if (!strncmp(chan->name, name, strlen(name))) { ast_mutex_unlock(&ret->lock);
ret = chan;
break;
}
chan = local_channel_walk(chan);
}
ast_mutex_unlock(&modlock); ast_mutex_unlock(&modlock);
return ret; return ret;
@ -185,7 +183,6 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
return 0; return 0;
} }
static struct ast_generator spygen = { static struct ast_generator spygen = {
.alloc = spy_alloc, .alloc = spy_alloc,
.release = spy_release, .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); res = ast_channel_spy_add(chan, spy);
ast_channel_unlock(chan); 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); ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
}
return res; return res;
} }
@ -250,20 +246,21 @@ 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)) if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
csth->volfactor = 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) static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
{ {
struct chanspy_translation_helper csth; struct chanspy_translation_helper csth;
int running, res = 0, x = 0; int running, res, x = 0;
char inp[24]; char inp[24] = {0};
char *name=NULL; char *name;
struct ast_frame *f; struct ast_frame *f;
running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)); if (!(chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee)))
return 0;
if (running) {
memset(inp, 0, sizeof(inp));
name = ast_strdupa(spyee->name); name = ast_strdupa(spyee->name);
if (option_verbose >= 2) if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
@ -279,76 +276,68 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int
ast_mutex_init(&csth.spy.lock); ast_mutex_init(&csth.spy.lock);
csth.volfactor = *volfactor; csth.volfactor = *volfactor;
set_volume(chan, &csth); set_volume(chan, &csth);
csth.spy.read_vol_adjustment = csth.volfactor;
csth.spy.write_vol_adjustment = csth.volfactor;
csth.fd = fd; csth.fd = fd;
if (start_spying(spyee, chan, &csth.spy)) if (start_spying(spyee, chan, &csth.spy)) {
running = 0; ast_mutex_destroy(&csth.spy.lock);
return 0;
} }
if (running) {
running = 1;
ast_activate_generator(chan, &spygen, &csth); ast_activate_generator(chan, &spygen, &csth);
while (csth.spy.status == CHANSPY_RUNNING && /* Note: it is very important that the ast_waitfor() be the first
chan && !ast_check_hangup(chan) && condition in this expression, so that if we wait for some period
spyee && of time before receiving a frame from our spying channel, we check
!ast_check_hangup(spyee) && for hangup on the spied-on channel _after_ knowing that frame
running == 1 && has arrived, since the spied-on channel could have gone away while
(res = ast_waitfor(chan, -1) > -1)) { we were waiting
if ((f = ast_read(chan))) { */
res = 0; while ((res = ast_waitfor(chan, 500) > -1) &&
if (f->frametype == AST_FRAME_DTMF) { csth.spy.status == CHANSPY_RUNNING &&
res = f->subclass; !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); ast_frfree(f);
if (!res) { if (!res)
continue; continue;
}
} else { if (x == sizeof(inp))
break;
}
if (x == sizeof(inp)) {
x = 0; x = 0;
}
if (res < 0) { if (res < 0) {
running = -1; running = -1;
break;
} }
if (res == 0) {
continue; if (res == '*') {
} else if (res == '*') {
running = 0; running = 0;
break;
} else if (res == '#') { } else if (res == '#') {
if (!ast_strlen_zero(inp)) { if (!ast_strlen_zero(inp)) {
running = x ? atoi(inp) : -1; running = atoi(inp);
break; break;
} else { }
(*volfactor)++; (*volfactor)++;
if (*volfactor > 4) { if (*volfactor > 4)
*volfactor = -4; *volfactor = -4;
} if (option_verbose > 2)
if (option_verbose > 2) {
ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
}
csth.volfactor = *volfactor; csth.volfactor = *volfactor;
set_volume(chan, &csth); set_volume(chan, &csth);
csth.spy.read_vol_adjustment = csth.volfactor; } else if (res >= '0' && res <= '9') {
csth.spy.write_vol_adjustment = csth.volfactor;
}
} else if (res >= 48 && res <= 57) {
inp[x++] = res; inp[x++] = res;
} }
} }
ast_deactivate_generator(chan); ast_deactivate_generator(chan);
stop_spying(spyee, &csth.spy); stop_spying(spyee, &csth.spy);
if (option_verbose >= 2) { if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
}
} else {
running = 0;
}
ast_mutex_destroy(&csth.spy.lock); ast_mutex_destroy(&csth.spy.lock);
@ -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) static int chanspy_exec(struct ast_channel *chan, void *data)
{ {
struct localuser *u; struct localuser *u;
struct ast_channel *peer=NULL, *prev=NULL; struct ast_channel *peer, *prev;
char name[AST_NAME_STRLEN], char name[AST_NAME_STRLEN],
peer_name[AST_NAME_STRLEN + 5], peer_name[AST_NAME_STRLEN + 5],
*args, *ptr,
*ptr = NULL,
*options = NULL, *options = NULL,
*spec = NULL, *spec = NULL,
*argv[5], *argv[5],
*mygroup = NULL, *mygroup = NULL,
*recbase = NULL; *recbase = NULL;
int res = -1, int res = -1,
volfactor = 0, volfactor,
silent = 0, silent = 0,
argc = 0, argc,
bronly = 0, bronly = 0,
chosen = 0, waitms,
count=0, num,
waitms = 100, oldwf,
num = 0,
oldrf = 0,
oldwf = 0,
fd = 0; fd = 0;
struct ast_flags flags; struct ast_flags flags;
signed char zero_volume = 0; signed char zero_volume = 0;
if (!(args = ast_strdupa(data))) data = ast_strdupa(data);
return -1;
LOCAL_USER_ADD(u); LOCAL_USER_ADD(u);
oldrf = chan->readformat;
oldwf = chan->writeformat; 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) { if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
@ -406,7 +383,7 @@ 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 */ 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]; spec = argv[0];
if (argc > 1) { if (argc > 1) {
options = argv[1]; options = argv[1];
@ -418,21 +395,22 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
if (options) { if (options) {
char *opts[OPT_ARG_ARRAY_SIZE]; char *opts[OPT_ARG_ARRAY_SIZE];
ast_app_parse_options(chanspy_opts, &flags, opts, options); ast_app_parse_options(chanspy_opts, &flags, opts, options);
if (ast_test_flag(&flags, OPTION_GROUP)) { if (ast_test_flag(&flags, OPTION_GROUP))
mygroup = opts[1]; mygroup = opts[OPT_ARG_GROUP];
}
if (ast_test_flag(&flags, OPTION_RECORD)) { if (ast_test_flag(&flags, OPTION_RECORD) &&
if (!(recbase = opts[2])) { !(recbase = opts[OPT_ARG_RECORD]))
recbase = "chanspy"; recbase = "chanspy";
}
}
silent = ast_test_flag(&flags, OPTION_QUIET); silent = ast_test_flag(&flags, OPTION_QUIET);
bronly = ast_test_flag(&flags, OPTION_BRIDGED); 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; 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"); ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
else else
volfactor = vol; volfactor = vol;
@ -441,55 +419,60 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
if (recbase) { if (recbase) {
char filename[512]; 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) { 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; fd = 0;
} }
} }
waitms = 100;
for (;;) { for (;;) {
if (!silent) { if (!silent) {
res = ast_streamfile(chan, "beep", chan->language); res = ast_streamfile(chan, "beep", chan->language);
if (!res) if (!res)
res = ast_waitstream(chan, ""); res = ast_waitstream(chan, "");
if (res < 0) { else if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING); ast_clear_flag(chan, AST_FLAG_SPYING);
break; break;
} }
} }
count = 0;
res = ast_waitfordigit(chan, waitms); res = ast_waitfordigit(chan, waitms);
if (res < 0) { if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING); ast_clear_flag(chan, AST_FLAG_SPYING);
break; break;
} }
peer = local_channel_walk(NULL); /* reset for the next loop around, unless overridden later */
prev=NULL; waitms = 100;
while(peer) {
if (peer != chan) { for (peer = local_channel_walk(NULL), prev = NULL;
const char *group = NULL; peer;
int igrp = 1; peer = local_channel_walk(peer)) {
char *groups[25] = {0}; const char *group;
int igrp = 0;
char *groups[25];
int num_groups = 0; int num_groups = 0;
char *dup_group; char *dup_group;
int x;
char *s;
if (peer == prev && !chosen) { if (peer == chan)
continue;
if (peer == prev)
break; break;
}
chosen = 0;
if (mygroup) { if (mygroup) {
int x;
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
dup_group = ast_strdupa(group); dup_group = ast_strdupa(group);
num_groups = ast_app_separate_args(dup_group, ':', groups, sizeof(groups) / sizeof(groups[0])); num_groups = ast_app_separate_args(dup_group, ':', groups,
sizeof(groups) / sizeof(groups[0]));
} }
igrp = 0;
if (num_groups) { if (num_groups) {
for (x = 0; x < num_groups; x++) { for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroup, groups[x])) { if (!strcmp(mygroup, groups[x])) {
@ -500,22 +483,25 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
} }
} }
if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) && if (!igrp)
!strncasecmp(peer->name, spec, strlen(spec)))))) { continue;
if (peer && (!bronly || ast_bridged_channel(peer)) &&
!ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) { if (spec && strncasecmp(peer->name, spec, strlen(spec)))
int x = 0; continue;
strncpy(peer_name, "spy-", 5);
strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN); 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 = strchr(peer_name, '/');
*ptr = '\0'; *ptr++ = '\0';
ptr++;
for (x = 0 ; x < strlen(peer_name) ; x++) { for (s = peer_name; s < ptr; s++)
if (peer_name[x] == '/') { *s = tolower(*s);
break;
}
peer_name[x] = tolower(peer_name[x]);
}
if (!silent) { if (!silent) {
if (ast_fileexists(peer_name, NULL, NULL) != -1) { if (ast_fileexists(peer_name, NULL, NULL) != -1) {
@ -529,46 +515,36 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
if ((num = atoi(ptr))) if ((num = atoi(ptr)))
ast_say_digits(chan, atoi(ptr), "", chan->language); ast_say_digits(chan, atoi(ptr), "", chan->language);
} }
count++;
waitms = 5000;
prev = peer; prev = peer;
res = channel_spy(chan, peer, &volfactor, fd); res = channel_spy(chan, peer, &volfactor, fd);
if (res == -1) { if (res == -1) {
break; break;
} else if (res > 1 && spec) { } else if (res > 1 && spec) {
snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res); snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((peer = local_get_channel_begin_name(name))) { if ((peer = local_get_channel_begin_name(name)))
chosen = 1; prev = NULL;
}
continue; continue;
} }
} }
} }
}
if ((peer = local_channel_walk(peer)) == NULL) {
break;
}
}
waitms = count ? 100 : 5000;
}
if (fd)
if (fd > 0) {
close(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_log(LOG_ERROR, "Could Not Set Write Format.\n");
}
ast_clear_flag(chan, AST_FLAG_SPYING); ast_clear_flag(chan, AST_FLAG_SPYING);
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 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) static int unload_module(void *mod)
@ -585,6 +561,7 @@ static int unload_module(void *mod)
static int load_module(void *mod) static int load_module(void *mod)
{ {
__mod_desc = mod; __mod_desc = mod;
return ast_register_application(app, chanspy_exec, tdesc, desc); return ast_register_application(app, chanspy_exec, tdesc, desc);
} }

Loading…
Cancel
Save