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