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