summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorRussell Bryant <russell@russellbryant.com>2009-04-24 14:04:26 +0000
committerRussell Bryant <russell@russellbryant.com>2009-04-24 14:04:26 +0000
commitcba19c8a671c76a3969a7d36bc43444792a13a81 (patch)
tree1812569845aaf29df5f2a18285e73bc1fcc6268c /apps
parentf314c5f13fd84bc2084e183e39b0d1fbec4b9a5a (diff)
Convert the ast_channel data structure over to the astobj2 framework.
There is a lot that could be said about this, but the patch is a big improvement for performance, stability, code maintainability, and ease of future code development. The channel list is no longer an unsorted linked list. The main container for channels is an astobj2 hash table. All of the code related to searching for channels or iterating active channels has been rewritten. Let n be the number of active channels. Iterating the channel list has gone from O(n^2) to O(n). Searching for a channel by name went from O(n) to O(1). Searching for a channel by extension is still O(n), but uses a new method for doing so, which is more efficient. The ast_channel object is now a reference counted object. The benefits here are plentiful. Some benefits directly related to issues in the previous code include: 1) When threads other than the channel thread owning a channel wanted access to a channel, it had to hold the lock on it to ensure that it didn't go away. This is no longer a requirement. Holding a reference is sufficient. 2) There are places that now require less dealing with channel locks. 3) There are places where channel locks are held for much shorter periods of time. 4) There are places where dealing with more than one channel at a time becomes _MUCH_ easier. ChanSpy is a great example of this. Writing code in the future that deals with multiple channels will be much easier. Some additional information regarding channel locking and reference count handling can be found in channel.h, where a new section has been added that discusses some of the rules associated with it. Mark Michelson also assisted with the development of this patch. He did the conversion of ChanSpy and introduced a new API, ast_autochan, which makes it much easier to deal with holding on to a channel pointer for an extended period of time and having it get automatically updated if the channel gets masqueraded. Mark was also a huge help in the code review process. Thanks to David Vossel for his assistance with this branch, as well. David did the conversion of the DAHDIScan application by making it become a wrapper for ChanSpy internally. The changes come from the svn/asterisk/team/russell/ast_channel_ao2 branch. Review: http://reviewboard.digium.com/r/203/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@190423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
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 {