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: 118509 $")
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 int next_unique_id_to_use = 0;
00146
00147 struct chanspy_translation_helper {
00148
00149 struct ast_audiohook spy_audiohook;
00150 struct ast_audiohook whisper_audiohook;
00151 int fd;
00152 int volfactor;
00153 };
00154
00155 static void *spy_alloc(struct ast_channel *chan, void *data)
00156 {
00157
00158 return data;
00159 }
00160
00161 static void spy_release(struct ast_channel *chan, void *data)
00162 {
00163
00164 }
00165
00166 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
00167 {
00168 struct chanspy_translation_helper *csth = data;
00169 struct ast_frame *f;
00170
00171 ast_audiohook_lock(&csth->spy_audiohook);
00172 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00173 ast_audiohook_unlock(&csth->spy_audiohook);
00174 return -1;
00175 }
00176
00177 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
00178
00179 ast_audiohook_unlock(&csth->spy_audiohook);
00180
00181 if (!f)
00182 return 0;
00183
00184 if (ast_write(chan, f)) {
00185 ast_frfree(f);
00186 return -1;
00187 }
00188
00189 if (csth->fd)
00190 write(csth->fd, f->data, f->datalen);
00191
00192 ast_frfree(f);
00193
00194 return 0;
00195 }
00196
00197 static struct ast_generator spygen = {
00198 .alloc = spy_alloc,
00199 .release = spy_release,
00200 .generate = spy_generate,
00201 };
00202
00203 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
00204 {
00205 int res;
00206 struct ast_channel *peer;
00207
00208 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
00209
00210 res = ast_audiohook_attach(chan, audiohook);
00211
00212 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
00213 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00214 }
00215 return res;
00216 }
00217
00218 struct chanspy_ds {
00219 struct ast_channel *chan;
00220 char unique_id[20];
00221 ast_mutex_t lock;
00222 };
00223
00224 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
00225 int *volfactor, int fd, const struct ast_flags *flags)
00226 {
00227 struct chanspy_translation_helper csth;
00228 int running = 0, res, x = 0;
00229 char inp[24] = {0};
00230 char *name;
00231 struct ast_frame *f;
00232 struct ast_silence_generator *silgen = NULL;
00233 struct ast_channel *spyee = NULL;
00234 const char *spyer_name;
00235
00236 ast_channel_lock(chan);
00237 spyer_name = ast_strdupa(chan->name);
00238 ast_channel_unlock(chan);
00239
00240 ast_mutex_lock(&spyee_chanspy_ds->lock);
00241 if (spyee_chanspy_ds->chan) {
00242 spyee = spyee_chanspy_ds->chan;
00243 ast_channel_lock(spyee);
00244 }
00245 ast_mutex_unlock(&spyee_chanspy_ds->lock);
00246
00247 if (!spyee)
00248 return 0;
00249
00250
00251
00252 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00253 ast_channel_unlock(spyee);
00254 return 0;
00255 }
00256
00257 name = ast_strdupa(spyee->name);
00258 if (option_verbose >= 2)
00259 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00260
00261 memset(&csth, 0, sizeof(csth));
00262
00263 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00264
00265 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
00266 ast_audiohook_destroy(&csth.spy_audiohook);
00267 ast_channel_unlock(spyee);
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 ast_channel_unlock(spyee);
00277 spyee = NULL;
00278
00279 csth.volfactor = *volfactor;
00280
00281 if (csth.volfactor) {
00282 csth.spy_audiohook.options.read_volume = csth.volfactor;
00283 csth.spy_audiohook.options.write_volume = csth.volfactor;
00284 }
00285
00286 csth.fd = fd;
00287
00288 if (ast_test_flag(flags, OPTION_PRIVATE))
00289 silgen = ast_channel_start_silence_generator(chan);
00290 else
00291 ast_activate_generator(chan, &spygen, &csth);
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00308 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00309 running = -1;
00310 break;
00311 }
00312
00313 if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
00314 ast_audiohook_lock(&csth.whisper_audiohook);
00315 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00316 ast_audiohook_unlock(&csth.whisper_audiohook);
00317 ast_frfree(f);
00318 continue;
00319 }
00320
00321 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00322 ast_frfree(f);
00323 if (!res)
00324 continue;
00325
00326 if (x == sizeof(inp))
00327 x = 0;
00328
00329 if (res < 0) {
00330 running = -1;
00331 break;
00332 }
00333
00334 if (res == '*') {
00335 running = 0;
00336 break;
00337 } else if (res == '#') {
00338 if (!ast_strlen_zero(inp)) {
00339 running = atoi(inp);
00340 break;
00341 }
00342
00343 (*volfactor)++;
00344 if (*volfactor > 4)
00345 *volfactor = -4;
00346 if (option_verbose > 2)
00347 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00348 csth.volfactor = *volfactor;
00349 csth.spy_audiohook.options.read_volume = csth.volfactor;
00350 csth.spy_audiohook.options.write_volume = csth.volfactor;
00351 } else if (res >= '0' && res <= '9') {
00352 inp[x++] = res;
00353 }
00354 }
00355
00356 if (ast_test_flag(flags, OPTION_PRIVATE))
00357 ast_channel_stop_silence_generator(chan, silgen);
00358 else
00359 ast_deactivate_generator(chan);
00360
00361 if (ast_test_flag(flags, OPTION_WHISPER)) {
00362 ast_audiohook_lock(&csth.whisper_audiohook);
00363 ast_audiohook_detach(&csth.whisper_audiohook);
00364 ast_audiohook_unlock(&csth.whisper_audiohook);
00365 ast_audiohook_destroy(&csth.whisper_audiohook);
00366 }
00367
00368 ast_audiohook_lock(&csth.spy_audiohook);
00369 ast_audiohook_detach(&csth.spy_audiohook);
00370 ast_audiohook_unlock(&csth.spy_audiohook);
00371 ast_audiohook_destroy(&csth.spy_audiohook);
00372
00373 if (option_verbose >= 2)
00374 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00375
00376 return running;
00377 }
00378
00379
00380
00381
00382
00383 static void chanspy_ds_destroy(void *data)
00384 {
00385 struct chanspy_ds *chanspy_ds = data;
00386
00387
00388
00389
00390
00391 ast_mutex_lock(&chanspy_ds->lock);
00392 chanspy_ds->chan = NULL;
00393 ast_mutex_unlock(&chanspy_ds->lock);
00394 }
00395
00396 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00397 {
00398 struct chanspy_ds *chanspy_ds = data;
00399
00400 ast_mutex_lock(&chanspy_ds->lock);
00401 chanspy_ds->chan = new_chan;
00402 ast_mutex_unlock(&chanspy_ds->lock);
00403 }
00404
00405 static const struct ast_datastore_info chanspy_ds_info = {
00406 .type = "chanspy",
00407 .destroy = chanspy_ds_destroy,
00408 .chan_fixup = chanspy_ds_chan_fixup,
00409 };
00410
00411 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
00412 {
00413 if (!chanspy_ds)
00414 return NULL;
00415
00416 ast_mutex_lock(&chanspy_ds->lock);
00417 if (chanspy_ds->chan) {
00418 struct ast_datastore *datastore;
00419 struct ast_channel *chan;
00420
00421 chan = chanspy_ds->chan;
00422
00423 ast_channel_lock(chan);
00424 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
00425 ast_channel_datastore_remove(chan, datastore);
00426
00427 chanspy_ds_destroy(datastore->data);
00428 datastore->data = NULL;
00429 ast_channel_datastore_free(datastore);
00430 }
00431 ast_channel_unlock(chan);
00432 }
00433 ast_mutex_unlock(&chanspy_ds->lock);
00434
00435 return NULL;
00436 }
00437
00438
00439 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
00440 {
00441 struct ast_datastore *datastore = NULL;
00442
00443 ast_mutex_lock(&chanspy_ds->lock);
00444
00445 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
00446 ast_mutex_unlock(&chanspy_ds->lock);
00447 chanspy_ds = chanspy_ds_free(chanspy_ds);
00448 ast_channel_unlock(chan);
00449 return NULL;
00450 }
00451
00452 chanspy_ds->chan = chan;
00453 datastore->data = chanspy_ds;
00454 ast_channel_datastore_add(chan, datastore);
00455
00456 return chanspy_ds;
00457 }
00458
00459 static struct chanspy_ds *next_channel(struct ast_channel *chan,
00460 const struct ast_channel *last, const char *spec,
00461 const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
00462 {
00463 struct ast_channel *this;
00464
00465 redo:
00466 if (spec)
00467 this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00468 else if (exten)
00469 this = ast_walk_channel_by_exten_locked(last, exten, context);
00470 else
00471 this = ast_channel_walk_locked(last);
00472
00473 if (!this)
00474 return NULL;
00475
00476 if (!strncmp(this->name, "Zap/pseudo", 10)) {
00477 ast_channel_unlock(this);
00478 goto redo;
00479 } else if (this == chan) {
00480 last = this;
00481 ast_channel_unlock(this);
00482 goto redo;
00483 }
00484
00485 return setup_chanspy_ds(this, chanspy_ds);
00486 }
00487
00488 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00489 int volfactor, const int fd, const char *mygroup, const char *spec,
00490 const char *exten, const char *context)
00491 {
00492 char nameprefix[AST_NAME_STRLEN];
00493 char peer_name[AST_NAME_STRLEN + 5];
00494 signed char zero_volume = 0;
00495 int waitms;
00496 int res;
00497 char *ptr;
00498 int num;
00499 int num_spyed_upon = 1;
00500 struct chanspy_ds chanspy_ds;
00501
00502 ast_mutex_init(&chanspy_ds.lock);
00503
00504 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
00505
00506 if (chan->_state != AST_STATE_UP)
00507 ast_answer(chan);
00508
00509 ast_set_flag(chan, AST_FLAG_SPYING);
00510
00511 waitms = 100;
00512
00513 for (;;) {
00514 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00515 struct ast_channel *prev = NULL, *peer = NULL;
00516
00517 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00518 res = ast_streamfile(chan, "beep", chan->language);
00519 if (!res)
00520 res = ast_waitstream(chan, "");
00521 else if (res < 0) {
00522 ast_clear_flag(chan, AST_FLAG_SPYING);
00523 break;
00524 }
00525 }
00526
00527 res = ast_waitfordigit(chan, waitms);
00528 if (res < 0) {
00529 ast_clear_flag(chan, AST_FLAG_SPYING);
00530 break;
00531 }
00532
00533
00534 waitms = 100;
00535 num_spyed_upon = 0;
00536
00537 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00538 peer_chanspy_ds;
00539 chanspy_ds_free(peer_chanspy_ds), prev = peer,
00540 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
00541 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00542 const char *group;
00543 int igrp = !mygroup;
00544 char *groups[25];
00545 int num_groups = 0;
00546 char *dup_group;
00547 int x;
00548 char *s;
00549
00550 peer = peer_chanspy_ds->chan;
00551
00552 ast_mutex_unlock(&peer_chanspy_ds->lock);
00553
00554 if (peer == prev) {
00555 ast_channel_unlock(peer);
00556 chanspy_ds_free(peer_chanspy_ds);
00557 break;
00558 }
00559
00560 if (ast_check_hangup(chan)) {
00561 ast_channel_unlock(peer);
00562 chanspy_ds_free(peer_chanspy_ds);
00563 break;
00564 }
00565
00566 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00567 ast_channel_unlock(peer);
00568 continue;
00569 }
00570
00571 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00572 ast_channel_unlock(peer);
00573 continue;
00574 }
00575
00576 if (mygroup) {
00577 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00578 dup_group = ast_strdupa(group);
00579 num_groups = ast_app_separate_args(dup_group, ':', groups,
00580 sizeof(groups) / sizeof(groups[0]));
00581 }
00582
00583 for (x = 0; x < num_groups; x++) {
00584 if (!strcmp(mygroup, groups[x])) {
00585 igrp = 1;
00586 break;
00587 }
00588 }
00589 }
00590
00591 if (!igrp) {
00592 ast_channel_unlock(peer);
00593 continue;
00594 }
00595
00596 strcpy(peer_name, "spy-");
00597 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00598 ptr = strchr(peer_name, '/');
00599 *ptr++ = '\0';
00600
00601 for (s = peer_name; s < ptr; s++)
00602 *s = tolower(*s);
00603
00604
00605
00606
00607
00608 ast_channel_unlock(peer);
00609
00610 if (!ast_test_flag(flags, OPTION_QUIET)) {
00611 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00612 res = ast_streamfile(chan, peer_name, chan->language);
00613 if (!res)
00614 res = ast_waitstream(chan, "");
00615 if (res) {
00616 chanspy_ds_free(peer_chanspy_ds);
00617 break;
00618 }
00619 } else
00620 res = ast_say_character_str(chan, peer_name, "", chan->language);
00621 if ((num = atoi(ptr)))
00622 ast_say_digits(chan, atoi(ptr), "", chan->language);
00623 }
00624
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[PATH_MAX];
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[PATH_MAX];
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");