diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_channelredirect.c | 8 | ||||
-rw-r--r-- | apps/app_chanspy.c | 450 | ||||
-rw-r--r-- | apps/app_dahdiscan.c | 378 | ||||
-rw-r--r-- | apps/app_directed_pickup.c | 112 | ||||
-rw-r--r-- | apps/app_minivm.c | 5 | ||||
-rw-r--r-- | apps/app_mixmonitor.c | 100 | ||||
-rw-r--r-- | apps/app_senddtmf.c | 16 | ||||
-rw-r--r-- | apps/app_softhangup.c | 14 | ||||
-rw-r--r-- | apps/app_voicemail.c | 12 |
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 { |