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: 284881 $")
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'.\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'.\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 while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) {
00254
00255
00256 DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock);
00257 }
00258 ast_mutex_unlock(&spyee_chanspy_ds->lock);
00259
00260 if (!spyee)
00261 return 0;
00262
00263
00264
00265 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00266 ast_channel_unlock(spyee);
00267 return 0;
00268 }
00269
00270 name = ast_strdupa(spyee->name);
00271 if (option_verbose >= 2)
00272 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00273
00274 memset(&csth, 0, sizeof(csth));
00275
00276 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00277
00278 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
00279 ast_audiohook_destroy(&csth.spy_audiohook);
00280 ast_channel_unlock(spyee);
00281 return 0;
00282 }
00283
00284 if (ast_test_flag(flags, OPTION_WHISPER)) {
00285 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00286 start_spying(spyee, spyer_name, &csth.whisper_audiohook);
00287 }
00288
00289 ast_channel_unlock(spyee);
00290 spyee = NULL;
00291
00292 csth.volfactor = *volfactor;
00293
00294 if (csth.volfactor) {
00295 csth.spy_audiohook.options.read_volume = csth.volfactor;
00296 csth.spy_audiohook.options.write_volume = csth.volfactor;
00297 }
00298
00299 csth.fd = fd;
00300
00301 if (ast_test_flag(flags, OPTION_PRIVATE))
00302 silgen = ast_channel_start_silence_generator(chan);
00303 else
00304 ast_activate_generator(chan, &spygen, &csth);
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00321 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00322 running = -1;
00323 break;
00324 }
00325
00326 if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
00327 ast_audiohook_lock(&csth.whisper_audiohook);
00328 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00329 ast_audiohook_unlock(&csth.whisper_audiohook);
00330 ast_frfree(f);
00331 continue;
00332 }
00333
00334 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00335 ast_frfree(f);
00336 if (!res)
00337 continue;
00338
00339 if (x == sizeof(inp))
00340 x = 0;
00341
00342 if (res < 0) {
00343 running = -1;
00344 break;
00345 }
00346
00347 if (res == '*') {
00348 running = 0;
00349 break;
00350 } else if (res == '#') {
00351 if (!ast_strlen_zero(inp)) {
00352 running = atoi(inp);
00353 break;
00354 }
00355
00356 (*volfactor)++;
00357 if (*volfactor > 4)
00358 *volfactor = -4;
00359 if (option_verbose > 2)
00360 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00361 csth.volfactor = *volfactor;
00362 csth.spy_audiohook.options.read_volume = csth.volfactor;
00363 csth.spy_audiohook.options.write_volume = csth.volfactor;
00364 } else if (res >= '0' && res <= '9') {
00365 inp[x++] = res;
00366 }
00367 }
00368
00369 if (ast_test_flag(flags, OPTION_PRIVATE))
00370 ast_channel_stop_silence_generator(chan, silgen);
00371 else
00372 ast_deactivate_generator(chan);
00373
00374 if (ast_test_flag(flags, OPTION_WHISPER)) {
00375 ast_audiohook_lock(&csth.whisper_audiohook);
00376 ast_audiohook_detach(&csth.whisper_audiohook);
00377 ast_audiohook_unlock(&csth.whisper_audiohook);
00378 ast_audiohook_destroy(&csth.whisper_audiohook);
00379 }
00380
00381 ast_audiohook_lock(&csth.spy_audiohook);
00382 ast_audiohook_detach(&csth.spy_audiohook);
00383 ast_audiohook_unlock(&csth.spy_audiohook);
00384 ast_audiohook_destroy(&csth.spy_audiohook);
00385
00386 if (option_verbose >= 2)
00387 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00388
00389 return running;
00390 }
00391
00392
00393
00394
00395
00396 static void chanspy_ds_destroy(void *data)
00397 {
00398 struct chanspy_ds *chanspy_ds = data;
00399
00400
00401
00402
00403
00404 ast_mutex_lock(&chanspy_ds->lock);
00405 chanspy_ds->chan = NULL;
00406 ast_mutex_unlock(&chanspy_ds->lock);
00407 }
00408
00409 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00410 {
00411 struct chanspy_ds *chanspy_ds = data;
00412
00413 ast_mutex_lock(&chanspy_ds->lock);
00414 chanspy_ds->chan = new_chan;
00415 ast_mutex_unlock(&chanspy_ds->lock);
00416 }
00417
00418 static const struct ast_datastore_info chanspy_ds_info = {
00419 .type = "chanspy",
00420 .destroy = chanspy_ds_destroy,
00421 .chan_fixup = chanspy_ds_chan_fixup,
00422 };
00423
00424 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
00425 {
00426 struct ast_channel *chan;
00427
00428 if (!chanspy_ds) {
00429 return NULL;
00430 }
00431
00432 ast_mutex_lock(&chanspy_ds->lock);
00433 while ((chan = chanspy_ds->chan)) {
00434 struct ast_datastore *datastore;
00435
00436 if (ast_channel_trylock(chan)) {
00437 DEADLOCK_AVOIDANCE(&chanspy_ds->lock);
00438 continue;
00439 }
00440 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
00441 ast_channel_datastore_remove(chan, datastore);
00442
00443 chanspy_ds_destroy(datastore->data);
00444 datastore->data = NULL;
00445 ast_channel_datastore_free(datastore);
00446 }
00447 ast_channel_unlock(chan);
00448 break;
00449 }
00450 ast_mutex_unlock(&chanspy_ds->lock);
00451
00452 return NULL;
00453 }
00454
00455
00456 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
00457 {
00458 struct ast_datastore *datastore = NULL;
00459
00460 ast_mutex_lock(&chanspy_ds->lock);
00461
00462 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
00463 ast_mutex_unlock(&chanspy_ds->lock);
00464 chanspy_ds = chanspy_ds_free(chanspy_ds);
00465 ast_channel_unlock(chan);
00466 return NULL;
00467 }
00468
00469 chanspy_ds->chan = chan;
00470 datastore->data = chanspy_ds;
00471 ast_channel_datastore_add(chan, datastore);
00472
00473 return chanspy_ds;
00474 }
00475
00476 static struct chanspy_ds *next_channel(struct ast_channel *chan,
00477 const struct ast_channel *last, const char *spec,
00478 const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
00479 {
00480 struct ast_channel *this;
00481 char channel_name[AST_CHANNEL_NAME];
00482 static size_t PSEUDO_CHAN_LEN = 0;
00483
00484 if (!PSEUDO_CHAN_LEN) {
00485 PSEUDO_CHAN_LEN = *dahdi_chan_name_len + strlen("/pseudo");
00486 }
00487
00488 redo:
00489 if (spec)
00490 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00491 else if (exten)
00492 this = ast_walk_channel_by_exten_locked(last, exten, context);
00493 else
00494 this = ast_channel_walk_locked(last);
00495
00496 if (!this)
00497 return NULL;
00498
00499 snprintf(channel_name, AST_CHANNEL_NAME, "%s/pseudo", dahdi_chan_name);
00500 if (!strncmp(this->name, channel_name, PSEUDO_CHAN_LEN)) {
00501 last = this;
00502 ast_channel_unlock(this);
00503 goto redo;
00504 } else if (this == chan) {
00505 last = this;
00506 ast_channel_unlock(this);
00507 goto redo;
00508 }
00509
00510 return setup_chanspy_ds(this, chanspy_ds);
00511 }
00512
00513 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00514 int volfactor, const int fd, const char *mygroup, const char *spec,
00515 const char *exten, const char *context)
00516 {
00517 char nameprefix[AST_NAME_STRLEN];
00518 char peer_name[AST_NAME_STRLEN + 5];
00519 signed char zero_volume = 0;
00520 int waitms;
00521 int res;
00522 char *ptr;
00523 int num;
00524 int num_spyed_upon = 1;
00525 struct chanspy_ds chanspy_ds = { 0, };
00526
00527 ast_mutex_init(&chanspy_ds.lock);
00528
00529 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
00530
00531 if (chan->_state != AST_STATE_UP)
00532 ast_answer(chan);
00533
00534 ast_set_flag(chan, AST_FLAG_SPYING);
00535
00536 waitms = 100;
00537
00538 for (;;) {
00539 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00540 struct ast_channel *prev = NULL, *peer = NULL;
00541
00542 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00543 res = ast_streamfile(chan, "beep", chan->language);
00544 if (!res)
00545 res = ast_waitstream(chan, "");
00546 else if (res < 0) {
00547 ast_clear_flag(chan, AST_FLAG_SPYING);
00548 break;
00549 }
00550 }
00551
00552 res = ast_waitfordigit(chan, waitms);
00553 if (res < 0) {
00554 ast_clear_flag(chan, AST_FLAG_SPYING);
00555 break;
00556 }
00557
00558
00559 waitms = 100;
00560 num_spyed_upon = 0;
00561
00562 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00563 peer_chanspy_ds;
00564 chanspy_ds_free(peer_chanspy_ds), prev = peer,
00565 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
00566 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00567 const char *group;
00568 int igrp = !mygroup;
00569 char *groups[25];
00570 int num_groups = 0;
00571 char dup_group[512];
00572 int x;
00573 char *s;
00574
00575 peer = peer_chanspy_ds->chan;
00576
00577 ast_mutex_unlock(&peer_chanspy_ds->lock);
00578
00579 if (peer == prev) {
00580 ast_channel_unlock(peer);
00581 chanspy_ds_free(peer_chanspy_ds);
00582 break;
00583 }
00584
00585 if (ast_check_hangup(chan)) {
00586 ast_channel_unlock(peer);
00587 chanspy_ds_free(peer_chanspy_ds);
00588 break;
00589 }
00590
00591 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00592 ast_channel_unlock(peer);
00593 continue;
00594 }
00595
00596 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00597 ast_channel_unlock(peer);
00598 continue;
00599 }
00600
00601 if (mygroup) {
00602 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00603 ast_copy_string(dup_group, group, sizeof(dup_group));
00604 num_groups = ast_app_separate_args(dup_group, ':', groups,
00605 sizeof(groups) / sizeof(groups[0]));
00606 }
00607
00608 for (x = 0; x < num_groups; x++) {
00609 if (!strcmp(mygroup, groups[x])) {
00610 igrp = 1;
00611 break;
00612 }
00613 }
00614 }
00615
00616 if (!igrp) {
00617 ast_channel_unlock(peer);
00618 continue;
00619 }
00620
00621 strcpy(peer_name, "spy-");
00622 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00623 ptr = strchr(peer_name, '/');
00624 *ptr++ = '\0';
00625
00626 for (s = peer_name; s < ptr; s++)
00627 *s = tolower(*s);
00628
00629
00630
00631
00632
00633 ast_channel_unlock(peer);
00634
00635 if (!ast_test_flag(flags, OPTION_QUIET)) {
00636 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
00637 res = ast_streamfile(chan, peer_name, chan->language);
00638 if (!res)
00639 res = ast_waitstream(chan, "");
00640 if (res) {
00641 chanspy_ds_free(peer_chanspy_ds);
00642 break;
00643 }
00644 } else
00645 res = ast_say_character_str(chan, peer_name, "", chan->language);
00646 if ((num = atoi(ptr)))
00647 ast_say_digits(chan, atoi(ptr), "", chan->language);
00648 }
00649
00650 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
00651 num_spyed_upon++;
00652
00653 if (res == -1) {
00654 chanspy_ds_free(peer_chanspy_ds);
00655 break;
00656 } else if (res > 1 && spec) {
00657 struct ast_channel *next;
00658
00659 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00660
00661 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00662 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
00663 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
00664 } else {
00665
00666
00667 ast_mutex_lock(&peer_chanspy_ds->lock);
00668 if (peer_chanspy_ds->chan) {
00669 ast_channel_lock(peer_chanspy_ds->chan);
00670 next_chanspy_ds = peer_chanspy_ds;
00671 peer_chanspy_ds = NULL;
00672 } else {
00673
00674 ast_mutex_unlock(&peer_chanspy_ds->lock);
00675 next_chanspy_ds = NULL;
00676 }
00677 }
00678
00679 peer = NULL;
00680 }
00681 }
00682 if (res == -1 || ast_check_hangup(chan))
00683 break;
00684 }
00685
00686 ast_clear_flag(chan, AST_FLAG_SPYING);
00687
00688 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00689
00690 ast_mutex_lock(&chanspy_ds.lock);
00691 ast_mutex_unlock(&chanspy_ds.lock);
00692 ast_mutex_destroy(&chanspy_ds.lock);
00693
00694 return res;
00695 }
00696
00697 static int chanspy_exec(struct ast_channel *chan, void *data)
00698 {
00699 struct ast_module_user *u;
00700 char *options = NULL;
00701 char *spec = NULL;
00702 char *argv[2];
00703 char *mygroup = NULL;
00704 char *recbase = NULL;
00705 int fd = 0;
00706 struct ast_flags flags;
00707 int oldwf = 0;
00708 int argc = 0;
00709 int volfactor = 0;
00710 int res;
00711
00712 data = ast_strdupa(data);
00713
00714 u = ast_module_user_add(chan);
00715
00716 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00717 spec = argv[0];
00718 if (argc > 1)
00719 options = argv[1];
00720
00721 if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
00722 spec = NULL;
00723 }
00724
00725 if (options) {
00726 char *opts[OPT_ARG_ARRAY_SIZE];
00727
00728 ast_app_parse_options(spy_opts, &flags, opts, options);
00729 if (ast_test_flag(&flags, OPTION_GROUP))
00730 mygroup = opts[OPT_ARG_GROUP];
00731
00732 if (ast_test_flag(&flags, OPTION_RECORD) &&
00733 !(recbase = opts[OPT_ARG_RECORD]))
00734 recbase = "chanspy";
00735
00736 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00737 int vol;
00738
00739 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
00740 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00741 else
00742 volfactor = vol;
00743 }
00744
00745 if (ast_test_flag(&flags, OPTION_PRIVATE))
00746 ast_set_flag(&flags, OPTION_WHISPER);
00747 } else
00748 ast_clear_flag(&flags, AST_FLAGS_ALL);
00749
00750 oldwf = chan->writeformat;
00751 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00752 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00753 ast_module_user_remove(u);
00754 return -1;
00755 }
00756
00757 if (recbase) {
00758 char filename[PATH_MAX];
00759
00760 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00761 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00762 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00763 fd = 0;
00764 }
00765 }
00766
00767 res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
00768
00769 if (fd)
00770 close(fd);
00771
00772 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00773 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00774
00775 ast_module_user_remove(u);
00776
00777 return res;
00778 }
00779
00780 static int extenspy_exec(struct ast_channel *chan, void *data)
00781 {
00782 struct ast_module_user *u;
00783 char *options = NULL;
00784 char *exten = NULL;
00785 char *context = NULL;
00786 char *argv[2];
00787 char *mygroup = NULL;
00788 char *recbase = NULL;
00789 int fd = 0;
00790 struct ast_flags flags;
00791 int oldwf = 0;
00792 int argc = 0;
00793 int volfactor = 0;
00794 int res;
00795
00796 data = ast_strdupa(data);
00797
00798 u = ast_module_user_add(chan);
00799
00800 if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00801 context = argv[0];
00802 if (!ast_strlen_zero(argv[0]))
00803 exten = strsep(&context, "@");
00804 if (ast_strlen_zero(context))
00805 context = ast_strdupa(chan->context);
00806 if (argc > 1)
00807 options = argv[1];
00808 }
00809
00810 if (options) {
00811 char *opts[OPT_ARG_ARRAY_SIZE];
00812
00813 ast_app_parse_options(spy_opts, &flags, opts, options);
00814 if (ast_test_flag(&flags, OPTION_GROUP))
00815 mygroup = opts[OPT_ARG_GROUP];
00816
00817 if (ast_test_flag(&flags, OPTION_RECORD) &&
00818 !(recbase = opts[OPT_ARG_RECORD]))
00819 recbase = "chanspy";
00820
00821 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00822 int vol;
00823
00824 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
00825 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00826 else
00827 volfactor = vol;
00828 }
00829
00830 if (ast_test_flag(&flags, OPTION_PRIVATE))
00831 ast_set_flag(&flags, OPTION_WHISPER);
00832 } else
00833 ast_clear_flag(&flags, AST_FLAGS_ALL);
00834
00835 oldwf = chan->writeformat;
00836 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00837 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00838 ast_module_user_remove(u);
00839 return -1;
00840 }
00841
00842 if (recbase) {
00843 char filename[PATH_MAX];
00844
00845 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00846 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
00847 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00848 fd = 0;
00849 }
00850 }
00851
00852 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
00853
00854 if (fd)
00855 close(fd);
00856
00857 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00858 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00859
00860 ast_module_user_remove(u);
00861
00862 return res;
00863 }
00864
00865 static int unload_module(void)
00866 {
00867 int res = 0;
00868
00869 res |= ast_unregister_application(app_chan);
00870 res |= ast_unregister_application(app_ext);
00871
00872 ast_module_user_hangup_all();
00873
00874 return res;
00875 }
00876
00877 static int load_module(void)
00878 {
00879 int res = 0;
00880
00881 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00882 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00883
00884 return res;
00885 }
00886
00887 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");