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 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <ctype.h>
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 42054 $")
00035
00036 #include "asterisk/file.h"
00037 #include "asterisk/logger.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/chanspy.h"
00040 #include "asterisk/features.h"
00041 #include "asterisk/options.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/utils.h"
00044 #include "asterisk/say.h"
00045 #include "asterisk/pbx.h"
00046 #include "asterisk/translate.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/lock.h"
00049
00050 AST_MUTEX_DEFINE_STATIC(modlock);
00051
00052 #define AST_NAME_STRLEN 256
00053 #define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
00054 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
00055
00056 static const char *synopsis = "Listen to the audio of an active channel\n";
00057 static const char *app = "ChanSpy";
00058 static const char *desc =
00059 " ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
00060 "audio from an active Asterisk channel. This includes the audio coming in and\n"
00061 "out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
00062 "only channels beginning with this string will be spied upon.\n"
00063 " While Spying, the following actions may be performed:\n"
00064 " - Dialing # cycles the volume level.\n"
00065 " - Dialing * will stop spying and look for another channel to spy on.\n"
00066 " - Dialing a series of digits followed by # builds a channel name to append\n"
00067 " to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
00068 " the digits '1234#' while spying will begin spying on the channel,\n"
00069 " 'Agent/1234'.\n"
00070 " Options:\n"
00071 " b - Only spy on channels involved in a bridged call.\n"
00072 " g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
00073 " 'grp'.\n"
00074 " q - Don't play a beep when beginning to spy on a channel.\n"
00075 " r[(basename)] - Record the session to the monitor spool directory. An\n"
00076 " optional base for the filename may be specified. The\n"
00077 " default is 'chanspy'.\n"
00078 " v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
00079 " negative value refers to a quieter setting.\n"
00080 ;
00081
00082 static const char *chanspy_spy_type = "ChanSpy";
00083
00084 enum {
00085 OPTION_QUIET = (1 << 0),
00086 OPTION_BRIDGED = (1 << 1),
00087 OPTION_VOLUME = (1 << 2),
00088 OPTION_GROUP = (1 << 3),
00089 OPTION_RECORD = (1 << 4),
00090 } chanspy_opt_flags;
00091
00092 enum {
00093 OPT_ARG_VOLUME = 0,
00094 OPT_ARG_GROUP,
00095 OPT_ARG_RECORD,
00096 OPT_ARG_ARRAY_SIZE,
00097 } chanspy_opt_args;
00098
00099 AST_APP_OPTIONS(chanspy_opts, {
00100 AST_APP_OPTION('q', OPTION_QUIET),
00101 AST_APP_OPTION('b', OPTION_BRIDGED),
00102 AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
00103 AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
00104 AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
00105 });
00106
00107 STANDARD_LOCAL_USER;
00108 LOCAL_USER_DECL;
00109
00110 struct chanspy_translation_helper {
00111
00112 struct ast_channel_spy spy;
00113 int fd;
00114 int volfactor;
00115 };
00116
00117 static struct ast_channel *local_channel_walk(struct ast_channel *chan)
00118 {
00119 struct ast_channel *ret;
00120 ast_mutex_lock(&modlock);
00121 if ((ret = ast_channel_walk_locked(chan))) {
00122 ast_mutex_unlock(&ret->lock);
00123 }
00124 ast_mutex_unlock(&modlock);
00125 return ret;
00126 }
00127
00128 static struct ast_channel *local_get_channel_begin_name(char *name)
00129 {
00130 struct ast_channel *chan, *ret = NULL;
00131 ast_mutex_lock(&modlock);
00132 chan = local_channel_walk(NULL);
00133 while (chan) {
00134 if (!strncmp(chan->name, name, strlen(name)) && strncmp(chan->name, "Zap/pseudo", 10)) {
00135 ret = chan;
00136 break;
00137 }
00138 chan = local_channel_walk(chan);
00139 }
00140 ast_mutex_unlock(&modlock);
00141
00142 return ret;
00143 }
00144
00145 static void *spy_alloc(struct ast_channel *chan, void *data)
00146 {
00147
00148 return data;
00149 }
00150
00151 static void spy_release(struct ast_channel *chan, void *data)
00152 {
00153
00154 }
00155
00156 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
00157 {
00158 struct chanspy_translation_helper *csth = data;
00159 struct ast_frame *f;
00160
00161 if (csth->spy.status != CHANSPY_RUNNING)
00162
00163 return -1;
00164
00165 ast_mutex_lock(&csth->spy.lock);
00166 f = ast_channel_spy_read_frame(&csth->spy, samples);
00167 ast_mutex_unlock(&csth->spy.lock);
00168
00169 if (!f)
00170 return 0;
00171
00172 if (ast_write(chan, f)) {
00173 ast_frfree(f);
00174 return -1;
00175 }
00176
00177 if (csth->fd)
00178 write(csth->fd, f->data, f->datalen);
00179
00180 ast_frfree(f);
00181
00182 return 0;
00183 }
00184
00185
00186 static struct ast_generator spygen = {
00187 .alloc = spy_alloc,
00188 .release = spy_release,
00189 .generate = spy_generate,
00190 };
00191
00192 static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy)
00193 {
00194 int res;
00195 struct ast_channel *peer;
00196
00197 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
00198
00199 ast_mutex_lock(&chan->lock);
00200 res = ast_channel_spy_add(chan, spy);
00201 ast_mutex_unlock(&chan->lock);
00202
00203 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
00204 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00205 }
00206
00207 return res;
00208 }
00209
00210
00211
00212
00213 static signed char volfactor_map[] = {
00214 -24,
00215 -18,
00216 -12,
00217 -6,
00218 0,
00219 6,
00220 12,
00221 18,
00222 24,
00223 };
00224
00225
00226
00227
00228
00229 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
00230 {
00231 signed char volume_adjust = volfactor_map[csth->volfactor + 4];
00232
00233 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
00234 csth->volfactor = 0;
00235 }
00236
00237 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
00238 {
00239 struct chanspy_translation_helper csth;
00240 int running, res = 0, x = 0;
00241 char inp[24];
00242 char *name=NULL;
00243 struct ast_frame *f;
00244
00245 running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
00246
00247 if (running) {
00248 memset(inp, 0, sizeof(inp));
00249 name = ast_strdupa(spyee->name);
00250 if (option_verbose >= 2)
00251 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00252
00253 memset(&csth, 0, sizeof(csth));
00254 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
00255 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
00256 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
00257 csth.spy.type = chanspy_spy_type;
00258 csth.spy.status = CHANSPY_RUNNING;
00259 csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
00260 csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
00261 ast_mutex_init(&csth.spy.lock);
00262 csth.volfactor = *volfactor;
00263 set_volume(chan, &csth);
00264 csth.spy.read_vol_adjustment = csth.volfactor;
00265 csth.spy.write_vol_adjustment = csth.volfactor;
00266 csth.fd = fd;
00267
00268 if (start_spying(spyee, chan, &csth.spy))
00269 running = 0;
00270 }
00271
00272 if (running) {
00273 running = 1;
00274 ast_activate_generator(chan, &spygen, &csth);
00275
00276 while (csth.spy.status == CHANSPY_RUNNING &&
00277 chan && !ast_check_hangup(chan) &&
00278 spyee &&
00279 !ast_check_hangup(spyee) &&
00280 running == 1 &&
00281 (res = ast_waitfor(chan, -1) > -1)) {
00282 if ((f = ast_read(chan))) {
00283 res = 0;
00284 if (f->frametype == AST_FRAME_DTMF) {
00285 res = f->subclass;
00286 }
00287 ast_frfree(f);
00288 if (!res) {
00289 continue;
00290 }
00291 } else {
00292 break;
00293 }
00294 if (x == sizeof(inp)) {
00295 x = 0;
00296 }
00297 if (res < 0) {
00298 running = -1;
00299 }
00300 if (res == 0) {
00301 continue;
00302 } else if (res == '*') {
00303 running = 0;
00304 } else if (res == '#') {
00305 if (!ast_strlen_zero(inp)) {
00306 running = x ? atoi(inp) : -1;
00307 break;
00308 } else {
00309 (*volfactor)++;
00310 if (*volfactor > 4) {
00311 *volfactor = -4;
00312 }
00313 if (option_verbose > 2) {
00314 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00315 }
00316 csth.volfactor = *volfactor;
00317 set_volume(chan, &csth);
00318 csth.spy.read_vol_adjustment = csth.volfactor;
00319 csth.spy.write_vol_adjustment = csth.volfactor;
00320 }
00321 } else if (res >= 48 && res <= 57) {
00322 inp[x++] = res;
00323 }
00324 }
00325 ast_deactivate_generator(chan);
00326
00327 if (csth.spy.chan) {
00328 csth.spy.status = CHANSPY_DONE;
00329 ast_mutex_lock(&csth.spy.chan->lock);
00330 ast_channel_spy_remove(csth.spy.chan, &csth.spy);
00331 ast_mutex_unlock(&csth.spy.chan->lock);
00332 }
00333
00334 if (option_verbose >= 2) {
00335 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00336 }
00337 } else {
00338 running = 0;
00339 }
00340
00341 ast_channel_spy_free(&csth.spy);
00342
00343 return running;
00344 }
00345
00346 static int chanspy_exec(struct ast_channel *chan, void *data)
00347 {
00348 struct localuser *u;
00349 struct ast_channel *peer=NULL, *prev=NULL;
00350 char name[AST_NAME_STRLEN],
00351 peer_name[AST_NAME_STRLEN + 5],
00352 *args,
00353 *ptr = NULL,
00354 *options = NULL,
00355 *spec = NULL,
00356 *argv[5],
00357 *mygroup = NULL,
00358 *recbase = NULL;
00359 int res = -1,
00360 volfactor = 0,
00361 silent = 0,
00362 argc = 0,
00363 bronly = 0,
00364 chosen = 0,
00365 count=0,
00366 waitms = 100,
00367 num = 0,
00368 oldrf = 0,
00369 oldwf = 0,
00370 fd = 0;
00371 struct ast_flags flags;
00372 signed char zero_volume = 0;
00373
00374 if (!(args = ast_strdupa((char *)data))) {
00375 ast_log(LOG_ERROR, "Out of memory!\n");
00376 return -1;
00377 }
00378
00379 LOCAL_USER_ADD(u);
00380
00381 oldrf = chan->readformat;
00382 oldwf = chan->writeformat;
00383 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
00384 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
00385 LOCAL_USER_REMOVE(u);
00386 return -1;
00387 }
00388
00389 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00390 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00391 LOCAL_USER_REMOVE(u);
00392 return -1;
00393 }
00394
00395 ast_answer(chan);
00396
00397 ast_set_flag(chan, AST_FLAG_SPYING);
00398
00399 if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00400 spec = argv[0];
00401 if ( argc > 1) {
00402 options = argv[1];
00403 }
00404 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
00405 spec = NULL;
00406 }
00407 }
00408
00409 if (options) {
00410 char *opts[OPT_ARG_ARRAY_SIZE];
00411 ast_app_parse_options(chanspy_opts, &flags, opts, options);
00412 if (ast_test_flag(&flags, OPTION_GROUP)) {
00413 mygroup = opts[OPT_ARG_GROUP];
00414 }
00415 if (ast_test_flag(&flags, OPTION_RECORD)) {
00416 if (!(recbase = opts[OPT_ARG_RECORD])) {
00417 recbase = "chanspy";
00418 }
00419 }
00420 silent = ast_test_flag(&flags, OPTION_QUIET);
00421 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
00422 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00423 int vol;
00424
00425 if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00426 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00427 else
00428 volfactor = vol;
00429 }
00430 }
00431
00432 if (recbase) {
00433 char filename[512];
00434 snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
00435 if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC, 0644)) <= 0) {
00436 ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
00437 fd = 0;
00438 }
00439 }
00440
00441 for(;;) {
00442 if (!silent) {
00443 res = ast_streamfile(chan, "beep", chan->language);
00444 if (!res)
00445 res = ast_waitstream(chan, "");
00446 if (res < 0) {
00447 ast_clear_flag(chan, AST_FLAG_SPYING);
00448 break;
00449 }
00450 }
00451
00452 count = 0;
00453 res = ast_waitfordigit(chan, waitms);
00454 if (res < 0) {
00455 ast_clear_flag(chan, AST_FLAG_SPYING);
00456 break;
00457 }
00458
00459 peer = local_channel_walk(NULL);
00460 prev=NULL;
00461 while(peer) {
00462 if (peer != chan) {
00463 char *group = NULL;
00464 int igrp = 1;
00465
00466 if (peer == prev && !chosen) {
00467 break;
00468 }
00469 chosen = 0;
00470 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
00471 if (mygroup) {
00472 if (!group || strcmp(mygroup, group)) {
00473 igrp = 0;
00474 }
00475 }
00476
00477 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
00478 !strncasecmp(peer->name, spec, strlen(spec)))))) {
00479 if (peer && (!bronly || ast_bridged_channel(peer)) &&
00480 !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
00481 int x = 0;
00482 strncpy(peer_name, "spy-", 5);
00483 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
00484 ptr = strchr(peer_name, '/');
00485 *ptr = '\0';
00486 ptr++;
00487 for (x = 0 ; x < strlen(peer_name) ; x++) {
00488 if (peer_name[x] == '/') {
00489 break;
00490 }
00491 peer_name[x] = tolower(peer_name[x]);
00492 }
00493
00494 if (!silent) {
00495 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00496 res = ast_streamfile(chan, peer_name, chan->language);
00497 if (!res)
00498 res = ast_waitstream(chan, "");
00499 if (res)
00500 break;
00501 } else
00502 res = ast_say_character_str(chan, peer_name, "", chan->language);
00503 if ((num=atoi(ptr)))
00504 ast_say_digits(chan, atoi(ptr), "", chan->language);
00505 }
00506 count++;
00507 prev = peer;
00508 res = channel_spy(chan, peer, &volfactor, fd);
00509 if (res == -1) {
00510 break;
00511 } else if (res > 1 && spec) {
00512 snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
00513 if ((peer = local_get_channel_begin_name(name))) {
00514 chosen = 1;
00515 }
00516 continue;
00517 }
00518 }
00519 }
00520 }
00521 if ((peer = local_channel_walk(peer)) == NULL) {
00522 break;
00523 }
00524 }
00525 waitms = count ? 100 : 5000;
00526 }
00527
00528
00529 if (fd > 0) {
00530 close(fd);
00531 }
00532
00533 if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
00534 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
00535 }
00536
00537 if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
00538 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00539 }
00540
00541 ast_clear_flag(chan, AST_FLAG_SPYING);
00542
00543 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00544
00545 ALL_DONE(u, res);
00546 }
00547
00548 int unload_module(void)
00549 {
00550 int res;
00551
00552 res = ast_unregister_application(app);
00553
00554 STANDARD_HANGUP_LOCALUSERS;
00555
00556 return res;
00557 }
00558
00559 int load_module(void)
00560 {
00561 return ast_register_application(app, chanspy_exec, synopsis, desc);
00562 }
00563
00564 char *description(void)
00565 {
00566 return (char *) synopsis;
00567 }
00568
00569 int usecount(void)
00570 {
00571 int res;
00572 STANDARD_USECOUNT(res);
00573 return res;
00574 }
00575
00576 char *key()
00577 {
00578 return ASTERISK_GPL_KEY;
00579 }