summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/app_channelredirect.c8
-rw-r--r--apps/app_chanspy.c450
-rw-r--r--apps/app_dahdiscan.c378
-rw-r--r--apps/app_directed_pickup.c112
-rw-r--r--apps/app_minivm.c5
-rw-r--r--apps/app_mixmonitor.c100
-rw-r--r--apps/app_senddtmf.c16
-rw-r--r--apps/app_softhangup.c14
-rw-r--r--apps/app_voicemail.c12
9 files changed, 349 insertions, 746 deletions
diff --git a/apps/app_channelredirect.c b/apps/app_channelredirect.c
index a20d20f43..f604151ee 100644
--- a/apps/app_channelredirect.c
+++ b/apps/app_channelredirect.c
@@ -86,8 +86,7 @@ static int asyncgoto_exec(struct ast_channel *chan, void *data)
return -1;
}
- chan2 = ast_get_channel_by_name_locked(args.channel);
- if (!chan2) {
+ if (!(chan2 = ast_channel_get_by_name(args.channel))) {
ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
pbx_builtin_setvar_helper(chan, "CHANNELREDIRECT_STATUS", "NOCHANNEL");
return 0;
@@ -96,9 +95,12 @@ static int asyncgoto_exec(struct ast_channel *chan, void *data)
if (chan2->pbx) {
ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
}
+
res = ast_async_parseable_goto(chan2, args.label);
+
+ chan2 = ast_channel_unref(chan2);
+
pbx_builtin_setvar_helper(chan, "CHANNELREDIRECT_STATUS", "SUCCESS");
- ast_channel_unlock(chan2);
return res;
}
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index 9d087c4d1..07eac74a2 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -50,6 +50,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
+#include "asterisk/autochan.h"
#define AST_NAME_STRLEN 256
#define NUM_SPYGROUPS 128
@@ -141,6 +142,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
name of the last channel that was spied on will be stored
in the <variable>SPY_CHANNEL</variable> variable.</para>
</option>
+ <option name="x">
+ <argument name="digit" required="true">
+ <para>Specify a DTMF digit that can be used to exit the application.</para>
+ </argument>
+ </option>
+ <option name="c">
+ <argument name="digit" required="true">
+ <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
+ </argument>
+ </option>
<option name="e">
<argument name="ext" required="true" />
<para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
@@ -262,6 +273,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
name of the last channel that was spied on will be stored
in the <variable>SPY_CHANNEL</variable> variable.</para>
</option>
+ <option name="x">
+ <argument name="digit" required="true">
+ <para>Specify a DTMF digit that can be used to exit the application.</para>
+ </argument>
+ </option>
+ <option name="c">
+ <argument name="digit" required="true">
+ <para>Specify a DTMF digit that can be used to spy on the next available channel.</para>
+ </argument>
+ </option>
<option name="e">
<argument name="ext" required="true" />
<para>Enable <emphasis>enforced</emphasis> mode, so the spying channel can
@@ -287,12 +308,29 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
<ref type="application">ChanSpy</ref>
</see-also>
</application>
-
+
+ <application name="DAHDIScan" language="en_US">
+ <synopsis>
+ Scan DAHDI channels to monitor calls.
+ </synopsis>
+ <syntax>
+ <parameter name="group">
+ <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
+ </parameter>
+ </syntax>
+ <description>
+ <para>Allows a call center manager to monitor DAHDI channels in a
+ convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
+ </description>
+ </application>
***/
+
static const char *app_chan = "ChanSpy";
static const char *app_ext = "ExtenSpy";
+static const char *app_dahdiscan = "DAHDIScan";
+
enum {
OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
@@ -307,7 +345,10 @@ enum {
OPTION_NOTECH = (1 << 10), /* Skip technology name playback */
OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */
OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */
- OPTION_DTMF_SWITCH_MODES = (1 << 13), /*Allow numeric DTMF to switch between chanspy modes */
+ OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */
+ OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */
+ OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next avaliable channel, (default is '*') */
+ OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */
} chanspy_opt_flags;
enum {
@@ -316,6 +357,8 @@ enum {
OPT_ARG_RECORD,
OPT_ARG_ENFORCED,
OPT_ARG_NAME,
+ OPT_ARG_EXIT,
+ OPT_ARG_CYCLE,
OPT_ARG_ARRAY_SIZE,
} chanspy_opt_args;
@@ -334,10 +377,10 @@ AST_APP_OPTIONS(spy_opts, {
AST_APP_OPTION('s', OPTION_NOTECH),
AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
+ AST_APP_OPTION_ARG('x', OPTION_DTMF_EXIT, OPT_ARG_EXIT),
+ AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE),
});
-static int next_unique_id_to_use = 0;
-
struct chanspy_translation_helper {
/* spy data */
struct ast_audiohook spy_audiohook;
@@ -347,6 +390,12 @@ struct chanspy_translation_helper {
int volfactor;
};
+struct spy_dtmf_options {
+ char exit;
+ char cycle;
+ char volume;
+};
+
static void *spy_alloc(struct ast_channel *chan, void *data)
{
/* just store the data pointer in the channel structure */
@@ -399,27 +448,21 @@ static struct ast_generator spygen = {
.generate = spy_generate,
};
-static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
+static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
{
int res = 0;
struct ast_channel *peer = NULL;
- ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
+ ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name);
- res = ast_audiohook_attach(chan, audiohook);
+ res = ast_audiohook_attach(autochan->chan, audiohook);
- if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
+ if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
}
return res;
}
-struct chanspy_ds {
- struct ast_channel *chan;
- char unique_id[20];
- ast_mutex_t lock;
-};
-
static void change_spy_mode(const char digit, struct ast_flags *flags)
{
if (digit == '4') {
@@ -434,8 +477,9 @@ static void change_spy_mode(const char digit, struct ast_flags *flags)
}
}
-static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
- int *volfactor, int fd, struct ast_flags *flags, char *exitcontext)
+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)
{
struct chanspy_translation_helper csth;
int running = 0, res, x = 0;
@@ -443,32 +487,22 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp
char *name;
struct ast_frame *f;
struct ast_silence_generator *silgen = NULL;
- struct ast_channel *spyee = NULL, *spyee_bridge = NULL;
+ struct ast_autochan *spyee_bridge_autochan = NULL;
const char *spyer_name;
ast_channel_lock(chan);
spyer_name = ast_strdupa(chan->name);
ast_channel_unlock(chan);
- ast_mutex_lock(&spyee_chanspy_ds->lock);
- if (spyee_chanspy_ds->chan) {
- spyee = spyee_chanspy_ds->chan;
- ast_channel_lock(spyee);
- }
- ast_mutex_unlock(&spyee_chanspy_ds->lock);
-
- if (!spyee) {
- return 0;
- }
-
/* We now hold the channel lock on spyee */
- if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
- ast_channel_unlock(spyee);
+ if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
return 0;
}
- name = ast_strdupa(spyee->name);
+ ast_channel_lock(spyee_autochan->chan);
+ name = ast_strdupa(spyee_autochan->chan->name);
+ ast_channel_unlock(spyee_autochan->chan);
ast_verb(2, "Spying on channel %s\n", name);
manager_event(EVENT_FLAG_CALL, "ChanSpyStart",
@@ -480,26 +514,23 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp
ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
- if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
+ if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
ast_audiohook_destroy(&csth.spy_audiohook);
- ast_channel_unlock(spyee);
return 0;
}
- ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
+ ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy");
- if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) {
- ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name);
+ if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
+ ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
}
- if ((spyee_bridge = ast_bridged_channel(spyee))) {
- ast_channel_lock(spyee_bridge);
- if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) {
- ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name);
+ if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
+ ast_channel_lock(spyee_bridge_autochan->chan);
+ if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
+ ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
}
- ast_channel_unlock(spyee_bridge);
+ ast_channel_unlock(spyee_bridge_autochan->chan);
}
- ast_channel_unlock(spyee);
- spyee = NULL;
ast_channel_lock(chan);
ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
@@ -589,10 +620,13 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp
}
}
- if (res == '*') {
+ if (res == user_options->cycle) {
running = 0;
break;
- } else if (res == '#') {
+ } else if (res == user_options->exit) {
+ running = -2;
+ break;
+ } else if (res == user_options->volume) {
if (!ast_strlen_zero(inp)) {
running = atoi(inp);
break;
@@ -632,128 +666,45 @@ static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chansp
ast_audiohook_detach(&csth.spy_audiohook);
ast_audiohook_unlock(&csth.spy_audiohook);
ast_audiohook_destroy(&csth.spy_audiohook);
-
+
+ if (spyee_bridge_autochan) {
+ ast_autochan_destroy(spyee_bridge_autochan);
+ }
+
ast_verb(2, "Done Spying on channel %s\n", name);
manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
return running;
}
-/*!
- * \note This relies on the embedded lock to be recursive, as it may be called
- * due to a call to chanspy_ds_free with the lock held there.
- */
-static void chanspy_ds_destroy(void *data)
-{
- struct chanspy_ds *chanspy_ds = data;
-
- /* Setting chan to be NULL is an atomic operation, but we don't want this
- * value to change while this lock is held. The lock is held elsewhere
- * while it performs non-atomic operations with this channel pointer */
-
- ast_mutex_lock(&chanspy_ds->lock);
- chanspy_ds->chan = NULL;
- ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
- struct chanspy_ds *chanspy_ds = data;
-
- ast_mutex_lock(&chanspy_ds->lock);
- chanspy_ds->chan = new_chan;
- ast_mutex_unlock(&chanspy_ds->lock);
-}
-
-static const struct ast_datastore_info chanspy_ds_info = {
- .type = "chanspy",
- .destroy = chanspy_ds_destroy,
- .chan_fixup = chanspy_ds_chan_fixup,
-};
-
-static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
-{
- if (!chanspy_ds)
- return NULL;
-
- ast_mutex_lock(&chanspy_ds->lock);
- if (chanspy_ds->chan) {
- struct ast_datastore *datastore;
- struct ast_channel *chan;
-
- chan = chanspy_ds->chan;
-
- ast_channel_lock(chan);
- if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
- ast_channel_datastore_remove(chan, datastore);
- /* chanspy_ds->chan is NULL after this call */
- chanspy_ds_destroy(datastore->data);
- datastore->data = NULL;
- ast_datastore_free(datastore);
- }
- ast_channel_unlock(chan);
- }
- ast_mutex_unlock(&chanspy_ds->lock);
-
- return NULL;
-}
-
-/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
-static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
+static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
+ struct ast_autochan *autochan, struct ast_channel *chan)
{
- struct ast_datastore *datastore = NULL;
-
- ast_mutex_lock(&chanspy_ds->lock);
+ struct ast_channel *next;
+ const size_t pseudo_len = strlen("DAHDI/pseudo");
- if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
- ast_mutex_unlock(&chanspy_ds->lock);
- chanspy_ds = chanspy_ds_free(chanspy_ds);
- ast_channel_unlock(chan);
+ if (!iter) {
return NULL;
}
-
- chanspy_ds->chan = chan;
- datastore->data = chanspy_ds;
- ast_channel_datastore_add(chan, datastore);
-
- return chanspy_ds;
-}
-
-static struct chanspy_ds *next_channel(struct ast_channel *chan,
- const struct ast_channel *last, const char *spec,
- const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
-{
- struct ast_channel *next;
- const size_t pseudo_len = strlen("DAHDI/pseudo");
redo:
- if (!ast_strlen_zero(spec))
- next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
- else if (!ast_strlen_zero(exten))
- next = ast_walk_channel_by_exten_locked(last, exten, context);
- else
- next = ast_channel_walk_locked(last);
-
- if (!next)
+ if (!(next = ast_channel_iterator_next(iter))) {
return NULL;
+ }
if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
- last = next;
- ast_channel_unlock(next);
goto redo;
} else if (next == chan) {
- last = next;
- ast_channel_unlock(next);
goto redo;
}
- return setup_chanspy_ds(next, chanspy_ds);
+ return ast_autochan_setup(next);
}
static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
- int volfactor, const int fd, const char *mygroup, const char *myenforced,
- const char *spec, const char *exten, const char *context, const char *mailbox,
- const char *name_context)
+ 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)
{
char nameprefix[AST_NAME_STRLEN];
char peer_name[AST_NAME_STRLEN + 5];
@@ -764,7 +715,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
char *ptr;
int num;
int num_spyed_upon = 1;
- struct chanspy_ds chanspy_ds = { 0, };
+ struct ast_channel_iterator *iter = NULL;
if (ast_test_flag(flags, OPTION_EXIT)) {
const char *c;
@@ -779,10 +730,6 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
ast_channel_unlock(chan);
}
- ast_mutex_init(&chanspy_ds.lock);
-
- snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
-
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
@@ -791,8 +738,8 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
waitms = 100;
for (;;) {
- struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
- struct ast_channel *prev = NULL, *peer = NULL;
+ struct ast_autochan *autochan = NULL, *next_autochan = NULL;
+ struct ast_channel *prev = NULL;
if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
res = ast_streamfile(chan, "beep", chan->language);
@@ -813,6 +760,19 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
}
}
+ /* Set up the iterator we'll be using during this call */
+ if (!ast_strlen_zero(spec)) {
+ iter = ast_channel_iterator_by_name_new(0, spec, strlen(spec));
+ } else if (!ast_strlen_zero(exten)) {
+ iter = ast_channel_iterator_by_exten_new(0, exten, context);
+ } else {
+ iter = ast_channel_iterator_all_new(0);
+ }
+
+ if (!iter) {
+ return -1;
+ }
+
res = ast_waitfordigit(chan, waitms);
if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING);
@@ -832,38 +792,30 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
waitms = 100;
num_spyed_upon = 0;
- for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
- peer_chanspy_ds;
- chanspy_ds_free(peer_chanspy_ds), prev = peer,
- peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
- next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
+ for (autochan = next_channel(iter, autochan, chan);
+ autochan;
+ prev = autochan->chan, ast_autochan_destroy(autochan),
+ autochan = next_autochan ? next_autochan :
+ next_channel(iter, autochan, chan), next_autochan = NULL) {
int igrp = !mygroup;
int ienf = !myenforced;
char *s;
- peer = peer_chanspy_ds->chan;
-
- ast_mutex_unlock(&peer_chanspy_ds->lock);
-
- if (peer == prev) {
- ast_channel_unlock(peer);
- chanspy_ds_free(peer_chanspy_ds);
+ if (autochan->chan == prev) {
+ ast_autochan_destroy(autochan);
break;
}
if (ast_check_hangup(chan)) {
- ast_channel_unlock(peer);
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
break;
}
- if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
- ast_channel_unlock(peer);
+ if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
continue;
}
- if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
- ast_channel_unlock(peer);
+ if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
continue;
}
@@ -874,14 +826,22 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
char dup_mygroup[512];
char *groups[NUM_SPYGROUPS];
char *mygroups[NUM_SPYGROUPS];
- const char *group;
+ 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));
- if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
+ /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable
+ * rather than "SPYGROUP", this check is done to preserve expected behavior */
+ 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");
+ }
+
+ 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));
@@ -898,10 +858,8 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
}
if (!igrp) {
- ast_channel_unlock(peer);
continue;
}
-
if (myenforced) {
char ext[AST_CHANNEL_NAME + 3];
char buffer[512];
@@ -909,7 +867,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
- ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
+ ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
if ((end = strchr(ext, '-'))) {
*end++ = ':';
*end = '\0';
@@ -927,18 +885,13 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
}
strcpy(peer_name, "spy-");
- strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
+ strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
ptr = strchr(peer_name, '/');
*ptr++ = '\0';
ptr = strsep(&ptr, "-");
for (s = peer_name; s < ptr; s++)
*s = tolower(*s);
- /* We have to unlock the peer channel here to avoid a deadlock.
- * So, when we need to dereference it again, we have to lock the
- * datastore and get the pointer from there to see if the channel
- * is still valid. */
- ast_channel_unlock(peer);
if (!ast_test_flag(flags, OPTION_QUIET)) {
if (ast_test_flag(flags, OPTION_NAME)) {
@@ -954,7 +907,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
res = ast_waitstream(chan, "");
}
if (res) {
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
break;
}
} else {
@@ -966,42 +919,38 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
}
}
- res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
- num_spyed_upon++;
+ res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
+ num_spyed_upon++;
if (res == -1) {
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
goto exit;
} else if (res == -2) {
res = 0;
- chanspy_ds_free(peer_chanspy_ds);
+ ast_autochan_destroy(autochan);
goto exit;
} else if (res > 1 && spec) {
struct ast_channel *next;
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
- if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
- peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
- next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
+ 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_mutex_lock(&peer_chanspy_ds->lock);
- if (peer_chanspy_ds->chan) {
- ast_channel_lock(peer_chanspy_ds->chan);
- next_chanspy_ds = peer_chanspy_ds;
- peer_chanspy_ds = NULL;
+ if (!ast_check_hangup(autochan->chan)) {
+ next_autochan = ast_autochan_setup(autochan->chan);
} else {
/* the channel is gone */
- ast_mutex_unlock(&peer_chanspy_ds->lock);
- next_chanspy_ds = NULL;
+ next_autochan = NULL;
}
}
-
- peer = NULL;
}
}
+
+ iter = ast_channel_iterator_destroy(iter);
+
if (res == -1 || ast_check_hangup(chan))
break;
}
@@ -1011,10 +960,6 @@ exit:
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
- ast_mutex_lock(&chanspy_ds.lock);
- ast_mutex_unlock(&chanspy_ds.lock);
- ast_mutex_destroy(&chanspy_ds.lock);
-
return res;
}
@@ -1025,6 +970,11 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
+ struct spy_dtmf_options user_options = {
+ .cycle = '*',
+ .volume = '#',
+ .exit = '\0',
+ };
int oldwf = 0;
int volfactor = 0;
int res;
@@ -1043,6 +993,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
args.spec = NULL;
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];
@@ -1051,6 +1002,24 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
!(recbase = opts[OPT_ARG_RECORD]))
recbase = "chanspy";
+ if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
+ tmp = opts[OPT_ARG_EXIT][0];
+ if (strchr("0123456789*#", tmp) && tmp != '\0') {
+ user_options.exit = tmp;
+ } else {
+ ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
+ }
+ }
+
+ if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
+ tmp = opts[OPT_ARG_CYCLE][0];
+ if (strchr("0123456789*#", tmp) && tmp != '\0') {
+ user_options.cycle = tmp;
+ } else {
+ ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
+ }
+ }
+
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
int vol;
@@ -1065,7 +1034,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
if (ast_test_flag(&flags, OPTION_ENFORCED))
myenforced = opts[OPT_ARG_ENFORCED];
-
+
if (ast_test_flag(&flags, OPTION_NAME)) {
if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
char *delimiter;
@@ -1078,10 +1047,9 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
}
}
}
-
-
- } else
+ } else {
ast_clear_flag(&flags, AST_FLAGS_ALL);
+ }
oldwf = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
@@ -1099,7 +1067,7 @@ static int chanspy_exec(struct ast_channel *chan, void *data)
}
}
- res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
+ res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
if (fd)
close(fd);
@@ -1117,6 +1085,11 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
+ struct spy_dtmf_options user_options = {
+ .cycle = '*',
+ .volume = '#',
+ .exit = '\0',
+ };
int oldwf = 0;
int volfactor = 0;
int res;
@@ -1141,6 +1114,7 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
if (args.options) {
char *opts[OPT_ARG_ARRAY_SIZE];
+ char tmp;
ast_app_parse_options(spy_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, OPTION_GROUP))
@@ -1150,6 +1124,24 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
!(recbase = opts[OPT_ARG_RECORD]))
recbase = "chanspy";
+ if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
+ tmp = opts[OPT_ARG_EXIT][0];
+ if (strchr("0123456789*#", tmp) && tmp != '\0') {
+ user_options.exit = tmp;
+ } else {
+ ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
+ }
+ }
+
+ if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
+ tmp = opts[OPT_ARG_CYCLE][0];
+ if (strchr("0123456789*#", tmp) && tmp != '\0') {
+ user_options.cycle = tmp;
+ } else {
+ ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
+ }
+ }
+
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
int vol;
@@ -1162,7 +1154,6 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
if (ast_test_flag(&flags, OPTION_PRIVATE))
ast_set_flag(&flags, OPTION_WHISPER);
-
if (ast_test_flag(&flags, OPTION_NAME)) {
if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
char *delimiter;
@@ -1176,8 +1167,9 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
}
}
- } else
+ } else {
ast_clear_flag(&flags, AST_FLAGS_ALL);
+ }
oldwf = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
@@ -1196,7 +1188,7 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
}
- res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
+ res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
if (fd)
close(fd);
@@ -1207,12 +1199,49 @@ static int extenspy_exec(struct ast_channel *chan, void *data)
return res;
}
+static int dahdiscan_exec(struct ast_channel *chan, void *data)
+{
+ const char *spec = "DAHDI";
+ struct ast_flags flags;
+ struct spy_dtmf_options user_options = {
+ .cycle = '#',
+ .volume = '\0',
+ .exit = '*',
+ };
+ int oldwf = 0;
+ int res;
+ char *mygroup = NULL;
+
+ ast_clear_flag(&flags, AST_FLAGS_ALL);
+
+ if (!ast_strlen_zero(data)) {
+ mygroup = ast_strdupa(data);
+ }
+ ast_set_flag(&flags, OPTION_DTMF_EXIT);
+ ast_set_flag(&flags, OPTION_DTMF_CYCLE);
+ ast_set_flag(&flags, OPTION_DAHDI_SCAN);
+
+ oldwf = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+ return -1;
+ }
+
+ res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
+
+ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+
+ return res;
+}
+
static int unload_module(void)
{
int res = 0;
res |= ast_unregister_application(app_chan);
res |= ast_unregister_application(app_ext);
+ res |= ast_unregister_application(app_dahdiscan);
return res;
}
@@ -1223,6 +1252,7 @@ static int load_module(void)
res |= ast_register_application_xml(app_chan, chanspy_exec);
res |= ast_register_application_xml(app_ext, extenspy_exec);
+ res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
return res;
}
diff --git a/apps/app_dahdiscan.c b/apps/app_dahdiscan.c
deleted file mode 100644
index 8251ffcbf..000000000
--- a/apps/app_dahdiscan.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * Modified from app_zapbarge by David Troy <dave@toad.net>
- *
- * Special thanks to comphealth.com for sponsoring this
- * GPL application.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
-
-/*! \file
- *
- * \brief DAHDI Scanner
- *
- * \author Mark Spencer <markster@digium.com>
- *
- * \ingroup applications
- */
-
-/*** MODULEINFO
- <depend>dahdi</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <dahdi/user.h>
-
-#include "asterisk/lock.h"
-#include "asterisk/file.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/config.h"
-#include "asterisk/app.h"
-#include "asterisk/utils.h"
-#include "asterisk/cli.h"
-#include "asterisk/say.h"
-#include "asterisk/options.h"
-
-/*** DOCUMENTATION
- <application name="DAHDIScan" language="en_US">
- <synopsis>
- Scan DAHDI channels to monitor calls.
- </synopsis>
- <syntax>
- <parameter name="group">
- <para>Limit scanning to a channel <replaceable>group</replaceable> by setting this option.</para>
- </parameter>
- </syntax>
- <description>
- <para>Allows a call center manager to monitor DAHDI channels in a
- convenient way. Use <literal>#</literal> to select the next channel and use <literal>*</literal> to exit.</para>
- </description>
- </application>
- ***/
-static char *app = "DAHDIScan";
-
-#define CONF_SIZE 160
-
-static struct ast_channel *get_dahdi_channel_locked(int num) {
- char name[80];
-
- snprintf(name, sizeof(name), "DAHDI/%d-1", num);
- return ast_get_channel_by_name_locked(name);
-}
-
-static int careful_write(int fd, unsigned char *data, int len)
-{
- int res;
- while (len) {
- res = write(fd, data, len);
- if (res < 1) {
- if (errno != EAGAIN) {
- ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
- return -1;
- } else {
- return 0;
- }
- }
- len -= res;
- data += res;
- }
- return 0;
-}
-
-static int conf_run(struct ast_channel *chan, int confno, int confflags)
-{
- int fd;
- struct dahdi_confinfo dahdic;
- struct ast_frame *f;
- struct ast_channel *c;
- struct ast_frame fr;
- int outfd;
- int ms;
- int nfds;
- int res;
- int flags;
- int retrydahdi;
- int origfd;
- int ret = -1;
- char input[4];
- int ic = 0;
-
- struct dahdi_bufferinfo bi;
- char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
- char *buf = __buf + AST_FRIENDLY_OFFSET;
-
- /* Set it into U-law mode (write) */
- if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
- ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
- goto outrun;
- }
-
- /* Set it into U-law mode (read) */
- if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
- ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
- goto outrun;
- }
- ast_indicate(chan, -1);
- retrydahdi = strcasecmp(chan->tech->type, "DAHDI");
- dahdiretry:
- origfd = chan->fds[0];
- if (retrydahdi) {
- fd = open("/dev/dahdi/pseudo", O_RDWR);
- if (fd < 0) {
- ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
- goto outrun;
- }
- /* Make non-blocking */
- flags = fcntl(fd, F_GETFL);
- if (flags < 0) {
- ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
- close(fd);
- goto outrun;
- }
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
- ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
- close(fd);
- goto outrun;
- }
- /* Setup buffering information */
- memset(&bi, 0, sizeof(bi));
- bi.bufsize = CONF_SIZE;
- bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
- bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
- bi.numbufs = 4;
- if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
- ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
- close(fd);
- goto outrun;
- }
- nfds = 1;
- } else {
- /* XXX Make sure we're not running on a pseudo channel XXX */
- fd = chan->fds[0];
- nfds = 0;
- }
- memset(&dahdic, 0, sizeof(dahdic));
- /* Check to see if we're in a conference... */
- dahdic.chan = 0;
- if (ioctl(fd, DAHDI_GETCONF, &dahdic)) {
- ast_log(LOG_WARNING, "Error getting conference\n");
- close(fd);
- goto outrun;
- }
- if (dahdic.confmode) {
- /* Whoa, already in a conference... Retry... */
- if (!retrydahdi) {
- ast_debug(1, "DAHDI channel is in a conference already, retrying with pseudo\n");
- retrydahdi = 1;
- goto dahdiretry;
- }
- }
- memset(&dahdic, 0, sizeof(dahdic));
- /* Add us to the conference */
- dahdic.chan = 0;
- dahdic.confno = confno;
- dahdic.confmode = DAHDI_CONF_MONITORBOTH;
-
- if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
- ast_log(LOG_WARNING, "Error setting conference\n");
- close(fd);
- goto outrun;
- }
- ast_debug(1, "Placed channel %s in DAHDI channel %d monitor\n", chan->name, confno);
-
- for (;;) {
- outfd = -1;
- ms = -1;
- c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
- if (c) {
- if (c->fds[0] != origfd) {
- if (retrydahdi) {
- /* Kill old pseudo */
- close(fd);
- }
- ast_debug(1, "Ooh, something swapped out under us, starting over\n");
- retrydahdi = 0;
- goto dahdiretry;
- }
- f = ast_read(c);
- if (!f) {
- break;
- }
- if (f->frametype == AST_FRAME_DTMF) {
- if (f->subclass == '#') {
- ret = 0;
- break;
- } else if (f->subclass == '*') {
- ret = -1;
- break;
- } else {
- input[ic++] = f->subclass;
- }
- if (ic == 3) {
- input[ic++] = '\0';
- ic = 0;
- ret = atoi(input);
- ast_verb(3, "DAHDIScan: change channel to %d\n", ret);
- break;
- }
- }
-
- if (fd != chan->fds[0]) {
- if (f->frametype == AST_FRAME_VOICE) {
- if (f->subclass == AST_FORMAT_ULAW) {
- /* Carefully write */
- careful_write(fd, f->data.ptr, f->datalen);
- } else {
- ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
- }
- }
- }
- ast_frfree(f);
- } else if (outfd > -1) {
- res = read(outfd, buf, CONF_SIZE);
- if (res > 0) {
- memset(&fr, 0, sizeof(fr));
- fr.frametype = AST_FRAME_VOICE;
- fr.subclass = AST_FORMAT_ULAW;
- fr.datalen = res;
- fr.samples = res;
- fr.data.ptr = buf;
- fr.offset = AST_FRIENDLY_OFFSET;
- if (ast_write(chan, &fr) < 0) {
- ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
- /* break; */
- }
- } else {
- ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
- }
- }
- }
- if (f) {
- ast_frfree(f);
- }
- if (fd != chan->fds[0]) {
- close(fd);
- } else {
- /* Take out of conference */
- /* Add us to the conference */
- dahdic.chan = 0;
- dahdic.confno = 0;
- dahdic.confmode = 0;
- if (ioctl(fd, DAHDI_SETCONF, &dahdic)) {
- ast_log(LOG_WARNING, "Error setting conference\n");
- }
- }
-
- outrun:
-
- return ret;
-}
-
-static int conf_exec(struct ast_channel *chan, void *data)
-{
- int res=-1;
- int confflags = 0;
- int confno = 0;
- char confnostr[80] = "", *tmp = NULL;
- struct ast_channel *tempchan = NULL, *lastchan = NULL, *ichan = NULL;
- struct ast_frame *f;
- char *desired_group;
- int input = 0, search_group = 0;
-
- if (chan->_state != AST_STATE_UP)
- ast_answer(chan);
-
- desired_group = ast_strdupa(data);
- if (!ast_strlen_zero(desired_group)) {
- ast_verb(3, "Scanning for group %s\n", desired_group);
- search_group = 1;
- }
-
- for (;;) {
- if (ast_waitfor(chan, 100) < 0)
- break;
-
- f = ast_read(chan);
- if (!f)
- break;
- if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
- ast_frfree(f);
- break;
- }
- ast_frfree(f);
- ichan = NULL;
- if(input) {
- ichan = get_dahdi_channel_locked(input);
- input = 0;
- }
-
- tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
-
- if (!tempchan && !lastchan) {
- break;
- }
-
- if (tempchan && search_group) {
- const char *mygroup;
- if ((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
- ast_verb(3, "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
- } else {
- ast_channel_unlock(tempchan);
- lastchan = tempchan;
- continue;
- }
- }
- if (tempchan && (!strcmp(tempchan->tech->type, "DAHDI")) && (tempchan != chan)) {
- ast_verb(3, "DAHDI channel %s is in-use, monitoring...\n", tempchan->name);
- ast_copy_string(confnostr, tempchan->name, sizeof(confnostr));
- ast_channel_unlock(tempchan);
- if ((tmp = strchr(confnostr, '-'))) {
- *tmp = '\0';
- }
- confno = atoi(strchr(confnostr, '/') + 1);
- ast_stopstream(chan);
- ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
- res = conf_run(chan, confno, confflags);
- if (res < 0) {
- break;
- }
- input = res;
- } else if (tempchan) {
- ast_channel_unlock(tempchan);
- }
- lastchan = tempchan;
- }
- return res;
-}
-
-static int unload_module(void)
-{
- return ast_unregister_application(app);
-}
-
-static int load_module(void)
-{
- return ((ast_register_application_xml(app, conf_exec)) ? AST_MODULE_LOAD_FAILURE : AST_MODULE_LOAD_SUCCESS);
-}
-
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan DAHDI channels application");
-
diff --git a/apps/app_directed_pickup.c b/apps/app_directed_pickup.c
index 5ce217d7a..0cf691c59 100644
--- a/apps/app_directed_pickup.c
+++ b/apps/app_directed_pickup.c
@@ -135,17 +135,35 @@ static int can_pickup(struct ast_channel *chan)
return 0;
}
+struct pickup_by_name_args {
+ const char *name;
+ size_t len;
+};
+
+static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
+{
+ struct ast_channel *chan = obj;
+ struct pickup_by_name_args *args = data;
+
+ ast_channel_lock(chan);
+ if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
+ /* Return with the channel still locked on purpose */
+ return CMP_MATCH | CMP_STOP;
+ }
+ ast_channel_unlock(chan);
+
+ return 0;
+}
+
/*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
{
- struct ast_channel *chan;
char *chkchan;
- size_t channame_len, chkchan_len;
+ struct pickup_by_name_args pickup_args;
- channame_len = strlen(channame);
- chkchan_len = channame_len + 2;
+ pickup_args.len = strlen(channame) + 2;
- chkchan = alloca(chkchan_len);
+ chkchan = alloca(pickup_args.len);
/* need to append a '-' for the comparison so we check full channel name,
* i.e SIP/hgc- , use a temporary variable so original stays the same for
@@ -154,15 +172,9 @@ static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channam
strcpy(chkchan, channame);
strcat(chkchan, "-");
- for (chan = ast_walk_channel_by_name_prefix_locked(NULL, channame, channame_len);
- chan;
- chan = ast_walk_channel_by_name_prefix_locked(chan, channame, channame_len)) {
- if (!strncasecmp(chan->name, chkchan, chkchan_len) && can_pickup(chan)) {
- return chan;
- }
- ast_channel_unlock(chan);
- }
- return NULL;
+ pickup_args.name = chkchan;
+
+ return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
}
/*! \brief Attempt to pick up specified channel named , does not use context */
@@ -171,76 +183,82 @@ static int pickup_by_channel(struct ast_channel *chan, char *pickup)
int res = 0;
struct ast_channel *target;
- if (!(target = my_ast_get_channel_by_name_locked(pickup)))
+ if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
return -1;
+ }
/* Just check that we are not picking up the SAME as target */
- if (chan->name != target->name && chan != target) {
+ if (chan != target) {
res = pickup_do(chan, target);
}
+
ast_channel_unlock(target);
+ target = ast_channel_unref(target);
return res;
}
-struct pickup_criteria {
- const char *exten;
- const char *context;
-};
-
-static int find_by_exten(struct ast_channel *c, void *data)
-{
- struct pickup_criteria *info = data;
-
- return (!strcasecmp(c->macroexten, info->exten) || !strcasecmp(c->exten, info->exten)) &&
- !strcasecmp(c->dialcontext, info->context) &&
- can_pickup(c);
-}
-
/* Attempt to pick up specified extension with context */
static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
{
struct ast_channel *target = NULL;
- struct pickup_criteria search = {
- .exten = exten,
- .context = context,
- };
+ struct ast_channel_iterator *iter;
+ int res = -1;
+
+ if (!(iter = ast_channel_iterator_by_exten_new(0, exten, context))) {
+ return -1;
+ }
- target = ast_channel_search_locked(find_by_exten, &search);
+ while ((target = ast_channel_iterator_next(iter))) {
+ ast_channel_lock(target);
+ if (can_pickup(target)) {
+ break;
+ }
+ ast_channel_unlock(target);
+ target = ast_channel_unref(target);
+ }
if (target) {
- int res = pickup_do(chan, target);
+ res = pickup_do(chan, target);
ast_channel_unlock(target);
- target = NULL;
- return res;
+ target = ast_channel_unref(target);
}
- return -1;
+ return res;
}
-static int find_by_mark(struct ast_channel *c, void *data)
+static int find_by_mark(void *obj, void *arg, void *data, int flags)
{
+ struct ast_channel *c = obj;
const char *mark = data;
const char *tmp;
+ int res;
+
+ ast_channel_lock(c);
- return (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
+ res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
!strcasecmp(tmp, mark) &&
can_pickup(c);
+
+ ast_channel_unlock(c);
+
+ return res ? CMP_MATCH | CMP_STOP : 0;
}
/* Attempt to pick up specified mark */
static int pickup_by_mark(struct ast_channel *chan, const char *mark)
{
- struct ast_channel *target = ast_channel_search_locked(find_by_mark, (char *) mark);
+ struct ast_channel *target;
+ int res = -1;
- if (target) {
- int res = pickup_do(chan, target);
+ if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
+ ast_channel_lock(target);
+ res = pickup_do(chan, target);
ast_channel_unlock(target);
- target = NULL;
- return res;
+ target = ast_channel_unref(target);
}
- return -1;
+ return res;
}
/* application entry point for Pickup() */
diff --git a/apps/app_minivm.c b/apps/app_minivm.c
index 3e5058067..9148ee130 100644
--- a/apps/app_minivm.c
+++ b/apps/app_minivm.c
@@ -1254,8 +1254,9 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
ast_safe_system(tmp2);
ast_debug(1, "Sent message to %s with command '%s' - %s\n", vmu->email, global_mailcmd, template->attachment ? "(media attachment)" : "");
ast_debug(3, "Actual command used: %s\n", tmp2);
- if (ast)
- ast_channel_free(ast);
+ if (ast) {
+ ast = ast_channel_release(ast);
+ }
return 0;
}
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 3056e7e92..f67422aae 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -45,6 +45,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
+#include "asterisk/autochan.h"
/*** DOCUMENTATION
<application name="MixMonitor" language="en_US">
@@ -138,7 +139,7 @@ struct mixmonitor {
char *post_process;
char *name;
unsigned int flags;
- struct mixmonitor_ds *mixmonitor_ds;
+ struct ast_autochan *autochan;
};
enum {
@@ -164,50 +165,6 @@ AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
});
-/* This structure is used as a means of making sure that our pointer to
- * the channel we are monitoring remains valid. This is very similar to
- * what is used in app_chanspy.c.
- */
-struct mixmonitor_ds {
- struct ast_channel *chan;
- /* These condition variables are used to be sure that the channel
- * hangup code completes before the mixmonitor thread attempts to
- * free this structure. The combination of a bookean flag and a
- * ast_cond_t ensure that no matter what order the threads run in,
- * we are guaranteed to never have the waiting thread block forever
- * in the case that the signaling thread runs first.
- */
- unsigned int destruction_ok;
- ast_cond_t destruction_condition;
- ast_mutex_t lock;
-};
-
-static void mixmonitor_ds_destroy(void *data)
-{
- struct mixmonitor_ds *mixmonitor_ds = data;
-
- ast_mutex_lock(&mixmonitor_ds->lock);
- mixmonitor_ds->chan = NULL;
- mixmonitor_ds->destruction_ok = 1;
- ast_cond_signal(&mixmonitor_ds->destruction_condition);
- ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
-{
- struct mixmonitor_ds *mixmonitor_ds = data;
-
- ast_mutex_lock(&mixmonitor_ds->lock);
- mixmonitor_ds->chan = new_chan;
- ast_mutex_unlock(&mixmonitor_ds->lock);
-}
-
-static struct ast_datastore_info mixmonitor_ds_info = {
- .type = "mixmonitor",
- .destroy = mixmonitor_ds_destroy,
- .chan_fixup = mixmonitor_ds_chan_fixup,
-};
-
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
{
struct ast_channel *peer = NULL;
@@ -249,9 +206,7 @@ static void *mixmonitor_thread(void *obj)
if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
continue;
- ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
- if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
+ if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
/* Initialize the file if not already done so */
if (!fs && !errflag) {
oflags = O_CREAT | O_WRONLY;
@@ -271,10 +226,7 @@ static void *mixmonitor_thread(void *obj)
/* Write out frame */
if (fs)
ast_writestream(fs, fr);
- } else {
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
-
/* All done! free it. */
ast_frame_free(fr, 0);
@@ -294,48 +246,12 @@ static void *mixmonitor_thread(void *obj)
ast_safe_system(mixmonitor->post_process);
}
- ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
- if (!mixmonitor->mixmonitor_ds->destruction_ok) {
- ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
- }
- ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
- ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
- ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
- ast_free(mixmonitor->mixmonitor_ds);
+ ast_autochan_destroy(mixmonitor->autochan);
ast_free(mixmonitor);
return NULL;
}
-static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
-{
- struct ast_datastore *datastore = NULL;
- struct mixmonitor_ds *mixmonitor_ds;
-
- if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
- return -1;
- }
-
- ast_mutex_init(&mixmonitor_ds->lock);
- ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
-
- if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
- ast_free(mixmonitor_ds);
- return -1;
- }
-
- /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
- mixmonitor_ds->chan = chan;
- datastore->data = mixmonitor_ds;
-
- ast_channel_lock(chan);
- ast_channel_datastore_add(chan, datastore);
- ast_channel_unlock(chan);
-
- mixmonitor->mixmonitor_ds = mixmonitor_ds;
- return 0;
-}
-
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
int readvol, int writevol, const char *post_process)
{
@@ -369,7 +285,7 @@ static void launch_monitor_thread(struct ast_channel *chan, const char *filename
/* Copy over flags and channel name */
mixmonitor->flags = flags;
- if (setup_mixmonitor_ds(mixmonitor, chan)) {
+ if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
return;
}
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
@@ -512,12 +428,14 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
if (a->argc < 3)
return CLI_SHOWUSAGE;
- if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) {
+ if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
/* Technically this is a failure, but we don't want 2 errors printing out */
return CLI_SUCCESS;
}
+ ast_channel_lock(chan);
+
if (!strcasecmp(a->argv[1], "start")) {
mixmonitor_exec(chan, a->argv[3]);
ast_channel_unlock(chan);
@@ -526,6 +444,8 @@ static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
}
+ chan = ast_channel_unref(chan);
+
return CLI_SUCCESS;
}
diff --git a/apps/app_senddtmf.c b/apps/app_senddtmf.c
index 9842c412e..a1c28a8f9 100644
--- a/apps/app_senddtmf.c
+++ b/apps/app_senddtmf.c
@@ -100,23 +100,25 @@ static int manager_play_dtmf(struct mansession *s, const struct message *m)
{
const char *channel = astman_get_header(m, "Channel");
const char *digit = astman_get_header(m, "Digit");
- struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
-
- if (!chan) {
- astman_send_error(s, m, "Channel not specified");
+ struct ast_channel *chan;
+
+ if (!(chan = ast_channel_get_by_name(channel))) {
+ astman_send_error(s, m, "Channel not found");
return 0;
}
+
if (ast_strlen_zero(digit)) {
astman_send_error(s, m, "No digit specified");
- ast_channel_unlock(chan);
+ chan = ast_channel_unref(chan);
return 0;
}
ast_senddigit(chan, *digit, 0);
- ast_channel_unlock(chan);
+ chan = ast_channel_unref(chan);
+
astman_send_ack(s, m, "DTMF successfully queued");
-
+
return 0;
}
diff --git a/apps/app_softhangup.c b/apps/app_softhangup.c
index a7ba753fd..6a4889acf 100644
--- a/apps/app_softhangup.c
+++ b/apps/app_softhangup.c
@@ -80,6 +80,7 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
AST_APP_ARG(channel);
AST_APP_ARG(options);
);
+ struct ast_channel_iterator *iter;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SoftHangup requires an argument (Technology/resource)\n");
@@ -93,9 +94,12 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
ast_app_parse_options(app_opts, &flags, opts, args.options);
lenmatch = strlen(args.channel);
- for (c = ast_walk_channel_by_name_prefix_locked(NULL, args.channel, lenmatch);
- c;
- c = ast_walk_channel_by_name_prefix_locked(c, args.channel, lenmatch)) {
+ if (!(iter = ast_channel_iterator_by_name_new(0, args.channel, lenmatch))) {
+ return -1;
+ }
+
+ while ((c = ast_channel_iterator_next(iter))) {
+ ast_channel_lock(c);
ast_copy_string(name, c->name, sizeof(name));
if (ast_test_flag(&flags, OPTION_ALL)) {
/* CAPI is set up like CAPI[foo/bar]/clcnt */
@@ -113,12 +117,16 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
if (!ast_test_flag(&flags, OPTION_ALL)) {
ast_channel_unlock(c);
+ c = ast_channel_unref(c);
break;
}
}
ast_channel_unlock(c);
+ c = ast_channel_unref(c);
}
+ ast_channel_iterator_destroy(iter);
+
return 0;
}
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index bcfc0793b..27aabf4c7 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -4106,7 +4106,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
} else {
fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
}
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
}
@@ -4156,7 +4156,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
} else {
fprintf(p, "Subject: %s" ENDL, passdata);
}
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
}
@@ -4229,7 +4229,7 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
pbx_substitute_variables_helper(ast, e_body, passdata, vmlen);
fprintf(p, "%s" ENDL, passdata);
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
} else if (msgnum > -1) {
@@ -4413,7 +4413,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
fprintf(p, "From: %s <%s>\n", passdata, who);
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
} else
@@ -4429,7 +4429,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
fprintf(p, "Subject: %s\n\n", passdata);
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
} else {
@@ -4451,7 +4451,7 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
fprintf(p, "%s\n", passdata);
- ast_channel_free(ast);
+ ast = ast_channel_release(ast);
} else
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
} else {