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