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