#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 = "ac1f6a56484a8820659555499174e588" , .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 1344 of file app_chanspy.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1344 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_FLAG_ZOMBIE, 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 ast_test_flag(spyee_autochan->chan, AST_FLAG_ZOMBIE)) { 00531 return 0; 00532 } 00533 00534 ast_channel_lock(spyee_autochan->chan); 00535 name = ast_strdupa(spyee_autochan->chan->name); 00536 ast_channel_unlock(spyee_autochan->chan); 00537 00538 ast_verb(2, "Spying on channel %s\n", name); 00539 ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans, 00540 "SpyerChannel: %s\r\n" 00541 "SpyeeChannel: %s\r\n", 00542 spyer_name, name); 00543 00544 memset(&csth, 0, sizeof(csth)); 00545 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL); 00546 00547 /* This is the audiohook which gives us the audio off the channel we are 00548 spying on. 00549 */ 00550 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00551 00552 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) { 00553 ast_audiohook_destroy(&csth.spy_audiohook); 00554 return 0; 00555 } 00556 00557 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00558 /* This audiohook will let us inject audio from our channel into the 00559 channel we are currently spying on. 00560 */ 00561 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00562 00563 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) { 00564 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name); 00565 } 00566 } 00567 00568 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00569 /* And this hook lets us inject audio into the channel that the spied on 00570 channel is currently bridged with. 00571 */ 00572 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); 00573 00574 if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) { 00575 ast_channel_lock(spyee_bridge_autochan->chan); 00576 if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) { 00577 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name); 00578 } 00579 ast_channel_unlock(spyee_bridge_autochan->chan); 00580 } 00581 } 00582 00583 ast_channel_lock(chan); 00584 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00585 ast_channel_unlock(chan); 00586 00587 csth.volfactor = *volfactor; 00588 00589 if (csth.volfactor) { 00590 csth.spy_audiohook.options.read_volume = csth.volfactor; 00591 csth.spy_audiohook.options.write_volume = csth.volfactor; 00592 } 00593 00594 csth.fd = fd; 00595 00596 if (ast_test_flag(flags, OPTION_PRIVATE)) 00597 silgen = ast_channel_start_silence_generator(chan); 00598 else 00599 ast_activate_generator(chan, &spygen, &csth); 00600 00601 /* We can no longer rely on 'spyee' being an actual channel; 00602 it can be hung up and freed out from under us. However, the 00603 channel destructor will put NULL into our csth.spy.chan 00604 field when that happens, so that is our signal that the spyee 00605 channel has gone away. 00606 */ 00607 00608 /* Note: it is very important that the ast_waitfor() be the first 00609 condition in this expression, so that if we wait for some period 00610 of time before receiving a frame from our spying channel, we check 00611 for hangup on the spied-on channel _after_ knowing that a frame 00612 has arrived, since the spied-on channel could have gone away while 00613 we were waiting 00614 */ 00615 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00616 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00617 running = -1; 00618 break; 00619 } 00620 00621 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { 00622 ast_audiohook_lock(&csth.whisper_audiohook); 00623 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00624 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00625 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00626 ast_audiohook_unlock(&csth.whisper_audiohook); 00627 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00628 ast_frfree(f); 00629 continue; 00630 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { 00631 ast_audiohook_lock(&csth.whisper_audiohook); 00632 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00633 ast_audiohook_unlock(&csth.whisper_audiohook); 00634 ast_frfree(f); 00635 continue; 00636 } 00637 00638 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0; 00639 ast_frfree(f); 00640 if (!res) 00641 continue; 00642 00643 if (x == sizeof(inp)) 00644 x = 0; 00645 00646 if (res < 0) { 00647 running = -1; 00648 break; 00649 } 00650 00651 if (ast_test_flag(flags, OPTION_EXIT)) { 00652 char tmp[2]; 00653 tmp[0] = res; 00654 tmp[1] = '\0'; 00655 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00656 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); 00657 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); 00658 running = -2; 00659 break; 00660 } else { 00661 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00662 } 00663 } else if (res >= '0' && res <= '9') { 00664 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { 00665 change_spy_mode(res, flags); 00666 } else { 00667 inp[x++] = res; 00668 } 00669 } 00670 00671 if (res == user_options->cycle) { 00672 running = 0; 00673 break; 00674 } else if (res == user_options->exit) { 00675 running = -2; 00676 break; 00677 } else if (res == user_options->volume) { 00678 if (!ast_strlen_zero(inp)) { 00679 running = atoi(inp); 00680 break; 00681 } 00682 00683 (*volfactor)++; 00684 if (*volfactor > 4) 00685 *volfactor = -4; 00686 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00687 00688 csth.volfactor = *volfactor; 00689 csth.spy_audiohook.options.read_volume = csth.volfactor; 00690 csth.spy_audiohook.options.write_volume = csth.volfactor; 00691 } 00692 } 00693 00694 if (ast_test_flag(flags, OPTION_PRIVATE)) 00695 ast_channel_stop_silence_generator(chan, silgen); 00696 else 00697 ast_deactivate_generator(chan); 00698 00699 ast_channel_lock(chan); 00700 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00701 ast_channel_unlock(chan); 00702 00703 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00704 ast_audiohook_lock(&csth.whisper_audiohook); 00705 ast_audiohook_detach(&csth.whisper_audiohook); 00706 ast_audiohook_unlock(&csth.whisper_audiohook); 00707 ast_audiohook_destroy(&csth.whisper_audiohook); 00708 } 00709 00710 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) { 00711 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00712 ast_audiohook_detach(&csth.bridge_whisper_audiohook); 00713 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00714 ast_audiohook_destroy(&csth.bridge_whisper_audiohook); 00715 } 00716 00717 ast_audiohook_lock(&csth.spy_audiohook); 00718 ast_audiohook_detach(&csth.spy_audiohook); 00719 ast_audiohook_unlock(&csth.spy_audiohook); 00720 ast_audiohook_destroy(&csth.spy_audiohook); 00721 00722 if (spyee_bridge_autochan) { 00723 ast_autochan_destroy(spyee_bridge_autochan); 00724 } 00725 00726 ast_verb(2, "Done Spying on channel %s\n", name); 00727 ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); 00728 00729 return running; 00730 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1045 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().
01046 { 01047 char *myenforced = NULL; 01048 char *mygroup = NULL; 01049 char *recbase = NULL; 01050 int fd = 0; 01051 struct ast_flags flags; 01052 struct spy_dtmf_options user_options = { 01053 .cycle = '*', 01054 .volume = '#', 01055 .exit = '\0', 01056 }; 01057 int oldwf = 0; 01058 int volfactor = 0; 01059 int res; 01060 char *mailbox = NULL; 01061 char *name_context = NULL; 01062 AST_DECLARE_APP_ARGS(args, 01063 AST_APP_ARG(spec); 01064 AST_APP_ARG(options); 01065 ); 01066 char *opts[OPT_ARG_ARRAY_SIZE]; 01067 char *parse = ast_strdupa(data); 01068 01069 AST_STANDARD_APP_ARGS(args, parse); 01070 01071 if (args.spec && !strcmp(args.spec, "all")) 01072 args.spec = NULL; 01073 01074 if (args.options) { 01075 char tmp; 01076 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01077 if (ast_test_flag(&flags, OPTION_GROUP)) 01078 mygroup = opts[OPT_ARG_GROUP]; 01079 01080 if (ast_test_flag(&flags, OPTION_RECORD) && 01081 !(recbase = opts[OPT_ARG_RECORD])) 01082 recbase = "chanspy"; 01083 01084 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { 01085 tmp = opts[OPT_ARG_EXIT][0]; 01086 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01087 user_options.exit = tmp; 01088 } else { 01089 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); 01090 } 01091 } 01092 01093 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { 01094 tmp = opts[OPT_ARG_CYCLE][0]; 01095 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01096 user_options.cycle = tmp; 01097 } else { 01098 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); 01099 } 01100 } 01101 01102 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01103 int vol; 01104 01105 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01106 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01107 else 01108 volfactor = vol; 01109 } 01110 01111 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01112 ast_set_flag(&flags, OPTION_WHISPER); 01113 01114 if (ast_test_flag(&flags, OPTION_ENFORCED)) 01115 myenforced = opts[OPT_ARG_ENFORCED]; 01116 01117 if (ast_test_flag(&flags, OPTION_NAME)) { 01118 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01119 char *delimiter; 01120 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01121 mailbox = opts[OPT_ARG_NAME]; 01122 *delimiter++ = '\0'; 01123 name_context = delimiter; 01124 } else { 01125 mailbox = opts[OPT_ARG_NAME]; 01126 } 01127 } 01128 } 01129 } else { 01130 ast_clear_flag(&flags, AST_FLAGS_ALL); 01131 } 01132 01133 oldwf = chan->writeformat; 01134 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01135 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01136 return -1; 01137 } 01138 01139 if (recbase) { 01140 char filename[PATH_MAX]; 01141 01142 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01143 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01144 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01145 fd = 0; 01146 } 01147 } 01148 01149 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); 01150 01151 if (fd) 01152 close(fd); 01153 01154 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01155 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01156 01157 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) { 01158 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n"); 01159 } 01160 01161 return res; 01162 }
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 762 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, and strcasestr().
Referenced by chanspy_exec(), dahdiscan_exec(), and extenspy_exec().
00766 { 00767 char nameprefix[AST_NAME_STRLEN]; 00768 char exitcontext[AST_MAX_CONTEXT] = ""; 00769 signed char zero_volume = 0; 00770 int waitms; 00771 int res; 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 00862 if (autochan->chan == prev) { 00863 ast_autochan_destroy(autochan); 00864 break; 00865 } 00866 00867 if (ast_check_hangup(chan)) { 00868 ast_autochan_destroy(autochan); 00869 break; 00870 } 00871 00872 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) { 00873 continue; 00874 } 00875 00876 if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) { 00877 continue; 00878 } 00879 00880 if (mygroup) { 00881 int num_groups = 0; 00882 int num_mygroups = 0; 00883 char dup_group[512]; 00884 char dup_mygroup[512]; 00885 char *groups[NUM_SPYGROUPS]; 00886 char *mygroups[NUM_SPYGROUPS]; 00887 const char *group = NULL; 00888 int x; 00889 int y; 00890 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); 00891 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, 00892 ARRAY_LEN(mygroups)); 00893 00894 /* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 00895 * rather than "SPYGROUP", this check is done to preserve expected behavior */ 00896 if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) { 00897 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP"); 00898 } else { 00899 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP"); 00900 } 00901 00902 if (!ast_strlen_zero(group)) { 00903 ast_copy_string(dup_group, group, sizeof(dup_group)); 00904 num_groups = ast_app_separate_args(dup_group, ':', groups, 00905 ARRAY_LEN(groups)); 00906 } 00907 00908 for (y = 0; y < num_mygroups; y++) { 00909 for (x = 0; x < num_groups; x++) { 00910 if (!strcmp(mygroups[y], groups[x])) { 00911 igrp = 1; 00912 break; 00913 } 00914 } 00915 } 00916 } 00917 00918 if (!igrp) { 00919 continue; 00920 } 00921 if (myenforced) { 00922 char ext[AST_CHANNEL_NAME + 3]; 00923 char buffer[512]; 00924 char *end; 00925 00926 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); 00927 00928 ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1); 00929 if ((end = strchr(ext, '-'))) { 00930 *end++ = ':'; 00931 *end = '\0'; 00932 } 00933 00934 ext[0] = ':'; 00935 00936 if (strcasestr(buffer, ext)) { 00937 ienf = 1; 00938 } 00939 } 00940 00941 if (!ienf) { 00942 continue; 00943 } 00944 00945 00946 if (!ast_test_flag(flags, OPTION_QUIET)) { 00947 char peer_name[AST_NAME_STRLEN + 5]; 00948 char *ptr, *s; 00949 00950 strcpy(peer_name, "spy-"); 00951 strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1); 00952 if ((ptr = strchr(peer_name, '/'))) { 00953 *ptr++ = '\0'; 00954 for (s = peer_name; s < ptr; s++) { 00955 *s = tolower(*s); 00956 } 00957 if ((s = strchr(ptr, '-'))) { 00958 *s = '\0'; 00959 } 00960 } 00961 00962 if (ast_test_flag(flags, OPTION_NAME)) { 00963 const char *local_context = S_OR(name_context, "default"); 00964 const char *local_mailbox = S_OR(mailbox, ptr); 00965 if (local_mailbox) { 00966 res = ast_app_sayname(chan, local_mailbox, local_context); 00967 } else { 00968 res = -1; 00969 } 00970 } 00971 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { 00972 int num; 00973 if (!ast_test_flag(flags, OPTION_NOTECH)) { 00974 if (ast_fileexists(peer_name, NULL, NULL) > 0) { 00975 res = ast_streamfile(chan, peer_name, chan->language); 00976 if (!res) { 00977 res = ast_waitstream(chan, ""); 00978 } 00979 if (res) { 00980 ast_autochan_destroy(autochan); 00981 break; 00982 } 00983 } else { 00984 res = ast_say_character_str(chan, peer_name, "", chan->language); 00985 } 00986 } 00987 if (ptr && (num = atoi(ptr))) { 00988 ast_say_digits(chan, num, "", chan->language); 00989 } 00990 } 00991 } 00992 00993 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext); 00994 num_spyed_upon++; 00995 00996 if (res == -1) { 00997 ast_autochan_destroy(autochan); 00998 iter = ast_channel_iterator_destroy(iter); 00999 goto exit; 01000 } else if (res == -2) { 01001 res = 0; 01002 ast_autochan_destroy(autochan); 01003 iter = ast_channel_iterator_destroy(iter); 01004 goto exit; 01005 } else if (res > 1 && spec) { 01006 struct ast_channel *next; 01007 01008 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 01009 01010 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) { 01011 next_autochan = ast_autochan_setup(next); 01012 next = ast_channel_unref(next); 01013 } else { 01014 /* stay on this channel, if it is still valid */ 01015 if (!ast_check_hangup(autochan->chan)) { 01016 next_autochan = ast_autochan_setup(autochan->chan); 01017 } else { 01018 /* the channel is gone */ 01019 next_autochan = NULL; 01020 } 01021 } 01022 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) { 01023 iter = ast_channel_iterator_destroy(iter); 01024 goto exit; 01025 } 01026 } 01027 01028 iter = ast_channel_iterator_destroy(iter); 01029 01030 if (res == -1 || ast_check_hangup(chan)) 01031 break; 01032 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) { 01033 break; 01034 } 01035 } 01036 exit: 01037 01038 ast_clear_flag(chan, AST_FLAG_SPYING); 01039 01040 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 01041 01042 return res; 01043 }
static int dahdiscan_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1285 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().
01286 { 01287 const char *spec = "DAHDI"; 01288 struct ast_flags flags; 01289 struct spy_dtmf_options user_options = { 01290 .cycle = '#', 01291 .volume = '\0', 01292 .exit = '*', 01293 }; 01294 int oldwf = 0; 01295 int res; 01296 char *mygroup = NULL; 01297 01298 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 01299 ast_clear_flag(&flags, AST_FLAGS_ALL); 01300 01301 if (!ast_strlen_zero(data)) { 01302 mygroup = ast_strdupa(data); 01303 } 01304 ast_set_flag(&flags, OPTION_DTMF_EXIT); 01305 ast_set_flag(&flags, OPTION_DTMF_CYCLE); 01306 ast_set_flag(&flags, OPTION_DAHDI_SCAN); 01307 01308 oldwf = chan->writeformat; 01309 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01310 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01311 return -1; 01312 } 01313 01314 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL); 01315 01316 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01317 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01318 01319 return res; 01320 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 1164 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().
01165 { 01166 char *ptr, *exten = NULL; 01167 char *mygroup = NULL; 01168 char *recbase = NULL; 01169 int fd = 0; 01170 struct ast_flags flags; 01171 struct spy_dtmf_options user_options = { 01172 .cycle = '*', 01173 .volume = '#', 01174 .exit = '\0', 01175 }; 01176 int oldwf = 0; 01177 int volfactor = 0; 01178 int res; 01179 char *mailbox = NULL; 01180 char *name_context = NULL; 01181 AST_DECLARE_APP_ARGS(args, 01182 AST_APP_ARG(context); 01183 AST_APP_ARG(options); 01184 ); 01185 char *parse = ast_strdupa(data); 01186 01187 AST_STANDARD_APP_ARGS(args, parse); 01188 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { 01189 exten = args.context; 01190 *ptr++ = '\0'; 01191 args.context = ptr; 01192 } 01193 01194 if (ast_strlen_zero(args.context)) 01195 args.context = ast_strdupa(chan->context); 01196 01197 if (args.options) { 01198 char *opts[OPT_ARG_ARRAY_SIZE]; 01199 char tmp; 01200 01201 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01202 if (ast_test_flag(&flags, OPTION_GROUP)) 01203 mygroup = opts[OPT_ARG_GROUP]; 01204 01205 if (ast_test_flag(&flags, OPTION_RECORD) && 01206 !(recbase = opts[OPT_ARG_RECORD])) 01207 recbase = "chanspy"; 01208 01209 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) { 01210 tmp = opts[OPT_ARG_EXIT][0]; 01211 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01212 user_options.exit = tmp; 01213 } else { 01214 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.\n"); 01215 } 01216 } 01217 01218 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) { 01219 tmp = opts[OPT_ARG_CYCLE][0]; 01220 if (strchr("0123456789*#", tmp) && tmp != '\0') { 01221 user_options.cycle = tmp; 01222 } else { 01223 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.\n"); 01224 } 01225 } 01226 01227 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01228 int vol; 01229 01230 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01231 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01232 else 01233 volfactor = vol; 01234 } 01235 01236 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01237 ast_set_flag(&flags, OPTION_WHISPER); 01238 01239 if (ast_test_flag(&flags, OPTION_NAME)) { 01240 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01241 char *delimiter; 01242 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01243 mailbox = opts[OPT_ARG_NAME]; 01244 *delimiter++ = '\0'; 01245 name_context = delimiter; 01246 } else { 01247 mailbox = opts[OPT_ARG_NAME]; 01248 } 01249 } 01250 } 01251 01252 } else { 01253 /* Coverity - This uninit_use should be ignored since this macro initializes the flags */ 01254 ast_clear_flag(&flags, AST_FLAGS_ALL); 01255 } 01256 01257 oldwf = chan->writeformat; 01258 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01259 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01260 return -1; 01261 } 01262 01263 if (recbase) { 01264 char filename[PATH_MAX]; 01265 01266 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01267 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01268 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01269 fd = 0; 01270 } 01271 } 01272 01273 01274 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); 01275 01276 if (fd) 01277 close(fd); 01278 01279 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01280 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01281 01282 return res; 01283 }
static int load_module | ( | void | ) | [static] |
Definition at line 1333 of file app_chanspy.c.
References ast_register_application_xml, chanspy_exec(), dahdiscan_exec(), and extenspy_exec().
01334 { 01335 int res = 0; 01336 01337 res |= ast_register_application_xml(app_chan, chanspy_exec); 01338 res |= ast_register_application_xml(app_ext, extenspy_exec); 01339 res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec); 01340 01341 return res; 01342 }
static struct ast_autochan* next_channel | ( | struct ast_channel_iterator * | iter, | |
struct ast_autochan * | autochan, | |||
struct ast_channel * | chan | |||
) | [static] |
Definition at line 732 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().
00734 { 00735 struct ast_channel *next; 00736 struct ast_autochan *autochan_store; 00737 const size_t pseudo_len = strlen("DAHDI/pseudo"); 00738 00739 if (!iter) { 00740 return NULL; 00741 } 00742 00743 redo: 00744 if (!(next = ast_channel_iterator_next(iter))) { 00745 return NULL; 00746 } 00747 00748 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) { 00749 ast_channel_unref(next); 00750 goto redo; 00751 } else if (next == chan) { 00752 ast_channel_unref(next); 00753 goto redo; 00754 } 00755 00756 autochan_store = ast_autochan_setup(next); 00757 ast_channel_unref(next); 00758 00759 return autochan_store; 00760 }
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 1322 of file app_chanspy.c.
References ast_unregister_application().
01323 { 01324 int res = 0; 01325 01326 res |= ast_unregister_application(app_chan); 01327 res |= ast_unregister_application(app_ext); 01328 res |= ast_unregister_application(app_dahdiscan); 01329 01330 return res; 01331 }
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static] |
Definition at line 1344 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 1344 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().