#include "asterisk.h"
#include <ctype.h>
#include <errno.h>
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/say.h"
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
#include "asterisk/manager.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"

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 = AST_BUILDOPT_SUM, .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 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 |
Definition in file app_chanspy.c.
| #define AST_NAME_STRLEN 256 |
| #define NUM_SPYGROUPS 128 |
| anonymous enum |
Definition at line 296 of file app_chanspy.c.
00296 { 00297 OPTION_QUIET = (1 << 0), /* Quiet, no announcement */ 00298 OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */ 00299 OPTION_VOLUME = (1 << 2), /* Specify initial volume */ 00300 OPTION_GROUP = (1 << 3), /* Only look at channels in group */ 00301 OPTION_RECORD = (1 << 4), 00302 OPTION_WHISPER = (1 << 5), 00303 OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */ 00304 OPTION_READONLY = (1 << 7), /* Don't mix the two channels */ 00305 OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */ 00306 OPTION_ENFORCED = (1 << 9), /* Enforced mode */ 00307 OPTION_NOTECH = (1 << 10), /* Skip technology name playback */ 00308 OPTION_BARGE = (1 << 11), /* Barge mode (whisper to both channels) */ 00309 OPTION_NAME = (1 << 12), /* Say the name of the person on whom we will spy */ 00310 OPTION_DTMF_SWITCH_MODES = (1 << 13), /*Allow numeric DTMF to switch between chanspy modes */ 00311 } 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 313 of file app_chanspy.c.
00313 { 00314 OPT_ARG_VOLUME = 0, 00315 OPT_ARG_GROUP, 00316 OPT_ARG_RECORD, 00317 OPT_ARG_ENFORCED, 00318 OPT_ARG_NAME, 00319 OPT_ARG_ARRAY_SIZE, 00320 } chanspy_opt_args;
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1246 of file app_chanspy.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1246 of file app_chanspy.c.
| static void change_spy_mode | ( | const char | digit, | |
| struct ast_flags * | flags | |||
| ) | [static] |
Definition at line 432 of file app_chanspy.c.
References ast_clear_flag, ast_set_flag, OPTION_BARGE, and OPTION_WHISPER.
Referenced by channel_spy().
00433 { 00434 if (digit == '4') { 00435 ast_clear_flag(flags, OPTION_WHISPER); 00436 ast_clear_flag(flags, OPTION_BARGE); 00437 } else if (digit == '5') { 00438 ast_clear_flag(flags, OPTION_BARGE); 00439 ast_set_flag(flags, OPTION_WHISPER); 00440 } else if (digit == '6') { 00441 ast_clear_flag(flags, OPTION_WHISPER); 00442 ast_set_flag(flags, OPTION_BARGE); 00443 } 00444 }
| 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 446 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_translation_helper::bridge_whisper_audiohook, chanspy_ds::chan, change_spy_mode(), DEADLOCK_AVOIDANCE, EVENT_FLAG_CALL, f, chanspy_translation_helper::fd, chanspy_translation_helper::flags, ast_frame::frametype, chanspy_ds::lock, LOG_WARNING, manager_event, ast_channel::name, name, OPTION_BARGE, OPTION_DTMF_SWITCH_MODES, OPTION_EXIT, OPTION_PRIVATE, OPTION_WHISPER, ast_audiohook::options, pbx_builtin_setvar_helper(), ast_audiohook_options::read_volume, chanspy_translation_helper::spy_audiohook, start_spying(), ast_audiohook::status, ast_frame::subclass, chanspy_translation_helper::volfactor, chanspy_translation_helper::whisper_audiohook, and ast_audiohook_options::write_volume.
Referenced by common_exec().
00448 { 00449 struct chanspy_translation_helper csth; 00450 int running = 0, res, x = 0; 00451 char inp[24] = {0}; 00452 char *name; 00453 struct ast_frame *f; 00454 struct ast_silence_generator *silgen = NULL; 00455 struct ast_channel *spyee = NULL, *spyee_bridge = NULL; 00456 const char *spyer_name; 00457 00458 ast_channel_lock(chan); 00459 spyer_name = ast_strdupa(chan->name); 00460 ast_channel_unlock(chan); 00461 00462 ast_mutex_lock(&spyee_chanspy_ds->lock); 00463 while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) { 00464 /* avoid a deadlock here, just in case spyee is masqueraded and 00465 * chanspy_ds_chan_fixup() is called with the channel locked */ 00466 DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock); 00467 } 00468 ast_mutex_unlock(&spyee_chanspy_ds->lock); 00469 00470 if (!spyee) { 00471 return 0; 00472 } 00473 00474 /* We now hold the channel lock on spyee */ 00475 00476 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) { 00477 ast_channel_unlock(spyee); 00478 return 0; 00479 } 00480 00481 name = ast_strdupa(spyee->name); 00482 00483 ast_verb(2, "Spying on channel %s\n", name); 00484 manager_event(EVENT_FLAG_CALL, "ChanSpyStart", 00485 "SpyerChannel: %s\r\n" 00486 "SpyeeChannel: %s\r\n", 00487 spyer_name, name); 00488 00489 memset(&csth, 0, sizeof(csth)); 00490 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL); 00491 00492 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00493 00494 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { 00495 ast_audiohook_destroy(&csth.spy_audiohook); 00496 ast_channel_unlock(spyee); 00497 return 0; 00498 } 00499 00500 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00501 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); 00502 if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) { 00503 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name); 00504 } 00505 if ((spyee_bridge = ast_bridged_channel(spyee))) { 00506 ast_channel_lock(spyee_bridge); 00507 if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) { 00508 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name); 00509 } 00510 ast_channel_unlock(spyee_bridge); 00511 } 00512 ast_channel_unlock(spyee); 00513 spyee = NULL; 00514 00515 ast_channel_lock(chan); 00516 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00517 ast_channel_unlock(chan); 00518 00519 csth.volfactor = *volfactor; 00520 00521 if (csth.volfactor) { 00522 csth.spy_audiohook.options.read_volume = csth.volfactor; 00523 csth.spy_audiohook.options.write_volume = csth.volfactor; 00524 } 00525 00526 csth.fd = fd; 00527 00528 if (ast_test_flag(flags, OPTION_PRIVATE)) 00529 silgen = ast_channel_start_silence_generator(chan); 00530 else 00531 ast_activate_generator(chan, &spygen, &csth); 00532 00533 /* We can no longer rely on 'spyee' being an actual channel; 00534 it can be hung up and freed out from under us. However, the 00535 channel destructor will put NULL into our csth.spy.chan 00536 field when that happens, so that is our signal that the spyee 00537 channel has gone away. 00538 */ 00539 00540 /* Note: it is very important that the ast_waitfor() be the first 00541 condition in this expression, so that if we wait for some period 00542 of time before receiving a frame from our spying channel, we check 00543 for hangup on the spied-on channel _after_ knowing that a frame 00544 has arrived, since the spied-on channel could have gone away while 00545 we were waiting 00546 */ 00547 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00548 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00549 running = -1; 00550 break; 00551 } 00552 00553 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { 00554 ast_audiohook_lock(&csth.whisper_audiohook); 00555 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00556 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00557 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00558 ast_audiohook_unlock(&csth.whisper_audiohook); 00559 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00560 ast_frfree(f); 00561 continue; 00562 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { 00563 ast_audiohook_lock(&csth.whisper_audiohook); 00564 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00565 ast_audiohook_unlock(&csth.whisper_audiohook); 00566 ast_frfree(f); 00567 continue; 00568 } 00569 00570 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00571 ast_frfree(f); 00572 if (!res) 00573 continue; 00574 00575 if (x == sizeof(inp)) 00576 x = 0; 00577 00578 if (res < 0) { 00579 running = -1; 00580 break; 00581 } 00582 00583 if (ast_test_flag(flags, OPTION_EXIT)) { 00584 char tmp[2]; 00585 tmp[0] = res; 00586 tmp[1] = '\0'; 00587 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00588 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); 00589 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); 00590 running = -2; 00591 break; 00592 } else { 00593 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00594 } 00595 } else if (res >= '0' && res <= '9') { 00596 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { 00597 change_spy_mode(res, flags); 00598 } else { 00599 inp[x++] = res; 00600 } 00601 } 00602 00603 if (res == '*') { 00604 running = 0; 00605 break; 00606 } else if (res == '#') { 00607 if (!ast_strlen_zero(inp)) { 00608 running = atoi(inp); 00609 break; 00610 } 00611 00612 (*volfactor)++; 00613 if (*volfactor > 4) 00614 *volfactor = -4; 00615 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00616 00617 csth.volfactor = *volfactor; 00618 csth.spy_audiohook.options.read_volume = csth.volfactor; 00619 csth.spy_audiohook.options.write_volume = csth.volfactor; 00620 } 00621 } 00622 00623 if (ast_test_flag(flags, OPTION_PRIVATE)) 00624 ast_channel_stop_silence_generator(chan, silgen); 00625 else 00626 ast_deactivate_generator(chan); 00627 00628 ast_channel_lock(chan); 00629 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00630 ast_channel_unlock(chan); 00631 00632 ast_audiohook_lock(&csth.whisper_audiohook); 00633 ast_audiohook_detach(&csth.whisper_audiohook); 00634 ast_audiohook_unlock(&csth.whisper_audiohook); 00635 ast_audiohook_destroy(&csth.whisper_audiohook); 00636 00637 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00638 ast_audiohook_detach(&csth.bridge_whisper_audiohook); 00639 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00640 ast_audiohook_destroy(&csth.bridge_whisper_audiohook); 00641 00642 ast_audiohook_lock(&csth.spy_audiohook); 00643 ast_audiohook_detach(&csth.spy_audiohook); 00644 ast_audiohook_unlock(&csth.spy_audiohook); 00645 ast_audiohook_destroy(&csth.spy_audiohook); 00646 00647 ast_verb(2, "Done Spying on channel %s\n", name); 00648 manager_event(EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name); 00649 00650 return running; 00651 }
| static void chanspy_ds_chan_fixup | ( | void * | data, | |
| struct ast_channel * | old_chan, | |||
| struct ast_channel * | new_chan | |||
| ) | [static] |
Definition at line 670 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
00671 { 00672 struct chanspy_ds *chanspy_ds = data; 00673 00674 ast_mutex_lock(&chanspy_ds->lock); 00675 chanspy_ds->chan = new_chan; 00676 ast_mutex_unlock(&chanspy_ds->lock); 00677 }
| static void chanspy_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 657 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
Referenced by chanspy_ds_free().
00658 { 00659 struct chanspy_ds *chanspy_ds = data; 00660 00661 /* Setting chan to be NULL is an atomic operation, but we don't want this 00662 * value to change while this lock is held. The lock is held elsewhere 00663 * while it performs non-atomic operations with this channel pointer */ 00664 00665 ast_mutex_lock(&chanspy_ds->lock); 00666 chanspy_ds->chan = NULL; 00667 ast_mutex_unlock(&chanspy_ds->lock); 00668 }
| static struct chanspy_ds* chanspy_ds_free | ( | struct chanspy_ds * | chanspy_ds | ) | [static, read] |
Definition at line 685 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(), ast_datastore::data, DEADLOCK_AVOIDANCE, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and setup_chanspy_ds().
00686 { 00687 struct ast_channel *chan; 00688 00689 if (!chanspy_ds) { 00690 return NULL; 00691 } 00692 00693 ast_mutex_lock(&chanspy_ds->lock); 00694 while ((chan = chanspy_ds->chan)) { 00695 struct ast_datastore *datastore; 00696 00697 if (ast_channel_trylock(chan)) { 00698 DEADLOCK_AVOIDANCE(&chanspy_ds->lock); 00699 continue; 00700 } 00701 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) { 00702 ast_channel_datastore_remove(chan, datastore); 00703 /* chanspy_ds->chan is NULL after this call */ 00704 chanspy_ds_destroy(datastore->data); 00705 datastore->data = NULL; 00706 ast_datastore_free(datastore); 00707 } 00708 ast_channel_unlock(chan); 00709 break; 00710 } 00711 ast_mutex_unlock(&chanspy_ds->lock); 00712 00713 return NULL; 00714 }
| static int chanspy_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 1037 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, common_exec(), 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().
01038 { 01039 char *myenforced = NULL; 01040 char *mygroup = NULL; 01041 char *recbase = NULL; 01042 int fd = 0; 01043 struct ast_flags flags; 01044 int oldwf = 0; 01045 int volfactor = 0; 01046 int res; 01047 char *mailbox = NULL; 01048 char *name_context = NULL; 01049 AST_DECLARE_APP_ARGS(args, 01050 AST_APP_ARG(spec); 01051 AST_APP_ARG(options); 01052 ); 01053 char *opts[OPT_ARG_ARRAY_SIZE]; 01054 01055 data = ast_strdupa(data); 01056 AST_STANDARD_APP_ARGS(args, data); 01057 01058 if (args.spec && !strcmp(args.spec, "all")) 01059 args.spec = NULL; 01060 01061 if (args.options) { 01062 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01063 if (ast_test_flag(&flags, OPTION_GROUP)) 01064 mygroup = opts[OPT_ARG_GROUP]; 01065 01066 if (ast_test_flag(&flags, OPTION_RECORD) && 01067 !(recbase = opts[OPT_ARG_RECORD])) 01068 recbase = "chanspy"; 01069 01070 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01071 int vol; 01072 01073 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01074 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01075 else 01076 volfactor = vol; 01077 } 01078 01079 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01080 ast_set_flag(&flags, OPTION_WHISPER); 01081 01082 if (ast_test_flag(&flags, OPTION_ENFORCED)) 01083 myenforced = opts[OPT_ARG_ENFORCED]; 01084 01085 if (ast_test_flag(&flags, OPTION_NAME)) { 01086 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01087 char *delimiter; 01088 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01089 mailbox = opts[OPT_ARG_NAME]; 01090 *delimiter++ = '\0'; 01091 name_context = delimiter; 01092 } else { 01093 mailbox = opts[OPT_ARG_NAME]; 01094 } 01095 } 01096 } 01097 01098 01099 } else 01100 ast_clear_flag(&flags, AST_FLAGS_ALL); 01101 01102 oldwf = chan->writeformat; 01103 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01104 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01105 return -1; 01106 } 01107 01108 if (recbase) { 01109 char filename[PATH_MAX]; 01110 01111 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01112 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01113 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01114 fd = 0; 01115 } 01116 } 01117 01118 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); 01119 01120 if (fd) 01121 close(fd); 01122 01123 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01124 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01125 01126 return res; 01127 }
| 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 768 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(), channel_spy(), chanspy_ds_free(), ast_channel::context, exitcontext, ext, ast_channel::language, 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().
00772 { 00773 char nameprefix[AST_NAME_STRLEN]; 00774 char peer_name[AST_NAME_STRLEN + 5]; 00775 char exitcontext[AST_MAX_CONTEXT] = ""; 00776 signed char zero_volume = 0; 00777 int waitms; 00778 int res; 00779 char *ptr; 00780 int num; 00781 int num_spyed_upon = 1; 00782 struct chanspy_ds chanspy_ds = { 0, }; 00783 00784 if (ast_test_flag(flags, OPTION_EXIT)) { 00785 const char *c; 00786 ast_channel_lock(chan); 00787 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { 00788 ast_copy_string(exitcontext, c, sizeof(exitcontext)); 00789 } else if (!ast_strlen_zero(chan->macrocontext)) { 00790 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 00791 } else { 00792 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 00793 } 00794 ast_channel_unlock(chan); 00795 } 00796 00797 ast_mutex_init(&chanspy_ds.lock); 00798 00799 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); 00800 00801 if (chan->_state != AST_STATE_UP) 00802 ast_answer(chan); 00803 00804 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00805 00806 waitms = 100; 00807 00808 for (;;) { 00809 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; 00810 struct ast_channel *prev = NULL, *peer = NULL; 00811 00812 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00813 res = ast_streamfile(chan, "beep", chan->language); 00814 if (!res) 00815 res = ast_waitstream(chan, ""); 00816 else if (res < 0) { 00817 ast_clear_flag(chan, AST_FLAG_SPYING); 00818 break; 00819 } 00820 if (!ast_strlen_zero(exitcontext)) { 00821 char tmp[2]; 00822 tmp[0] = res; 00823 tmp[1] = '\0'; 00824 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00825 goto exit; 00826 else 00827 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00828 } 00829 } 00830 00831 res = ast_waitfordigit(chan, waitms); 00832 if (res < 0) { 00833 ast_clear_flag(chan, AST_FLAG_SPYING); 00834 break; 00835 } 00836 if (!ast_strlen_zero(exitcontext)) { 00837 char tmp[2]; 00838 tmp[0] = res; 00839 tmp[1] = '\0'; 00840 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00841 goto exit; 00842 else 00843 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00844 } 00845 00846 /* reset for the next loop around, unless overridden later */ 00847 waitms = 100; 00848 num_spyed_upon = 0; 00849 00850 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); 00851 peer_chanspy_ds; 00852 chanspy_ds_free(peer_chanspy_ds), prev = peer, 00853 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 00854 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { 00855 int igrp = !mygroup; 00856 int ienf = !myenforced; 00857 char *s; 00858 00859 peer = peer_chanspy_ds->chan; 00860 00861 ast_mutex_unlock(&peer_chanspy_ds->lock); 00862 00863 if (peer == prev) { 00864 ast_channel_unlock(peer); 00865 chanspy_ds_free(peer_chanspy_ds); 00866 break; 00867 } 00868 00869 if (ast_check_hangup(chan)) { 00870 ast_channel_unlock(peer); 00871 chanspy_ds_free(peer_chanspy_ds); 00872 break; 00873 } 00874 00875 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { 00876 ast_channel_unlock(peer); 00877 continue; 00878 } 00879 00880 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { 00881 ast_channel_unlock(peer); 00882 continue; 00883 } 00884 00885 if (mygroup) { 00886 int num_groups = 0; 00887 int num_mygroups = 0; 00888 char dup_group[512]; 00889 char dup_mygroup[512]; 00890 char *groups[NUM_SPYGROUPS]; 00891 char *mygroups[NUM_SPYGROUPS]; 00892 const char *group; 00893 int x; 00894 int y; 00895 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); 00896 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, 00897 ARRAY_LEN(mygroups)); 00898 00899 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00900 ast_copy_string(dup_group, group, sizeof(dup_group)); 00901 num_groups = ast_app_separate_args(dup_group, ':', groups, 00902 ARRAY_LEN(groups)); 00903 } 00904 00905 for (y = 0; y < num_mygroups; y++) { 00906 for (x = 0; x < num_groups; x++) { 00907 if (!strcmp(mygroups[y], groups[x])) { 00908 igrp = 1; 00909 break; 00910 } 00911 } 00912 } 00913 } 00914 00915 if (!igrp) { 00916 ast_channel_unlock(peer); 00917 continue; 00918 } 00919 00920 if (myenforced) { 00921 char ext[AST_CHANNEL_NAME + 3]; 00922 char buffer[512]; 00923 char *end; 00924 00925 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); 00926 00927 ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1); 00928 if ((end = strchr(ext, '-'))) { 00929 *end++ = ':'; 00930 *end = '\0'; 00931 } 00932 00933 ext[0] = ':'; 00934 00935 if (strcasestr(buffer, ext)) { 00936 ienf = 1; 00937 } 00938 } 00939 00940 if (!ienf) { 00941 ast_channel_unlock(peer); 00942 continue; 00943 } 00944 00945 strcpy(peer_name, "spy-"); 00946 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); 00947 ptr = strchr(peer_name, '/'); 00948 *ptr++ = '\0'; 00949 ptr = strsep(&ptr, "-"); 00950 00951 for (s = peer_name; s < ptr; s++) 00952 *s = tolower(*s); 00953 /* We have to unlock the peer channel here to avoid a deadlock. 00954 * So, when we need to dereference it again, we have to lock the 00955 * datastore and get the pointer from there to see if the channel 00956 * is still valid. */ 00957 ast_channel_unlock(peer); 00958 00959 if (!ast_test_flag(flags, OPTION_QUIET)) { 00960 if (ast_test_flag(flags, OPTION_NAME)) { 00961 const char *local_context = S_OR(name_context, "default"); 00962 const char *local_mailbox = S_OR(mailbox, ptr); 00963 res = ast_app_sayname(chan, local_mailbox, local_context); 00964 } 00965 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { 00966 if (!ast_test_flag(flags, OPTION_NOTECH)) { 00967 if (ast_fileexists(peer_name, NULL, NULL) > 0) { 00968 res = ast_streamfile(chan, peer_name, chan->language); 00969 if (!res) { 00970 res = ast_waitstream(chan, ""); 00971 } 00972 if (res) { 00973 chanspy_ds_free(peer_chanspy_ds); 00974 break; 00975 } 00976 } else { 00977 res = ast_say_character_str(chan, peer_name, "", chan->language); 00978 } 00979 } 00980 if ((num = atoi(ptr))) 00981 ast_say_digits(chan, atoi(ptr), "", chan->language); 00982 } 00983 } 00984 00985 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); 00986 num_spyed_upon++; 00987 00988 if (res == -1) { 00989 chanspy_ds_free(peer_chanspy_ds); 00990 goto exit; 00991 } else if (res == -2) { 00992 res = 0; 00993 chanspy_ds_free(peer_chanspy_ds); 00994 goto exit; 00995 } else if (res > 1 && spec) { 00996 struct ast_channel *next; 00997 00998 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00999 01000 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 01001 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); 01002 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); 01003 } else { 01004 /* stay on this channel, if it is still valid */ 01005 01006 ast_mutex_lock(&peer_chanspy_ds->lock); 01007 if (peer_chanspy_ds->chan) { 01008 ast_channel_lock(peer_chanspy_ds->chan); 01009 next_chanspy_ds = peer_chanspy_ds; 01010 peer_chanspy_ds = NULL; 01011 } else { 01012 /* the channel is gone */ 01013 ast_mutex_unlock(&peer_chanspy_ds->lock); 01014 next_chanspy_ds = NULL; 01015 } 01016 } 01017 01018 peer = NULL; 01019 } 01020 } 01021 if (res == -1 || ast_check_hangup(chan)) 01022 break; 01023 } 01024 exit: 01025 01026 ast_clear_flag(chan, AST_FLAG_SPYING); 01027 01028 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 01029 01030 ast_mutex_lock(&chanspy_ds.lock); 01031 ast_mutex_unlock(&chanspy_ds.lock); 01032 ast_mutex_destroy(&chanspy_ds.lock); 01033 01034 return res; 01035 }
| static int extenspy_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 1129 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, common_exec(), ast_channel::context, context, exten, 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().
01130 { 01131 char *ptr, *exten = NULL; 01132 char *mygroup = NULL; 01133 char *recbase = NULL; 01134 int fd = 0; 01135 struct ast_flags flags; 01136 int oldwf = 0; 01137 int volfactor = 0; 01138 int res; 01139 char *mailbox = NULL; 01140 char *name_context = NULL; 01141 AST_DECLARE_APP_ARGS(args, 01142 AST_APP_ARG(context); 01143 AST_APP_ARG(options); 01144 ); 01145 01146 data = ast_strdupa(data); 01147 01148 AST_STANDARD_APP_ARGS(args, data); 01149 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { 01150 exten = args.context; 01151 *ptr++ = '\0'; 01152 args.context = ptr; 01153 } 01154 01155 if (ast_strlen_zero(args.context)) 01156 args.context = ast_strdupa(chan->context); 01157 01158 if (args.options) { 01159 char *opts[OPT_ARG_ARRAY_SIZE]; 01160 01161 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01162 if (ast_test_flag(&flags, OPTION_GROUP)) 01163 mygroup = opts[OPT_ARG_GROUP]; 01164 01165 if (ast_test_flag(&flags, OPTION_RECORD) && 01166 !(recbase = opts[OPT_ARG_RECORD])) 01167 recbase = "chanspy"; 01168 01169 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01170 int vol; 01171 01172 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01173 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01174 else 01175 volfactor = vol; 01176 } 01177 01178 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01179 ast_set_flag(&flags, OPTION_WHISPER); 01180 01181 01182 if (ast_test_flag(&flags, OPTION_NAME)) { 01183 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01184 char *delimiter; 01185 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01186 mailbox = opts[OPT_ARG_NAME]; 01187 *delimiter++ = '\0'; 01188 name_context = delimiter; 01189 } else { 01190 mailbox = opts[OPT_ARG_NAME]; 01191 } 01192 } 01193 } 01194 01195 } else 01196 ast_clear_flag(&flags, AST_FLAGS_ALL); 01197 01198 oldwf = chan->writeformat; 01199 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01200 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01201 return -1; 01202 } 01203 01204 if (recbase) { 01205 char filename[PATH_MAX]; 01206 01207 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01208 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01209 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01210 fd = 0; 01211 } 01212 } 01213 01214 01215 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); 01216 01217 if (fd) 01218 close(fd); 01219 01220 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01221 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01222 01223 return res; 01224 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1236 of file app_chanspy.c.
References ast_register_application_xml, chanspy_exec(), and extenspy_exec().
01237 { 01238 int res = 0; 01239 01240 res |= ast_register_application_xml(app_chan, chanspy_exec); 01241 res |= ast_register_application_xml(app_ext, extenspy_exec); 01242 01243 return res; 01244 }
| 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, read] |
Definition at line 737 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(), ast_channel::name, ast_channel::next, and setup_chanspy_ds().
Referenced by common_exec().
00740 { 00741 struct ast_channel *next; 00742 const size_t pseudo_len = strlen("DAHDI/pseudo"); 00743 00744 redo: 00745 if (!ast_strlen_zero(spec)) 00746 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00747 else if (!ast_strlen_zero(exten)) 00748 next = ast_walk_channel_by_exten_locked(last, exten, context); 00749 else 00750 next = ast_channel_walk_locked(last); 00751 00752 if (!next) 00753 return NULL; 00754 00755 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) { 00756 last = next; 00757 ast_channel_unlock(next); 00758 goto redo; 00759 } else if (next == chan) { 00760 last = next; 00761 ast_channel_unlock(next); 00762 goto redo; 00763 } 00764 00765 return setup_chanspy_ds(next, chanspy_ds); 00766 }
| static struct chanspy_ds* setup_chanspy_ds | ( | struct ast_channel * | chan, | |
| struct chanspy_ds * | chanspy_ds | |||
| ) | [static, read] |
Definition at line 717 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, chanspy_ds_free(), ast_datastore::data, chanspy_ds::lock, and chanspy_ds::unique_id.
Referenced by common_exec(), and next_channel().
00718 { 00719 struct ast_datastore *datastore = NULL; 00720 00721 ast_mutex_lock(&chanspy_ds->lock); 00722 00723 if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { 00724 ast_mutex_unlock(&chanspy_ds->lock); 00725 chanspy_ds = chanspy_ds_free(chanspy_ds); 00726 ast_channel_unlock(chan); 00727 return NULL; 00728 } 00729 00730 chanspy_ds->chan = chan; 00731 datastore->data = chanspy_ds; 00732 ast_channel_datastore_add(chan, datastore); 00733 00734 return chanspy_ds; 00735 }
| static void* spy_alloc | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 351 of file app_chanspy.c.
00352 { 00353 /* just store the data pointer in the channel structure */ 00354 return data; 00355 }
| static int spy_generate | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | len, | |||
| int | samples | |||
| ) | [static] |
Definition at line 362 of file app_chanspy.c.
References AST_AUDIOHOOK_DIRECTION_BOTH, AST_AUDIOHOOK_DIRECTION_READ, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_unlock, AST_FORMAT_SLINEAR, ast_frfree, AST_LIST_NEXT, ast_log(), ast_test_flag, ast_write(), ast_frame::data, ast_frame::datalen, errno, f, chanspy_translation_helper::fd, chanspy_translation_helper::flags, LOG_WARNING, OPTION_READONLY, ast_frame::ptr, chanspy_translation_helper::spy_audiohook, and ast_audiohook::status.
00363 { 00364 struct chanspy_translation_helper *csth = data; 00365 struct ast_frame *f, *cur; 00366 00367 ast_audiohook_lock(&csth->spy_audiohook); 00368 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) { 00369 /* Channel is already gone more than likely */ 00370 ast_audiohook_unlock(&csth->spy_audiohook); 00371 return -1; 00372 } 00373 00374 if (ast_test_flag(&csth->flags, OPTION_READONLY)) { 00375 /* Option 'o' was set, so don't mix channel audio */ 00376 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR); 00377 } else { 00378 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR); 00379 } 00380 00381 ast_audiohook_unlock(&csth->spy_audiohook); 00382 00383 if (!f) 00384 return 0; 00385 00386 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) { 00387 if (ast_write(chan, cur)) { 00388 ast_frfree(f); 00389 return -1; 00390 } 00391 00392 if (csth->fd) { 00393 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) { 00394 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno)); 00395 } 00396 } 00397 } 00398 00399 ast_frfree(f); 00400 00401 return 0; 00402 }
| 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 410 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, LOG_NOTICE, and ast_channel::name.
Referenced by channel_spy().
00411 { 00412 int res = 0; 00413 struct ast_channel *peer = NULL; 00414 00415 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name); 00416 00417 ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE); 00418 res = ast_audiohook_attach(chan, audiohook); 00419 00420 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) { 00421 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00422 } 00423 return res; 00424 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1226 of file app_chanspy.c.
References ast_unregister_application().
01227 { 01228 int res = 0; 01229 01230 res |= ast_unregister_application(app_chan); 01231 res |= ast_unregister_application(app_ext); 01232 01233 return res; 01234 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 1246 of file app_chanspy.c.
const char* app_chan = "ChanSpy" [static] |
Definition at line 292 of file app_chanspy.c.
const char* app_ext = "ExtenSpy" [static] |
Definition at line 294 of file app_chanspy.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1246 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 679 of file app_chanspy.c.
| enum { ... } chanspy_opt_args |
| enum { ... } chanspy_opt_flags |
int next_unique_id_to_use = 0 [static] |
Definition at line 339 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 404 of file app_chanspy.c.
1.5.6