#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/audiohook.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"
Include dependency graph for app_chanspy.c:
Go to the source code of this file.
Data Structures | |
struct | chanspy_ds |
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 chanspy_ds *spyee_chanspy_ds, int *volfactor, int fd, const struct ast_flags *flags) |
static void | chanspy_ds_chan_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) |
static void | chanspy_ds_destroy (void *data) |
static struct chanspy_ds * | chanspy_ds_free (struct chanspy_ds *chanspy_ds) |
static int | chanspy_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) |
static int | extenspy_exec (struct ast_channel *chan, void *data) |
static int | load_module (void) |
static struct chanspy_ds * | next_channel (struct ast_channel *chan, const struct ast_channel *last, const char *spec, const char *exten, const char *context, struct chanspy_ds *chanspy_ds) |
static struct chanspy_ds * | setup_chanspy_ds (struct ast_channel *chan, struct chanspy_ds *chanspy_ds) |
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, const char *spychan_name, struct ast_audiohook *audiohook) |
static int | unload_module (void) |
Variables | |
static const char * | app_chan = "ChanSpy" |
static const char * | app_ext = "ExtenSpy" |
static struct ast_datastore_info | chanspy_ds_info |
enum { ... } | chanspy_opt_args |
enum { ... } | chanspy_opt_flags |
static const char * | desc_chan |
static const char * | desc_ext |
static struct ast_generator | spygen |
static const char * | tdesc = "Listen to a channel, and optionally whisper into it" |
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 118 of file app_chanspy.c.
00118 { 00119 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00120 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00121 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00122 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00123 OPTION_RECORD = (1 << 4), 00124 OPTION_WHISPER = (1 << 5), 00125 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00126 } chanspy_opt_flags;
anonymous enum |
Definition at line 128 of file app_chanspy.c.
00128 { 00129 OPT_ARG_VOLUME = 0, 00130 OPT_ARG_GROUP, 00131 OPT_ARG_RECORD, 00132 OPT_ARG_ARRAY_SIZE, 00133 } 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 chanspy_ds * | spyee_chanspy_ds, | |||
int * | volfactor, | |||
int | fd, | |||
const struct ast_flags * | flags | |||
) | [static] |
Definition at line 225 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_channel_lock, ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_unlock, ast_check_hangup(), ast_deactivate_generator(), AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verbose(), ast_waitfor(), chanspy_ds::chan, f, ast_channel::flags, chanspy_ds::lock, name, OPTION_PRIVATE, option_verbose, OPTION_WHISPER, spygen, start_spying(), VERBOSE_PREFIX_2, and VERBOSE_PREFIX_3.
Referenced by common_exec().
00227 { 00228 struct chanspy_translation_helper csth; 00229 int running = 0, res, x = 0; 00230 char inp[24] = {0}; 00231 char *name; 00232 struct ast_frame *f; 00233 struct ast_silence_generator *silgen = NULL; 00234 struct ast_channel *spyee = NULL; 00235 const char *spyer_name; 00236 00237 ast_channel_lock(chan); 00238 spyer_name = ast_strdupa(chan->name); 00239 ast_channel_unlock(chan); 00240 00241 ast_mutex_lock(&spyee_chanspy_ds->lock); 00242 if (spyee_chanspy_ds->chan) { 00243 spyee = spyee_chanspy_ds->chan; 00244 ast_channel_lock(spyee); 00245 } 00246 ast_mutex_unlock(&spyee_chanspy_ds->lock); 00247 00248 if (!spyee) 00249 return 0; 00250 00251 /* We now hold the channel lock on spyee */ 00252 00253 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) { 00254 ast_channel_unlock(spyee); 00255 return 0; 00256 } 00257 00258 name = ast_strdupa(spyee->name); 00259 if (option_verbose >= 2) 00260 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); 00261 00262 memset(&csth, 0, sizeof(csth)); 00263 00264 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00265 00266 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { /* Unlocks spyee */ 00267 ast_audiohook_destroy(&csth.spy_audiohook); 00268 return 0; 00269 } 00270 00271 if (ast_test_flag(flags, OPTION_WHISPER)) { 00272 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00273 start_spying(spyee, spyer_name, &csth.whisper_audiohook); /* Unlocks spyee */ 00274 } 00275 00276 spyee = NULL; 00277 00278 csth.volfactor = *volfactor; 00279 00280 if (csth.volfactor) { 00281 csth.spy_audiohook.options.read_volume = csth.volfactor; 00282 csth.spy_audiohook.options.write_volume = csth.volfactor; 00283 } 00284 00285 csth.fd = fd; 00286 00287 if (ast_test_flag(flags, OPTION_PRIVATE)) 00288 silgen = ast_channel_start_silence_generator(chan); 00289 else 00290 ast_activate_generator(chan, &spygen, &csth); 00291 00292 /* We can no longer rely on 'spyee' being an actual channel; 00293 it can be hung up and freed out from under us. However, the 00294 channel destructor will put NULL into our csth.spy.chan 00295 field when that happens, so that is our signal that the spyee 00296 channel has gone away. 00297 */ 00298 00299 /* Note: it is very important that the ast_waitfor() be the first 00300 condition in this expression, so that if we wait for some period 00301 of time before receiving a frame from our spying channel, we check 00302 for hangup on the spied-on channel _after_ knowing that a frame 00303 has arrived, since the spied-on channel could have gone away while 00304 we were waiting 00305 */ 00306 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00307 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00308 running = -1; 00309 break; 00310 } 00311 00312 if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) { 00313 ast_audiohook_lock(&csth.whisper_audiohook); 00314 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00315 ast_audiohook_unlock(&csth.whisper_audiohook); 00316 ast_frfree(f); 00317 continue; 00318 } 00319 00320 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00321 ast_frfree(f); 00322 if (!res) 00323 continue; 00324 00325 if (x == sizeof(inp)) 00326 x = 0; 00327 00328 if (res < 0) { 00329 running = -1; 00330 break; 00331 } 00332 00333 if (res == '*') { 00334 running = 0; 00335 break; 00336 } else if (res == '#') { 00337 if (!ast_strlen_zero(inp)) { 00338 running = atoi(inp); 00339 break; 00340 } 00341 00342 (*volfactor)++; 00343 if (*volfactor > 4) 00344 *volfactor = -4; 00345 if (option_verbose > 2) 00346 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00347 csth.volfactor = *volfactor; 00348 csth.spy_audiohook.options.read_volume = csth.volfactor; 00349 csth.spy_audiohook.options.write_volume = csth.volfactor; 00350 } else if (res >= '0' && res <= '9') { 00351 inp[x++] = res; 00352 } 00353 } 00354 00355 if (ast_test_flag(flags, OPTION_PRIVATE)) 00356 ast_channel_stop_silence_generator(chan, silgen); 00357 else 00358 ast_deactivate_generator(chan); 00359 00360 if (ast_test_flag(flags, OPTION_WHISPER)) { 00361 ast_audiohook_lock(&csth.whisper_audiohook); 00362 ast_audiohook_detach(&csth.whisper_audiohook); 00363 ast_audiohook_unlock(&csth.whisper_audiohook); 00364 ast_audiohook_destroy(&csth.whisper_audiohook); 00365 } 00366 00367 ast_audiohook_lock(&csth.spy_audiohook); 00368 ast_audiohook_detach(&csth.spy_audiohook); 00369 ast_audiohook_unlock(&csth.spy_audiohook); 00370 ast_audiohook_destroy(&csth.spy_audiohook); 00371 00372 if (option_verbose >= 2) 00373 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00374 00375 return running; 00376 }
static void chanspy_ds_chan_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Definition at line 395 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
00396 { 00397 struct chanspy_ds *chanspy_ds = data; 00398 00399 ast_mutex_lock(&chanspy_ds->lock); 00400 chanspy_ds->chan = new_chan; 00401 ast_mutex_unlock(&chanspy_ds->lock); 00402 }
static void chanspy_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 382 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
Referenced by chanspy_ds_free().
00383 { 00384 struct chanspy_ds *chanspy_ds = data; 00385 00386 /* Setting chan to be NULL is an atomic operation, but we don't want this 00387 * value to change while this lock is held. The lock is held elsewhere 00388 * while it performs non-atomic operations with this channel pointer */ 00389 00390 ast_mutex_lock(&chanspy_ds->lock); 00391 chanspy_ds->chan = NULL; 00392 ast_mutex_unlock(&chanspy_ds->lock); 00393 }
static struct chanspy_ds* chanspy_ds_free | ( | struct chanspy_ds * | chanspy_ds | ) | [static] |
Definition at line 410 of file app_chanspy.c.
References ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, chanspy_ds_destroy(), chanspy_ds_info, ast_datastore::data, and chanspy_ds::lock.
Referenced by common_exec(), and setup_chanspy_ds().
00411 { 00412 if (!chanspy_ds) 00413 return NULL; 00414 00415 ast_mutex_lock(&chanspy_ds->lock); 00416 if (chanspy_ds->chan) { 00417 struct ast_datastore *datastore; 00418 struct ast_channel *chan; 00419 00420 chan = chanspy_ds->chan; 00421 00422 ast_channel_lock(chan); 00423 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) { 00424 ast_channel_datastore_remove(chan, datastore); 00425 /* chanspy_ds->chan is NULL after this call */ 00426 chanspy_ds_destroy(datastore->data); 00427 datastore->data = NULL; 00428 ast_channel_datastore_free(datastore); 00429 } 00430 ast_channel_unlock(chan); 00431 } 00432 ast_mutex_unlock(&chanspy_ds->lock); 00433 00434 return NULL; 00435 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 670 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_flags::flags, 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().
00671 { 00672 struct ast_module_user *u; 00673 char *options = NULL; 00674 char *spec = NULL; 00675 char *argv[2]; 00676 char *mygroup = NULL; 00677 char *recbase = NULL; 00678 int fd = 0; 00679 struct ast_flags flags; 00680 int oldwf = 0; 00681 int argc = 0; 00682 int volfactor = 0; 00683 int res; 00684 00685 data = ast_strdupa(data); 00686 00687 u = ast_module_user_add(chan); 00688 00689 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00690 spec = argv[0]; 00691 if (argc > 1) 00692 options = argv[1]; 00693 00694 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) 00695 spec = NULL; 00696 } 00697 00698 if (options) { 00699 char *opts[OPT_ARG_ARRAY_SIZE]; 00700 00701 ast_app_parse_options(spy_opts, &flags, opts, options); 00702 if (ast_test_flag(&flags, OPTION_GROUP)) 00703 mygroup = opts[OPT_ARG_GROUP]; 00704 00705 if (ast_test_flag(&flags, OPTION_RECORD) && 00706 !(recbase = opts[OPT_ARG_RECORD])) 00707 recbase = "chanspy"; 00708 00709 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00710 int vol; 00711 00712 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00713 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00714 else 00715 volfactor = vol; 00716 } 00717 00718 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00719 ast_set_flag(&flags, OPTION_WHISPER); 00720 } else 00721 ast_clear_flag(&flags, AST_FLAGS_ALL); 00722 00723 oldwf = chan->writeformat; 00724 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00725 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00726 ast_module_user_remove(u); 00727 return -1; 00728 } 00729 00730 if (recbase) { 00731 char filename[512]; 00732 00733 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00734 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00735 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00736 fd = 0; 00737 } 00738 } 00739 00740 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL); 00741 00742 if (fd) 00743 close(fd); 00744 00745 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00746 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00747 00748 ast_module_user_remove(u); 00749 00750 return res; 00751 }
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 | |||
) | [static] |
Definition at line 487 of file app_chanspy.c.
References ast_channel::_state, ast_answer(), ast_app_separate_args(), ast_bridged_channel(), ast_channel_lock, 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_mutex_destroy(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), 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(), chanspy_ds::chan, channel_spy(), chanspy_ds_free(), ast_channel::flags, group, chanspy_ds::lock, next_channel(), OPTION_BRIDGED, OPTION_QUIET, pbx_builtin_getvar_helper(), s, and setup_chanspy_ds().
Referenced by chanspy_exec(), and extenspy_exec().
00490 { 00491 char nameprefix[AST_NAME_STRLEN]; 00492 char peer_name[AST_NAME_STRLEN + 5]; 00493 signed char zero_volume = 0; 00494 int waitms; 00495 int res; 00496 char *ptr; 00497 int num; 00498 int num_spyed_upon = 1; 00499 struct chanspy_ds chanspy_ds; 00500 00501 ast_mutex_init(&chanspy_ds.lock); 00502 00503 if (chan->_state != AST_STATE_UP) 00504 ast_answer(chan); 00505 00506 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00507 00508 waitms = 100; 00509 00510 for (;;) { 00511 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; 00512 struct ast_channel *prev = NULL, *peer = NULL; 00513 00514 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00515 res = ast_streamfile(chan, "beep", chan->language); 00516 if (!res) 00517 res = ast_waitstream(chan, ""); 00518 else if (res < 0) { 00519 ast_clear_flag(chan, AST_FLAG_SPYING); 00520 break; 00521 } 00522 } 00523 00524 res = ast_waitfordigit(chan, waitms); 00525 if (res < 0) { 00526 ast_clear_flag(chan, AST_FLAG_SPYING); 00527 break; 00528 } 00529 00530 /* reset for the next loop around, unless overridden later */ 00531 waitms = 100; 00532 num_spyed_upon = 0; 00533 00534 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); 00535 peer_chanspy_ds; 00536 chanspy_ds_free(peer_chanspy_ds), prev = peer, 00537 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 00538 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { 00539 const char *group; 00540 int igrp = !mygroup; 00541 char *groups[25]; 00542 int num_groups = 0; 00543 char *dup_group; 00544 int x; 00545 char *s; 00546 struct ast_channel *peer; 00547 00548 peer = peer_chanspy_ds->chan; 00549 00550 ast_mutex_unlock(&peer_chanspy_ds->lock); 00551 00552 if (peer == prev) { 00553 ast_channel_unlock(peer); 00554 chanspy_ds_free(peer_chanspy_ds); 00555 break; 00556 } 00557 00558 if (ast_check_hangup(chan)) { 00559 ast_channel_unlock(peer); 00560 chanspy_ds_free(peer_chanspy_ds); 00561 break; 00562 } 00563 00564 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { 00565 ast_channel_unlock(peer); 00566 continue; 00567 } 00568 00569 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { 00570 ast_channel_unlock(peer); 00571 continue; 00572 } 00573 00574 if (mygroup) { 00575 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00576 dup_group = ast_strdupa(group); 00577 num_groups = ast_app_separate_args(dup_group, ':', groups, 00578 sizeof(groups) / sizeof(groups[0])); 00579 } 00580 00581 for (x = 0; x < num_groups; x++) { 00582 if (!strcmp(mygroup, groups[x])) { 00583 igrp = 1; 00584 break; 00585 } 00586 } 00587 } 00588 00589 if (!igrp) { 00590 ast_channel_unlock(peer); 00591 continue; 00592 } 00593 00594 strcpy(peer_name, "spy-"); 00595 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); 00596 ptr = strchr(peer_name, '/'); 00597 *ptr++ = '\0'; 00598 00599 for (s = peer_name; s < ptr; s++) 00600 *s = tolower(*s); 00601 00602 00603 /* We have to unlock the peer channel here to avoid a deadlock. 00604 * So, when we need it again, we have to lock the datastore and get 00605 * the pointer from there to see if the channel is still valid. */ 00606 ast_channel_unlock(peer); 00607 peer = NULL; 00608 00609 if (!ast_test_flag(flags, OPTION_QUIET)) { 00610 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00611 res = ast_streamfile(chan, peer_name, chan->language); 00612 if (!res) 00613 res = ast_waitstream(chan, ""); 00614 if (res) { 00615 chanspy_ds_free(peer_chanspy_ds); 00616 break; 00617 } 00618 } else 00619 res = ast_say_character_str(chan, peer_name, "", chan->language); 00620 if ((num = atoi(ptr))) 00621 ast_say_digits(chan, atoi(ptr), "", chan->language); 00622 } 00623 00624 waitms = 5000; 00625 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags); 00626 num_spyed_upon++; 00627 00628 if (res == -1) { 00629 chanspy_ds_free(peer_chanspy_ds); 00630 break; 00631 } else if (res > 1 && spec) { 00632 struct ast_channel *next; 00633 00634 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00635 00636 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00637 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); 00638 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); 00639 } else { 00640 /* stay on this channel, if it is still valid */ 00641 00642 ast_mutex_lock(&peer_chanspy_ds->lock); 00643 if (peer_chanspy_ds->chan) { 00644 ast_channel_lock(peer_chanspy_ds->chan); 00645 next_chanspy_ds = peer_chanspy_ds; 00646 peer_chanspy_ds = NULL; 00647 } else { 00648 /* the channel is gone */ 00649 ast_mutex_unlock(&peer_chanspy_ds->lock); 00650 next_chanspy_ds = NULL; 00651 } 00652 } 00653 00654 peer = NULL; 00655 } 00656 } 00657 if (res == -1 || ast_check_hangup(chan)) 00658 break; 00659 } 00660 00661 ast_clear_flag(chan, AST_FLAG_SPYING); 00662 00663 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00664 00665 ast_mutex_destroy(&chanspy_ds.lock); 00666 00667 return res; 00668 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 753 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, ast_flags::flags, 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().
00754 { 00755 struct ast_module_user *u; 00756 char *options = NULL; 00757 char *exten = NULL; 00758 char *context = NULL; 00759 char *argv[2]; 00760 char *mygroup = NULL; 00761 char *recbase = NULL; 00762 int fd = 0; 00763 struct ast_flags flags; 00764 int oldwf = 0; 00765 int argc = 0; 00766 int volfactor = 0; 00767 int res; 00768 00769 data = ast_strdupa(data); 00770 00771 u = ast_module_user_add(chan); 00772 00773 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00774 context = argv[0]; 00775 if (!ast_strlen_zero(argv[0])) 00776 exten = strsep(&context, "@"); 00777 if (ast_strlen_zero(context)) 00778 context = ast_strdupa(chan->context); 00779 if (argc > 1) 00780 options = argv[1]; 00781 } 00782 00783 if (options) { 00784 char *opts[OPT_ARG_ARRAY_SIZE]; 00785 00786 ast_app_parse_options(spy_opts, &flags, opts, options); 00787 if (ast_test_flag(&flags, OPTION_GROUP)) 00788 mygroup = opts[OPT_ARG_GROUP]; 00789 00790 if (ast_test_flag(&flags, OPTION_RECORD) && 00791 !(recbase = opts[OPT_ARG_RECORD])) 00792 recbase = "chanspy"; 00793 00794 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00795 int vol; 00796 00797 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00798 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00799 else 00800 volfactor = vol; 00801 } 00802 00803 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00804 ast_set_flag(&flags, OPTION_WHISPER); 00805 } else 00806 ast_clear_flag(&flags, AST_FLAGS_ALL); 00807 00808 oldwf = chan->writeformat; 00809 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00810 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00811 ast_module_user_remove(u); 00812 return -1; 00813 } 00814 00815 if (recbase) { 00816 char filename[512]; 00817 00818 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00819 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00820 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00821 fd = 0; 00822 } 00823 } 00824 00825 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context); 00826 00827 if (fd) 00828 close(fd); 00829 00830 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00831 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00832 00833 ast_module_user_remove(u); 00834 00835 return res; 00836 }
static int load_module | ( | void | ) | [static] |
Definition at line 850 of file app_chanspy.c.
References ast_register_application(), chanspy_exec(), and extenspy_exec().
00851 { 00852 int res = 0; 00853 00854 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 00855 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 00856 00857 return res; 00858 }
static struct chanspy_ds* next_channel | ( | struct ast_channel * | chan, | |
const struct ast_channel * | last, | |||
const char * | spec, | |||
const char * | exten, | |||
const char * | context, | |||
struct chanspy_ds * | chanspy_ds | |||
) | [static] |
Definition at line 458 of file app_chanspy.c.
References ast_channel_unlock, ast_channel_walk_locked(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), last, and setup_chanspy_ds().
Referenced by common_exec().
00461 { 00462 struct ast_channel *this; 00463 00464 redo: 00465 if (spec) 00466 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00467 else if (exten) 00468 this = ast_walk_channel_by_exten_locked(last, exten, context); 00469 else 00470 this = ast_channel_walk_locked(last); 00471 00472 if (!this) 00473 return NULL; 00474 00475 if (!strncmp(this->name, "Zap/pseudo", 10)) { 00476 ast_channel_unlock(this); 00477 goto redo; 00478 } else if (this == chan) { 00479 last = this; 00480 ast_channel_unlock(this); 00481 goto redo; 00482 } 00483 00484 return setup_chanspy_ds(this, chanspy_ds); 00485 }
static struct chanspy_ds* setup_chanspy_ds | ( | struct ast_channel * | chan, | |
struct chanspy_ds * | chanspy_ds | |||
) | [static] |
Definition at line 438 of file app_chanspy.c.
References ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_unlock, ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, chanspy_ds_free(), chanspy_ds_info, ast_datastore::data, and chanspy_ds::lock.
Referenced by common_exec(), and next_channel().
00439 { 00440 struct ast_datastore *datastore = NULL; 00441 00442 ast_mutex_lock(&chanspy_ds->lock); 00443 00444 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) { 00445 ast_mutex_unlock(&chanspy_ds->lock); 00446 chanspy_ds = chanspy_ds_free(chanspy_ds); 00447 ast_channel_unlock(chan); 00448 return NULL; 00449 } 00450 00451 chanspy_ds->chan = chan; 00452 datastore->data = chanspy_ds; 00453 ast_channel_datastore_add(chan, datastore); 00454 00455 return chanspy_ds; 00456 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 154 of file app_chanspy.c.
00155 { 00156 /* just store the data pointer in the channel structure */ 00157 return data; 00158 }
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 165 of file app_chanspy.c.
References AST_AUDIOHOOK_DIRECTION_BOTH, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, ast_write(), f, chanspy_translation_helper::fd, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.
00166 { 00167 struct chanspy_translation_helper *csth = data; 00168 struct ast_frame *f; 00169 00170 ast_audiohook_lock(&csth->spy_audiohook); 00171 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00172 ast_audiohook_unlock(&csth->spy_audiohook); 00173 return -1; 00174 } 00175 00176 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); 00177 00178 ast_audiohook_unlock(&csth->spy_audiohook); 00179 00180 if (!f) 00181 return 0; 00182 00183 if (ast_write(chan, f)) { 00184 ast_frfree(f); 00185 return -1; 00186 } 00187 00188 if (csth->fd) 00189 write(csth->fd, f->data, f->datalen); 00190 00191 ast_frfree(f); 00192 00193 return 0; 00194 }
static void spy_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
static int start_spying | ( | struct ast_channel * | chan, | |
const char * | spychan_name, | |||
struct ast_audiohook * | audiohook | |||
) | [static] |
Definition at line 202 of file app_chanspy.c.
References ast_audiohook_attach(), ast_bridged_channel(), ast_channel_unlock, AST_FLAG_NBRIDGE, ast_log(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and LOG_NOTICE.
Referenced by channel_spy().
00203 { 00204 int res; 00205 struct ast_channel *peer; 00206 00207 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name); 00208 00209 res = ast_audiohook_attach(chan, audiohook); 00210 00211 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 00212 ast_channel_unlock(chan); 00213 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00214 } else 00215 ast_channel_unlock(chan); 00216 00217 return res; 00218 }
static int unload_module | ( | void | ) | [static] |
Definition at line 838 of file app_chanspy.c.
References ast_module_user_hangup_all, and ast_unregister_application().
00839 { 00840 int res = 0; 00841 00842 res |= ast_unregister_application(app_chan); 00843 res |= ast_unregister_application(app_ext); 00844 00845 ast_module_user_hangup_all(); 00846 00847 return res; 00848 }
const char* app_chan = "ChanSpy" [static] |
Definition at line 59 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 90 of file app_chanspy.c.
struct ast_datastore_info chanspy_ds_info [static] |
Initial value:
{ .type = "chanspy", .destroy = chanspy_ds_destroy, .chan_fixup = chanspy_ds_chan_fixup, }
Definition at line 404 of file app_chanspy.c.
Referenced by chanspy_ds_free(), and setup_chanspy_ds().
enum { ... } chanspy_opt_args |
enum { ... } chanspy_opt_flags |
const char* desc_chan [static] |
Definition at line 60 of file app_chanspy.c.
const char* desc_ext [static] |
Definition at line 91 of file app_chanspy.c.
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 196 of file app_chanspy.c.
Referenced by channel_spy().
const char* tdesc = "Listen to a channel, and optionally whisper into it" [static] |
Definition at line 58 of file app_chanspy.c.