#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#include "asterisk/autochan.h"
Go to the source code of this file.
Data Structures | |
struct | chanspy_translation_helper |
struct | spy_dtmf_options |
Defines | |
#define | AST_NAME_STRLEN 256 |
#define | NUM_SPYGROUPS 128 |
Enumerations | |
enum | { OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3), OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6), OPTION_READONLY = (1 << 7), OPTION_EXIT = (1 << 8), OPTION_ENFORCED = (1 << 9), OPTION_NOTECH = (1 << 10), OPTION_BARGE = (1 << 11), OPTION_NAME = (1 << 12), OPTION_DTMF_SWITCH_MODES = (1 << 13), OPTION_DTMF_EXIT = (1 << 14), OPTION_DTMF_CYCLE = (1 << 15), OPTION_DAHDI_SCAN = (1 << 16), OPTION_STOP = (1 << 17), OPTION_EXITONHANGUP = (1 << 18) } |
enum | { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ENFORCED, OPT_ARG_NAME, OPT_ARG_EXIT, OPT_ARG_CYCLE, OPT_ARG_ARRAY_SIZE } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | change_spy_mode (const char digit, struct ast_flags *flags) |
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) |
static int | chanspy_exec (struct ast_channel *chan, const char *data) |
static int | common_exec (struct ast_channel *chan, struct ast_flags *flags, int volfactor, const int fd, struct spy_dtmf_options *user_options, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_context) |
static int | dahdiscan_exec (struct ast_channel *chan, const char *data) |
static int | extenspy_exec (struct ast_channel *chan, const char *data) |
static int | load_module (void) |
static struct ast_autochan * | next_channel (struct ast_channel_iterator *iter, struct ast_autochan *autochan, struct ast_channel *chan) |
static void * | spy_alloc (struct ast_channel *chan, void *data) |
static int | spy_generate (struct ast_channel *chan, void *data, int len, int samples) |
static void | spy_release (struct ast_channel *chan, void *data) |
static int | start_spying (struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } |
static const char | app_chan [] = "ChanSpy" |
static const char | app_dahdiscan [] = "DAHDIScan" |
static const char | app_ext [] = "ExtenSpy" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_app_option | spy_opts [128] = { [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'c' ] = { .flag = OPTION_DTMF_CYCLE , .arg_index = OPT_ARG_CYCLE + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'E' ] = { .flag = OPTION_EXITONHANGUP }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'S' ] = { .flag = OPTION_STOP }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'x' ] = { .flag = OPTION_DTMF_EXIT , .arg_index = OPT_ARG_EXIT + 1 }, [ 'X' ] = { .flag = OPTION_EXIT },} |
static struct ast_generator | spygen |
Joshua Colp <jcolp@digium.com>
Russell Bryant <russell@digium.com>
Definition in file app_chanspy.c.
#define AST_NAME_STRLEN 256 |
#define NUM_SPYGROUPS 128 |
anonymous enum |
Definition at line 350 of file app_chanspy.c.
00350 { 00351 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00352 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00353 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00354 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00355 OPTION_RECORD = (1 << 4), 00356 OPTION_WHISPER = (1 << 5), 00357 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00358 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */ 00359 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */ 00360 OPTION_ENFORCED = (1 << 9), /* Enforced mode */ 00361 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */ 00362 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */ 00363 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */ 00364 OPTION_DTMF_SWITCH_MODES = (1 << 13), /* Allow numeric DTMF to switch between chanspy modes */ 00365 OPTION_DTMF_EXIT = (1 << 14), /* Set DTMF to exit, added for DAHDIScan integration */ 00366 OPTION_DTMF_CYCLE = (1 << 15), /* Custom DTMF for cycling next avaliable channel, (default is '*') */ 00367 OPTION_DAHDI_SCAN = (1 << 16), /* Scan groups in DAHDIScan mode */ 00368 OPTION_STOP = (1 << 17), 00369 OPTION_EXITONHANGUP = (1 << 18), /* Hang up when the spied-on channel hangs up. */ 00370 };
anonymous enum |
OPT_ARG_VOLUME | |
OPT_ARG_GROUP | |
OPT_ARG_RECORD | |
OPT_ARG_ENFORCED | |
OPT_ARG_NAME | |
OPT_ARG_EXIT | |
OPT_ARG_CYCLE | |
OPT_ARG_ARRAY_SIZE |
Definition at line 372 of file app_chanspy.c.
00372 { 00373 OPT_ARG_VOLUME = 0, 00374 OPT_ARG_GROUP, 00375 OPT_ARG_RECORD, 00376 OPT_ARG_ENFORCED, 00377 OPT_ARG_NAME, 00378 OPT_ARG_EXIT, 00379 OPT_ARG_CYCLE, 00380 OPT_ARG_ARRAY_SIZE, 00381 };
static void __reg_module | ( | void | ) | [static] |
Definition at line 1330 of file app_chanspy.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1330 of file app_chanspy.c.
static void change_spy_mode | ( | const char | digit, | |
struct ast_flags * | flags | |||
) | [static] |
Definition at line 495 of file app_chanspy.c.
References ast_clear_flag, ast_set_flag, ast_channel::flags, OPTION_BARGE, and OPTION_WHISPER.
Referenced by channel_spy().
00496 { 00497 if (digit == '4') { 00498 ast_clear_flag(flags, OPTION_WHISPER); 00499 ast_clear_flag(flags, OPTION_BARGE); 00500 } else if (digit == '5') { 00501 ast_clear_flag(flags, OPTION_BARGE); 00502 ast_set_flag(flags, OPTION_WHISPER); 00503 } else if (digit == '6') { 00504 ast_clear_flag(flags, OPTION_WHISPER); 00505 ast_set_flag(flags, OPTION_BARGE); 00506 } 00507 }
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 | |||
) | [static] |
Definition at line 509 of file app_chanspy.c.
References ast_activate_generator(), ast_audiohook_destroy(), ast_audiohook_detach(), AST_AUDIOHOOK_DIRECTION_WRITE, ast_audiohook_init(), ast_audiohook_lock, AST_AUDIOHOOK_STATUS_RUNNING, AST_AUDIOHOOK_TYPE_SPY, AST_AUDIOHOOK_TYPE_WHISPER, ast_audiohook_unlock, ast_audiohook_write_frame(), ast_autochan_destroy(), ast_autochan_setup(), ast_bridged_channel(), ast_channel_lock, ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_flags, ast_deactivate_generator(), ast_debug, AST_FLAG_END_DTMF_ONLY, AST_FLAGS_ALL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_log(), ast_manager_event, ast_manager_event_multichan, ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor(), ast_autochan::chan, change_spy_mode(), spy_dtmf_options::cycle, EVENT_FLAG_CALL, spy_dtmf_options::exit, f, ast_channel::flags, LOG_WARNING, ast_channel::name, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, pbx_builtin_setvar_helper(), spygen, start_spying(), and spy_dtmf_options::volume.
Referenced by common_exec().
00512 { 00513 struct chanspy_translation_helper csth; 00514 int running = 0, res, x = 0; 00515 char inp[24] = {0}; 00516 char *name; 00517 struct ast_frame *f; 00518 struct ast_silence_generator *silgen = NULL; 00519 struct ast_autochan *spyee_bridge_autochan = NULL; 00520 const char *spyer_name; 00521 struct ast_channel *chans[] = { chan, spyee_autochan->chan }; 00522 00523 ast_channel_lock(chan); 00524 spyer_name = ast_strdupa(chan->name); 00525 ast_channel_unlock(chan); 00526 00527 /* We now hold the channel lock on spyee */ 00528 00529 if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) { 00530 return 0; 00531 } 00532 00533 ast_channel_lock(spyee_autochan->chan); 00534 name = ast_strdupa(spyee_autochan->chan->name); 00535 ast_channel_unlock(spyee_autochan->chan); 00536 00537 ast_verb(2, "Spying on channel %s\n", name); 00538 ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans, 00539 "SpyerChannel: %s\r\n" 00540 "SpyeeChannel: %s\r\n", 00541 spyer_name, name); 00542 00543 memset(&csth, 0, sizeof(csth)); 00544 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL); 00545 00546 /* This is the audiohook which gives us the audio off the channel we are 00547 spying on. 00548 */ 00549 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00550 00551 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) { 00552 ast_audiohook_destroy(&csth.spy_audiohook); 00553 return 0; 00554 } 00555 00556 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00557 /* This audiohook will let us inject audio from our channel into the 00558 channel we are currently spying on. 00559 */ 00560 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00561 00562 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) { 00563 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name); 00564 } 00565 } 00566 00567 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00568 /* And this hook lets us inject audio into the channel that the spied on 00569 channel is currently bridged with. 00570 */ 00571 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); 00572 00573 if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) { 00574 ast_channel_lock(spyee_bridge_autochan->chan); 00575 if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) { 00576 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name); 00577 } 00578 ast_channel_unlock(spyee_bridge_autochan->chan); 00579 } 00580 } 00581 00582 ast_channel_lock(chan); 00583 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00584 ast_channel_unlock(chan); 00585 00586 csth.volfactor = *volfactor; 00587 00588 if (csth.volfactor) { 00589 csth.spy_audiohook.options.read_volume = csth.volfactor; 00590 csth.spy_audiohook.options.write_volume = csth.volfactor; 00591 } 00592 00593 csth.fd = fd; 00594 00595 if (ast_test_flag(flags, OPTION_PRIVATE)) 00596 silgen = ast_channel_start_silence_generator(chan); 00597 else 00598 ast_activate_generator(chan, &spygen, &csth); 00599 00600 /* We can no longer rely on 'spyee' being an actual channel; 00601 it can be hung up and freed out from under us. However, the 00602 channel destructor will put NULL into our csth.spy.chan 00603 field when that happens, so that is our signal that the spyee 00604 channel has gone away. 00605 */ 00606 00607 /* Note: it is very important that the ast_waitfor() be the first 00608 condition in this expression, so that if we wait for some period 00609 of time before receiving a frame from our spying channel, we check 00610 for hangup on the spied-on channel _after_ knowing that a frame 00611 has arrived, since the spied-on channel could have gone away while 00612 we were waiting 00613 */ 00614 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00615 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00616 running = -1; 00617 break; 00618 } 00619 00620 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { 00621 ast_audiohook_lock(&csth.whisper_audiohook); 00622 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00623 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00624 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00625 ast_audiohook_unlock(&csth.whisper_audiohook); 00626 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00627 ast_frfree(f); 00628 continue; 00629 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { 00630 ast_audiohook_lock(&csth.whisper_audiohook); 00631 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00632 ast_audiohook_unlock(&csth.whisper_audiohook); 00633 ast_frfree(f); 00634 continue; 00635 } 00636 00637 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0; 00638 ast_frfree(f); 00639 if (!res) 00640 continue; 00641 00642 if (x == sizeof(inp)) 00643 x = 0; 00644 00645 if (res < 0) { 00646 running = -1; 00647 break; 00648 } 00649 00650 if (ast_test_flag(flags, OPTION_EXIT)) { 00651 char tmp[2]; 00652 tmp[0] = res; 00653 tmp[1] = '\0'; 00654 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00655 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); 00656 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); 00657 running = -2; 00658 break; 00659 } else { 00660 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00661 } 00662 } else if (res >= '0' && res <= '9') { 00663 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { 00664 change_spy_mode(res, flags); 00665 } else { 00666 inp[x++] = res; 00667 } 00668 } 00669 00670 if (res == user_options->cycle) { 00671 running = 0; 00672 break; 00673 } else if (res == user_options->exit) { 00674 running = -2; 00675 break; 00676 } else if (res == user_options->volume) { 00677 if (!ast_strlen_zero(inp)) { 00678 running = atoi(inp); 00679 break; 00680 } 00681 00682 (*volfactor)++; 00683 if (*volfactor > 4) 00684 *volfactor = -4; 00685 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00686 00687 csth.volfactor = *volfactor; 00688 csth.spy_audiohook.options.read_volume = csth.volfactor; 00689 csth.spy_audiohook.options.write_volume = csth.volfactor; 00690 } 00691 } 00692 00693 if (ast_test_flag(flags, OPTION_PRIVATE)) 00694 ast_channel_stop_silence_generator(chan, silgen); 00695 else 00696 ast_deactivate_generator(chan); 00697 00698 ast_channel_lock(chan); 00699 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00700 ast_channel_unlock(chan); 00701 00702 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00703 ast_audiohook_lock(&csth.whisper_audiohook); 00704 ast_audiohook_detach(&csth.whisper_audiohook); 00705 ast_audiohook_unlock(&csth.whisper_audiohook); 00706 ast_audiohook_destroy(&csth.whisper_audiohook); 00707 } 00708 00709 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00710 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00711 ast_audiohook_detach(&csth.bridge_whisper_audiohook); 00712 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00713 ast_audiohook_destroy(&csth.bridge_whisper_audiohook); 00714 } 00715 00716 ast_audiohook_lock(&csth.spy_audiohook); 00717 ast_audiohook_detach(&csth.spy_audiohook); 00718 ast_audiohook_unlock(&csth.spy_audiohook); 00719 ast_audiohook_destroy(&csth.spy_audiohook); 00720 00721 if (spyee_bridge_autochan) { 00722 ast_autochan_destroy(spyee_bridge_autochan); 00723 } 00724 00725 ast_verb(2, "Done Spying on channel %s\n", name); 00726 ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); 00727 00728 return running; 00729 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1033 of file app_chanspy.c.
References args, AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, common_exec(), spy_dtmf_options::cycle, spy_dtmf_options::exit, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_CYCLE, OPT_ARG_ENFORCED, OPT_ARG_EXIT, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, OPTION_ENFORCED, OPTION_EXITONHANGUP, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, parse(), spy_opts, and ast_channel::writeformat.
Referenced by load_module().
01034 { 01035 char *myenforced = NULL; 01036 char *mygroup = NULL; 01037 char *recbase = NULL; 01038 int fd = 0; 01039 struct ast_flags flags; 01040 struct spy_dtmf_options user_options = { 01041 .cycle = '*', 01042 .volume = '#', 01043 .exit = '\0', 01044 }; 01045 int oldwf = 0; 01046 int volfactor = 0; 01047 int res; 01048 char *mailbox = NULL; 01049 char *name_context = NULL; 01050 AST_DECLARE_APP_ARGS(args, 01051 AST_APP_ARG(spec); 01052 AST_APP_ARG(options); 01053 ); 01054 char *opts[OPT_ARG_ARRAY_SIZE]; 01055 char *parse = ast_strdupa(data); 01056 01057 AST_STANDARD_APP_ARGS(args, parse); 01058 01059 if (args.spec && !strcmp(args.spec, "all")) 01060 args.spec = NULL; 01061 01062 if (args.options) { 01063 char tmp; 01064 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01065 if (ast_test_flag(&flags, OPTION_GROUP)) 01066 mygroup = opts[OPT_ARG_GROUP]; 01067 01068 if (ast_test_flag(&flags, OPTION_RECORD) && 01069 !(recbase = opts[OPT_ARG_RECORD])) 01070 recbase = "chanspy"; 01071 01072 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { 01073 tmp = opts[OPT_ARG_EXIT][0]; 01074 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01075 user_options.exit = tmp; 01076 } else { 01077 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit."); 01078 } 01079 } 01080 01081 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { 01082 tmp = opts[OPT_ARG_CYCLE][0]; 01083 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01084 user_options.cycle = tmp; 01085 } else { 01086 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit."); 01087 } 01088 } 01089 01090 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01091 int vol; 01092 01093 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01094 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01095 else 01096 volfactor = vol; 01097 } 01098 01099 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01100 ast_set_flag(&flags, OPTION_WHISPER); 01101 01102 if (ast_test_flag(&flags, OPTION_ENFORCED)) 01103 myenforced = opts[OPT_ARG_ENFORCED]; 01104 01105 if (ast_test_flag(&flags, OPTION_NAME)) { 01106 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01107 char *delimiter; 01108 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01109 mailbox = opts[OPT_ARG_NAME]; 01110 *delimiter++ = '\0'; 01111 name_context = delimiter; 01112 } else { 01113 mailbox = opts[OPT_ARG_NAME]; 01114 } 01115 } 01116 } 01117 } else { 01118 ast_clear_flag(&flags, AST_FLAGS_ALL); 01119 } 01120 01121 oldwf = chan->writeformat; 01122 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01123 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01124 return -1; 01125 } 01126 01127 if (recbase) { 01128 char filename[PATH_MAX]; 01129 01130 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01131 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01132 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01133 fd = 0; 01134 } 01135 } 01136 01137 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); 01138 01139 if (fd) 01140 close(fd); 01141 01142 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01143 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01144 01145 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) { 01146 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n"); 01147 } 01148 01149 return res; 01150 }
static int common_exec | ( | struct ast_channel * | chan, | |
struct ast_flags * | flags, | |||
int | volfactor, | |||
const int | fd, | |||
struct spy_dtmf_options * | user_options, | |||
const char * | mygroup, | |||
const char * | myenforced, | |||
const char * | spec, | |||
const char * | exten, | |||
const char * | context, | |||
const char * | mailbox, | |||
const char * | name_context | |||
) | [static] |
Definition at line 759 of file app_chanspy.c.
References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_sayname(), ast_app_separate_args, ast_autochan_destroy(), ast_autochan_setup(), ast_bridged_channel(), ast_channel_get_by_name_prefix(), ast_channel_iterator_all_new(), ast_channel_iterator_by_exten_new(), ast_channel_iterator_by_name_new(), ast_channel_iterator_destroy(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_setoption(), ast_channel_unlock, ast_channel_unref, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_fileexists(), AST_FLAG_SPYING, ast_goto_if_exists(), AST_MAX_CONTEXT, AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), ast_channel::context, exitcontext, ext, ast_channel::flags, ast_channel::macrocontext, next_channel(), NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_DAHDI_SCAN, OPTION_EXIT, OPTION_EXITONHANGUP, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, OPTION_STOP, pbx_builtin_getvar_helper(), S_OR, strcasestr(), and strsep().
Referenced by chanspy_exec(), dahdiscan_exec(), and extenspy_exec().
00763 { 00764 char nameprefix[AST_NAME_STRLEN]; 00765 char peer_name[AST_NAME_STRLEN + 5]; 00766 char exitcontext[AST_MAX_CONTEXT] = ""; 00767 signed char zero_volume = 0; 00768 int waitms; 00769 int res; 00770 char *ptr; 00771 int num; 00772 int num_spyed_upon = 1; 00773 struct ast_channel_iterator *iter = NULL; 00774 00775 if (ast_test_flag(flags, OPTION_EXIT)) { 00776 const char *c; 00777 ast_channel_lock(chan); 00778 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { 00779 ast_copy_string(exitcontext, c, sizeof(exitcontext)); 00780 } else if (!ast_strlen_zero(chan->macrocontext)) { 00781 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 00782 } else { 00783 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 00784 } 00785 ast_channel_unlock(chan); 00786 } 00787 00788 if (chan->_state != AST_STATE_UP) 00789 ast_answer(chan); 00790 00791 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00792 00793 waitms = 100; 00794 00795 for (;;) { 00796 struct ast_autochan *autochan = NULL, *next_autochan = NULL; 00797 struct ast_channel *prev = NULL; 00798 00799 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00800 res = ast_streamfile(chan, "beep", chan->language); 00801 if (!res) 00802 res = ast_waitstream(chan, ""); 00803 else if (res < 0) { 00804 ast_clear_flag(chan, AST_FLAG_SPYING); 00805 break; 00806 } 00807 if (!ast_strlen_zero(exitcontext)) { 00808 char tmp[2]; 00809 tmp[0] = res; 00810 tmp[1] = '\0'; 00811 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00812 goto exit; 00813 else 00814 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00815 } 00816 } 00817 00818 /* Set up the iterator we'll be using during this call */ 00819 if (!ast_strlen_zero(spec)) { 00820 iter = ast_channel_iterator_by_name_new(spec, strlen(spec)); 00821 } else if (!ast_strlen_zero(exten)) { 00822 iter = ast_channel_iterator_by_exten_new(exten, context); 00823 } else { 00824 iter = ast_channel_iterator_all_new(); 00825 } 00826 00827 if (!iter) { 00828 res = -1; 00829 goto exit; 00830 } 00831 00832 res = ast_waitfordigit(chan, waitms); 00833 if (res < 0) { 00834 iter = ast_channel_iterator_destroy(iter); 00835 ast_clear_flag(chan, AST_FLAG_SPYING); 00836 break; 00837 } 00838 if (!ast_strlen_zero(exitcontext)) { 00839 char tmp[2]; 00840 tmp[0] = res; 00841 tmp[1] = '\0'; 00842 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00843 iter = ast_channel_iterator_destroy(iter); 00844 goto exit; 00845 } else { 00846 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00847 } 00848 } 00849 00850 /* reset for the next loop around, unless overridden later */ 00851 waitms = 100; 00852 num_spyed_upon = 0; 00853 00854 for (autochan = next_channel(iter, autochan, chan); 00855 autochan; 00856 prev = autochan->chan, ast_autochan_destroy(autochan), 00857 autochan = next_autochan ? next_autochan : 00858 next_channel(iter, autochan, chan), next_autochan = NULL) { 00859 int igrp = !mygroup; 00860 int ienf = !myenforced; 00861 char *s; 00862 00863 if (autochan->chan == prev) { 00864 ast_autochan_destroy(autochan); 00865 break; 00866 } 00867 00868 if (ast_check_hangup(chan)) { 00869 ast_autochan_destroy(autochan); 00870 break; 00871 } 00872 00873 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) { 00874 continue; 00875 } 00876 00877 if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) { 00878 continue; 00879 } 00880 00881 if (mygroup) { 00882 int num_groups = 0; 00883 int num_mygroups = 0; 00884 char dup_group[512]; 00885 char dup_mygroup[512]; 00886 char *groups[NUM_SPYGROUPS]; 00887 char *mygroups[NUM_SPYGROUPS]; 00888 const char *group = NULL; 00889 int x; 00890 int y; 00891 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); 00892 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, 00893 ARRAY_LEN(mygroups)); 00894 00895 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 00896 * rather than "SPYGROUP", this check is done to preserve expected behavior */ 00897 if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { 00898 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); 00899 } else { 00900 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); 00901 } 00902 00903 if (!ast_strlen_zero(group)) { 00904 ast_copy_string(dup_group, group, sizeof(dup_group)); 00905 num_groups = ast_app_separate_args(dup_group, ':', groups, 00906 ARRAY_LEN(groups)); 00907 } 00908 00909 for (y = 0; y < num_mygroups; y++) { 00910 for (x = 0; x < num_groups; x++) { 00911 if (!strcmp(mygroups[y], groups[x])) { 00912 igrp = 1; 00913 break; 00914 } 00915 } 00916 } 00917 } 00918 00919 if (!igrp) { 00920 continue; 00921 } 00922 if (myenforced) { 00923 char ext[AST_CHANNEL_NAME + 3]; 00924 char buffer[512]; 00925 char *end; 00926 00927 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); 00928 00929 ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1); 00930 if ((end = strchr(ext, '-'))) { 00931 *end++ = ':'; 00932 *end = '\0'; 00933 } 00934 00935 ext[0] = ':'; 00936 00937 if (strcasestr(buffer, ext)) { 00938 ienf = 1; 00939 } 00940 } 00941 00942 if (!ienf) { 00943 continue; 00944 } 00945 00946 strcpy(peer_name, "spy-"); 00947 strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); 00948 ptr = strchr(peer_name, '/'); 00949 *ptr++ = '\0'; 00950 ptr = strsep(&ptr, "-"); 00951 00952 for (s = peer_name; s < ptr; s++) 00953 *s = tolower(*s); 00954 00955 if (!ast_test_flag(flags, OPTION_QUIET)) { 00956 if (ast_test_flag(flags, OPTION_NAME)) { 00957 const char *local_context = S_OR(name_context, "default"); 00958 const char *local_mailbox = S_OR(mailbox, ptr); 00959 res = ast_app_sayname(chan, local_mailbox, local_context); 00960 } 00961 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { 00962 if (!ast_test_flag(flags, OPTION_NOTECH)) { 00963 if (ast_fileexists(peer_name, NULL, NULL) > 0) { 00964 res = ast_streamfile(chan, peer_name, chan->language); 00965 if (!res) { 00966 res = ast_waitstream(chan, ""); 00967 } 00968 if (res) { 00969 ast_autochan_destroy(autochan); 00970 break; 00971 } 00972 } else { 00973 res = ast_say_character_str(chan, peer_name, "", chan->language); 00974 } 00975 } 00976 if ((num = atoi(ptr))) 00977 ast_say_digits(chan, atoi(ptr), "", chan->language); 00978 } 00979 } 00980 00981 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext); 00982 num_spyed_upon++; 00983 00984 if (res == -1) { 00985 ast_autochan_destroy(autochan); 00986 iter = ast_channel_iterator_destroy(iter); 00987 goto exit; 00988 } else if (res == -2) { 00989 res = 0; 00990 ast_autochan_destroy(autochan); 00991 iter = ast_channel_iterator_destroy(iter); 00992 goto exit; 00993 } else if (res > 1 && spec) { 00994 struct ast_channel *next; 00995 00996 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00997 00998 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) { 00999 next_autochan = ast_autochan_setup(next); 01000 next = ast_channel_unref(next); 01001 } else { 01002 /* stay on this channel, if it is still valid */ 01003 if (!ast_check_hangup(autochan->chan)) { 01004 next_autochan = ast_autochan_setup(autochan->chan); 01005 } else { 01006 /* the channel is gone */ 01007 next_autochan = NULL; 01008 } 01009 } 01010 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { 01011 iter = ast_channel_iterator_destroy(iter); 01012 goto exit; 01013 } 01014 } 01015 01016 iter = ast_channel_iterator_destroy(iter); 01017 01018 if (res == -1 || ast_check_hangup(chan)) 01019 break; 01020 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) { 01021 break; 01022 } 01023 } 01024 exit: 01025 01026 ast_clear_flag(chan, AST_FLAG_SPYING); 01027 01028 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 01029 01030 return res; 01031 }
static int dahdiscan_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1272 of file app_chanspy.c.
References ast_clear_flag, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), common_exec(), spy_dtmf_options::cycle, ast_flags::flags, LOG_ERROR, OPTION_DAHDI_SCAN, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, and ast_channel::writeformat.
Referenced by load_module().
01273 { 01274 const char *spec = "DAHDI"; 01275 struct ast_flags flags; 01276 struct spy_dtmf_options user_options = { 01277 .cycle = '#', 01278 .volume = '\0', 01279 .exit = '*', 01280 }; 01281 int oldwf = 0; 01282 int res; 01283 char *mygroup = NULL; 01284 01285 ast_clear_flag(&flags, AST_FLAGS_ALL); 01286 01287 if (!ast_strlen_zero(data)) { 01288 mygroup = ast_strdupa(data); 01289 } 01290 ast_set_flag(&flags, OPTION_DTMF_EXIT); 01291 ast_set_flag(&flags, OPTION_DTMF_CYCLE); 01292 ast_set_flag(&flags, OPTION_DAHDI_SCAN); 01293 01294 oldwf = chan->writeformat; 01295 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01296 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01297 return -1; 01298 } 01299 01300 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); 01301 01302 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01303 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01304 01305 return res; 01306 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1152 of file app_chanspy.c.
References args, AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_channel::context, context, spy_dtmf_options::cycle, spy_dtmf_options::exit, exten, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_CYCLE, OPT_ARG_EXIT, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_DTMF_CYCLE, OPTION_DTMF_EXIT, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, parse(), spy_opts, and ast_channel::writeformat.
Referenced by load_module().
01153 { 01154 char *ptr, *exten = NULL; 01155 char *mygroup = NULL; 01156 char *recbase = NULL; 01157 int fd = 0; 01158 struct ast_flags flags; 01159 struct spy_dtmf_options user_options = { 01160 .cycle = '*', 01161 .volume = '#', 01162 .exit = '\0', 01163 }; 01164 int oldwf = 0; 01165 int volfactor = 0; 01166 int res; 01167 char *mailbox = NULL; 01168 char *name_context = NULL; 01169 AST_DECLARE_APP_ARGS(args, 01170 AST_APP_ARG(context); 01171 AST_APP_ARG(options); 01172 ); 01173 char *parse = ast_strdupa(data); 01174 01175 AST_STANDARD_APP_ARGS(args, parse); 01176 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { 01177 exten = args.context; 01178 *ptr++ = '\0'; 01179 args.context = ptr; 01180 } 01181 01182 if (ast_strlen_zero(args.context)) 01183 args.context = ast_strdupa(chan->context); 01184 01185 if (args.options) { 01186 char *opts[OPT_ARG_ARRAY_SIZE]; 01187 char tmp; 01188 01189 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01190 if (ast_test_flag(&flags, OPTION_GROUP)) 01191 mygroup = opts[OPT_ARG_GROUP]; 01192 01193 if (ast_test_flag(&flags, OPTION_RECORD) && 01194 !(recbase = opts[OPT_ARG_RECORD])) 01195 recbase = "chanspy"; 01196 01197 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { 01198 tmp = opts[OPT_ARG_EXIT][0]; 01199 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01200 user_options.exit = tmp; 01201 } else { 01202 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit."); 01203 } 01204 } 01205 01206 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { 01207 tmp = opts[OPT_ARG_CYCLE][0]; 01208 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01209 user_options.cycle = tmp; 01210 } else { 01211 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit."); 01212 } 01213 } 01214 01215 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01216 int vol; 01217 01218 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01219 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01220 else 01221 volfactor = vol; 01222 } 01223 01224 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01225 ast_set_flag(&flags, OPTION_WHISPER); 01226 01227 if (ast_test_flag(&flags, OPTION_NAME)) { 01228 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01229 char *delimiter; 01230 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01231 mailbox = opts[OPT_ARG_NAME]; 01232 *delimiter++ = '\0'; 01233 name_context = delimiter; 01234 } else { 01235 mailbox = opts[OPT_ARG_NAME]; 01236 } 01237 } 01238 } 01239 01240 } else { 01241 ast_clear_flag(&flags, AST_FLAGS_ALL); 01242 } 01243 01244 oldwf = chan->writeformat; 01245 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01246 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01247 return -1; 01248 } 01249 01250 if (recbase) { 01251 char filename[PATH_MAX]; 01252 01253 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01254 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01255 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01256 fd = 0; 01257 } 01258 } 01259 01260 01261 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); 01262 01263 if (fd) 01264 close(fd); 01265 01266 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01267 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01268 01269 return res; 01270 }
static int load_module | ( | void | ) | [static] |
Definition at line 1319 of file app_chanspy.c.
References ast_register_application_xml, chanspy_exec(), dahdiscan_exec(), and extenspy_exec().
01320 { 01321 int res = 0; 01322 01323 res |= ast_register_application_xml(app_chan, chanspy_exec); 01324 res |= ast_register_application_xml(app_ext, extenspy_exec); 01325 res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec); 01326 01327 return res; 01328 }
static struct ast_autochan* next_channel | ( | struct ast_channel_iterator * | iter, | |
struct ast_autochan * | autochan, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 731 of file app_chanspy.c.
References ast_autochan_setup(), ast_channel_iterator_next(), ast_channel_unref, ast_autochan::chan, and ast_autochan::next.
Referenced by common_exec().
00733 { 00734 struct ast_channel *next; 00735 struct ast_autochan *autochan_store; 00736 const size_t pseudo_len = strlen("DAHDI/pseudo"); 00737 00738 if (!iter) { 00739 return NULL; 00740 } 00741 00742 redo: 00743 if (!(next = ast_channel_iterator_next(iter))) { 00744 return NULL; 00745 } 00746 00747 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) { 00748 goto redo; 00749 } else if (next == chan) { 00750 goto redo; 00751 } 00752 00753 autochan_store = ast_autochan_setup(next); 00754 ast_channel_unref(next); 00755 00756 return autochan_store; 00757 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 431 of file app_chanspy.c.
References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, AST_LIST_NEXT, ast_log(), ast_test_flag, ast_write(), ast_frame::data, ast_frame::datalen, errno, f, chanspy_translation_helper::fd, chanspy_translation_helper::flags, LOG_WARNING, OPTION_READONLY, ast_frame::ptr, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.
00432 { 00433 struct chanspy_translation_helper *csth = data; 00434 struct ast_frame *f, *cur; 00435 00436 ast_audiohook_lock(&csth->spy_audiohook); 00437 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00438 /* Channel is already gone more than likely */ 00439 ast_audiohook_unlock(&csth->spy_audiohook); 00440 return -1; 00441 } 00442 00443 if (ast_test_flag(&csth->flags, OPTION_READONLY)) { 00444 /* Option 'o' was set, so don't mix channel audio */ 00445 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR); 00446 } else { 00447 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); 00448 } 00449 00450 ast_audiohook_unlock(&csth->spy_audiohook); 00451 00452 if (!f) 00453 return 0; 00454 00455 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00456 if (ast_write(chan, cur)) { 00457 ast_frfree(f); 00458 return -1; 00459 } 00460 00461 if (csth->fd) { 00462 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) { 00463 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 00464 } 00465 } 00466 } 00467 00468 ast_frfree(f); 00469 00470 return 0; 00471 }
static void spy_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static int start_spying | ( | struct ast_autochan * | autochan, | |
const char * | spychan_name, | |||
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 479 of file app_chanspy.c.
References ast_audiohook_attach(), AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_log(), ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, ast_autochan::chan, LOG_NOTICE, and ast_channel::name.
Referenced by channel_spy().
00480 { 00481 int res = 0; 00482 struct ast_channel *peer = NULL; 00483 00484 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, autochan->chan->name); 00485 00486 ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE); 00487 res = ast_audiohook_attach(autochan->chan, audiohook); 00488 00489 if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) { 00490 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00491 } 00492 return res; 00493 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1308 of file app_chanspy.c.
References ast_unregister_application().
01309 { 01310 int res = 0; 01311 01312 res |= ast_unregister_application(app_chan); 01313 res |= ast_unregister_application(app_ext); 01314 res |= ast_unregister_application(app_dahdiscan); 01315 01316 return res; 01317 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1330 of file app_chanspy.c.
const char app_chan[] = "ChanSpy" [static] |
Definition at line 344 of file app_chanspy.c.
const char app_dahdiscan[] = "DAHDIScan" [static] |
Definition at line 348 of file app_chanspy.c.
const char app_ext[] = "ExtenSpy" [static] |
Definition at line 346 of file app_chanspy.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1330 of file app_chanspy.c.
struct ast_app_option spy_opts[128] = { [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'c' ] = { .flag = OPTION_DTMF_CYCLE , .arg_index = OPT_ARG_CYCLE + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'E' ] = { .flag = OPTION_EXITONHANGUP }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'q' ] = { .flag = OPTION_QUIET }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'S' ] = { .flag = OPTION_STOP }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'x' ] = { .flag = OPTION_DTMF_EXIT , .arg_index = OPT_ARG_EXIT + 1 }, [ 'X' ] = { .flag = OPTION_EXIT },} [static] |
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 473 of file app_chanspy.c.
Referenced by channel_spy().