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