#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
Go to the source code of this file.
Data Structures | |
struct | chanspy_ds |
struct | chanspy_translation_helper |
Defines | |
#define | AST_NAME_STRLEN 256 |
#define | NUM_SPYGROUPS 128 |
Enumerations | |
enum | { OPTION_QUIET = (1 << 0), OPTION_BRIDGED = (1 << 1), OPTION_VOLUME = (1 << 2), OPTION_GROUP = (1 << 3), OPTION_RECORD = (1 << 4), OPTION_WHISPER = (1 << 5), OPTION_PRIVATE = (1 << 6), OPTION_READONLY = (1 << 7), OPTION_EXIT = (1 << 8), OPTION_ENFORCED = (1 << 9), OPTION_NOTECH = (1 << 10), OPTION_BARGE = (1 << 11), OPTION_NAME = (1 << 12), OPTION_DTMF_SWITCH_MODES = (1 << 13) } |
enum | { OPT_ARG_VOLUME = 0, OPT_ARG_GROUP, OPT_ARG_RECORD, OPT_ARG_ENFORCED, OPT_ARG_NAME, OPT_ARG_ARRAY_SIZE } |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | change_spy_mode (const char digit, struct ast_flags *flags) |
static int | channel_spy (struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds, int *volfactor, int fd, struct ast_flags *flags, char *exitcontext) |
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, struct ast_flags *flags, int volfactor, const int fd, const char *mygroup, const char *myenforced, const char *spec, const char *exten, const char *context, const char *mailbox, const char *name_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 struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } |
static const char * | app_chan = "ChanSpy" |
static const char * | app_ext = "ExtenSpy" |
static struct ast_module_info * | ast_module_info = &__mod_info |
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 int | next_unique_id_to_use = 0 |
static struct ast_app_option | spy_opts [128] = { [ 'q' ] = { .flag = OPTION_QUIET }, [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'X' ] = { .flag = OPTION_EXIT }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES },} |
static struct ast_generator | spygen |
static const char * | tdesc = "Listen to a channel, and optionally whisper into it" |
Joshua Colp <jcolp@digium.com>
Russell Bryant <russell@digium.com>
Definition in file app_chanspy.c.
#define AST_NAME_STRLEN 256 |
#define NUM_SPYGROUPS 128 |
anonymous enum |
Definition at line 179 of file app_chanspy.c.
00179 { 00180 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00181 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00182 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00183 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00184 OPTION_RECORD = (1 << 4), 00185 OPTION_WHISPER = (1 << 5), 00186 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00187 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */ 00188 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */ 00189 OPTION_ENFORCED = (1 << 9), /* Enforced mode */ 00190 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */ 00191 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */ 00192 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */ 00193 OPTION_DTMF_SWITCH_MODES = (1 << 13), /*Allow numeric DTMF to switch between chanspy modes */ 00194 } chanspy_opt_flags;
anonymous enum |
OPT_ARG_VOLUME | |
OPT_ARG_GROUP | |
OPT_ARG_RECORD | |
OPT_ARG_ENFORCED | |
OPT_ARG_NAME | |
OPT_ARG_ARRAY_SIZE |
Definition at line 196 of file app_chanspy.c.
00196 { 00197 OPT_ARG_VOLUME = 0, 00198 OPT_ARG_GROUP, 00199 OPT_ARG_RECORD, 00200 OPT_ARG_ENFORCED, 00201 OPT_ARG_NAME, 00202 OPT_ARG_ARRAY_SIZE, 00203 } chanspy_opt_args;
static void __reg_module | ( | void | ) | [static] |
Definition at line 1120 of file app_chanspy.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1120 of file app_chanspy.c.
static void change_spy_mode | ( | const char | digit, | |
struct ast_flags * | flags | |||
) | [static] |
Definition at line 314 of file app_chanspy.c.
References ast_clear_flag, ast_set_flag, ast_channel::flags, OPTION_BARGE, and OPTION_WHISPER.
Referenced by channel_spy().
00315 { 00316 if (digit == '4') { 00317 ast_clear_flag(flags, OPTION_WHISPER); 00318 ast_clear_flag(flags, OPTION_BARGE); 00319 } else if (digit == '5') { 00320 ast_clear_flag(flags, OPTION_BARGE); 00321 ast_set_flag(flags, OPTION_WHISPER); 00322 } else if (digit == '6') { 00323 ast_clear_flag(flags, OPTION_WHISPER); 00324 ast_set_flag(flags, OPTION_BARGE); 00325 } 00326 }
static int channel_spy | ( | struct ast_channel * | chan, | |
struct chanspy_ds * | spyee_chanspy_ds, | |||
int * | volfactor, | |||
int | fd, | |||
struct ast_flags * | flags, | |||
char * | exitcontext | |||
) | [static] |
Definition at line 328 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_bridged_channel(), ast_channel_lock, ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_flags, ast_deactivate_generator(), ast_debug, AST_FLAG_END_DTMF_ONLY, AST_FLAGS_ALL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_frfree, ast_goto_if_exists(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_set_flag, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, ast_waitfor(), chanspy_ds::chan, chan, change_spy_mode(), DEADLOCK_AVOIDANCE, f, ast_channel::flags, chanspy_ds::lock, LOG_WARNING, ast_channel::name, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, pbx_builtin_setvar_helper(), spygen, and start_spying().
Referenced by common_exec().
00330 { 00331 struct chanspy_translation_helper csth; 00332 int running = 0, res, x = 0; 00333 char inp[24] = {0}; 00334 char *name; 00335 struct ast_frame *f; 00336 struct ast_silence_generator *silgen = NULL; 00337 struct ast_channel *spyee = NULL, *spyee_bridge = NULL; 00338 const char *spyer_name; 00339 00340 ast_channel_lock(chan); 00341 spyer_name = ast_strdupa(chan->name); 00342 ast_channel_unlock(chan); 00343 00344 ast_mutex_lock(&spyee_chanspy_ds->lock); 00345 while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) { 00346 /* avoid a deadlock here, just in case spyee is masqueraded and 00347 * chanspy_ds_chan_fixup() is called with the channel locked */ 00348 DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock); 00349 } 00350 ast_mutex_unlock(&spyee_chanspy_ds->lock); 00351 00352 if (!spyee) 00353 return 0; 00354 00355 /* We now hold the channel lock on spyee */ 00356 00357 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) { 00358 ast_channel_unlock(spyee); 00359 return 0; 00360 } 00361 00362 name = ast_strdupa(spyee->name); 00363 ast_verb(2, "Spying on channel %s\n", name); 00364 00365 memset(&csth, 0, sizeof(csth)); 00366 ast_copy_flags(&csth.spy_audiohook, flags, AST_FLAGS_ALL); 00367 00368 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00369 00370 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { 00371 ast_audiohook_destroy(&csth.spy_audiohook); 00372 ast_channel_unlock(spyee); 00373 return 0; 00374 } 00375 00376 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00377 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); 00378 if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) { 00379 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name); 00380 } 00381 if ((spyee_bridge = ast_bridged_channel(spyee))) { 00382 ast_channel_lock(spyee_bridge); 00383 if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) { 00384 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name); 00385 } 00386 ast_channel_unlock(spyee_bridge); 00387 } 00388 ast_channel_unlock(spyee); 00389 spyee = NULL; 00390 00391 ast_channel_lock(chan); 00392 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00393 ast_channel_unlock(chan); 00394 00395 csth.volfactor = *volfactor; 00396 00397 if (csth.volfactor) { 00398 csth.spy_audiohook.options.read_volume = csth.volfactor; 00399 csth.spy_audiohook.options.write_volume = csth.volfactor; 00400 } 00401 00402 csth.fd = fd; 00403 00404 if (ast_test_flag(flags, OPTION_PRIVATE)) 00405 silgen = ast_channel_start_silence_generator(chan); 00406 else 00407 ast_activate_generator(chan, &spygen, &csth); 00408 00409 /* We can no longer rely on 'spyee' being an actual channel; 00410 it can be hung up and freed out from under us. However, the 00411 channel destructor will put NULL into our csth.spy.chan 00412 field when that happens, so that is our signal that the spyee 00413 channel has gone away. 00414 */ 00415 00416 /* Note: it is very important that the ast_waitfor() be the first 00417 condition in this expression, so that if we wait for some period 00418 of time before receiving a frame from our spying channel, we check 00419 for hangup on the spied-on channel _after_ knowing that a frame 00420 has arrived, since the spied-on channel could have gone away while 00421 we were waiting 00422 */ 00423 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00424 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00425 running = -1; 00426 break; 00427 } 00428 00429 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { 00430 ast_audiohook_lock(&csth.whisper_audiohook); 00431 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00432 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00433 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00434 ast_audiohook_unlock(&csth.whisper_audiohook); 00435 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00436 ast_frfree(f); 00437 continue; 00438 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { 00439 ast_audiohook_lock(&csth.whisper_audiohook); 00440 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00441 ast_audiohook_unlock(&csth.whisper_audiohook); 00442 ast_frfree(f); 00443 continue; 00444 } 00445 00446 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00447 ast_frfree(f); 00448 if (!res) 00449 continue; 00450 00451 if (x == sizeof(inp)) 00452 x = 0; 00453 00454 if (res < 0) { 00455 running = -1; 00456 break; 00457 } 00458 00459 if (ast_test_flag(flags, OPTION_EXIT)) { 00460 char tmp[2]; 00461 tmp[0] = res; 00462 tmp[1] = '\0'; 00463 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00464 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); 00465 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); 00466 running = -2; 00467 break; 00468 } else { 00469 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00470 } 00471 } else if (res >= '0' && res <= '9') { 00472 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { 00473 change_spy_mode(res, flags); 00474 } else { 00475 inp[x++] = res; 00476 } 00477 } 00478 00479 if (res == '*') { 00480 running = 0; 00481 break; 00482 } else if (res == '#') { 00483 if (!ast_strlen_zero(inp)) { 00484 running = atoi(inp); 00485 break; 00486 } 00487 00488 (*volfactor)++; 00489 if (*volfactor > 4) 00490 *volfactor = -4; 00491 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00492 00493 csth.volfactor = *volfactor; 00494 csth.spy_audiohook.options.read_volume = csth.volfactor; 00495 csth.spy_audiohook.options.write_volume = csth.volfactor; 00496 } 00497 } 00498 00499 if (ast_test_flag(flags, OPTION_PRIVATE)) 00500 ast_channel_stop_silence_generator(chan, silgen); 00501 else 00502 ast_deactivate_generator(chan); 00503 00504 ast_channel_lock(chan); 00505 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00506 ast_channel_unlock(chan); 00507 00508 ast_audiohook_lock(&csth.whisper_audiohook); 00509 ast_audiohook_detach(&csth.whisper_audiohook); 00510 ast_audiohook_unlock(&csth.whisper_audiohook); 00511 ast_audiohook_destroy(&csth.whisper_audiohook); 00512 00513 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00514 ast_audiohook_detach(&csth.bridge_whisper_audiohook); 00515 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00516 ast_audiohook_destroy(&csth.bridge_whisper_audiohook); 00517 00518 ast_audiohook_lock(&csth.spy_audiohook); 00519 ast_audiohook_detach(&csth.spy_audiohook); 00520 ast_audiohook_unlock(&csth.spy_audiohook); 00521 ast_audiohook_destroy(&csth.spy_audiohook); 00522 00523 ast_verb(2, "Done Spying on channel %s\n", name); 00524 00525 return running; 00526 }
static void chanspy_ds_chan_fixup | ( | void * | data, | |
struct ast_channel * | old_chan, | |||
struct ast_channel * | new_chan | |||
) | [static] |
Definition at line 545 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
00546 { 00547 struct chanspy_ds *chanspy_ds = data; 00548 00549 ast_mutex_lock(&chanspy_ds->lock); 00550 chanspy_ds->chan = new_chan; 00551 ast_mutex_unlock(&chanspy_ds->lock); 00552 }
static void chanspy_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 532 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
Referenced by chanspy_ds_free().
00533 { 00534 struct chanspy_ds *chanspy_ds = data; 00535 00536 /* Setting chan to be NULL is an atomic operation, but we don't want this 00537 * value to change while this lock is held. The lock is held elsewhere 00538 * while it performs non-atomic operations with this channel pointer */ 00539 00540 ast_mutex_lock(&chanspy_ds->lock); 00541 chanspy_ds->chan = NULL; 00542 ast_mutex_unlock(&chanspy_ds->lock); 00543 }
static struct chanspy_ds* chanspy_ds_free | ( | struct chanspy_ds * | chanspy_ds | ) | [static] |
Definition at line 560 of file app_chanspy.c.
References ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_trylock, ast_channel_unlock, ast_datastore_free(), ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, chan, chanspy_ds_destroy(), chanspy_ds_info, ast_datastore::data, DEADLOCK_AVOIDANCE, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and setup_chanspy_ds().
00561 { 00562 struct ast_channel *chan; 00563 00564 if (!chanspy_ds) { 00565 return NULL; 00566 } 00567 00568 ast_mutex_lock(&chanspy_ds->lock); 00569 while ((chan = chanspy_ds->chan)) { 00570 struct ast_datastore *datastore; 00571 00572 if (ast_channel_trylock(chan)) { 00573 DEADLOCK_AVOIDANCE(&chanspy_ds->lock); 00574 continue; 00575 } 00576 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) { 00577 ast_channel_datastore_remove(chan, datastore); 00578 /* chanspy_ds->chan is NULL after this call */ 00579 chanspy_ds_destroy(datastore->data); 00580 datastore->data = NULL; 00581 ast_datastore_free(datastore); 00582 } 00583 ast_channel_unlock(chan); 00584 break; 00585 } 00586 ast_mutex_unlock(&chanspy_ds->lock); 00587 00588 return NULL; 00589 }
static int chanspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 911 of file app_chanspy.c.
References AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, common_exec(), ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_ENFORCED, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_ENFORCED, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, spy_opts, and ast_channel::writeformat.
Referenced by load_module().
00912 { 00913 char *myenforced = NULL; 00914 char *mygroup = NULL; 00915 char *recbase = NULL; 00916 int fd = 0; 00917 struct ast_flags flags; 00918 int oldwf = 0; 00919 int volfactor = 0; 00920 int res; 00921 char *mailbox = NULL; 00922 char *name_context = NULL; 00923 AST_DECLARE_APP_ARGS(args, 00924 AST_APP_ARG(spec); 00925 AST_APP_ARG(options); 00926 ); 00927 char *opts[OPT_ARG_ARRAY_SIZE]; 00928 00929 data = ast_strdupa(data); 00930 AST_STANDARD_APP_ARGS(args, data); 00931 00932 if (args.spec && !strcmp(args.spec, "all")) 00933 args.spec = NULL; 00934 00935 if (args.options) { 00936 ast_app_parse_options(spy_opts, &flags, opts, args.options); 00937 if (ast_test_flag(&flags, OPTION_GROUP)) 00938 mygroup = opts[OPT_ARG_GROUP]; 00939 00940 if (ast_test_flag(&flags, OPTION_RECORD) && 00941 !(recbase = opts[OPT_ARG_RECORD])) 00942 recbase = "chanspy"; 00943 00944 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00945 int vol; 00946 00947 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 00948 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00949 else 00950 volfactor = vol; 00951 } 00952 00953 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00954 ast_set_flag(&flags, OPTION_WHISPER); 00955 00956 if (ast_test_flag(&flags, OPTION_ENFORCED)) 00957 myenforced = opts[OPT_ARG_ENFORCED]; 00958 00959 if (ast_test_flag(&flags, OPTION_NAME)) { 00960 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 00961 char *delimiter; 00962 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 00963 mailbox = opts[OPT_ARG_NAME]; 00964 *delimiter++ = '\0'; 00965 name_context = delimiter; 00966 } else { 00967 mailbox = opts[OPT_ARG_NAME]; 00968 } 00969 } 00970 } 00971 00972 00973 } else 00974 ast_clear_flag(&flags, AST_FLAGS_ALL); 00975 00976 oldwf = chan->writeformat; 00977 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00978 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00979 return -1; 00980 } 00981 00982 if (recbase) { 00983 char filename[PATH_MAX]; 00984 00985 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00986 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 00987 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00988 fd = 0; 00989 } 00990 } 00991 00992 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); 00993 00994 if (fd) 00995 close(fd); 00996 00997 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00998 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00999 01000 return res; 01001 }
static int common_exec | ( | struct ast_channel * | chan, | |
struct ast_flags * | flags, | |||
int | volfactor, | |||
const int | fd, | |||
const char * | mygroup, | |||
const char * | myenforced, | |||
const char * | spec, | |||
const char * | exten, | |||
const char * | context, | |||
const char * | mailbox, | |||
const char * | name_context | |||
) | [static] |
Definition at line 643 of file app_chanspy.c.
References ast_channel::_state, ARRAY_LEN, ast_answer(), ast_app_sayname(), ast_app_separate_args, ast_atomic_fetchadd_int(), ast_bridged_channel(), ast_channel_lock, AST_CHANNEL_NAME, ast_channel_setoption(), ast_channel_unlock, ast_check_hangup(), ast_clear_flag, ast_copy_string(), ast_debug, ast_fileexists(), AST_FLAG_SPYING, ast_get_channel_by_name_prefix_locked(), ast_goto_if_exists(), AST_MAX_CONTEXT, 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_streamfile(), ast_strlen_zero(), ast_test_flag, ast_waitfordigit(), ast_waitstream(), chan, channel_spy(), chanspy_ds_free(), ast_channel::context, exitcontext, ext, ast_channel::flags, chanspy_ds::lock, ast_channel::macrocontext, ast_channel::next, next_channel(), num, NUM_SPYGROUPS, OPTION_BRIDGED, OPTION_EXIT, OPTION_NAME, OPTION_NOTECH, OPTION_QUIET, pbx_builtin_getvar_helper(), s, S_OR, setup_chanspy_ds(), strcasestr(), strsep(), and chanspy_ds::unique_id.
Referenced by chanspy_exec(), and extenspy_exec().
00647 { 00648 char nameprefix[AST_NAME_STRLEN]; 00649 char peer_name[AST_NAME_STRLEN + 5]; 00650 char exitcontext[AST_MAX_CONTEXT] = ""; 00651 signed char zero_volume = 0; 00652 int waitms; 00653 int res; 00654 char *ptr; 00655 int num; 00656 int num_spyed_upon = 1; 00657 struct chanspy_ds chanspy_ds = { 0, }; 00658 00659 if (ast_test_flag(flags, OPTION_EXIT)) { 00660 const char *c; 00661 ast_channel_lock(chan); 00662 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { 00663 ast_copy_string(exitcontext, c, sizeof(exitcontext)); 00664 } else if (!ast_strlen_zero(chan->macrocontext)) { 00665 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 00666 } else { 00667 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 00668 } 00669 ast_channel_unlock(chan); 00670 } 00671 00672 ast_mutex_init(&chanspy_ds.lock); 00673 00674 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); 00675 00676 if (chan->_state != AST_STATE_UP) 00677 ast_answer(chan); 00678 00679 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00680 00681 waitms = 100; 00682 00683 for (;;) { 00684 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; 00685 struct ast_channel *prev = NULL, *peer = NULL; 00686 00687 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00688 res = ast_streamfile(chan, "beep", chan->language); 00689 if (!res) 00690 res = ast_waitstream(chan, ""); 00691 else if (res < 0) { 00692 ast_clear_flag(chan, AST_FLAG_SPYING); 00693 break; 00694 } 00695 if (!ast_strlen_zero(exitcontext)) { 00696 char tmp[2]; 00697 tmp[0] = res; 00698 tmp[1] = '\0'; 00699 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00700 goto exit; 00701 else 00702 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00703 } 00704 } 00705 00706 res = ast_waitfordigit(chan, waitms); 00707 if (res < 0) { 00708 ast_clear_flag(chan, AST_FLAG_SPYING); 00709 break; 00710 } 00711 if (!ast_strlen_zero(exitcontext)) { 00712 char tmp[2]; 00713 tmp[0] = res; 00714 tmp[1] = '\0'; 00715 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00716 goto exit; 00717 else 00718 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00719 } 00720 00721 /* reset for the next loop around, unless overridden later */ 00722 waitms = 100; 00723 num_spyed_upon = 0; 00724 00725 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); 00726 peer_chanspy_ds; 00727 chanspy_ds_free(peer_chanspy_ds), prev = peer, 00728 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 00729 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { 00730 int igrp = !mygroup; 00731 int ienf = !myenforced; 00732 char *s; 00733 00734 peer = peer_chanspy_ds->chan; 00735 00736 ast_mutex_unlock(&peer_chanspy_ds->lock); 00737 00738 if (peer == prev) { 00739 ast_channel_unlock(peer); 00740 chanspy_ds_free(peer_chanspy_ds); 00741 break; 00742 } 00743 00744 if (ast_check_hangup(chan)) { 00745 ast_channel_unlock(peer); 00746 chanspy_ds_free(peer_chanspy_ds); 00747 break; 00748 } 00749 00750 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { 00751 ast_channel_unlock(peer); 00752 continue; 00753 } 00754 00755 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { 00756 ast_channel_unlock(peer); 00757 continue; 00758 } 00759 00760 if (mygroup) { 00761 int num_groups = 0; 00762 int num_mygroups = 0; 00763 char dup_group[512]; 00764 char dup_mygroup[512]; 00765 char *groups[NUM_SPYGROUPS]; 00766 char *mygroups[NUM_SPYGROUPS]; 00767 const char *group; 00768 int x; 00769 int y; 00770 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); 00771 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, 00772 ARRAY_LEN(mygroups)); 00773 00774 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00775 ast_copy_string(dup_group, group, sizeof(dup_group)); 00776 num_groups = ast_app_separate_args(dup_group, ':', groups, 00777 ARRAY_LEN(groups)); 00778 } 00779 00780 for (y = 0; y < num_mygroups; y++) { 00781 for (x = 0; x < num_groups; x++) { 00782 if (!strcmp(mygroups[y], groups[x])) { 00783 igrp = 1; 00784 break; 00785 } 00786 } 00787 } 00788 } 00789 00790 if (!igrp) { 00791 ast_channel_unlock(peer); 00792 continue; 00793 } 00794 00795 if (myenforced) { 00796 char ext[AST_CHANNEL_NAME + 3]; 00797 char buffer[512]; 00798 char *end; 00799 00800 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); 00801 00802 ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1); 00803 if ((end = strchr(ext, '-'))) { 00804 *end++ = ':'; 00805 *end = '\0'; 00806 } 00807 00808 ext[0] = ':'; 00809 00810 if (strcasestr(buffer, ext)) { 00811 ienf = 1; 00812 } 00813 } 00814 00815 if (!ienf) { 00816 continue; 00817 } 00818 00819 strcpy(peer_name, "spy-"); 00820 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); 00821 ptr = strchr(peer_name, '/'); 00822 *ptr++ = '\0'; 00823 ptr = strsep(&ptr, "-"); 00824 00825 for (s = peer_name; s < ptr; s++) 00826 *s = tolower(*s); 00827 /* We have to unlock the peer channel here to avoid a deadlock. 00828 * So, when we need to dereference it again, we have to lock the 00829 * datastore and get the pointer from there to see if the channel 00830 * is still valid. */ 00831 ast_channel_unlock(peer); 00832 00833 if (!ast_test_flag(flags, OPTION_QUIET)) { 00834 if (ast_test_flag(flags, OPTION_NAME)) { 00835 const char *local_context = S_OR(name_context, "default"); 00836 const char *local_mailbox = S_OR(mailbox, ptr); 00837 res = ast_app_sayname(chan, local_mailbox, local_context); 00838 } 00839 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { 00840 if (!ast_test_flag(flags, OPTION_NOTECH)) { 00841 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00842 res = ast_streamfile(chan, peer_name, chan->language); 00843 if (!res) { 00844 res = ast_waitstream(chan, ""); 00845 } 00846 if (res) { 00847 chanspy_ds_free(peer_chanspy_ds); 00848 break; 00849 } 00850 } else { 00851 res = ast_say_character_str(chan, peer_name, "", chan->language); 00852 } 00853 } 00854 if ((num = atoi(ptr))) 00855 ast_say_digits(chan, atoi(ptr), "", chan->language); 00856 } 00857 } 00858 00859 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); 00860 num_spyed_upon++; 00861 00862 if (res == -1) { 00863 chanspy_ds_free(peer_chanspy_ds); 00864 goto exit; 00865 } else if (res == -2) { 00866 res = 0; 00867 chanspy_ds_free(peer_chanspy_ds); 00868 goto exit; 00869 } else if (res > 1 && spec) { 00870 struct ast_channel *next; 00871 00872 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00873 00874 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00875 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); 00876 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); 00877 } else { 00878 /* stay on this channel, if it is still valid */ 00879 00880 ast_mutex_lock(&peer_chanspy_ds->lock); 00881 if (peer_chanspy_ds->chan) { 00882 ast_channel_lock(peer_chanspy_ds->chan); 00883 next_chanspy_ds = peer_chanspy_ds; 00884 peer_chanspy_ds = NULL; 00885 } else { 00886 /* the channel is gone */ 00887 ast_mutex_unlock(&peer_chanspy_ds->lock); 00888 next_chanspy_ds = NULL; 00889 } 00890 } 00891 00892 peer = NULL; 00893 } 00894 } 00895 if (res == -1 || ast_check_hangup(chan)) 00896 break; 00897 } 00898 exit: 00899 00900 ast_clear_flag(chan, AST_FLAG_SPYING); 00901 00902 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00903 00904 ast_mutex_lock(&chanspy_ds.lock); 00905 ast_mutex_unlock(&chanspy_ds.lock); 00906 ast_mutex_destroy(&chanspy_ds.lock); 00907 00908 return res; 00909 }
static int extenspy_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 1003 of file app_chanspy.c.
References AST_APP_ARG, ast_app_parse_options(), ast_clear_flag, ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, AST_FILE_MODE, AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, common_exec(), ast_channel::context, context, exten, ast_flags::flags, LOG_ERROR, LOG_NOTICE, LOG_WARNING, mailbox, OPT_ARG_ARRAY_SIZE, OPT_ARG_GROUP, OPT_ARG_NAME, OPT_ARG_RECORD, OPT_ARG_VOLUME, OPTION_GROUP, OPTION_NAME, OPTION_PRIVATE, OPTION_RECORD, OPTION_VOLUME, OPTION_WHISPER, spy_opts, and ast_channel::writeformat.
Referenced by load_module().
01004 { 01005 char *ptr, *exten = NULL; 01006 char *mygroup = NULL; 01007 char *recbase = NULL; 01008 int fd = 0; 01009 struct ast_flags flags; 01010 int oldwf = 0; 01011 int volfactor = 0; 01012 int res; 01013 char *mailbox = NULL; 01014 char *name_context = NULL; 01015 AST_DECLARE_APP_ARGS(args, 01016 AST_APP_ARG(context); 01017 AST_APP_ARG(options); 01018 ); 01019 01020 data = ast_strdupa(data); 01021 01022 AST_STANDARD_APP_ARGS(args, data); 01023 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { 01024 exten = args.context; 01025 *ptr++ = '\0'; 01026 args.context = ptr; 01027 } 01028 01029 if (ast_strlen_zero(args.context)) 01030 args.context = ast_strdupa(chan->context); 01031 01032 if (args.options) { 01033 char *opts[OPT_ARG_ARRAY_SIZE]; 01034 01035 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01036 if (ast_test_flag(&flags, OPTION_GROUP)) 01037 mygroup = opts[OPT_ARG_GROUP]; 01038 01039 if (ast_test_flag(&flags, OPTION_RECORD) && 01040 !(recbase = opts[OPT_ARG_RECORD])) 01041 recbase = "chanspy"; 01042 01043 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01044 int vol; 01045 01046 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01047 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01048 else 01049 volfactor = vol; 01050 } 01051 01052 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01053 ast_set_flag(&flags, OPTION_WHISPER); 01054 01055 01056 if (ast_test_flag(&flags, OPTION_NAME)) { 01057 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01058 char *delimiter; 01059 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01060 mailbox = opts[OPT_ARG_NAME]; 01061 *delimiter++ = '\0'; 01062 name_context = delimiter; 01063 } else { 01064 mailbox = opts[OPT_ARG_NAME]; 01065 } 01066 } 01067 } 01068 01069 } else 01070 ast_clear_flag(&flags, AST_FLAGS_ALL); 01071 01072 oldwf = chan->writeformat; 01073 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01074 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01075 return -1; 01076 } 01077 01078 if (recbase) { 01079 char filename[PATH_MAX]; 01080 01081 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01082 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01083 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01084 fd = 0; 01085 } 01086 } 01087 01088 01089 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); 01090 01091 if (fd) 01092 close(fd); 01093 01094 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01095 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01096 01097 return res; 01098 }
static int load_module | ( | void | ) | [static] |
Definition at line 1110 of file app_chanspy.c.
References ast_register_application, chanspy_exec(), and extenspy_exec().
01111 { 01112 int res = 0; 01113 01114 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 01115 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 01116 01117 return res; 01118 }
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 612 of file app_chanspy.c.
References ast_channel_unlock, ast_channel_walk_locked(), ast_strlen_zero(), ast_walk_channel_by_exten_locked(), ast_walk_channel_by_name_prefix_locked(), chan, last, ast_channel::name, ast_channel::next, and setup_chanspy_ds().
Referenced by common_exec().
00615 { 00616 struct ast_channel *next; 00617 const size_t pseudo_len = strlen("DAHDI/pseudo"); 00618 00619 redo: 00620 if (!ast_strlen_zero(spec)) 00621 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00622 else if (!ast_strlen_zero(exten)) 00623 next = ast_walk_channel_by_exten_locked(last, exten, context); 00624 else 00625 next = ast_channel_walk_locked(last); 00626 00627 if (!next) 00628 return NULL; 00629 00630 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) { 00631 last = next; 00632 ast_channel_unlock(next); 00633 goto redo; 00634 } else if (next == chan) { 00635 last = next; 00636 ast_channel_unlock(next); 00637 goto redo; 00638 } 00639 00640 return setup_chanspy_ds(next, chanspy_ds); 00641 }
static struct chanspy_ds* setup_chanspy_ds | ( | struct ast_channel * | chan, | |
struct chanspy_ds * | chanspy_ds | |||
) | [static] |
Definition at line 592 of file app_chanspy.c.
References ast_channel_datastore_add(), ast_channel_unlock, ast_datastore_alloc, ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, chan, chanspy_ds_free(), chanspy_ds_info, ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and next_channel().
00593 { 00594 struct ast_datastore *datastore = NULL; 00595 00596 ast_mutex_lock(&chanspy_ds->lock); 00597 00598 if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { 00599 ast_mutex_unlock(&chanspy_ds->lock); 00600 chanspy_ds = chanspy_ds_free(chanspy_ds); 00601 ast_channel_unlock(chan); 00602 return NULL; 00603 } 00604 00605 chanspy_ds->chan = chan; 00606 datastore->data = chanspy_ds; 00607 ast_channel_datastore_add(chan, datastore); 00608 00609 return chanspy_ds; 00610 }
static void* spy_alloc | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 233 of file app_chanspy.c.
00234 { 00235 /* just store the data pointer in the channel structure */ 00236 return data; 00237 }
static int spy_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 244 of file app_chanspy.c.
References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, AST_LIST_NEXT, ast_log(), ast_test_flag, ast_write(), chan, ast_frame::data, ast_frame::datalen, errno, f, chanspy_translation_helper::fd, LOG_WARNING, OPTION_READONLY, ast_frame::ptr, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.
00245 { 00246 struct chanspy_translation_helper *csth = data; 00247 struct ast_frame *f, *cur; 00248 00249 ast_audiohook_lock(&csth->spy_audiohook); 00250 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00251 /* Channel is already gone more than likely */ 00252 ast_audiohook_unlock(&csth->spy_audiohook); 00253 return -1; 00254 } 00255 00256 if (ast_test_flag(&csth->spy_audiohook, OPTION_READONLY)) { 00257 /* Option 'o' was set, so don't mix channel audio */ 00258 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR); 00259 } else { 00260 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); 00261 } 00262 00263 ast_audiohook_unlock(&csth->spy_audiohook); 00264 00265 if (!f) 00266 return 0; 00267 00268 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00269 if (ast_write(chan, cur)) { 00270 ast_frfree(f); 00271 return -1; 00272 } 00273 00274 if (csth->fd) { 00275 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) { 00276 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 00277 } 00278 } 00279 } 00280 00281 ast_frfree(f); 00282 00283 return 0; 00284 }
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 292 of file app_chanspy.c.
References ast_audiohook_attach(), AST_AUDIOHOOK_SMALL_QUEUE, AST_AUDIOHOOK_TRIGGER_SYNC, ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_log(), ast_set_flag, ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, chan, LOG_NOTICE, and ast_channel::name.
Referenced by channel_spy().
00293 { 00294 int res = 0; 00295 struct ast_channel *peer = NULL; 00296 00297 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name); 00298 00299 ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE); 00300 res = ast_audiohook_attach(chan, audiohook); 00301 00302 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 00303 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00304 } 00305 return res; 00306 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1100 of file app_chanspy.c.
References ast_unregister_application().
01101 { 01102 int res = 0; 01103 01104 res |= ast_unregister_application(app_chan); 01105 res |= ast_unregister_application(app_ext); 01106 01107 return res; 01108 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Listen to the audio of an active channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 1120 of file app_chanspy.c.
const char* app_chan = "ChanSpy" [static] |
Definition at line 57 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 122 of file app_chanspy.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1120 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 554 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 58 of file app_chanspy.c.
const char* desc_ext [static] |
Definition at line 123 of file app_chanspy.c.
int next_unique_id_to_use = 0 [static] |
Definition at line 222 of file app_chanspy.c.
struct ast_app_option spy_opts[128] = { [ 'q' ] = { .flag = OPTION_QUIET }, [ 'b' ] = { .flag = OPTION_BRIDGED }, [ 'B' ] = { .flag = OPTION_BARGE }, [ 'w' ] = { .flag = OPTION_WHISPER }, [ 'W' ] = { .flag = OPTION_PRIVATE }, [ 'v' ] = { .flag = OPTION_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 }, [ 'g' ] = { .flag = OPTION_GROUP , .arg_index = OPT_ARG_GROUP + 1 }, [ 'r' ] = { .flag = OPTION_RECORD , .arg_index = OPT_ARG_RECORD + 1 }, [ 'e' ] = { .flag = OPTION_ENFORCED , .arg_index = OPT_ARG_ENFORCED + 1 }, [ 'o' ] = { .flag = OPTION_READONLY }, [ 'X' ] = { .flag = OPTION_EXIT }, [ 's' ] = { .flag = OPTION_NOTECH }, [ 'n' ] = { .flag = OPTION_NAME , .arg_index = OPT_ARG_NAME + 1 }, [ 'd' ] = { .flag = OPTION_DTMF_SWITCH_MODES },} [static] |
struct ast_generator spygen [static] |
Initial value:
{ .alloc = spy_alloc, .release = spy_release, .generate = spy_generate, }
Definition at line 286 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 56 of file app_chanspy.c.