#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/chanspy.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
Go to the source code of this file.
Data Structures | |
struct | chanspy_translation_helper |
Defines | |
#define | AST_NAME_STRLEN 256 |
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) } |
enum | { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ARRAY_SIZE } |
Functions | |
AST_APP_OPTIONS (spy_opts,{AST_APP_OPTION('q', OPTION_QUIET), AST_APP_OPTION('b', OPTION_BRIDGED), AST_APP_OPTION('w', OPTION_WHISPER), AST_APP_OPTION('W', OPTION_PRIVATE), AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME), AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP), AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),}) | |
AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Listen to the audio of an active channel") | |
static int | channel_spy (struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd, const struct ast_flags *flags) |
static int | chanspy_exec (struct ast_channel *chan, void *data) |
static int | chanspychan_exec (struct ast_channel *chan, void *data) |
static int | common_exec (struct ast_channel *chan, const struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *spec, const char *exten, const char *context, const char *uniqueid) |
static int | extenspy_exec (struct ast_channel *chan, void *data) |
static int | load_module (void) |
static struct ast_channel * | next_channel (const struct ast_channel *last, const char *spec, const char *exten, const char *context, const char *uniqueid) |
static void | set_volume (struct ast_channel *chan, struct chanspy_translation_helper *csth) |
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_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy) |
static int | unload_module (void) |
Variables | |
static const char * | app_chan = "ChanSpy" |
static const char * | app_chan2 = "ChanSpyChan" |
static const char * | app_ext = "ExtenSpy" |
enum { ... } | chanspy_opt_args |
enum { ... } | chanspy_opt_flags |
static const char * | desc_chan |
static const char * | desc_ext |
static const char * | desc_uniqueid |
static struct ast_generator | spygen |
static const char * | tdesc = "Listen to a channel, and optionally whisper into it" |
static signed char | volfactor_map [] |
Definition in file app_chanspy.c.
#define AST_NAME_STRLEN 256 |
anonymous enum |
OPTION_QUIET | |
OPTION_BRIDGED | |
OPTION_VOLUME | |
OPTION_GROUP | |
OPTION_RECORD | |
OPTION_WHISPER | |
OPTION_PRIVATE |
Definition at line 138 of file app_chanspy.c.
00138 { 00139 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00140 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00141 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00142 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00143 OPTION_RECORD = (1 << 4), 00144 OPTION_WHISPER = (1 << 5), 00145 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00146 } chanspy_opt_flags;
anonymous enum |
Definition at line 148 of file app_chanspy.c.
00148 { 00149 OPT_ARG_VOLUME = 0, 00150 OPT_ARG_GROUP, 00151 OPT_ARG_RECORD, 00152 OPT_ARG_ARRAY_SIZE, 00153 } chanspy_opt_args;
AST_APP_OPTIONS | ( | spy_opts | ) |
AST_MODULE_INFO_STANDARD | ( | ASTERISK_GPL_KEY | , | |
"Listen to the audio of an active channel" | ||||
) |
static int channel_spy | ( | struct ast_channel * | chan, | |
struct ast_channel * | spyee, | |||
int * | volfactor, | |||
int | fd, | |||
const struct ast_flags * | flags | |||
) | [static] |
Definition at line 265 of file app_chanspy.c.
References ast_activate_generator(), ast_channel_lock, ast_channel_spy_free(), ast_channel_spy_remove(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_channel_whisper_feed(), ast_channel_whisper_start(), ast_channel_whisper_stop(), ast_check_hangup(), ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_mutex_destroy(), ast_mutex_init(), ast_openstream_full(), ast_read(), ast_readframe(), ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor(), ast_channel_spy::chan, CHANSPY_DONE, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_RUNNING, CHANSPY_TRIGGER_NONE, CHANSPY_WRITE_VOLADJUST, f, chanspy_translation_helper::fd, ast_channel_spy_queue::format, ast_frame::frametype, ast_channel_spy::lock, name, OPTION_PRIVATE, option_verbose, OPTION_WHISPER, ast_channel_spy::read_queue, ast_channel_spy::read_vol_adjustment, set_volume(), chanspy_translation_helper::spy, start_spying(), ast_channel_spy::status, ast_channel::stream, ast_frame::subclass, ast_channel_spy::type, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, chanspy_translation_helper::volfactor, ast_channel_spy::write_queue, ast_channel_spy::write_vol_adjustment, and ast_channel::writeformat.
Referenced by common_exec().
00267 { 00268 struct chanspy_translation_helper csth; 00269 int running = 0, res, x = 0; 00270 char inp[24] = {0}; 00271 char *name; 00272 struct ast_frame *f; 00273 struct ast_silence_generator *silgen = NULL; 00274 00275 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) 00276 return 0; 00277 00278 name = ast_strdupa(spyee->name); 00279 if (option_verbose >= 2) 00280 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); 00281 00282 memset(&csth, 0, sizeof(csth)); 00283 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO); 00284 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE); 00285 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO); 00286 csth.spy.type = "ChanSpy"; 00287 csth.spy.status = CHANSPY_RUNNING; 00288 csth.spy.read_queue.format = AST_FORMAT_SLINEAR; 00289 csth.spy.write_queue.format = AST_FORMAT_SLINEAR; 00290 ast_mutex_init(&csth.spy.lock); 00291 csth.volfactor = *volfactor; 00292 set_volume(chan, &csth); 00293 if (csth.volfactor) { 00294 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00295 csth.spy.read_vol_adjustment = csth.volfactor; 00296 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00297 csth.spy.write_vol_adjustment = csth.volfactor; 00298 } 00299 csth.fd = fd; 00300 00301 if (start_spying(spyee, chan, &csth.spy)) { 00302 ast_mutex_destroy(&csth.spy.lock); 00303 return 0; 00304 } 00305 00306 if (ast_test_flag(flags, OPTION_WHISPER)) { 00307 struct ast_filestream *beepstream; 00308 int old_write_format = 0; 00309 00310 ast_channel_whisper_start(csth.spy.chan); 00311 old_write_format = chan->writeformat; 00312 if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) { 00313 struct ast_frame *f; 00314 00315 while ((f = ast_readframe(beepstream))) { 00316 ast_channel_whisper_feed(csth.spy.chan, f); 00317 ast_frfree(f); 00318 } 00319 00320 ast_closestream(beepstream); 00321 chan->stream = NULL; 00322 } 00323 if (old_write_format) 00324 ast_set_write_format(chan, old_write_format); 00325 } 00326 00327 if (ast_test_flag(flags, OPTION_PRIVATE)) 00328 silgen = ast_channel_start_silence_generator(chan); 00329 else 00330 ast_activate_generator(chan, &spygen, &csth); 00331 00332 /* We can no longer rely on 'spyee' being an actual channel; 00333 it can be hung up and freed out from under us. However, the 00334 channel destructor will put NULL into our csth.spy.chan 00335 field when that happens, so that is our signal that the spyee 00336 channel has gone away. 00337 */ 00338 00339 /* Note: it is very important that the ast_waitfor() be the first 00340 condition in this expression, so that if we wait for some period 00341 of time before receiving a frame from our spying channel, we check 00342 for hangup on the spied-on channel _after_ knowing that a frame 00343 has arrived, since the spied-on channel could have gone away while 00344 we were waiting 00345 */ 00346 while ((res = ast_waitfor(chan, -1) > -1) && 00347 csth.spy.status == CHANSPY_RUNNING && 00348 csth.spy.chan) { 00349 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00350 running = -1; 00351 break; 00352 } 00353 00354 if (ast_test_flag(flags, OPTION_WHISPER) && 00355 (f->frametype == AST_FRAME_VOICE)) { 00356 ast_channel_whisper_feed(csth.spy.chan, f); 00357 ast_frfree(f); 00358 continue; 00359 } 00360 00361 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00362 ast_frfree(f); 00363 if (!res) 00364 continue; 00365 00366 if (x == sizeof(inp)) 00367 x = 0; 00368 00369 if (res < 0) { 00370 running = -1; 00371 break; 00372 } 00373 00374 if (res == '*') { 00375 running = 0; 00376 break; 00377 } else if (res == '#') { 00378 if (!ast_strlen_zero(inp)) { 00379 running = atoi(inp); 00380 break; 00381 } 00382 00383 (*volfactor)++; 00384 if (*volfactor > 4) 00385 *volfactor = -4; 00386 if (option_verbose > 2) 00387 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00388 csth.volfactor = *volfactor; 00389 set_volume(chan, &csth); 00390 if (csth.volfactor) { 00391 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00392 csth.spy.read_vol_adjustment = csth.volfactor; 00393 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00394 csth.spy.write_vol_adjustment = csth.volfactor; 00395 } else { 00396 ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST); 00397 ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST); 00398 } 00399 } else if (res >= '0' && res <= '9') { 00400 inp[x++] = res; 00401 } 00402 } 00403 00404 if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan) 00405 ast_channel_whisper_stop(csth.spy.chan); 00406 00407 if (ast_test_flag(flags, OPTION_PRIVATE)) 00408 ast_channel_stop_silence_generator(chan, silgen); 00409 else 00410 ast_deactivate_generator(chan); 00411 00412 csth.spy.status = CHANSPY_DONE; 00413 00414 /* If a channel still exists on our spy structure then we need to remove ourselves */ 00415 if (csth.spy.chan) { 00416 ast_channel_lock(csth.spy.chan); 00417 ast_channel_spy_remove(csth.spy.chan, &csth.spy); 00418 ast_channel_unlock(csth.spy.chan); 00419 } 00420 ast_channel_spy_free(&csth.spy); 00421 00422 if (option_verbose >= 2) 00423 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00424 00425 return running; 00426 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 582 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, and ast_channel::writeformat.
Referenced by load_module().
00583 { 00584 struct ast_module_user *u; 00585 char *options = NULL; 00586 char *spec = NULL; 00587 char *argv[2]; 00588 char *mygroup = NULL; 00589 char *recbase = NULL; 00590 int fd = 0; 00591 struct ast_flags flags; 00592 int oldwf = 0; 00593 int argc = 0; 00594 int volfactor = 0; 00595 int res; 00596 00597 data = ast_strdupa(data); 00598 00599 u = ast_module_user_add(chan); 00600 00601 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00602 spec = argv[0]; 00603 if (argc > 1) 00604 options = argv[1]; 00605 00606 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) 00607 spec = NULL; 00608 } 00609 00610 if (options) { 00611 char *opts[OPT_ARG_ARRAY_SIZE]; 00612 00613 ast_app_parse_options(spy_opts, &flags, opts, options); 00614 if (ast_test_flag(&flags, OPTION_GROUP)) 00615 mygroup = opts[OPT_ARG_GROUP]; 00616 00617 if (ast_test_flag(&flags, OPTION_RECORD) && 00618 !(recbase = opts[OPT_ARG_RECORD])) 00619 recbase = "chanspy"; 00620 00621 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00622 int vol; 00623 00624 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00625 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00626 else 00627 volfactor = vol; 00628 } 00629 00630 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00631 ast_set_flag(&flags, OPTION_WHISPER); 00632 } else 00633 ast_clear_flag(&flags, AST_FLAGS_ALL); 00634 00635 oldwf = chan->writeformat; 00636 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00637 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00638 ast_module_user_remove(u); 00639 return -1; 00640 } 00641 00642 if (recbase) { 00643 char filename[512]; 00644 00645 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00646 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00647 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00648 fd = 0; 00649 } 00650 } 00651 00652 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL, NULL); 00653 00654 if (fd) 00655 close(fd); 00656 00657 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00658 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00659 00660 ast_module_user_remove(u); 00661 00662 return res; 00663 }
static int chanspychan_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 750 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_config_AST_MONITOR_DIR, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, and ast_channel::writeformat.
Referenced by load_module().
00751 { 00752 struct ast_module_user *u; 00753 char *options = NULL; 00754 char *uniqueid = NULL; 00755 char *argv[2]; 00756 char *mygroup = NULL; 00757 char *recbase = NULL; 00758 int fd = 0; 00759 struct ast_flags flags; 00760 int oldwf = 0; 00761 int argc = 0; 00762 int volfactor = 0; 00763 int res; 00764 00765 data = ast_strdupa(data); 00766 00767 u = ast_module_user_add(chan); 00768 00769 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00770 uniqueid = argv[0]; 00771 if (argc > 1) 00772 options = argv[1]; 00773 00774 if (ast_strlen_zero(uniqueid)) { 00775 ast_log(LOG_ERROR, "no uniqueid specified.\n"); 00776 ast_module_user_remove(u); 00777 return -1; 00778 } 00779 } 00780 00781 if (options) { 00782 char *opts[OPT_ARG_ARRAY_SIZE]; 00783 00784 ast_app_parse_options(spy_opts, &flags, opts, options); 00785 if (ast_test_flag(&flags, OPTION_GROUP)) 00786 mygroup = opts[OPT_ARG_GROUP]; 00787 00788 if (ast_test_flag(&flags, OPTION_RECORD) && 00789 !(recbase = opts[OPT_ARG_RECORD])) 00790 recbase = "chanspy"; 00791 00792 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00793 int vol; 00794 00795 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00796 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00797 else 00798 volfactor = vol; 00799 } 00800 00801 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00802 ast_set_flag(&flags, OPTION_WHISPER); 00803 } 00804 00805 oldwf = chan->writeformat; 00806 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00807 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00808 ast_module_user_remove(u); 00809 return -1; 00810 } 00811 00812 if (recbase) { 00813 char filename[512]; 00814 00815 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00816 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00817 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00818 fd = 0; 00819 } 00820 } 00821 00822 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, NULL, uniqueid); 00823 00824 if (fd) 00825 close(fd); 00826 00827 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00828 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00829 00830 ast_module_user_remove(u); 00831 00832 return res; 00833 }
static int common_exec | ( | struct ast_channel * | chan, | |
const struct ast_flags * | flags, | |||
int | volfactor, | |||
const int | fd, | |||
const char * | mygroup, | |||
const char * | spec, | |||
const char * | exten, | |||
const char * | context, | |||
const char * | uniqueid | |||
) | [static] |
Definition at line 452 of file app_chanspy.c.
References ast_channel::_state, ast_answer(), ast_app_separate_args(), ast_bridged_channel(), ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_fileexists(), AST_FLAG_SPYING, ast_get_channel_by_name_prefix_locked(), AST_NAME_STRLEN, AST_OPTION_TXGAIN, ast_say_character_str(), ast_say_digits(), ast_set_flag, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), channel_spy(), group, next_channel(), OPTION_BRIDGED, OPTION_QUIET, pbx_builtin_getvar_helper(), and s.
Referenced by chanspy_exec(), chanspychan_exec(), and extenspy_exec().
00455 { 00456 struct ast_channel *peer, *prev, *next; 00457 char nameprefix[AST_NAME_STRLEN]; 00458 char peer_name[AST_NAME_STRLEN + 5]; 00459 signed char zero_volume = 0; 00460 int waitms; 00461 int res; 00462 char *ptr; 00463 int num; 00464 00465 if (chan->_state != AST_STATE_UP) 00466 ast_answer(chan); 00467 00468 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00469 00470 waitms = 100; 00471 00472 for (;;) { 00473 if (!ast_test_flag(flags, OPTION_QUIET)) { 00474 res = ast_streamfile(chan, "beep", chan->language); 00475 if (!res) 00476 res = ast_waitstream(chan, ""); 00477 else if (res < 0) { 00478 ast_clear_flag(chan, AST_FLAG_SPYING); 00479 break; 00480 } 00481 } 00482 00483 res = ast_waitfordigit(chan, waitms); 00484 if (res < 0) { 00485 ast_clear_flag(chan, AST_FLAG_SPYING); 00486 break; 00487 } 00488 00489 /* reset for the next loop around, unless overridden later */ 00490 waitms = 100; 00491 peer = prev = next = NULL; 00492 00493 for (peer = next_channel(peer, spec, exten, context, NULL); 00494 peer; 00495 prev = peer, peer = next ? next : next_channel(peer, spec, exten, context, NULL), next = NULL) { 00496 const char *group; 00497 int igrp = !mygroup; 00498 char *groups[25]; 00499 int num_groups = 0; 00500 char *dup_group; 00501 int x; 00502 char *s; 00503 00504 if (peer == prev) 00505 break; 00506 00507 if (peer == chan) 00508 continue; 00509 00510 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) 00511 continue; 00512 00513 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) 00514 continue; 00515 00516 if (mygroup) { 00517 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00518 dup_group = ast_strdupa(group); 00519 num_groups = ast_app_separate_args(dup_group, ':', groups, 00520 sizeof(groups) / sizeof(groups[0])); 00521 } 00522 00523 for (x = 0; x < num_groups; x++) { 00524 if (!strcmp(mygroup, groups[x])) { 00525 igrp = 1; 00526 break; 00527 } 00528 } 00529 } 00530 00531 if (!igrp) 00532 continue; 00533 00534 strcpy(peer_name, "spy-"); 00535 strncat(peer_name, peer->name, AST_NAME_STRLEN); 00536 ptr = strchr(peer_name, '/'); 00537 *ptr++ = '\0'; 00538 00539 for (s = peer_name; s < ptr; s++) 00540 *s = tolower(*s); 00541 00542 if (!ast_test_flag(flags, OPTION_QUIET)) { 00543 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00544 res = ast_streamfile(chan, peer_name, chan->language); 00545 if (!res) 00546 res = ast_waitstream(chan, ""); 00547 if (res) 00548 break; 00549 } else 00550 res = ast_say_character_str(chan, peer_name, "", chan->language); 00551 if ((num = atoi(ptr))) 00552 ast_say_digits(chan, atoi(ptr), "", chan->language); 00553 } 00554 00555 waitms = 5000; 00556 res = channel_spy(chan, peer, &volfactor, fd, flags); 00557 00558 if (res == -1) { 00559 break; 00560 } else if (res > 1 && spec) { 00561 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00562 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00563 ast_channel_unlock(next); 00564 } else { 00565 /* stay on this channel */ 00566 next = peer; 00567 } 00568 peer = NULL; 00569 } 00570 } 00571 if (res == -1) 00572 break; 00573 } 00574 00575 ast_clear_flag(chan, AST_FLAG_SPYING); 00576 00577 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00578 00579 return res; 00580 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 665 of file app_chanspy.c.
References ast_app_parse_options(), ast_app_separate_args(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_module_user_add, ast_module_user_remove, ast_set_flag, ast_set_write_format(), ast_strdupa, ast_strlen_zero(), ast_test_flag, common_exec(), ast_channel::context, context, exten, LOG_ERROR, LOG_NOTICE, LOG_WARNING, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, strsep(), and ast_channel::writeformat.
Referenced by load_module().
00666 { 00667 struct ast_module_user *u; 00668 char *options = NULL; 00669 char *exten = NULL; 00670 char *context = NULL; 00671 char *argv[2]; 00672 char *mygroup = NULL; 00673 char *recbase = NULL; 00674 int fd = 0; 00675 struct ast_flags flags; 00676 int oldwf = 0; 00677 int argc = 0; 00678 int volfactor = 0; 00679 int res; 00680 00681 data = ast_strdupa(data); 00682 00683 u = ast_module_user_add(chan); 00684 00685 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00686 context = argv[0]; 00687 if (!ast_strlen_zero(argv[0])) 00688 exten = strsep(&context, "@"); 00689 if (ast_strlen_zero(context)) 00690 context = ast_strdupa(chan->context); 00691 if (argc > 1) 00692 options = argv[1]; 00693 } 00694 00695 if (options) { 00696 char *opts[OPT_ARG_ARRAY_SIZE]; 00697 00698 ast_app_parse_options(spy_opts, &flags, opts, options); 00699 if (ast_test_flag(&flags, OPTION_GROUP)) 00700 mygroup = opts[OPT_ARG_GROUP]; 00701 00702 if (ast_test_flag(&flags, OPTION_RECORD) && 00703 !(recbase = opts[OPT_ARG_RECORD])) 00704 recbase = "chanspy"; 00705 00706 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00707 int vol; 00708 00709 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00710 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00711 else 00712 volfactor = vol; 00713 } 00714 00715 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00716 ast_set_flag(&flags, OPTION_WHISPER); 00717 } else 00718 ast_clear_flag(&flags, AST_FLAGS_ALL); 00719 00720 oldwf = chan->writeformat; 00721 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00722 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00723 ast_module_user_remove(u); 00724 return -1; 00725 } 00726 00727 if (recbase) { 00728 char filename[512]; 00729 00730 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00731 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00732 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00733 fd = 0; 00734 } 00735 } 00736 00737 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context, NULL); 00738 00739 if (fd) 00740 close(fd); 00741 00742 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00743 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00744 00745 ast_module_user_remove(u); 00746 00747 return res; 00748 }
static int load_module | ( | void | ) | [static] |
Definition at line 848 of file app_chanspy.c.
References ast_register_application(), chanspy_exec(), chanspychan_exec(), and extenspy_exec().
00849 { 00850 int res = 0; 00851 00852 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 00853 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 00854 res |= ast_register_application(app_chan2, chanspychan_exec, tdesc, desc_uniqueid); 00855 00856 return res; 00857 }
static struct ast_channel* next_channel | ( | const struct ast_channel * | last, | |
const char * | spec, | |||
const char * | exten, | |||
const char * | context, | |||
const char * | uniqueid | |||
) | [static, read] |
Definition at line 428 of file app_chanspy.c.
References ast_channel_unlock, ast_channel_walk_locked(), ast_get_channel_by_uniqueid_locked(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), and name.
Referenced by common_exec().
00430 { 00431 struct ast_channel *this; 00432 00433 redo: 00434 if (spec) 00435 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00436 else if (exten) 00437 this = ast_walk_channel_by_exten_locked(last, exten, context); 00438 else if (uniqueid) 00439 this = ast_get_channel_by_uniqueid_locked(uniqueid); 00440 else 00441 this = ast_channel_walk_locked(last); 00442 00443 if (this) { 00444 ast_channel_unlock(this); 00445 if (!strncmp(this->name, "Zap/pseudo", 10)) 00446 goto redo; 00447 } 00448 00449 return this; 00450 }
static void set_volume | ( | struct ast_channel * | chan, | |
struct chanspy_translation_helper * | csth | |||
) | [static] |
Definition at line 255 of file app_chanspy.c.
References ast_channel_setoption(), AST_OPTION_TXGAIN, ast_channel_spy::read_vol_adjustment, chanspy_translation_helper::spy, chanspy_translation_helper::volfactor, and ast_channel_spy::write_vol_adjustment.
Referenced by channel_spy().
00256 { 00257 signed char volume_adjust = volfactor_map[csth->volfactor + 4]; 00258 00259 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0)) 00260 csth->volfactor = 0; 00261 csth->spy.read_vol_adjustment = csth->volfactor; 00262 csth->spy.write_vol_adjustment = csth->volfactor; 00263 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 173 of file app_chanspy.c.
00174 { 00175 /* just store the data pointer in the channel structure */ 00176 return data; 00177 }
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 184 of file app_chanspy.c.
References ast_channel_spy_read_frame(), ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_write(), CHANSPY_RUNNING, ast_frame::data, ast_frame::datalen, f, chanspy_translation_helper::fd, ast_channel_spy::lock, chanspy_translation_helper::spy, and ast_channel_spy::status.
00185 { 00186 struct chanspy_translation_helper *csth = data; 00187 struct ast_frame *f; 00188 00189 if (csth->spy.status != CHANSPY_RUNNING) 00190 /* Channel is already gone more than likely */ 00191 return -1; 00192 00193 ast_mutex_lock(&csth->spy.lock); 00194 f = ast_channel_spy_read_frame(&csth->spy, samples); 00195 ast_mutex_unlock(&csth->spy.lock); 00196 00197 if (!f) 00198 return 0; 00199 00200 if (ast_write(chan, f)) { 00201 ast_frfree(f); 00202 return -1; 00203 } 00204 00205 if (csth->fd) 00206 write(csth->fd, f->data, f->datalen); 00207 00208 ast_frfree(f); 00209 00210 return 0; 00211 }
static void spy_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static int start_spying | ( | struct ast_channel * | chan, | |
struct ast_channel * | spychan, | |||
struct ast_channel_spy * | spy | |||
) | [static] |
Definition at line 219 of file app_chanspy.c.
References ast_bridged_channel(), ast_channel_lock, ast_channel_spy_add(), ast_channel_unlock, AST_FLAG_NBRIDGE, ast_log(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and LOG_NOTICE.
Referenced by channel_spy().
00220 { 00221 int res; 00222 struct ast_channel *peer; 00223 00224 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name); 00225 00226 ast_channel_lock(chan); 00227 res = ast_channel_spy_add(chan, spy); 00228 ast_channel_unlock(chan); 00229 00230 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00231 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00232 00233 return res; 00234 }
static int unload_module | ( | void | ) | [static] |
Definition at line 836 of file app_chanspy.c.
References ast_unregister_application().
00837 { 00838 int res = 0; 00839 00840 res |= ast_unregister_application(app_chan); 00841 res |= ast_unregister_application(app_chan2); 00842 res |= ast_unregister_application(app_ext); 00843 00844 00845 return res; 00846 }
const char* app_chan = "ChanSpy" [static] |
Definition at line 57 of file app_chanspy.c.
const char* app_chan2 = "ChanSpyChan" [static] |
Definition at line 58 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 110 of file app_chanspy.c.
enum { ... } chanspy_opt_args |
enum { ... } chanspy_opt_flags |
const char* desc_chan [static] |
Definition at line 59 of file app_chanspy.c.
const char* desc_ext [static] |
Definition at line 111 of file app_chanspy.c.
const char* desc_uniqueid [static] |
Definition at line 89 of file app_chanspy.c.
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 213 of file app_chanspy.c.
const char* tdesc = "Listen to a channel, and optionally whisper into it" [static] |
Definition at line 56 of file app_chanspy.c.
signed char volfactor_map[] [static] |
Definition at line 239 of file app_chanspy.c.