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