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