diff --git a/CHANGES b/CHANGES index 79a1e5a72827841674ef2cbc6c3af82797b6d76b..aef532e79384bd7623cf6841993ef70d33f8adc8 100644 --- a/CHANGES +++ b/CHANGES @@ -58,6 +58,7 @@ Changes since Asterisk 1.4-beta was branched: * Added the srvlookup option to iax.conf * Added 'E' and 'V' commands to ExternalIVR. * Added 'DBDel' and 'DBDelTree' manager commands. + * Added 'o' and 'X' options to Chanspy. AMI - The manager (TCP/TLS/HTTP) -------------------------------- diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 61d8afab5d5c79450abdffc8a4f86ebd4659796c..81d50ef69d0d7eb2030e9cd0d4b30917532f5f76 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -67,6 +67,10 @@ static const char *desc_chan = " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n" " the digits '1234#' while spying will begin spying on the channel\n" " 'Agent/1234'.\n" +" Note: The X option supersedes the three features above in that if a valid\n" +" single digit extension exists in the correct context ChanSpy will\n" +" exit to it. This also disables choosing a channel based on 'chanprefix'\n" +" and a digit sequence.\n" " Options:\n" " b - Only spy on channels involved in a bridged call.\n" " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n" @@ -83,6 +87,12 @@ static const char *desc_chan = " W - Enable 'private whisper' mode, so the spying channel can\n" " talk to the spied-on channel but cannot listen to that\n" " channel.\n" +" o - Only listen to audio coming from this channel.\n" +" X - Allow the user to exit ChanSpy to a valid single digit\n" +" numeric extension in the current context or the context\n" +" specified by the SPY_EXIT_CONTEXT channel variable. The\n" +" name of the last channel that was spied on will be stored\n" +" in the SPY_CHANNEL variable.\n" ; static const char *app_ext = "ExtenSpy"; @@ -95,6 +105,9 @@ static const char *desc_ext = " While spying, the following actions may be performed:\n" " - Dialing # cycles the volume level.\n" " - Dialing * will stop spying and look for another channel to spy on.\n" +" Note: The X option superseeds the two features above in that if a valid\n" +" single digit extension exists in the correct context it ChanSpy will\n" +" exit to it.\n" " Options:\n" " b - Only spy on channels involved in a bridged call.\n" " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n" @@ -111,6 +124,12 @@ static const char *desc_ext = " W - Enable 'private whisper' mode, so the spying channel can\n" " talk to the spied-on channel but cannot listen to that\n" " channel.\n" +" o - Only listen to audio coming from this channel.\n" +" X - Allow the user to exit ChanSpy to a valid single digit\n" +" numeric extension in the current context or the context\n" +" specified by the SPY_EXIT_CONTEXT channel variable. The\n" +" name of the last channel that was spied on will be stored\n" +" in the SPY_CHANNEL variable.\n" ; enum { @@ -121,6 +140,8 @@ enum { OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ + OPTION_READONLY = (1 << 7), /* Don't mix the two channels */ + OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */ } chanspy_opt_flags; enum { @@ -138,6 +159,8 @@ AST_APP_OPTIONS(spy_opts, { AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD), + AST_APP_OPTION('o', OPTION_READONLY), + AST_APP_OPTION('X', OPTION_EXIT), }); @@ -241,7 +264,7 @@ static void set_volume(struct ast_channel *chan, struct chanspy_translation_help } static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd, - const struct ast_flags *flags) + const struct ast_flags *flags, char *exitcontext) { struct chanspy_translation_helper csth; int running = 0, res, x = 0; @@ -260,7 +283,8 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int memset(&csth, 0, sizeof(csth)); ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO); ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE); - ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); + if (!ast_test_flag(flags, OPTION_READONLY)) + ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); csth.spy.type = "ChanSpy"; csth.spy.status = CHANSPY_RUNNING; csth.spy.read_queue.format = AST_FORMAT_SLINEAR; @@ -348,6 +372,22 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int running = -1; break; } + + if (ast_test_flag(flags, OPTION_EXIT)) { + char tmp[2]; + tmp[0] = res; + tmp[1] = '\0'; + if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { + ast_log(LOG_DEBUG, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); + pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); + running = -2; + break; + } else if (option_debug > 1) { + ast_log(LOG_DEBUG, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); + } + } else if (res >= '0' && res <= '9') { + inp[x++] = res; + } if (res == '*') { running = 0; @@ -374,8 +414,6 @@ static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST); ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); } - } else if (res >= '0' && res <= '9') { - inp[x++] = res; } } @@ -431,12 +469,23 @@ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, struct ast_channel *peer, *prev, *next; char nameprefix[AST_NAME_STRLEN]; char peer_name[AST_NAME_STRLEN + 5]; + char exitcontext[AST_MAX_CONTEXT] = ""; signed char zero_volume = 0; int waitms; int res; char *ptr; int num; + if (ast_test_flag(flags, OPTION_EXIT)) { + const char *c; + if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) + ast_copy_string(exitcontext, c, sizeof(exitcontext)); + else if (!ast_strlen_zero(chan->macrocontext)) + ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); + else + ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); + } + if (chan->_state != AST_STATE_UP) ast_answer(chan); @@ -453,6 +502,15 @@ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, ast_clear_flag(chan, AST_FLAG_SPYING); break; } + if (!ast_strlen_zero(exitcontext)) { + char tmp[2]; + tmp[0] = res; + tmp[1] = '\0'; + if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) + goto exit; + else if (option_debug > 1) + ast_log(LOG_DEBUG, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); + } } res = ast_waitfordigit(chan, waitms); @@ -460,6 +518,15 @@ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, ast_clear_flag(chan, AST_FLAG_SPYING); break; } + if (!ast_strlen_zero(exitcontext)) { + char tmp[2]; + tmp[0] = res; + tmp[1] = '\0'; + if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) + goto exit; + else if (option_debug > 1) + ast_log(LOG_DEBUG, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); + } /* reset for the next loop around, unless overridden later */ waitms = 100; @@ -528,10 +595,13 @@ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, } waitms = 5000; - res = channel_spy(chan, peer, &volfactor, fd, flags); + res = channel_spy(chan, peer, &volfactor, fd, flags, exitcontext); if (res == -1) { - break; + goto exit; + } else if (res == -2) { + res = 0; + goto exit; } else if (res > 1 && spec) { snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { @@ -543,10 +613,9 @@ static int common_exec(struct ast_channel *chan, const struct ast_flags *flags, peer = NULL; } } - if (res == -1) - break; } - +exit: + ast_clear_flag(chan, AST_FLAG_SPYING); ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);