#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"
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 | 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 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, const char *uniqueid) |
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_chan_uniqueid = "ChanSpyChan" |
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 const char * | desc_uniqueid |
int | next_unique_id_to_use = 0 |
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 140 of file app_chanspy.c.
00140 { 00141 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00142 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00143 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00144 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00145 OPTION_RECORD = (1 << 4), 00146 OPTION_WHISPER = (1 << 5), 00147 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00148 } chanspy_opt_flags;
anonymous enum |
Definition at line 150 of file app_chanspy.c.
00150 { 00151 OPT_ARG_VOLUME = 0, 00152 OPT_ARG_GROUP, 00153 OPT_ARG_RECORD, 00154 OPT_ARG_ARRAY_SIZE, 00155 } 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 246 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, chanspy_translation_helper::fd, ast_frame::frametype, chanspy_ds::lock, name, OPTION_PRIVATE, option_verbose, OPTION_WHISPER, ast_audiohook::options, ast_audiohook_options::read_volume, chanspy_translation_helper::spy_audiohook, start_spying(), ast_audiohook::status, ast_frame::subclass, VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, chanspy_translation_helper::volfactor, chanspy_translation_helper::whisper_audiohook, and ast_audiohook_options::write_volume.
Referenced by common_exec().
00248 { 00249 struct chanspy_translation_helper csth; 00250 int running = 0, res, x = 0; 00251 char inp[24] = {0}; 00252 char *name; 00253 struct ast_frame *f; 00254 struct ast_silence_generator *silgen = NULL; 00255 struct ast_channel *spyee = NULL; 00256 const char *spyer_name; 00257 00258 ast_channel_lock(chan); 00259 spyer_name = ast_strdupa(chan->name); 00260 ast_channel_unlock(chan); 00261 00262 ast_mutex_lock(&spyee_chanspy_ds->lock); 00263 if (spyee_chanspy_ds->chan) { 00264 spyee = spyee_chanspy_ds->chan; 00265 ast_channel_lock(spyee); 00266 } 00267 ast_mutex_unlock(&spyee_chanspy_ds->lock); 00268 00269 if (!spyee) 00270 return 0; 00271 00272 /* We now hold the channel lock on spyee */ 00273 00274 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) { 00275 ast_channel_unlock(spyee); 00276 return 0; 00277 } 00278 00279 name = ast_strdupa(spyee->name); 00280 if (option_verbose >= 2) 00281 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name); 00282 00283 memset(&csth, 0, sizeof(csth)); 00284 00285 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00286 00287 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { 00288 ast_audiohook_destroy(&csth.spy_audiohook); 00289 ast_channel_unlock(spyee); 00290 return 0; 00291 } 00292 00293 if (ast_test_flag(flags, OPTION_WHISPER)) { 00294 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00295 start_spying(spyee, spyer_name, &csth.whisper_audiohook); 00296 } 00297 00298 ast_channel_unlock(spyee); 00299 spyee = NULL; 00300 00301 csth.volfactor = *volfactor; 00302 00303 if (csth.volfactor) { 00304 csth.spy_audiohook.options.read_volume = csth.volfactor; 00305 csth.spy_audiohook.options.write_volume = csth.volfactor; 00306 } 00307 00308 csth.fd = fd; 00309 00310 if (ast_test_flag(flags, OPTION_PRIVATE)) 00311 silgen = ast_channel_start_silence_generator(chan); 00312 else 00313 ast_activate_generator(chan, &spygen, &csth); 00314 00315 /* We can no longer rely on 'spyee' being an actual channel; 00316 it can be hung up and freed out from under us. However, the 00317 channel destructor will put NULL into our csth.spy.chan 00318 field when that happens, so that is our signal that the spyee 00319 channel has gone away. 00320 */ 00321 00322 /* Note: it is very important that the ast_waitfor() be the first 00323 condition in this expression, so that if we wait for some period 00324 of time before receiving a frame from our spying channel, we check 00325 for hangup on the spied-on channel _after_ knowing that a frame 00326 has arrived, since the spied-on channel could have gone away while 00327 we were waiting 00328 */ 00329 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00330 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00331 running = -1; 00332 break; 00333 } 00334 00335 if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) { 00336 ast_audiohook_lock(&csth.whisper_audiohook); 00337 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00338 ast_audiohook_unlock(&csth.whisper_audiohook); 00339 ast_frfree(f); 00340 continue; 00341 } 00342 00343 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00344 ast_frfree(f); 00345 if (!res) 00346 continue; 00347 00348 if (x == sizeof(inp)) 00349 x = 0; 00350 00351 if (res < 0) { 00352 running = -1; 00353 break; 00354 } 00355 00356 if (res == '*') { 00357 running = 0; 00358 break; 00359 } else if (res == '#') { 00360 if (!ast_strlen_zero(inp)) { 00361 running = atoi(inp); 00362 break; 00363 } 00364 00365 (*volfactor)++; 00366 if (*volfactor > 4) 00367 *volfactor = -4; 00368 if (option_verbose > 2) 00369 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00370 csth.volfactor = *volfactor; 00371 csth.spy_audiohook.options.read_volume = csth.volfactor; 00372 csth.spy_audiohook.options.write_volume = csth.volfactor; 00373 } else if (res >= '0' && res <= '9') { 00374 inp[x++] = res; 00375 } 00376 } 00377 00378 if (ast_test_flag(flags, OPTION_PRIVATE)) 00379 ast_channel_stop_silence_generator(chan, silgen); 00380 else 00381 ast_deactivate_generator(chan); 00382 00383 if (ast_test_flag(flags, OPTION_WHISPER)) { 00384 ast_audiohook_lock(&csth.whisper_audiohook); 00385 ast_audiohook_detach(&csth.whisper_audiohook); 00386 ast_audiohook_unlock(&csth.whisper_audiohook); 00387 ast_audiohook_destroy(&csth.whisper_audiohook); 00388 } 00389 00390 ast_audiohook_lock(&csth.spy_audiohook); 00391 ast_audiohook_detach(&csth.spy_audiohook); 00392 ast_audiohook_unlock(&csth.spy_audiohook); 00393 ast_audiohook_destroy(&csth.spy_audiohook); 00394 00395 if (option_verbose >= 2) 00396 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name); 00397 00398 return running; 00399 }
static void chanspy_ds_chan_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Definition at line 418 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
00419 { 00420 struct chanspy_ds *chanspy_ds = data; 00421 00422 ast_mutex_lock(&chanspy_ds->lock); 00423 chanspy_ds->chan = new_chan; 00424 ast_mutex_unlock(&chanspy_ds->lock); 00425 }
static void chanspy_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 405 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
Referenced by chanspy_ds_free().
00406 { 00407 struct chanspy_ds *chanspy_ds = data; 00408 00409 /* Setting chan to be NULL is an atomic operation, but we don't want this 00410 * value to change while this lock is held. The lock is held elsewhere 00411 * while it performs non-atomic operations with this channel pointer */ 00412 00413 ast_mutex_lock(&chanspy_ds->lock); 00414 chanspy_ds->chan = NULL; 00415 ast_mutex_unlock(&chanspy_ds->lock); 00416 }
static struct chanspy_ds* chanspy_ds_free | ( | struct chanspy_ds * | chanspy_ds | ) | [static, read] |
Definition at line 433 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(), ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and setup_chanspy_ds().
00434 { 00435 if (!chanspy_ds) 00436 return NULL; 00437 00438 ast_mutex_lock(&chanspy_ds->lock); 00439 if (chanspy_ds->chan) { 00440 struct ast_datastore *datastore; 00441 struct ast_channel *chan; 00442 00443 chan = chanspy_ds->chan; 00444 00445 ast_channel_lock(chan); 00446 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) { 00447 ast_channel_datastore_remove(chan, datastore); 00448 /* chanspy_ds->chan is NULL after this call */ 00449 chanspy_ds_destroy(datastore->data); 00450 datastore->data = NULL; 00451 ast_channel_datastore_free(datastore); 00452 } 00453 ast_channel_unlock(chan); 00454 } 00455 ast_mutex_unlock(&chanspy_ds->lock); 00456 00457 return NULL; 00458 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 694 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().
00695 { 00696 struct ast_module_user *u; 00697 char *options = NULL; 00698 char *spec = NULL; 00699 char *argv[2]; 00700 char *mygroup = NULL; 00701 char *recbase = NULL; 00702 int fd = 0; 00703 struct ast_flags flags; 00704 int oldwf = 0; 00705 int argc = 0; 00706 int volfactor = 0; 00707 int res; 00708 00709 data = ast_strdupa(data); 00710 00711 u = ast_module_user_add(chan); 00712 00713 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00714 spec = argv[0]; 00715 if (argc > 1) 00716 options = argv[1]; 00717 00718 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) 00719 spec = NULL; 00720 } 00721 00722 if (options) { 00723 char *opts[OPT_ARG_ARRAY_SIZE]; 00724 00725 ast_app_parse_options(spy_opts, &flags, opts, options); 00726 if (ast_test_flag(&flags, OPTION_GROUP)) 00727 mygroup = opts[OPT_ARG_GROUP]; 00728 00729 if (ast_test_flag(&flags, OPTION_RECORD) && 00730 !(recbase = opts[OPT_ARG_RECORD])) 00731 recbase = "chanspy"; 00732 00733 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00734 int vol; 00735 00736 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00737 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00738 else 00739 volfactor = vol; 00740 } 00741 00742 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00743 ast_set_flag(&flags, OPTION_WHISPER); 00744 } else 00745 ast_clear_flag(&flags, AST_FLAGS_ALL); 00746 00747 oldwf = chan->writeformat; 00748 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00749 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00750 ast_module_user_remove(u); 00751 return -1; 00752 } 00753 00754 if (recbase) { 00755 char filename[PATH_MAX]; 00756 00757 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00758 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00759 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00760 fd = 0; 00761 } 00762 } 00763 00764 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL, NULL); 00765 00766 if (fd) 00767 close(fd); 00768 00769 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00770 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00771 00772 ast_module_user_remove(u); 00773 00774 return res; 00775 }
static int chanspychan_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 862 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().
00863 { 00864 struct ast_module_user *u; 00865 char *options = NULL; 00866 char *uniqueid = NULL; 00867 char *argv[2]; 00868 char *mygroup = NULL; 00869 char *recbase = NULL; 00870 int fd = 0; 00871 struct ast_flags flags; 00872 int oldwf = 0; 00873 int argc = 0; 00874 int volfactor = 0; 00875 int res; 00876 00877 data = ast_strdupa(data); 00878 00879 u = ast_module_user_add(chan); 00880 00881 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00882 uniqueid = argv[0]; 00883 if (argc > 1) 00884 options = argv[1]; 00885 00886 if (ast_strlen_zero(uniqueid)) { 00887 ast_log(LOG_ERROR, "no uniqueid specified.\n"); 00888 ast_module_user_remove(u); 00889 return -1; 00890 } 00891 } 00892 00893 if (options) { 00894 char *opts[OPT_ARG_ARRAY_SIZE]; 00895 00896 ast_app_parse_options(spy_opts, &flags, opts, options); 00897 if (ast_test_flag(&flags, OPTION_GROUP)) 00898 mygroup = opts[OPT_ARG_GROUP]; 00899 00900 if (ast_test_flag(&flags, OPTION_RECORD) && 00901 !(recbase = opts[OPT_ARG_RECORD])) 00902 recbase = "chanspy"; 00903 00904 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00905 int vol; 00906 00907 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00908 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00909 else 00910 volfactor = vol; 00911 } 00912 00913 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00914 ast_set_flag(&flags, OPTION_WHISPER); 00915 } 00916 00917 oldwf = chan->writeformat; 00918 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00919 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00920 ast_module_user_remove(u); 00921 return -1; 00922 } 00923 00924 if (recbase) { 00925 char filename[512]; 00926 00927 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00928 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00929 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00930 fd = 0; 00931 } 00932 } 00933 00934 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, NULL, uniqueid); 00935 00936 if (fd) 00937 close(fd); 00938 00939 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00940 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00941 00942 ast_module_user_remove(u); 00943 00944 return res; 00945 }
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 512 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(), channel_spy(), chanspy_ds_free(), group, chanspy_ds::lock, next_channel(), OPTION_BRIDGED, OPTION_QUIET, pbx_builtin_getvar_helper(), s, setup_chanspy_ds(), and chanspy_ds::unique_id.
Referenced by chanspy_exec(), chanspychan_exec(), and extenspy_exec().
00515 { 00516 char nameprefix[AST_NAME_STRLEN]; 00517 char peer_name[AST_NAME_STRLEN + 5]; 00518 signed char zero_volume = 0; 00519 int waitms; 00520 int res; 00521 char *ptr; 00522 int num; 00523 int num_spyed_upon = 1; 00524 struct chanspy_ds chanspy_ds; 00525 00526 ast_mutex_init(&chanspy_ds.lock); 00527 00528 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); 00529 00530 if (chan->_state != AST_STATE_UP) 00531 ast_answer(chan); 00532 00533 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00534 00535 waitms = 100; 00536 00537 for (;;) { 00538 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; 00539 struct ast_channel *prev = NULL, *peer = NULL; 00540 00541 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00542 res = ast_streamfile(chan, "beep", chan->language); 00543 if (!res) 00544 res = ast_waitstream(chan, ""); 00545 else if (res < 0) { 00546 ast_clear_flag(chan, AST_FLAG_SPYING); 00547 break; 00548 } 00549 } 00550 00551 res = ast_waitfordigit(chan, waitms); 00552 if (res < 0) { 00553 ast_clear_flag(chan, AST_FLAG_SPYING); 00554 break; 00555 } 00556 00557 /* reset for the next loop around, unless overridden later */ 00558 waitms = 100; 00559 num_spyed_upon = 0; 00560 00561 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL); 00562 peer_chanspy_ds; 00563 chanspy_ds_free(peer_chanspy_ds), prev = peer, 00564 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 00565 next_channel(chan, prev, spec, exten, context, &chanspy_ds, NULL), next_chanspy_ds = NULL) { 00566 const char *group; 00567 int igrp = !mygroup; 00568 char *groups[25]; 00569 int num_groups = 0; 00570 char *dup_group; 00571 int x; 00572 char *s; 00573 00574 peer = peer_chanspy_ds->chan; 00575 00576 ast_mutex_unlock(&peer_chanspy_ds->lock); 00577 00578 if (peer == prev) { 00579 ast_channel_unlock(peer); 00580 chanspy_ds_free(peer_chanspy_ds); 00581 break; 00582 } 00583 00584 if (ast_check_hangup(chan)) { 00585 ast_channel_unlock(peer); 00586 chanspy_ds_free(peer_chanspy_ds); 00587 break; 00588 } 00589 00590 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { 00591 ast_channel_unlock(peer); 00592 continue; 00593 } 00594 00595 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { 00596 ast_channel_unlock(peer); 00597 continue; 00598 } 00599 00600 if (mygroup) { 00601 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00602 dup_group = ast_strdupa(group); 00603 num_groups = ast_app_separate_args(dup_group, ':', groups, 00604 sizeof(groups) / sizeof(groups[0])); 00605 } 00606 00607 for (x = 0; x < num_groups; x++) { 00608 if (!strcmp(mygroup, groups[x])) { 00609 igrp = 1; 00610 break; 00611 } 00612 } 00613 } 00614 00615 if (!igrp) { 00616 ast_channel_unlock(peer); 00617 continue; 00618 } 00619 00620 strcpy(peer_name, "spy-"); 00621 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); 00622 ptr = strchr(peer_name, '/'); 00623 *ptr++ = '\0'; 00624 00625 for (s = peer_name; s < ptr; s++) 00626 *s = tolower(*s); 00627 00628 /* We have to unlock the peer channel here to avoid a deadlock. 00629 * So, when we need to dereference it again, we have to lock the 00630 * datastore and get the pointer from there to see if the channel 00631 * is still valid. */ 00632 ast_channel_unlock(peer); 00633 00634 if (!ast_test_flag(flags, OPTION_QUIET)) { 00635 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00636 res = ast_streamfile(chan, peer_name, chan->language); 00637 if (!res) 00638 res = ast_waitstream(chan, ""); 00639 if (res) { 00640 chanspy_ds_free(peer_chanspy_ds); 00641 break; 00642 } 00643 } else 00644 res = ast_say_character_str(chan, peer_name, "", chan->language); 00645 if ((num = atoi(ptr))) 00646 ast_say_digits(chan, atoi(ptr), "", chan->language); 00647 } 00648 00649 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags); 00650 num_spyed_upon++; 00651 00652 if (res == -1) { 00653 chanspy_ds_free(peer_chanspy_ds); 00654 break; 00655 } else if (res > 1 && spec) { 00656 struct ast_channel *next; 00657 00658 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00659 00660 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00661 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); 00662 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); 00663 } else { 00664 /* stay on this channel, if it is still valid */ 00665 00666 ast_mutex_lock(&peer_chanspy_ds->lock); 00667 if (peer_chanspy_ds->chan) { 00668 ast_channel_lock(peer_chanspy_ds->chan); 00669 next_chanspy_ds = peer_chanspy_ds; 00670 peer_chanspy_ds = NULL; 00671 } else { 00672 /* the channel is gone */ 00673 ast_mutex_unlock(&peer_chanspy_ds->lock); 00674 next_chanspy_ds = NULL; 00675 } 00676 } 00677 00678 peer = NULL; 00679 } 00680 } 00681 if (res == -1 || ast_check_hangup(chan)) 00682 break; 00683 } 00684 00685 ast_clear_flag(chan, AST_FLAG_SPYING); 00686 00687 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00688 00689 ast_mutex_destroy(&chanspy_ds.lock); 00690 00691 return res; 00692 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 777 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().
00778 { 00779 struct ast_module_user *u; 00780 char *options = NULL; 00781 char *exten = NULL; 00782 char *context = NULL; 00783 char *argv[2]; 00784 char *mygroup = NULL; 00785 char *recbase = NULL; 00786 int fd = 0; 00787 struct ast_flags flags; 00788 int oldwf = 0; 00789 int argc = 0; 00790 int volfactor = 0; 00791 int res; 00792 00793 data = ast_strdupa(data); 00794 00795 u = ast_module_user_add(chan); 00796 00797 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) { 00798 context = argv[0]; 00799 if (!ast_strlen_zero(argv[0])) 00800 exten = strsep(&context, "@"); 00801 if (ast_strlen_zero(context)) 00802 context = ast_strdupa(chan->context); 00803 if (argc > 1) 00804 options = argv[1]; 00805 } 00806 00807 if (options) { 00808 char *opts[OPT_ARG_ARRAY_SIZE]; 00809 00810 ast_app_parse_options(spy_opts, &flags, opts, options); 00811 if (ast_test_flag(&flags, OPTION_GROUP)) 00812 mygroup = opts[OPT_ARG_GROUP]; 00813 00814 if (ast_test_flag(&flags, OPTION_RECORD) && 00815 !(recbase = opts[OPT_ARG_RECORD])) 00816 recbase = "chanspy"; 00817 00818 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00819 int vol; 00820 00821 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4)) 00822 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00823 else 00824 volfactor = vol; 00825 } 00826 00827 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00828 ast_set_flag(&flags, OPTION_WHISPER); 00829 } else 00830 ast_clear_flag(&flags, AST_FLAGS_ALL); 00831 00832 oldwf = chan->writeformat; 00833 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00834 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00835 ast_module_user_remove(u); 00836 return -1; 00837 } 00838 00839 if (recbase) { 00840 char filename[PATH_MAX]; 00841 00842 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00843 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) { 00844 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00845 fd = 0; 00846 } 00847 } 00848 00849 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context, NULL); 00850 00851 if (fd) 00852 close(fd); 00853 00854 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00855 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00856 00857 ast_module_user_remove(u); 00858 00859 return res; 00860 }
static int load_module | ( | void | ) | [static] |
Definition at line 960 of file app_chanspy.c.
References ast_register_application(), chanspy_exec(), chanspychan_exec(), and extenspy_exec().
00961 { 00962 int res = 0; 00963 00964 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 00965 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 00966 res |= ast_register_application(app_chan_uniqueid, chanspychan_exec, tdesc, desc_uniqueid); 00967 00968 return res; 00969 }
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, | |||
const char * | uniqueid | |||
) | [static, read] |
Definition at line 481 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(), name, and setup_chanspy_ds().
Referenced by common_exec().
00484 { 00485 struct ast_channel *this; 00486 00487 redo: 00488 if (spec) 00489 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00490 else if (exten) 00491 this = ast_walk_channel_by_exten_locked(last, exten, context); 00492 else if (uniqueid) 00493 this = ast_get_channel_by_uniqueid_locked(uniqueid); 00494 else 00495 this = ast_channel_walk_locked(last); 00496 00497 if (!this) 00498 return NULL; 00499 00500 if (!strncmp(this->name, "Zap/pseudo", 10)) { 00501 ast_channel_unlock(this); 00502 goto redo; 00503 } else if (this == chan) { 00504 last = this; 00505 ast_channel_unlock(this); 00506 goto redo; 00507 } 00508 00509 return setup_chanspy_ds(this, chanspy_ds); 00510 }
static struct chanspy_ds* setup_chanspy_ds | ( | struct ast_channel * | chan, | |
struct chanspy_ds * | chanspy_ds | |||
) | [static, read] |
Definition at line 461 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(), ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and next_channel().
00462 { 00463 struct ast_datastore *datastore = NULL; 00464 00465 ast_mutex_lock(&chanspy_ds->lock); 00466 00467 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { 00468 ast_mutex_unlock(&chanspy_ds->lock); 00469 chanspy_ds = chanspy_ds_free(chanspy_ds); 00470 ast_channel_unlock(chan); 00471 return NULL; 00472 } 00473 00474 chanspy_ds->chan = chan; 00475 datastore->data = chanspy_ds; 00476 ast_channel_datastore_add(chan, datastore); 00477 00478 return chanspy_ds; 00479 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 177 of file app_chanspy.c.
00178 { 00179 /* just store the data pointer in the channel structure */ 00180 return data; 00181 }
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 188 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(), ast_frame::data, ast_frame::datalen, f, chanspy_translation_helper::fd, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.
00189 { 00190 struct chanspy_translation_helper *csth = data; 00191 struct ast_frame *f; 00192 00193 ast_audiohook_lock(&csth->spy_audiohook); 00194 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00195 ast_audiohook_unlock(&csth->spy_audiohook); 00196 return -1; 00197 } 00198 00199 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); 00200 00201 ast_audiohook_unlock(&csth->spy_audiohook); 00202 00203 if (!f) 00204 return 0; 00205 00206 if (ast_write(chan, f)) { 00207 ast_frfree(f); 00208 return -1; 00209 } 00210 00211 if (csth->fd) 00212 write(csth->fd, f->data, f->datalen); 00213 00214 ast_frfree(f); 00215 00216 return 0; 00217 }
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 225 of file app_chanspy.c.
References ast_audiohook_attach(), ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_log(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and LOG_NOTICE.
Referenced by channel_spy().
00226 { 00227 int res; 00228 struct ast_channel *peer; 00229 00230 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name); 00231 00232 res = ast_audiohook_attach(chan, audiohook); 00233 00234 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 00235 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00236 } 00237 return res; 00238 }
static int unload_module | ( | void | ) | [static] |
Definition at line 948 of file app_chanspy.c.
References ast_unregister_application().
00949 { 00950 int res = 0; 00951 00952 res |= ast_unregister_application(app_chan); 00953 res |= ast_unregister_application(app_chan_uniqueid); 00954 res |= ast_unregister_application(app_ext); 00955 00956 00957 return res; 00958 }
const char* app_chan = "ChanSpy" [static] |
Definition at line 59 of file app_chanspy.c.
const char* app_chan_uniqueid = "ChanSpyChan" [static] |
Definition at line 60 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 112 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 427 of file app_chanspy.c.
enum { ... } chanspy_opt_args |
enum { ... } chanspy_opt_flags |
const char* desc_chan [static] |
Definition at line 61 of file app_chanspy.c.
const char* desc_ext [static] |
Definition at line 113 of file app_chanspy.c.
const char* desc_uniqueid [static] |
Definition at line 91 of file app_chanspy.c.
int next_unique_id_to_use = 0 |
Definition at line 167 of file app_chanspy.c.
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 219 of file app_chanspy.c.
const char* tdesc = "Listen to a channel, and optionally whisper into it" [static] |
Definition at line 58 of file app_chanspy.c.