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 csth.spy.status = CHANSPY_DONE;
00391
00392
00393 if (csth.spy.chan) {
00394 ast_channel_lock(csth.spy.chan);
00395 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
00396 ast_channel_unlock(csth.spy.chan);
00397 }
00398 ast_channel_spy_free(&csth.spy);
00399
00400 if (option_verbose >= 2)
00401 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00402
00403 return running;
00404 }
00405
00406 static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
00407 const char *exten, const char *context)
00408 {
00409 struct ast_channel *this;
00410
00411 redo:
00412 if (spec)
00413 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00414 else if (exten)
00415 this = ast_walk_channel_by_exten_locked(last, exten, context);
00416 else
00417 this = ast_channel_walk_locked(last);
00418
00419 if (this) {
00420 ast_channel_unlock(this);
00421 if (!strncmp(this->name, "Zap/pseudo", 10))
00422 goto redo;
00423 }
00424
00425 return this;
00426 }
00427
00428 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00429 int volfactor, const int fd, const char *mygroup, const char *spec,
00430 const char *exten, const char *context)
00431 {
00432 struct ast_channel *peer, *prev, *next;
00433 char nameprefix[AST_NAME_STRLEN];
00434 char peer_name[AST_NAME_STRLEN + 5];
00435 signed char zero_volume = 0;
00436 int waitms;
00437 int res;
00438 char *ptr;
00439 int num;
00440
00441 if (chan->_state != AST_STATE_UP)
00442 ast_answer(chan);
00443
00444 ast_set_flag(chan, AST_FLAG_SPYING);
00445
00446 waitms = 100;
00447
00448 for (;;) {
00449 if (!ast_test_flag(flags, OPTION_QUIET)) {
00450 res = ast_streamfile(chan, "beep", chan->language);
00451 if (!res)
00452 res = ast_waitstream(chan, "");
00453 else if (res < 0) {
00454 ast_clear_flag(chan, AST_FLAG_SPYING);
00455 break;
00456 }
00457 }
00458
00459 res = ast_waitfordigit(chan, waitms);
00460 if (res < 0) {
00461 ast_clear_flag(chan, AST_FLAG_SPYING);
00462 break;
00463 }
00464
00465
00466 waitms = 100;
00467 peer = prev = next = NULL;
00468
00469 for (peer = next_channel(peer, spec, exten, context);
00470 peer;
00471 prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
00472 const char *group;
00473 int igrp = !mygroup;
00474 char *groups[25];
00475 int num_groups = 0;
00476 char *dup_group;
00477 int x;
00478 char *s;
00479
00480 if (peer == prev)
00481 break;
00482
00483 if (peer == chan)
00484 continue;
00485
00486 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
00487 continue;
00488
00489 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
00490 continue;
00491
00492 if (mygroup) {
00493 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00494 dup_group = ast_strdupa(group);
00495 num_groups = ast_app_separate_args(dup_group, ':', groups,
00496 sizeof(groups) / sizeof(groups[0]));
00497 }
00498
00499 for (x = 0; x < num_groups; x++) {
00500 if (!strcmp(mygroup, groups[x])) {
00501 igrp = 1;
00502 break;
00503 }
00504 }
00505 }
00506
00507 if (!igrp)
00508 continue;
00509
00510 strcpy(peer_name, "spy-");
00511 strncat(peer_name, peer->name, AST_NAME_STRLEN);
00512 ptr = strchr(peer_name, '/');
00513 *ptr++ = '\0';
00514
00515 for (s = peer_name; s < ptr; s++)
00516 *s = tolower(*s);
00517
00518 if (!ast_test_flag(flags, OPTION_QUIET)) {
00519 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00520 res = ast_streamfile(chan, peer_name, chan->language);
00521 if (!res)
00522 res = ast_waitstream(chan, "");
00523 if (res)
00524 break;
00525 } else
00526 res = ast_say_character_str(chan, peer_name, "", chan->language);
00527 if ((num = atoi(ptr)))
00528 ast_say_digits(chan, atoi(ptr), "", chan->language);
00529 }
00530
00531 waitms = 5000;
00532 res = channel_spy(chan, peer, &volfactor, fd, flags);
00533
00534 if (res == -1) {
00535 break;
00536 } else if (res > 1 && spec) {
00537 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00538 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00539 ast_channel_unlock(next);
00540 } else {
00541
00542 next = peer;
00543 }
00544 peer = NULL;
00545 }
00546 }
00547 if (res == -1)
00548 break;
00549 }
00550
00551 ast_clear_flag(chan, AST_FLAG_SPYING);
00552
00553 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00554
00555 return res;
00556 }
00557
00558 static int chanspy_exec(struct ast_channel *chan, void *data)
00559 {
00560 struct ast_module_user *u;
00561 char *options = NULL;
00562 char *spec = NULL;
00563 char *argv[2];
00564 char *mygroup = NULL;
00565 char *recbase = NULL;
00566 int fd = 0;
00567 struct ast_flags flags;
00568 int oldwf = 0;
00569 int argc = 0;
00570 int volfactor = 0;
00571 int res;
00572
00573 data = ast_strdupa(data);
00574
00575 u = ast_module_user_add(chan);
00576
00577 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00578 spec = argv[0];
00579 if (argc > 1)
00580 options = argv[1];
00581
00582 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00583 spec = NULL;
00584 }
00585
00586 if (options) {
00587 char *opts[OPT_ARG_ARRAY_SIZE];
00588
00589 ast_app_parse_options(spy_opts, &flags, opts, options);
00590 if (ast_test_flag(&flags, OPTION_GROUP))
00591 mygroup = opts[OPT_ARG_GROUP];
00592
00593 if (ast_test_flag(&flags, OPTION_RECORD) &&
00594 !(recbase = opts[OPT_ARG_RECORD]))
00595 recbase = "chanspy";
00596
00597 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00598 int vol;
00599
00600 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00601 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00602 else
00603 volfactor = vol;
00604 }
00605
00606 if (ast_test_flag(&flags, OPTION_PRIVATE))
00607 ast_set_flag(&flags, OPTION_WHISPER);
00608 } else
00609 ast_clear_flag(&flags, AST_FLAGS_ALL);
00610
00611 oldwf = chan->writeformat;
00612 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00613 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00614 ast_module_user_remove(u);
00615 return -1;
00616 }
00617
00618 if (recbase) {
00619 char filename[512];
00620
00621 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00622 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00623 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00624 fd = 0;
00625 }
00626 }
00627
00628 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00629
00630 if (fd)
00631 close(fd);
00632
00633 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00634 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00635
00636 ast_module_user_remove(u);
00637
00638 return res;
00639 }
00640
00641 static int extenspy_exec(struct ast_channel *chan, void *data)
00642 {
00643 struct ast_module_user *u;
00644 char *options = NULL;
00645 char *exten = NULL;
00646 char *context = NULL;
00647 char *argv[2];
00648 char *mygroup = NULL;
00649 char *recbase = NULL;
00650 int fd = 0;
00651 struct ast_flags flags;
00652 int oldwf = 0;
00653 int argc = 0;
00654 int volfactor = 0;
00655 int res;
00656
00657 data = ast_strdupa(data);
00658
00659 u = ast_module_user_add(chan);
00660
00661 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00662 context = argv[0];
00663 if (!ast_strlen_zero(argv[0]))
00664 exten = strsep(&context, "@");
00665 if (ast_strlen_zero(context))
00666 context = ast_strdupa(chan->context);
00667 if (argc > 1)
00668 options = argv[1];
00669 }
00670
00671 if (options) {
00672 char *opts[OPT_ARG_ARRAY_SIZE];
00673
00674 ast_app_parse_options(spy_opts, &flags, opts, options);
00675 if (ast_test_flag(&flags, OPTION_GROUP))
00676 mygroup = opts[OPT_ARG_GROUP];
00677
00678 if (ast_test_flag(&flags, OPTION_RECORD) &&
00679 !(recbase = opts[OPT_ARG_RECORD]))
00680 recbase = "chanspy";
00681
00682 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00683 int vol;
00684
00685 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00686 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00687 else
00688 volfactor = vol;
00689 }
00690
00691 if (ast_test_flag(&flags, OPTION_PRIVATE))
00692 ast_set_flag(&flags, OPTION_WHISPER);
00693 } else
00694 ast_clear_flag(&flags, AST_FLAGS_ALL);
00695
00696 oldwf = chan->writeformat;
00697 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00698 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00699 ast_module_user_remove(u);
00700 return -1;
00701 }
00702
00703 if (recbase) {
00704 char filename[512];
00705
00706 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00707 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00708 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00709 fd = 0;
00710 }
00711 }
00712
00713 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00714
00715 if (fd)
00716 close(fd);
00717
00718 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00719 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00720
00721 ast_module_user_remove(u);
00722
00723 return res;
00724 }
00725
00726 static int unload_module(void)
00727 {
00728 int res = 0;
00729
00730 res |= ast_unregister_application(app_chan);
00731 res |= ast_unregister_application(app_ext);
00732
00733 ast_module_user_hangup_all();
00734
00735 return res;
00736 }
00737
00738 static int load_module(void)
00739 {
00740 int res = 0;
00741
00742 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00743 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00744
00745 return res;
00746 }
00747
00748 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");