This commit is contained in:
Walter Doekes 2024-03-20 03:30:22 -06:00 committed by GitHub
commit bcde8cca3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 327 additions and 256 deletions

View File

@ -56,6 +56,7 @@
#include "asterisk/stasis_channels.h"
#include "asterisk/json.h"
#include "asterisk/format_cache.h"
#include "asterisk/vector.h"
#define AST_NAME_STRLEN 256
#define NUM_SPYGROUPS 128
@ -561,7 +562,7 @@ static struct ast_generator spygen = {
.generate = spy_generate,
};
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, struct ast_flags *flags)
static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook, const struct ast_flags *flags)
{
int res;
@ -695,8 +696,8 @@ static int attach_barge(struct ast_autochan *spyee_autochan,
}
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)
int *volfactor, int fd, const struct spy_dtmf_options *user_options, struct ast_flags *flags,
const char *exitcontext)
{
struct chanspy_translation_helper csth;
int running = 0, bridge_connected = 0, res, x = 0;
@ -913,7 +914,7 @@ static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_auto
}
static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
struct ast_channel *chan)
struct ast_channel *chan, struct ast_vector_const_string *skip)
{
struct ast_channel *next;
struct ast_autochan *autochan_store;
@ -924,8 +925,21 @@ static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
}
for (; (next = ast_channel_iterator_next(iter)); ast_channel_unref(next)) {
if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)
|| next == chan) {
const char *name = ast_channel_name(next);
int do_next = 0;
if (!strncmp(name, "DAHDI/pseudo", pseudo_len) || next == chan) {
do_next = 1;
} else {
for (unsigned i = 0; i < AST_VECTOR_SIZE(skip); ++i) {
if (!strcmp(name, AST_VECTOR_GET(skip, i))) {
do_next = 1;
break;
}
}
}
if (do_next) {
continue;
}
@ -946,18 +960,249 @@ static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char
return ast_app_sayname(chan, mailbox_id);
}
struct channel_spy_context {
const char *mygroup;
const char *myenforced;
const char *spec;
const char *exten;
const char *context;
const char *mailbox;
const char *name_context;
};
static int channel_spy_select_one(struct ast_channel_iterator *iter,
struct ast_vector_const_string *channels_spied_upon,
struct ast_channel *chan, int *num_spied_upon,
int *volfactor, const int fd, const struct spy_dtmf_options *user_options,
struct ast_flags *flags, const char *exitcontext, const struct channel_spy_context *ctx)
{
struct ast_autochan *autochan = NULL, *next_autochan = NULL;
struct ast_channel *prev = NULL;
int res = 0;
for (autochan = next_channel(iter, chan, channels_spied_upon);
autochan;
prev = autochan->chan,
ast_autochan_destroy(autochan),
autochan = next_autochan ?: (
iter ? next_channel(iter, chan, channels_spied_upon) : NULL),
next_autochan = NULL) {
int igrp = !ctx->mygroup;
int ienf = !ctx->myenforced;
if (autochan->chan == prev) {
ast_autochan_destroy(autochan);
break;
}
if (ast_check_hangup(chan)) {
ast_autochan_destroy(autochan);
break;
}
ast_autochan_channel_lock(autochan);
if (ast_test_flag(flags, OPTION_BRIDGED)
&& !ast_channel_is_bridged(autochan->chan)) {
ast_autochan_channel_unlock(autochan);
continue;
}
if (ast_check_hangup(autochan->chan)
|| ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) {
ast_autochan_channel_unlock(autochan);
continue;
}
ast_autochan_channel_unlock(autochan);
if (ctx->mygroup) {
int num_groups = 0;
int num_mygroups = 0;
char dup_group[512];
char dup_mygroup[512];
char *groups[NUM_SPYGROUPS];
char *mygroups[NUM_SPYGROUPS];
const char *group = NULL;
int x;
int y;
ast_copy_string(dup_mygroup, ctx->mygroup, sizeof(dup_mygroup));
num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
ARRAY_LEN(mygroups));
/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
* rather than "SPYGROUP", this check is done to preserve expected behavior */
ast_autochan_channel_lock(autochan);
if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
} else {
group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
}
ast_autochan_channel_unlock(autochan);
if (!ast_strlen_zero(group)) {
ast_copy_string(dup_group, group, sizeof(dup_group));
num_groups = ast_app_separate_args(dup_group, ':', groups,
ARRAY_LEN(groups));
}
for (y = 0; y < num_mygroups && !igrp; y++) {
for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroups[y], groups[x])) {
igrp = 1;
break;
}
}
}
}
if (!igrp) {
continue;
}
if (ctx->myenforced) {
char ext[AST_CHANNEL_NAME + 3];
char buffer[512];
char *end;
snprintf(buffer, sizeof(buffer) - 1, ":%s:", ctx->myenforced);
ast_autochan_channel_lock(autochan);
ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
ast_autochan_channel_unlock(autochan);
if ((end = strchr(ext, '-'))) {
*end++ = ':';
*end = '\0';
}
ext[0] = ':';
if (strcasestr(buffer, ext)) {
ienf = 1;
}
}
if (!ienf) {
continue;
}
/* Important! We destroy the channel iterator here, freeing unrelated channels
* that are held by refcount. We're now holding on to exactly one victim channel. */
iter = ast_channel_iterator_destroy(iter);
/* BUG: In theory, we're leaking (hoarding) memory until either:
* - the spying channels hangs up, or
* - we do a full iteration without getting finding a single channel to spy on.
* When either event occurs, the memory is freed. This is more
* likely to happen than not. */
AST_VECTOR_APPEND(channels_spied_upon, ast_strdup(ast_channel_name(autochan->chan)));
ast_debug(1, "After adding %s we have %zu items in the channels_spied_upon list\n",
ast_channel_name(autochan->chan), AST_VECTOR_SIZE(channels_spied_upon));
if (!ast_test_flag(flags, OPTION_QUIET)) {
char peer_name[AST_NAME_STRLEN + 5];
char *ptr, *s;
strcpy(peer_name, "spy-");
ast_autochan_channel_lock(autochan);
strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
ast_autochan_channel_unlock(autochan);
if ((ptr = strchr(peer_name, '/'))) {
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++) {
*s = tolower(*s);
}
if ((s = strchr(ptr, '-'))) {
*s = '\0';
}
}
if (ast_test_flag(flags, OPTION_NAME)) {
const char *local_context = S_OR(ctx->name_context, "default");
const char *local_mailbox = S_OR(ctx->mailbox, ptr);
if (local_mailbox) {
res = spy_sayname(chan, local_mailbox, local_context);
} else {
res = -1;
}
}
if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
int num;
if (!ast_test_flag(flags, OPTION_NOTECH)) {
if (ast_fileexists(peer_name, NULL, NULL) > 0) {
res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
if (!res) {
res = ast_waitstream(chan, "");
}
if (res) {
ast_autochan_destroy(autochan);
break;
}
} else {
res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
}
}
if (ptr && (num = atoi(ptr))) {
ast_say_digits(chan, num, "", ast_channel_language(chan));
}
}
}
res = channel_spy(chan, autochan, volfactor, fd, user_options, flags, exitcontext);
(*num_spied_upon)++;
if (res == -1 || res == -2) {
ast_autochan_destroy(autochan);
break;
} else if (res > 1 && ctx->spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
char nameprefix[AST_NAME_STRLEN];
struct ast_channel *next;
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", ctx->spec, res);
if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
next_autochan = ast_autochan_setup(next);
next = ast_channel_unref(next);
} else {
/* stay on this channel, if it is still valid */
ast_autochan_channel_lock(autochan);
if (!ast_check_hangup(autochan->chan)) {
next_autochan = ast_autochan_setup(autochan->chan);
} else {
/* the channel is gone */
next_autochan = NULL;
}
ast_autochan_channel_unlock(autochan);
}
} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
ast_autochan_destroy(autochan);
res = -2; /* propagates stop, but with 0 exit status */
break;
}
}
if (iter) {
iter = ast_channel_iterator_destroy(iter);
}
return res;
}
/* Same as ast_free_ptr(), but this allows us to free const char*'s without the
* compiler complaining about touching const. */
static void free_const_ptr(const char *ptr) {
ast_free((char *)ptr);
}
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)
const struct channel_spy_context *ctx)
{
char nameprefix[AST_NAME_STRLEN];
char exitcontext[AST_MAX_CONTEXT] = "";
signed char zero_volume = 0;
int waitms;
const int waitms = 100;
int res;
int num_spied_upon = 1;
struct ast_channel_iterator *iter = NULL;
struct ast_vector_const_string channels_spied_upon;
if (ast_test_flag(flags, OPTION_EXIT)) {
const char *c;
@ -975,12 +1220,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
ast_channel_set_flag(chan, AST_FLAG_SPYING);
waitms = 100;
AST_VECTOR_INIT(&channels_spied_upon, 0);
for (;;) {
struct ast_autochan *autochan = NULL, *next_autochan = NULL;
struct ast_channel *prev = NULL;
if (!ast_test_flag(flags, OPTION_QUIET) && num_spied_upon) {
res = ast_streamfile(chan, "beep", ast_channel_language(chan));
if (!res)
@ -993,42 +1235,41 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
char tmp[2];
tmp[0] = res;
tmp[1] = '\0';
if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
goto exit;
else
ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
break;
}
ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
}
}
/* Set up the iterator we'll be using during this call */
if (!ast_strlen_zero(spec)) {
if (!ast_strlen_zero(ctx->spec)) {
if (ast_test_flag(flags, OPTION_UNIQUEID)) {
struct ast_channel *unique_chan;
unique_chan = ast_channel_get_by_name(spec);
unique_chan = ast_channel_get_by_name(ctx->spec);
if (!unique_chan) {
res = -1;
goto exit;
break;
}
iter = ast_channel_iterator_by_name_new(ast_channel_name(unique_chan), 0);
ast_channel_unref(unique_chan);
} else {
iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
iter = ast_channel_iterator_by_name_new(ctx->spec, strlen(ctx->spec));
}
} else if (!ast_strlen_zero(exten)) {
iter = ast_channel_iterator_by_exten_new(exten, context);
} else if (!ast_strlen_zero(ctx->exten)) {
iter = ast_channel_iterator_by_exten_new(ctx->exten, ctx->context);
} else {
iter = ast_channel_iterator_all_new();
}
if (!iter) {
res = -1;
goto exit;
break;
}
res = ast_waitfordigit(chan, waitms);
if (res < 0) {
iter = ast_channel_iterator_destroy(iter);
ast_channel_clear_flag(chan, AST_FLAG_SPYING);
break;
}
@ -1037,216 +1278,49 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
tmp[0] = res;
tmp[1] = '\0';
if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
iter = ast_channel_iterator_destroy(iter);
goto exit;
} else {
ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
break;
}
ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
}
/* reset for the next loop around, unless overridden later */
waitms = 100;
/* The channel_spy_select_one spies on at most one channel. It
* destroys the iterator so the unused channels can be freed asap. */
num_spied_upon = 0;
res = channel_spy_select_one(iter, &channels_spied_upon, chan, &num_spied_upon, &volfactor, fd, user_options, flags, exitcontext, ctx);
iter = NULL;
for (autochan = next_channel(iter, chan);
autochan;
prev = autochan->chan,
ast_autochan_destroy(autochan),
autochan = next_autochan ?: next_channel(iter, chan),
next_autochan = NULL) {
int igrp = !mygroup;
int ienf = !myenforced;
if (autochan->chan == prev) {
ast_autochan_destroy(autochan);
break;
}
if (ast_check_hangup(chan)) {
ast_autochan_destroy(autochan);
break;
}
ast_autochan_channel_lock(autochan);
if (ast_test_flag(flags, OPTION_BRIDGED)
&& !ast_channel_is_bridged(autochan->chan)) {
ast_autochan_channel_unlock(autochan);
continue;
}
if (ast_check_hangup(autochan->chan)
|| ast_test_flag(ast_channel_flags(autochan->chan), AST_FLAG_SPYING)) {
ast_autochan_channel_unlock(autochan);
continue;
}
ast_autochan_channel_unlock(autochan);
if (mygroup) {
int num_groups = 0;
int num_mygroups = 0;
char dup_group[512];
char dup_mygroup[512];
char *groups[NUM_SPYGROUPS];
char *mygroups[NUM_SPYGROUPS];
const char *group = NULL;
int x;
int y;
ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
ARRAY_LEN(mygroups));
/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
* rather than "SPYGROUP", this check is done to preserve expected behavior */
ast_autochan_channel_lock(autochan);
if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
} else {
group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
}
ast_autochan_channel_unlock(autochan);
if (!ast_strlen_zero(group)) {
ast_copy_string(dup_group, group, sizeof(dup_group));
num_groups = ast_app_separate_args(dup_group, ':', groups,
ARRAY_LEN(groups));
}
for (y = 0; y < num_mygroups; y++) {
for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroups[y], groups[x])) {
igrp = 1;
break;
}
}
}
}
if (!igrp) {
continue;
}
if (myenforced) {
char ext[AST_CHANNEL_NAME + 3];
char buffer[512];
char *end;
snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
ast_autochan_channel_lock(autochan);
ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
ast_autochan_channel_unlock(autochan);
if ((end = strchr(ext, '-'))) {
*end++ = ':';
*end = '\0';
}
ext[0] = ':';
if (strcasestr(buffer, ext)) {
ienf = 1;
}
}
if (!ienf) {
continue;
}
if (!ast_test_flag(flags, OPTION_QUIET)) {
char peer_name[AST_NAME_STRLEN + 5];
char *ptr, *s;
strcpy(peer_name, "spy-");
ast_autochan_channel_lock(autochan);
strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
ast_autochan_channel_unlock(autochan);
if ((ptr = strchr(peer_name, '/'))) {
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++) {
*s = tolower(*s);
}
if ((s = strchr(ptr, '-'))) {
*s = '\0';
}
}
if (ast_test_flag(flags, OPTION_NAME)) {
const char *local_context = S_OR(name_context, "default");
const char *local_mailbox = S_OR(mailbox, ptr);
if (local_mailbox) {
res = spy_sayname(chan, local_mailbox, local_context);
} else {
res = -1;
}
}
if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
int num;
if (!ast_test_flag(flags, OPTION_NOTECH)) {
if (ast_fileexists(peer_name, NULL, NULL) > 0) {
res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
if (!res) {
res = ast_waitstream(chan, "");
}
if (res) {
ast_autochan_destroy(autochan);
break;
}
} else {
res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE);
}
}
if (ptr && (num = atoi(ptr))) {
ast_say_digits(chan, num, "", ast_channel_language(chan));
}
}
}
res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
num_spied_upon++;
if (res == -1) {
ast_autochan_destroy(autochan);
iter = ast_channel_iterator_destroy(iter);
goto exit;
} else if (res == -2) {
res = 0;
ast_autochan_destroy(autochan);
iter = ast_channel_iterator_destroy(iter);
goto exit;
} else if (res > 1 && spec && !ast_test_flag(flags, OPTION_UNIQUEID)) {
struct ast_channel *next;
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
next_autochan = ast_autochan_setup(next);
next = ast_channel_unref(next);
} else {
/* stay on this channel, if it is still valid */
ast_autochan_channel_lock(autochan);
if (!ast_check_hangup(autochan->chan)) {
next_autochan = ast_autochan_setup(autochan->chan);
} else {
/* the channel is gone */
next_autochan = NULL;
}
ast_autochan_channel_unlock(autochan);
}
} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
ast_autochan_destroy(autochan);
iter = ast_channel_iterator_destroy(iter);
goto exit;
}
if (res == -2) {
/* propagated stop */
res = 0;
break;
} else if (res == -1) {
/* stop because of error */
break;
} else if (ast_check_hangup(chan)) {
/* stop because spy hung up */
break;
}
iter = ast_channel_iterator_destroy(iter);
if (num_spied_upon == 0) {
if (ast_test_flag(flags, OPTION_STOP)) {
/* stop after one fully depleted iterator */
break;
}
if (res == -1 || ast_check_hangup(chan))
break;
if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
break;
/* If we did spy on a channel, we'll keep the channels_spied_upon
* list. If we spied on nothing, we'll wipe it so we
* can restart the iteration. */
AST_VECTOR_RESET(&channels_spied_upon, free_const_ptr);
}
}
exit:
if (iter) {
iter = ast_channel_iterator_destroy(iter);
}
/* Make sure we free our temp storage. */
AST_VECTOR_RESET(&channels_spied_upon, free_const_ptr);
AST_VECTOR_FREE(&channels_spied_upon);
ast_channel_clear_flag(chan, AST_FLAG_SPYING);
@ -1257,8 +1331,6 @@ exit:
static int chanspy_exec(struct ast_channel *chan, const char *data)
{
char *myenforced = NULL;
char *mygroup = NULL;
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
@ -1268,10 +1340,9 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
.exit = '\0',
};
RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
struct channel_spy_context ctx = {0};
int volfactor = 0;
int res;
char *mailbox = NULL;
char *name_context = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(spec);
AST_APP_ARG(options);
@ -1281,14 +1352,15 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
AST_STANDARD_APP_ARGS(args, parse);
if (args.spec && !strcmp(args.spec, "all"))
args.spec = NULL;
if (args.spec && strcmp(args.spec, "all")) {
ctx.spec = args.spec;
}
if (args.options) {
char tmp;
ast_app_parse_options(spy_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, OPTION_GROUP))
mygroup = opts[OPT_ARG_GROUP];
ctx.mygroup = opts[OPT_ARG_GROUP];
if (ast_test_flag(&flags, OPTION_RECORD) &&
!(recbase = opts[OPT_ARG_RECORD]))
@ -1325,17 +1397,17 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
ast_set_flag(&flags, OPTION_WHISPER);
if (ast_test_flag(&flags, OPTION_ENFORCED))
myenforced = opts[OPT_ARG_ENFORCED];
ctx.myenforced = opts[OPT_ARG_ENFORCED];
if (ast_test_flag(&flags, OPTION_NAME)) {
if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
char *delimiter;
if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
mailbox = opts[OPT_ARG_NAME];
ctx.mailbox = opts[OPT_ARG_NAME];
*delimiter++ = '\0';
name_context = delimiter;
ctx.name_context = delimiter;
} else {
mailbox = opts[OPT_ARG_NAME];
ctx.mailbox = opts[OPT_ARG_NAME];
}
}
}
@ -1359,7 +1431,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
}
}
res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
res = common_exec(chan, &flags, volfactor, fd, &user_options, &ctx);
if (fd)
close(fd);
@ -1376,8 +1448,7 @@ static int chanspy_exec(struct ast_channel *chan, const char *data)
static int extenspy_exec(struct ast_channel *chan, const char *data)
{
char *ptr, *exten = NULL;
char *mygroup = NULL;
char *ptr;
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
@ -1387,10 +1458,9 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
.exit = '\0',
};
RAII_VAR(struct ast_format *, oldwf, NULL, ao2_cleanup);
struct channel_spy_context ctx = {0};
int volfactor = 0;
int res;
char *mailbox = NULL;
char *name_context = NULL;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(context);
AST_APP_ARG(options);
@ -1400,12 +1470,13 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
AST_STANDARD_APP_ARGS(args, parse);
if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
exten = args.context;
ctx.exten = args.context;
*ptr++ = '\0';
args.context = ptr;
ctx.context = ptr;
}
if (ast_strlen_zero(ctx.context)) {
ctx.context = ast_strdupa(ast_channel_context(chan));
}
if (ast_strlen_zero(args.context))
args.context = ast_strdupa(ast_channel_context(chan));
if (args.options) {
char *opts[OPT_ARG_ARRAY_SIZE];
@ -1413,7 +1484,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
ast_app_parse_options(spy_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, OPTION_GROUP))
mygroup = opts[OPT_ARG_GROUP];
ctx.mygroup = opts[OPT_ARG_GROUP];
if (ast_test_flag(&flags, OPTION_RECORD) &&
!(recbase = opts[OPT_ARG_RECORD]))
@ -1453,11 +1524,11 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
char *delimiter;
if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
mailbox = opts[OPT_ARG_NAME];
ctx.mailbox = opts[OPT_ARG_NAME];
*delimiter++ = '\0';
name_context = delimiter;
ctx.name_context = delimiter;
} else {
mailbox = opts[OPT_ARG_NAME];
ctx.mailbox = opts[OPT_ARG_NAME];
}
}
}
@ -1483,8 +1554,7 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
}
}
res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
res = common_exec(chan, &flags, volfactor, fd, &user_options, &ctx);
if (fd)
close(fd);
@ -1497,23 +1567,24 @@ static int extenspy_exec(struct ast_channel *chan, const char *data)
static int dahdiscan_exec(struct ast_channel *chan, const char *data)
{
const char *spec = "DAHDI";
struct ast_flags flags = {0};
struct spy_dtmf_options user_options = {
.cycle = '#',
.volume = '\0',
.exit = '*',
};
struct channel_spy_context ctx = {0};
struct ast_format *oldwf;
int res;
char *mygroup = NULL;
/* Coverity - This uninit_use should be ignored since this macro initializes the flags */
ast_clear_flag(&flags, AST_FLAGS_ALL);
if (!ast_strlen_zero(data)) {
mygroup = ast_strdupa(data);
ctx.mygroup = data;
}
ctx.spec = "DAHDI";
ast_set_flag(&flags, OPTION_DTMF_EXIT);
ast_set_flag(&flags, OPTION_DTMF_CYCLE);
ast_set_flag(&flags, OPTION_DAHDI_SCAN);
@ -1525,7 +1596,7 @@ static int dahdiscan_exec(struct ast_channel *chan, const char *data)
return -1;
}
res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
res = common_exec(chan, &flags, 0, 0, &user_options, &ctx);
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");