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