#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 = 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 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" |
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 1119 of file app_chanspy.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1119 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, 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_deactivate_generator(), ast_debug, AST_FLAG_END_DTMF_ONLY, 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, f, chanspy_translation_helper::fd, ast_frame::frametype, chanspy_ds::lock, LOG_WARNING, 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().
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 00367 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy"); 00368 00369 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) { 00370 ast_audiohook_destroy(&csth.spy_audiohook); 00371 ast_channel_unlock(spyee); 00372 return 0; 00373 } 00374 00375 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy"); 00376 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy"); 00377 if (start_spying(spyee, spyer_name, &csth.whisper_audiohook)) { 00378 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", spyee->name); 00379 } 00380 if ((spyee_bridge = ast_bridged_channel(spyee))) { 00381 ast_channel_lock(spyee_bridge); 00382 if (start_spying(spyee_bridge, spyer_name, &csth.bridge_whisper_audiohook)) { 00383 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", spyee->name); 00384 } 00385 ast_channel_unlock(spyee_bridge); 00386 } 00387 ast_channel_unlock(spyee); 00388 spyee = NULL; 00389 00390 ast_channel_lock(chan); 00391 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY); 00392 ast_channel_unlock(chan); 00393 00394 csth.volfactor = *volfactor; 00395 00396 if (csth.volfactor) { 00397 csth.spy_audiohook.options.read_volume = csth.volfactor; 00398 csth.spy_audiohook.options.write_volume = csth.volfactor; 00399 } 00400 00401 csth.fd = fd; 00402 00403 if (ast_test_flag(flags, OPTION_PRIVATE)) 00404 silgen = ast_channel_start_silence_generator(chan); 00405 else 00406 ast_activate_generator(chan, &spygen, &csth); 00407 00408 /* We can no longer rely on 'spyee' being an actual channel; 00409 it can be hung up and freed out from under us. However, the 00410 channel destructor will put NULL into our csth.spy.chan 00411 field when that happens, so that is our signal that the spyee 00412 channel has gone away. 00413 */ 00414 00415 /* Note: it is very important that the ast_waitfor() be the first 00416 condition in this expression, so that if we wait for some period 00417 of time before receiving a frame from our spying channel, we check 00418 for hangup on the spied-on channel _after_ knowing that a frame 00419 has arrived, since the spied-on channel could have gone away while 00420 we were waiting 00421 */ 00422 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) { 00423 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) { 00424 running = -1; 00425 break; 00426 } 00427 00428 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) { 00429 ast_audiohook_lock(&csth.whisper_audiohook); 00430 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00431 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00432 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00433 ast_audiohook_unlock(&csth.whisper_audiohook); 00434 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00435 ast_frfree(f); 00436 continue; 00437 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) { 00438 ast_audiohook_lock(&csth.whisper_audiohook); 00439 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f); 00440 ast_audiohook_unlock(&csth.whisper_audiohook); 00441 ast_frfree(f); 00442 continue; 00443 } 00444 00445 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0; 00446 ast_frfree(f); 00447 if (!res) 00448 continue; 00449 00450 if (x == sizeof(inp)) 00451 x = 0; 00452 00453 if (res < 0) { 00454 running = -1; 00455 break; 00456 } 00457 00458 if (ast_test_flag(flags, OPTION_EXIT)) { 00459 char tmp[2]; 00460 tmp[0] = res; 00461 tmp[1] = '\0'; 00462 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) { 00463 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext); 00464 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name); 00465 running = -2; 00466 break; 00467 } else { 00468 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00469 } 00470 } else if (res >= '0' && res <= '9') { 00471 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) { 00472 change_spy_mode(res, flags); 00473 } else { 00474 inp[x++] = res; 00475 } 00476 } 00477 00478 if (res == '*') { 00479 running = 0; 00480 break; 00481 } else if (res == '#') { 00482 if (!ast_strlen_zero(inp)) { 00483 running = atoi(inp); 00484 break; 00485 } 00486 00487 (*volfactor)++; 00488 if (*volfactor > 4) 00489 *volfactor = -4; 00490 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor); 00491 00492 csth.volfactor = *volfactor; 00493 csth.spy_audiohook.options.read_volume = csth.volfactor; 00494 csth.spy_audiohook.options.write_volume = csth.volfactor; 00495 } 00496 } 00497 00498 if (ast_test_flag(flags, OPTION_PRIVATE)) 00499 ast_channel_stop_silence_generator(chan, silgen); 00500 else 00501 ast_deactivate_generator(chan); 00502 00503 ast_channel_lock(chan); 00504 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY); 00505 ast_channel_unlock(chan); 00506 00507 ast_audiohook_lock(&csth.whisper_audiohook); 00508 ast_audiohook_detach(&csth.whisper_audiohook); 00509 ast_audiohook_unlock(&csth.whisper_audiohook); 00510 ast_audiohook_destroy(&csth.whisper_audiohook); 00511 00512 ast_audiohook_lock(&csth.bridge_whisper_audiohook); 00513 ast_audiohook_detach(&csth.bridge_whisper_audiohook); 00514 ast_audiohook_unlock(&csth.bridge_whisper_audiohook); 00515 ast_audiohook_destroy(&csth.bridge_whisper_audiohook); 00516 00517 ast_audiohook_lock(&csth.spy_audiohook); 00518 ast_audiohook_detach(&csth.spy_audiohook); 00519 ast_audiohook_unlock(&csth.spy_audiohook); 00520 ast_audiohook_destroy(&csth.spy_audiohook); 00521 00522 ast_verb(2, "Done Spying on channel %s\n", name); 00523 00524 return running; 00525 }
| static void chanspy_ds_chan_fixup | ( | void * | data, | |
| struct ast_channel * | old_chan, | |||
| struct ast_channel * | new_chan | |||
| ) | [static] |
Definition at line 544 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
00545 { 00546 struct chanspy_ds *chanspy_ds = data; 00547 00548 ast_mutex_lock(&chanspy_ds->lock); 00549 chanspy_ds->chan = new_chan; 00550 ast_mutex_unlock(&chanspy_ds->lock); 00551 }
| static void chanspy_ds_destroy | ( | void * | data | ) | [static] |
Definition at line 531 of file app_chanspy.c.
References ast_mutex_lock(), ast_mutex_unlock(), chanspy_ds::chan, and chanspy_ds::lock.
Referenced by chanspy_ds_free().
00532 { 00533 struct chanspy_ds *chanspy_ds = data; 00534 00535 /* Setting chan to be NULL is an atomic operation, but we don't want this 00536 * value to change while this lock is held. The lock is held elsewhere 00537 * while it performs non-atomic operations with this channel pointer */ 00538 00539 ast_mutex_lock(&chanspy_ds->lock); 00540 chanspy_ds->chan = NULL; 00541 ast_mutex_unlock(&chanspy_ds->lock); 00542 }
| static struct chanspy_ds* chanspy_ds_free | ( | struct chanspy_ds * | chanspy_ds | ) | [static, read] |
Definition at line 559 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().
00560 { 00561 struct ast_channel *chan; 00562 00563 if (!chanspy_ds) { 00564 return NULL; 00565 } 00566 00567 ast_mutex_lock(&chanspy_ds->lock); 00568 while ((chan = chanspy_ds->chan)) { 00569 struct ast_datastore *datastore; 00570 00571 if (ast_channel_trylock(chan)) { 00572 DEADLOCK_AVOIDANCE(&chanspy_ds->lock); 00573 continue; 00574 } 00575 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) { 00576 ast_channel_datastore_remove(chan, datastore); 00577 /* chanspy_ds->chan is NULL after this call */ 00578 chanspy_ds_destroy(datastore->data); 00579 datastore->data = NULL; 00580 ast_datastore_free(datastore); 00581 } 00582 ast_channel_unlock(chan); 00583 break; 00584 } 00585 ast_mutex_unlock(&chanspy_ds->lock); 00586 00587 return NULL; 00588 }
| static int chanspy_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 910 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().
00911 { 00912 char *myenforced = NULL; 00913 char *mygroup = NULL; 00914 char *recbase = NULL; 00915 int fd = 0; 00916 struct ast_flags flags; 00917 int oldwf = 0; 00918 int volfactor = 0; 00919 int res; 00920 char *mailbox = NULL; 00921 char *name_context = NULL; 00922 AST_DECLARE_APP_ARGS(args, 00923 AST_APP_ARG(spec); 00924 AST_APP_ARG(options); 00925 ); 00926 char *opts[OPT_ARG_ARRAY_SIZE]; 00927 00928 data = ast_strdupa(data); 00929 AST_STANDARD_APP_ARGS(args, data); 00930 00931 if (args.spec && !strcmp(args.spec, "all")) 00932 args.spec = NULL; 00933 00934 if (args.options) { 00935 ast_app_parse_options(spy_opts, &flags, opts, args.options); 00936 if (ast_test_flag(&flags, OPTION_GROUP)) 00937 mygroup = opts[OPT_ARG_GROUP]; 00938 00939 if (ast_test_flag(&flags, OPTION_RECORD) && 00940 !(recbase = opts[OPT_ARG_RECORD])) 00941 recbase = "chanspy"; 00942 00943 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 00944 int vol; 00945 00946 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 00947 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 00948 else 00949 volfactor = vol; 00950 } 00951 00952 if (ast_test_flag(&flags, OPTION_PRIVATE)) 00953 ast_set_flag(&flags, OPTION_WHISPER); 00954 00955 if (ast_test_flag(&flags, OPTION_ENFORCED)) 00956 myenforced = opts[OPT_ARG_ENFORCED]; 00957 00958 if (ast_test_flag(&flags, OPTION_NAME)) { 00959 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 00960 char *delimiter; 00961 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 00962 mailbox = opts[OPT_ARG_NAME]; 00963 *delimiter++ = '\0'; 00964 name_context = delimiter; 00965 } else { 00966 mailbox = opts[OPT_ARG_NAME]; 00967 } 00968 } 00969 } 00970 00971 00972 } else 00973 ast_clear_flag(&flags, AST_FLAGS_ALL); 00974 00975 oldwf = chan->writeformat; 00976 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 00977 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00978 return -1; 00979 } 00980 00981 if (recbase) { 00982 char filename[PATH_MAX]; 00983 00984 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 00985 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 00986 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 00987 fd = 0; 00988 } 00989 } 00990 00991 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context); 00992 00993 if (fd) 00994 close(fd); 00995 00996 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 00997 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 00998 00999 return res; 01000 }
| 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 642 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().
00646 { 00647 char nameprefix[AST_NAME_STRLEN]; 00648 char peer_name[AST_NAME_STRLEN + 5]; 00649 char exitcontext[AST_MAX_CONTEXT] = ""; 00650 signed char zero_volume = 0; 00651 int waitms; 00652 int res; 00653 char *ptr; 00654 int num; 00655 int num_spyed_upon = 1; 00656 struct chanspy_ds chanspy_ds = { 0, }; 00657 00658 if (ast_test_flag(flags, OPTION_EXIT)) { 00659 const char *c; 00660 ast_channel_lock(chan); 00661 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) { 00662 ast_copy_string(exitcontext, c, sizeof(exitcontext)); 00663 } else if (!ast_strlen_zero(chan->macrocontext)) { 00664 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext)); 00665 } else { 00666 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext)); 00667 } 00668 ast_channel_unlock(chan); 00669 } 00670 00671 ast_mutex_init(&chanspy_ds.lock); 00672 00673 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1)); 00674 00675 if (chan->_state != AST_STATE_UP) 00676 ast_answer(chan); 00677 00678 ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */ 00679 00680 waitms = 100; 00681 00682 for (;;) { 00683 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL; 00684 struct ast_channel *prev = NULL, *peer = NULL; 00685 00686 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) { 00687 res = ast_streamfile(chan, "beep", chan->language); 00688 if (!res) 00689 res = ast_waitstream(chan, ""); 00690 else if (res < 0) { 00691 ast_clear_flag(chan, AST_FLAG_SPYING); 00692 break; 00693 } 00694 if (!ast_strlen_zero(exitcontext)) { 00695 char tmp[2]; 00696 tmp[0] = res; 00697 tmp[1] = '\0'; 00698 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00699 goto exit; 00700 else 00701 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00702 } 00703 } 00704 00705 res = ast_waitfordigit(chan, waitms); 00706 if (res < 0) { 00707 ast_clear_flag(chan, AST_FLAG_SPYING); 00708 break; 00709 } 00710 if (!ast_strlen_zero(exitcontext)) { 00711 char tmp[2]; 00712 tmp[0] = res; 00713 tmp[1] = '\0'; 00714 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) 00715 goto exit; 00716 else 00717 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext); 00718 } 00719 00720 /* reset for the next loop around, unless overridden later */ 00721 waitms = 100; 00722 num_spyed_upon = 0; 00723 00724 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds); 00725 peer_chanspy_ds; 00726 chanspy_ds_free(peer_chanspy_ds), prev = peer, 00727 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds : 00728 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) { 00729 int igrp = !mygroup; 00730 int ienf = !myenforced; 00731 char *s; 00732 00733 peer = peer_chanspy_ds->chan; 00734 00735 ast_mutex_unlock(&peer_chanspy_ds->lock); 00736 00737 if (peer == prev) { 00738 ast_channel_unlock(peer); 00739 chanspy_ds_free(peer_chanspy_ds); 00740 break; 00741 } 00742 00743 if (ast_check_hangup(chan)) { 00744 ast_channel_unlock(peer); 00745 chanspy_ds_free(peer_chanspy_ds); 00746 break; 00747 } 00748 00749 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) { 00750 ast_channel_unlock(peer); 00751 continue; 00752 } 00753 00754 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) { 00755 ast_channel_unlock(peer); 00756 continue; 00757 } 00758 00759 if (mygroup) { 00760 int num_groups = 0; 00761 int num_mygroups = 0; 00762 char dup_group[512]; 00763 char dup_mygroup[512]; 00764 char *groups[NUM_SPYGROUPS]; 00765 char *mygroups[NUM_SPYGROUPS]; 00766 const char *group; 00767 int x; 00768 int y; 00769 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup)); 00770 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups, 00771 ARRAY_LEN(mygroups)); 00772 00773 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) { 00774 ast_copy_string(dup_group, group, sizeof(dup_group)); 00775 num_groups = ast_app_separate_args(dup_group, ':', groups, 00776 ARRAY_LEN(groups)); 00777 } 00778 00779 for (y = 0; y < num_mygroups; y++) { 00780 for (x = 0; x < num_groups; x++) { 00781 if (!strcmp(mygroups[y], groups[x])) { 00782 igrp = 1; 00783 break; 00784 } 00785 } 00786 } 00787 } 00788 00789 if (!igrp) { 00790 ast_channel_unlock(peer); 00791 continue; 00792 } 00793 00794 if (myenforced) { 00795 char ext[AST_CHANNEL_NAME + 3]; 00796 char buffer[512]; 00797 char *end; 00798 00799 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced); 00800 00801 ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1); 00802 if ((end = strchr(ext, '-'))) { 00803 *end++ = ':'; 00804 *end = '\0'; 00805 } 00806 00807 ext[0] = ':'; 00808 00809 if (strcasestr(buffer, ext)) { 00810 ienf = 1; 00811 } 00812 } 00813 00814 if (!ienf) { 00815 continue; 00816 } 00817 00818 strcpy(peer_name, "spy-"); 00819 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1); 00820 ptr = strchr(peer_name, '/'); 00821 *ptr++ = '\0'; 00822 ptr = strsep(&ptr, "-"); 00823 00824 for (s = peer_name; s < ptr; s++) 00825 *s = tolower(*s); 00826 /* We have to unlock the peer channel here to avoid a deadlock. 00827 * So, when we need to dereference it again, we have to lock the 00828 * datastore and get the pointer from there to see if the channel 00829 * is still valid. */ 00830 ast_channel_unlock(peer); 00831 00832 if (!ast_test_flag(flags, OPTION_QUIET)) { 00833 if (ast_test_flag(flags, OPTION_NAME)) { 00834 const char *local_context = S_OR(name_context, "default"); 00835 const char *local_mailbox = S_OR(mailbox, ptr); 00836 res = ast_app_sayname(chan, local_mailbox, local_context); 00837 } 00838 if (!ast_test_flag(flags, OPTION_NAME) || res < 0) { 00839 if (!ast_test_flag(flags, OPTION_NOTECH)) { 00840 if (ast_fileexists(peer_name, NULL, NULL) != -1) { 00841 res = ast_streamfile(chan, peer_name, chan->language); 00842 if (!res) { 00843 res = ast_waitstream(chan, ""); 00844 } 00845 if (res) { 00846 chanspy_ds_free(peer_chanspy_ds); 00847 break; 00848 } 00849 } else { 00850 res = ast_say_character_str(chan, peer_name, "", chan->language); 00851 } 00852 } 00853 if ((num = atoi(ptr))) 00854 ast_say_digits(chan, atoi(ptr), "", chan->language); 00855 } 00856 } 00857 00858 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext); 00859 num_spyed_upon++; 00860 00861 if (res == -1) { 00862 chanspy_ds_free(peer_chanspy_ds); 00863 goto exit; 00864 } else if (res == -2) { 00865 res = 0; 00866 chanspy_ds_free(peer_chanspy_ds); 00867 goto exit; 00868 } else if (res > 1 && spec) { 00869 struct ast_channel *next; 00870 00871 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res); 00872 00873 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) { 00874 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds); 00875 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds); 00876 } else { 00877 /* stay on this channel, if it is still valid */ 00878 00879 ast_mutex_lock(&peer_chanspy_ds->lock); 00880 if (peer_chanspy_ds->chan) { 00881 ast_channel_lock(peer_chanspy_ds->chan); 00882 next_chanspy_ds = peer_chanspy_ds; 00883 peer_chanspy_ds = NULL; 00884 } else { 00885 /* the channel is gone */ 00886 ast_mutex_unlock(&peer_chanspy_ds->lock); 00887 next_chanspy_ds = NULL; 00888 } 00889 } 00890 00891 peer = NULL; 00892 } 00893 } 00894 if (res == -1 || ast_check_hangup(chan)) 00895 break; 00896 } 00897 exit: 00898 00899 ast_clear_flag(chan, AST_FLAG_SPYING); 00900 00901 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0); 00902 00903 ast_mutex_lock(&chanspy_ds.lock); 00904 ast_mutex_unlock(&chanspy_ds.lock); 00905 ast_mutex_destroy(&chanspy_ds.lock); 00906 00907 return res; 00908 }
| static int extenspy_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 1002 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().
01003 { 01004 char *ptr, *exten = NULL; 01005 char *mygroup = NULL; 01006 char *recbase = NULL; 01007 int fd = 0; 01008 struct ast_flags flags; 01009 int oldwf = 0; 01010 int volfactor = 0; 01011 int res; 01012 char *mailbox = NULL; 01013 char *name_context = NULL; 01014 AST_DECLARE_APP_ARGS(args, 01015 AST_APP_ARG(context); 01016 AST_APP_ARG(options); 01017 ); 01018 01019 data = ast_strdupa(data); 01020 01021 AST_STANDARD_APP_ARGS(args, data); 01022 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) { 01023 exten = args.context; 01024 *ptr++ = '\0'; 01025 args.context = ptr; 01026 } 01027 01028 if (ast_strlen_zero(args.context)) 01029 args.context = ast_strdupa(chan->context); 01030 01031 if (args.options) { 01032 char *opts[OPT_ARG_ARRAY_SIZE]; 01033 01034 ast_app_parse_options(spy_opts, &flags, opts, args.options); 01035 if (ast_test_flag(&flags, OPTION_GROUP)) 01036 mygroup = opts[OPT_ARG_GROUP]; 01037 01038 if (ast_test_flag(&flags, OPTION_RECORD) && 01039 !(recbase = opts[OPT_ARG_RECORD])) 01040 recbase = "chanspy"; 01041 01042 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) { 01043 int vol; 01044 01045 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4)) 01046 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n"); 01047 else 01048 volfactor = vol; 01049 } 01050 01051 if (ast_test_flag(&flags, OPTION_PRIVATE)) 01052 ast_set_flag(&flags, OPTION_WHISPER); 01053 01054 01055 if (ast_test_flag(&flags, OPTION_NAME)) { 01056 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) { 01057 char *delimiter; 01058 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) { 01059 mailbox = opts[OPT_ARG_NAME]; 01060 *delimiter++ = '\0'; 01061 name_context = delimiter; 01062 } else { 01063 mailbox = opts[OPT_ARG_NAME]; 01064 } 01065 } 01066 } 01067 01068 } else 01069 ast_clear_flag(&flags, AST_FLAGS_ALL); 01070 01071 oldwf = chan->writeformat; 01072 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) { 01073 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01074 return -1; 01075 } 01076 01077 if (recbase) { 01078 char filename[PATH_MAX]; 01079 01080 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL)); 01081 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) { 01082 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename); 01083 fd = 0; 01084 } 01085 } 01086 01087 01088 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context, mailbox, name_context); 01089 01090 if (fd) 01091 close(fd); 01092 01093 if (oldwf && ast_set_write_format(chan, oldwf) < 0) 01094 ast_log(LOG_ERROR, "Could Not Set Write Format.\n"); 01095 01096 return res; 01097 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1109 of file app_chanspy.c.
References ast_register_application, chanspy_exec(), and extenspy_exec().
01110 { 01111 int res = 0; 01112 01113 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan); 01114 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext); 01115 01116 return res; 01117 }
| 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 611 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().
00614 { 00615 struct ast_channel *next; 00616 const size_t pseudo_len = strlen("DAHDI/pseudo"); 00617 00618 redo: 00619 if (!ast_strlen_zero(spec)) 00620 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec)); 00621 else if (!ast_strlen_zero(exten)) 00622 next = ast_walk_channel_by_exten_locked(last, exten, context); 00623 else 00624 next = ast_channel_walk_locked(last); 00625 00626 if (!next) 00627 return NULL; 00628 00629 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) { 00630 last = next; 00631 ast_channel_unlock(next); 00632 goto redo; 00633 } else if (next == chan) { 00634 last = next; 00635 ast_channel_unlock(next); 00636 goto redo; 00637 } 00638 00639 return setup_chanspy_ds(next, chanspy_ds); 00640 }
| static struct chanspy_ds* setup_chanspy_ds | ( | struct ast_channel * | chan, | |
| struct chanspy_ds * | chanspy_ds | |||
| ) | [static, read] |
Definition at line 591 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().
00592 { 00593 struct ast_datastore *datastore = NULL; 00594 00595 ast_mutex_lock(&chanspy_ds->lock); 00596 00597 if (!(datastore = ast_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) { 00598 ast_mutex_unlock(&chanspy_ds->lock); 00599 chanspy_ds = chanspy_ds_free(chanspy_ds); 00600 ast_channel_unlock(chan); 00601 return NULL; 00602 } 00603 00604 chanspy_ds->chan = chan; 00605 datastore->data = chanspy_ds; 00606 ast_channel_datastore_add(chan, datastore); 00607 00608 return chanspy_ds; 00609 }
| 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(), ast_frame::data, ast_frame::datalen, errno, f, chanspy_translation_helper::fd, ast_frame::frame_list, 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(chan, 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, 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 1099 of file app_chanspy.c.
References ast_unregister_application().
01100 { 01101 int res = 0; 01102 01103 res |= ast_unregister_application(app_chan); 01104 res |= ast_unregister_application(app_ext); 01105 01106 return res; 01107 }
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 1119 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 1119 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 553 of file app_chanspy.c.
| 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.
const char* tdesc = "Listen to a channel, and optionally whisper into it" [static] |
Definition at line 56 of file app_chanspy.c.
1.5.6