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