00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
00033
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038 #include <ctype.h>
00039
00040 #include "asterisk/file.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/chanspy.h"
00044 #include "asterisk/features.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/say.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/translate.h"
00051 #include "asterisk/module.h"
00052 #include "asterisk/lock.h"
00053
00054 #define AST_NAME_STRLEN 256
00055
00056 static const char *tdesc = "Listen to a channel, and optionally whisper into it";
00057 static const char *app_chan = "ChanSpy";
00058 static const char *desc_chan =
00059 " ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
00060 "audio from an Asterisk channel. This includes the audio coming in and\n"
00061 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
00062 "only channels beginning with this string will be spied upon.\n"
00063 " While spying, the following actions may be performed:\n"
00064 " - Dialing # cycles the volume level.\n"
00065 " - Dialing * will stop spying and look for another channel to spy on.\n"
00066 " - Dialing a series of digits followed by # builds a channel name to append\n"
00067 " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
00068 " the digits '1234#' while spying will begin spying on the channel\n"
00069 " 'Agent/1234'.\n"
00070 " Options:\n"
00071 " b - Only spy on channels involved in a bridged call.\n"
00072 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
00073 " contain 'grp' in an optional : delimited list.\n"
00074 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
00075 " selected channel name.\n"
00076 " r[(basename)] - Record the session to the monitor spool directory. An\n"
00077 " optional base for the filename may be specified. The\n"
00078 " default is 'chanspy'.\n"
00079 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
00080 " negative value refers to a quieter setting.\n"
00081 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
00082 " the spied-on channel.\n"
00083 " W - Enable 'private whisper' mode, so the spying channel can\n"
00084 " talk to the spied-on channel but cannot listen to that\n"
00085 " channel.\n"
00086 ;
00087
00088 static const char *app_ext = "ExtenSpy";
00089 static const char *desc_ext =
00090 " ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
00091 "audio from an Asterisk channel. This includes the audio coming in and\n"
00092 "out of the channel being spied on. Only channels created by outgoing calls for the\n"
00093 "specified extension will be selected for spying. If the optional context is not\n"
00094 "supplied, the current channel's context will be used.\n"
00095 " While spying, the following actions may be performed:\n"
00096 " - Dialing # cycles the volume level.\n"
00097 " - Dialing * will stop spying and look for another channel to spy on.\n"
00098 " Options:\n"
00099 " b - Only spy on channels involved in a bridged call.\n"
00100 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
00101 " contain 'grp' in an optional : delimited list.\n"
00102 " q - Don't play a beep when beginning to spy on a channel, or speak the\n"
00103 " selected channel name.\n"
00104 " r[(basename)] - Record the session to the monitor spool directory. An\n"
00105 " optional base for the filename may be specified. The\n"
00106 " default is 'chanspy'.\n"
00107 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
00108 " negative value refers to a quieter setting.\n"
00109 " w - Enable 'whisper' mode, so the spying channel can talk to\n"
00110 " the spied-on channel.\n"
00111 " W - Enable 'private whisper' mode, so the spying channel can\n"
00112 " talk to the spied-on channel but cannot listen to that\n"
00113 " channel.\n"
00114 ;
00115
00116 enum {
00117 OPTION_QUIET = (1 << 0),
00118 OPTION_BRIDGED = (1 << 1),
00119 OPTION_VOLUME = (1 << 2),
00120 OPTION_GROUP = (1 << 3),
00121 OPTION_RECORD = (1 << 4),
00122 OPTION_WHISPER = (1 << 5),
00123 OPTION_PRIVATE = (1 << 6),
00124 } chanspy_opt_flags;
00125
00126 enum {
00127 OPT_ARG_VOLUME = 0,
00128 OPT_ARG_GROUP,
00129 OPT_ARG_RECORD,
00130 OPT_ARG_ARRAY_SIZE,
00131 } chanspy_opt_args;
00132
00133 AST_APP_OPTIONS(spy_opts, {
00134 AST_APP_OPTION('q', OPTION_QUIET),
00135 AST_APP_OPTION('b', OPTION_BRIDGED),
00136 AST_APP_OPTION('w', OPTION_WHISPER),
00137 AST_APP_OPTION('W', OPTION_PRIVATE),
00138 AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
00139 AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
00140 AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
00141 });
00142
00143
00144 struct chanspy_translation_helper {
00145
00146 struct ast_channel_spy spy;
00147 int fd;
00148 int volfactor;
00149 };
00150
00151 static void *spy_alloc(struct ast_channel *chan, void *data)
00152 {
00153
00154 return data;
00155 }
00156
00157 static void spy_release(struct ast_channel *chan, void *data)
00158 {
00159
00160 }
00161
00162 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
00163 {
00164 struct chanspy_translation_helper *csth = data;
00165 struct ast_frame *f;
00166
00167 if (csth->spy.status != CHANSPY_RUNNING)
00168
00169 return -1;
00170
00171 ast_mutex_lock(&csth->spy.lock);
00172 f = ast_channel_spy_read_frame(&csth->spy, samples);
00173 ast_mutex_unlock(&csth->spy.lock);
00174
00175 if (!f)
00176 return 0;
00177
00178 if (ast_write(chan, f)) {
00179 ast_frfree(f);
00180 return -1;
00181 }
00182
00183 if (csth->fd)
00184 write(csth->fd, f->data, f->datalen);
00185
00186 ast_frfree(f);
00187
00188 return 0;
00189 }
00190
00191 static struct ast_generator spygen = {
00192 .alloc = spy_alloc,
00193 .release = spy_release,
00194 .generate = spy_generate,
00195 };
00196
00197 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy)
00198 {
00199 int res;
00200 struct ast_channel *peer;
00201
00202 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
00203
00204 ast_channel_lock(chan);
00205 res = ast_channel_spy_add(chan, spy);
00206 ast_channel_unlock(chan);
00207
00208 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00209 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00210
00211 return res;
00212 }
00213
00214
00215
00216
00217 static signed char volfactor_map[] = {
00218 -24,
00219 -18,
00220 -12,
00221 -6,
00222 0,
00223 6,
00224 12,
00225 18,
00226 24,
00227 };
00228
00229
00230
00231
00232
00233 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
00234 {
00235 signed char volume_adjust = volfactor_map[csth->volfactor + 4];
00236
00237 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
00238 csth->volfactor = 0;
00239 csth->spy.read_vol_adjustment = csth->volfactor;
00240 csth->spy.write_vol_adjustment = csth->volfactor;
00241 }
00242
00243 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd,
00244 const struct ast_flags *flags)
00245 {
00246 struct chanspy_translation_helper csth;
00247 int running = 0, res, x = 0;
00248 char inp[24] = {0};
00249 char *name;
00250 struct ast_frame *f;
00251 struct ast_silence_generator *silgen = NULL;
00252
00253 if (ast_check_hangup(chan) || ast_check_hangup(spyee))
00254 return 0;
00255
00256 name = ast_strdupa(spyee->name);
00257 if (option_verbose >= 2)
00258 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00259
00260 memset(&csth, 0, sizeof(csth));
00261 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
00262 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
00263 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
00264 csth.spy.type = "ChanSpy";
00265 csth.spy.status = CHANSPY_RUNNING;
00266 csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
00267 csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
00268 ast_mutex_init(&csth.spy.lock);
00269 csth.volfactor = *volfactor;
00270 set_volume(chan, &csth);
00271 if (csth.volfactor) {
00272 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00273 csth.spy.read_vol_adjustment = csth.volfactor;
00274 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00275 csth.spy.write_vol_adjustment = csth.volfactor;
00276 }
00277 csth.fd = fd;
00278
00279 if (start_spying(spyee, chan, &csth.spy)) {
00280 ast_mutex_destroy(&csth.spy.lock);
00281 return 0;
00282 }
00283
00284 if (ast_test_flag(flags, OPTION_WHISPER)) {
00285 struct ast_filestream *beepstream;
00286 int old_write_format = 0;
00287
00288 ast_channel_whisper_start(csth.spy.chan);
00289 old_write_format = chan->writeformat;
00290 if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
00291 struct ast_frame *f;
00292
00293 while ((f = ast_readframe(beepstream))) {
00294 ast_channel_whisper_feed(csth.spy.chan, f);
00295 ast_frfree(f);
00296 }
00297
00298 ast_closestream(beepstream);
00299 chan->stream = NULL;
00300 }
00301 if (old_write_format)
00302 ast_set_write_format(chan, old_write_format);
00303 }
00304
00305 if (ast_test_flag(flags, OPTION_PRIVATE))
00306 silgen = ast_channel_start_silence_generator(chan);
00307 else
00308 ast_activate_generator(chan, &spygen, &csth);
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 while ((res = ast_waitfor(chan, -1) > -1) &&
00325 csth.spy.status == CHANSPY_RUNNING &&
00326 csth.spy.chan) {
00327 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00328 running = -1;
00329 break;
00330 }
00331
00332 if (ast_test_flag(flags, OPTION_WHISPER) &&
00333 (f->frametype == AST_FRAME_VOICE)) {
00334 ast_channel_whisper_feed(csth.spy.chan, f);
00335 ast_frfree(f);
00336 continue;
00337 }
00338
00339 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00340 ast_frfree(f);
00341 if (!res)
00342 continue;
00343
00344 if (x == sizeof(inp))
00345 x = 0;
00346
00347 if (res < 0) {
00348 running = -1;
00349 break;
00350 }
00351
00352 if (res == '*') {
00353 running = 0;
00354 break;
00355 } else if (res == '#') {
00356 if (!ast_strlen_zero(inp)) {
00357 running = atoi(inp);
00358 break;
00359 }
00360
00361 (*volfactor)++;
00362 if (*volfactor > 4)
00363 *volfactor = -4;
00364 if (option_verbose > 2)
00365 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00366 csth.volfactor = *volfactor;
00367 set_volume(chan, &csth);
00368 if (csth.volfactor) {
00369 ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00370 csth.spy.read_vol_adjustment = csth.volfactor;
00371 ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00372 csth.spy.write_vol_adjustment = csth.volfactor;
00373 } else {
00374 ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
00375 ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
00376 }
00377 } else if (res >= '0' && res <= '9') {
00378 inp[x++] = res;
00379 }
00380 }
00381
00382 if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
00383 ast_channel_whisper_stop(csth.spy.chan);
00384
00385 if (ast_test_flag(flags, OPTION_PRIVATE))
00386 ast_channel_stop_silence_generator(chan, silgen);
00387 else
00388 ast_deactivate_generator(chan);
00389
00390
00391 if (csth.spy.chan) {
00392 csth.spy.status = CHANSPY_DONE;
00393 ast_channel_lock(csth.spy.chan);
00394 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
00395 ast_channel_unlock(csth.spy.chan);
00396 }
00397 ast_channel_spy_free(&csth.spy);
00398
00399 if (option_verbose >= 2)
00400 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00401
00402 return running;
00403 }
00404
00405 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
00406 const char *exten, const char *context)
00407 {
00408 struct ast_channel *this;
00409
00410 redo:
00411 if (spec)
00412 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00413 else if (exten)
00414 this = ast_walk_channel_by_exten_locked(last, exten, context);
00415 else
00416 this = ast_channel_walk_locked(last);
00417
00418 if (this) {
00419 ast_channel_unlock(this);
00420 if (!strncmp(this->name, "Zap/pseudo", 10))
00421 goto redo;
00422 }
00423
00424 return this;
00425 }
00426
00427 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00428 int volfactor, const int fd, const char *mygroup, const char *spec,
00429 const char *exten, const char *context)
00430 {
00431 struct ast_channel *peer, *prev, *next;
00432 char nameprefix[AST_NAME_STRLEN];
00433 char peer_name[AST_NAME_STRLEN + 5];
00434 signed char zero_volume = 0;
00435 int waitms;
00436 int res;
00437 char *ptr;
00438 int num;
00439
00440 if (chan->_state != AST_STATE_UP)
00441 ast_answer(chan);
00442
00443 ast_set_flag(chan, AST_FLAG_SPYING);
00444
00445 waitms = 100;
00446
00447 for (;;) {
00448 if (!ast_test_flag(flags, OPTION_QUIET)) {
00449 res = ast_streamfile(chan, "beep", chan->language);
00450 if (!res)
00451 res = ast_waitstream(chan, "");
00452 else if (res < 0) {
00453 ast_clear_flag(chan, AST_FLAG_SPYING);
00454 break;
00455 }
00456 }
00457
00458 res = ast_waitfordigit(chan, waitms);
00459 if (res < 0) {
00460 ast_clear_flag(chan, AST_FLAG_SPYING);
00461 break;
00462 }
00463
00464
00465 waitms = 100;
00466 peer = prev = next = NULL;
00467
00468 for (peer = next_channel(peer, spec, exten, context);
00469 peer;
00470 prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
00471 const char *group;
00472 int igrp = !mygroup;
00473 char *groups[25];
00474 int num_groups = 0;
00475 char *dup_group;
00476 int x;
00477 char *s;
00478
00479 if (peer == prev)
00480 break;
00481
00482 if (peer == chan)
00483 continue;
00484
00485 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
00486 continue;
00487
00488 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
00489 continue;
00490
00491 if (mygroup) {
00492 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00493 dup_group = ast_strdupa(group);
00494 num_groups = ast_app_separate_args(dup_group, ':', groups,
00495 sizeof(groups) / sizeof(groups[0]));
00496 }
00497
00498 for (x = 0; x < num_groups; x++) {
00499 if (!strcmp(mygroup, groups[x])) {
00500 igrp = 1;
00501 break;
00502 }
00503 }
00504 }
00505
00506 if (!igrp)
00507 continue;
00508
00509 strcpy(peer_name, "spy-");
00510 strncat(peer_name, peer->name, AST_NAME_STRLEN);
00511 ptr = strchr(peer_name, '/');
00512 *ptr++ = '\0';
00513
00514 for (s = peer_name; s < ptr; s++)
00515 *s = tolower(*s);
00516
00517 if (!ast_test_flag(flags, OPTION_QUIET)) {
00518 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00519 res = ast_streamfile(chan, peer_name, chan->language);
00520 if (!res)
00521 res = ast_waitstream(chan, "");
00522 if (res)
00523 break;
00524 } else
00525 res = ast_say_character_str(chan, peer_name, "", chan->language);
00526 if ((num = atoi(ptr)))
00527 ast_say_digits(chan, atoi(ptr), "", chan->language);
00528 }
00529
00530 waitms = 5000;
00531 res = channel_spy(chan, peer, &volfactor, fd, flags);
00532
00533 if (res == -1) {
00534 break;
00535 } else if (res > 1 && spec) {
00536 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00537 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00538 ast_channel_unlock(next);
00539 } else {
00540
00541 next = peer;
00542 }
00543 peer = NULL;
00544 }
00545 }
00546 if (res == -1)
00547 break;
00548 }
00549
00550 ast_clear_flag(chan, AST_FLAG_SPYING);
00551
00552 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00553
00554 return res;
00555 }
00556
00557 static int chanspy_exec(struct ast_channel *chan, void *data)
00558 {
00559 struct ast_module_user *u;
00560 char *options = NULL;
00561 char *spec = NULL;
00562 char *argv[2];
00563 char *mygroup = NULL;
00564 char *recbase = NULL;
00565 int fd = 0;
00566 struct ast_flags flags;
00567 int oldwf = 0;
00568 int argc = 0;
00569 int volfactor = 0;
00570 int res;
00571
00572 data = ast_strdupa(data);
00573
00574 u = ast_module_user_add(chan);
00575
00576 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00577 spec = argv[0];
00578 if (argc > 1)
00579 options = argv[1];
00580
00581 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00582 spec = NULL;
00583 }
00584
00585 if (options) {
00586 char *opts[OPT_ARG_ARRAY_SIZE];
00587
00588 ast_app_parse_options(spy_opts, &flags, opts, options);
00589 if (ast_test_flag(&flags, OPTION_GROUP))
00590 mygroup = opts[OPT_ARG_GROUP];
00591
00592 if (ast_test_flag(&flags, OPTION_RECORD) &&
00593 !(recbase = opts[OPT_ARG_RECORD]))
00594 recbase = "chanspy";
00595
00596 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00597 int vol;
00598
00599 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00600 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00601 else
00602 volfactor = vol;
00603 }
00604
00605 if (ast_test_flag(&flags, OPTION_PRIVATE))
00606 ast_set_flag(&flags, OPTION_WHISPER);
00607 }
00608
00609 oldwf = chan->writeformat;
00610 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00611 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00612 ast_module_user_remove(u);
00613 return -1;
00614 }
00615
00616 if (recbase) {
00617 char filename[512];
00618
00619 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00620 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00621 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00622 fd = 0;
00623 }
00624 }
00625
00626 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00627
00628 if (fd)
00629 close(fd);
00630
00631 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00632 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00633
00634 ast_module_user_remove(u);
00635
00636 return res;
00637 }
00638
00639 static int extenspy_exec(struct ast_channel *chan, void *data)
00640 {
00641 struct ast_module_user *u;
00642 char *options = NULL;
00643 char *exten = NULL;
00644 char *context = NULL;
00645 char *argv[2];
00646 char *mygroup = NULL;
00647 char *recbase = NULL;
00648 int fd = 0;
00649 struct ast_flags flags;
00650 int oldwf = 0;
00651 int argc = 0;
00652 int volfactor = 0;
00653 int res;
00654
00655 data = ast_strdupa(data);
00656
00657 u = ast_module_user_add(chan);
00658
00659 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00660 context = argv[0];
00661 if (!ast_strlen_zero(argv[0]))
00662 exten = strsep(&context, "@");
00663 if (ast_strlen_zero(context))
00664 context = ast_strdupa(chan->context);
00665 if (argc > 1)
00666 options = argv[1];
00667 }
00668
00669 if (options) {
00670 char *opts[OPT_ARG_ARRAY_SIZE];
00671
00672 ast_app_parse_options(spy_opts, &flags, opts, options);
00673 if (ast_test_flag(&flags, OPTION_GROUP))
00674 mygroup = opts[OPT_ARG_GROUP];
00675
00676 if (ast_test_flag(&flags, OPTION_RECORD) &&
00677 !(recbase = opts[OPT_ARG_RECORD]))
00678 recbase = "chanspy";
00679
00680 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00681 int vol;
00682
00683 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00684 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00685 else
00686 volfactor = vol;
00687 }
00688
00689 if (ast_test_flag(&flags, OPTION_PRIVATE))
00690 ast_set_flag(&flags, OPTION_WHISPER);
00691 }
00692
00693 oldwf = chan->writeformat;
00694 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00695 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00696 ast_module_user_remove(u);
00697 return -1;
00698 }
00699
00700 if (recbase) {
00701 char filename[512];
00702
00703 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00704 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00705 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00706 fd = 0;
00707 }
00708 }
00709
00710 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00711
00712 if (fd)
00713 close(fd);
00714
00715 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00716 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00717
00718 ast_module_user_remove(u);
00719
00720 return res;
00721 }
00722
00723 static int unload_module(void)
00724 {
00725 int res = 0;
00726
00727 res |= ast_unregister_application(app_chan);
00728 res |= ast_unregister_application(app_ext);
00729
00730 ast_module_user_hangup_all();
00731
00732 return res;
00733 }
00734
00735 static int load_module(void)
00736 {
00737 int res = 0;
00738
00739 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00740 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00741
00742 return res;
00743 }
00744
00745 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");