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: 34087 $")
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))) {
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 static void stop_spying(struct ast_channel *chan, struct ast_channel_spy *spy)
00211 {
00212
00213
00214 if (spy->status == CHANSPY_DONE)
00215 return;
00216
00217 if (!chan)
00218 return;
00219
00220 ast_mutex_lock(&chan->lock);
00221 ast_channel_spy_remove(chan, spy);
00222 ast_mutex_unlock(&chan->lock);
00223 };
00224
00225
00226
00227
00228 static signed char volfactor_map[] = {
00229 -24,
00230 -18,
00231 -12,
00232 -6,
00233 0,
00234 6,
00235 12,
00236 18,
00237 24,
00238 };
00239
00240
00241
00242
00243
00244 static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
00245 {
00246 signed char volume_adjust = volfactor_map[csth->volfactor + 4];
00247
00248 if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
00249 csth->volfactor = 0;
00250 }
00251
00252 static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
00253 {
00254 struct chanspy_translation_helper csth;
00255 int running, res = 0, x = 0;
00256 char inp[24];
00257 char *name=NULL;
00258 struct ast_frame *f;
00259
00260 running = (chan && !ast_check_hangup(chan) && spyee && !ast_check_hangup(spyee));
00261
00262 if (running) {
00263 memset(inp, 0, sizeof(inp));
00264 name = ast_strdupa(spyee->name);
00265 if (option_verbose >= 2)
00266 ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
00267
00268 memset(&csth, 0, sizeof(csth));
00269 ast_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
00270 ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
00271 ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
00272 csth.spy.type = chanspy_spy_type;
00273 csth.spy.status = CHANSPY_RUNNING;
00274 csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
00275 csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
00276 ast_mutex_init(&csth.spy.lock);
00277 csth.volfactor = *volfactor;
00278 set_volume(chan, &csth);
00279 csth.spy.read_vol_adjustment = csth.volfactor;
00280 csth.spy.write_vol_adjustment = csth.volfactor;
00281 csth.fd = fd;
00282
00283 if (start_spying(spyee, chan, &csth.spy))
00284 running = 0;
00285 }
00286
00287 if (running) {
00288 running = 1;
00289 ast_activate_generator(chan, &spygen, &csth);
00290
00291 while (csth.spy.status == CHANSPY_RUNNING &&
00292 chan && !ast_check_hangup(chan) &&
00293 spyee &&
00294 !ast_check_hangup(spyee) &&
00295 running == 1 &&
00296 (res = ast_waitfor(chan, -1) > -1)) {
00297 if ((f = ast_read(chan))) {
00298 res = 0;
00299 if (f->frametype == AST_FRAME_DTMF) {
00300 res = f->subclass;
00301 }
00302 ast_frfree(f);
00303 if (!res) {
00304 continue;
00305 }
00306 } else {
00307 break;
00308 }
00309 if (x == sizeof(inp)) {
00310 x = 0;
00311 }
00312 if (res < 0) {
00313 running = -1;
00314 }
00315 if (res == 0) {
00316 continue;
00317 } else if (res == '*') {
00318 running = 0;
00319 } else if (res == '#') {
00320 if (!ast_strlen_zero(inp)) {
00321 running = x ? atoi(inp) : -1;
00322 break;
00323 } else {
00324 (*volfactor)++;
00325 if (*volfactor > 4) {
00326 *volfactor = -4;
00327 }
00328 if (option_verbose > 2) {
00329 ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00330 }
00331 csth.volfactor = *volfactor;
00332 set_volume(chan, &csth);
00333 csth.spy.read_vol_adjustment = csth.volfactor;
00334 csth.spy.write_vol_adjustment = csth.volfactor;
00335 }
00336 } else if (res >= 48 && res <= 57) {
00337 inp[x++] = res;
00338 }
00339 }
00340 ast_deactivate_generator(chan);
00341 stop_spying(spyee, &csth.spy);
00342
00343 if (option_verbose >= 2) {
00344 ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
00345 }
00346 } else {
00347 running = 0;
00348 }
00349
00350 ast_mutex_destroy(&csth.spy.lock);
00351
00352 return running;
00353 }
00354
00355 static int chanspy_exec(struct ast_channel *chan, void *data)
00356 {
00357 struct localuser *u;
00358 struct ast_channel *peer=NULL, *prev=NULL;
00359 char name[AST_NAME_STRLEN],
00360 peer_name[AST_NAME_STRLEN + 5],
00361 *args,
00362 *ptr = NULL,
00363 *options = NULL,
00364 *spec = NULL,
00365 *argv[5],
00366 *mygroup = NULL,
00367 *recbase = NULL;
00368 int res = -1,
00369 volfactor = 0,
00370 silent = 0,
00371 argc = 0,
00372 bronly = 0,
00373 chosen = 0,
00374 count=0,
00375 waitms = 100,
00376 num = 0,
00377 oldrf = 0,
00378 oldwf = 0,
00379 fd = 0;
00380 struct ast_flags flags;
00381 signed char zero_volume = 0;
00382
00383 if (!(args = ast_strdupa((char *)data))) {
00384 ast_log(LOG_ERROR, "Out of memory!\n");
00385 return -1;
00386 }
00387
00388 LOCAL_USER_ADD(u);
00389
00390 oldrf = chan->readformat;
00391 oldwf = chan->writeformat;
00392 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
00393 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
00394 LOCAL_USER_REMOVE(u);
00395 return -1;
00396 }
00397
00398 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00399 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00400 LOCAL_USER_REMOVE(u);
00401 return -1;
00402 }
00403
00404 ast_answer(chan);
00405
00406 ast_set_flag(chan, AST_FLAG_SPYING);
00407
00408 if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
00409 spec = argv[0];
00410 if ( argc > 1) {
00411 options = argv[1];
00412 }
00413 if (ast_strlen_zero(spec) || !strcmp(spec, "all")) {
00414 spec = NULL;
00415 }
00416 }
00417
00418 if (options) {
00419 char *opts[OPT_ARG_ARRAY_SIZE];
00420 ast_app_parse_options(chanspy_opts, &flags, opts, options);
00421 if (ast_test_flag(&flags, OPTION_GROUP)) {
00422 mygroup = opts[1];
00423 }
00424 if (ast_test_flag(&flags, OPTION_RECORD)) {
00425 if (!(recbase = opts[2])) {
00426 recbase = "chanspy";
00427 }
00428 }
00429 silent = ast_test_flag(&flags, OPTION_QUIET);
00430 bronly = ast_test_flag(&flags, OPTION_BRIDGED);
00431 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[1]) {
00432 int vol;
00433
00434 if ((sscanf(opts[0], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
00435 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00436 else
00437 volfactor = vol;
00438 }
00439 }
00440
00441 if (recbase) {
00442 char filename[512];
00443 snprintf(filename,sizeof(filename),"%s/%s.%d.raw",ast_config_AST_MONITOR_DIR, recbase, (int)time(NULL));
00444 if ((fd = open(filename, O_CREAT | O_WRONLY, O_TRUNC, 0644)) <= 0) {
00445 ast_log(LOG_WARNING, "Cannot open %s for recording\n", filename);
00446 fd = 0;
00447 }
00448 }
00449
00450 for(;;) {
00451 if (!silent) {
00452 res = ast_streamfile(chan, "beep", chan->language);
00453 if (!res)
00454 res = ast_waitstream(chan, "");
00455 if (res < 0) {
00456 ast_clear_flag(chan, AST_FLAG_SPYING);
00457 break;
00458 }
00459 }
00460
00461 count = 0;
00462 res = ast_waitfordigit(chan, waitms);
00463 if (res < 0) {
00464 ast_clear_flag(chan, AST_FLAG_SPYING);
00465 break;
00466 }
00467
00468 peer = local_channel_walk(NULL);
00469 prev=NULL;
00470 while(peer) {
00471 if (peer != chan) {
00472 char *group = NULL;
00473 int igrp = 1;
00474
00475 if (peer == prev && !chosen) {
00476 break;
00477 }
00478 chosen = 0;
00479 group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
00480 if (mygroup) {
00481 if (!group || strcmp(mygroup, group)) {
00482 igrp = 0;
00483 }
00484 }
00485
00486 if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
00487 !strncasecmp(peer->name, spec, strlen(spec)))))) {
00488 if (peer && (!bronly || ast_bridged_channel(peer)) &&
00489 !ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
00490 int x = 0;
00491 strncpy(peer_name, "spy-", 5);
00492 strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
00493 ptr = strchr(peer_name, '/');
00494 *ptr = '\0';
00495 ptr++;
00496 for (x = 0 ; x < strlen(peer_name) ; x++) {
00497 if (peer_name[x] == '/') {
00498 break;
00499 }
00500 peer_name[x] = tolower(peer_name[x]);
00501 }
00502
00503 if (!silent) {
00504 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00505 res = ast_streamfile(chan, peer_name, chan->language);
00506 if (!res)
00507 res = ast_waitstream(chan, "");
00508 if (res)
00509 break;
00510 } else
00511 res = ast_say_character_str(chan, peer_name, "", chan->language);
00512 if ((num=atoi(ptr)))
00513 ast_say_digits(chan, atoi(ptr), "", chan->language);
00514 }
00515 count++;
00516 prev = peer;
00517 res = channel_spy(chan, peer, &volfactor, fd);
00518 if (res == -1) {
00519 break;
00520 } else if (res > 1 && spec) {
00521 snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
00522 if ((peer = local_get_channel_begin_name(name))) {
00523 chosen = 1;
00524 }
00525 continue;
00526 }
00527 }
00528 }
00529 }
00530 if ((peer = local_channel_walk(peer)) == NULL) {
00531 break;
00532 }
00533 }
00534 waitms = count ? 100 : 5000;
00535 }
00536
00537
00538 if (fd > 0) {
00539 close(fd);
00540 }
00541
00542 if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
00543 ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
00544 }
00545
00546 if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
00547 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00548 }
00549
00550 ast_clear_flag(chan, AST_FLAG_SPYING);
00551
00552 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00553
00554 ALL_DONE(u, res);
00555 }
00556
00557 int unload_module(void)
00558 {
00559 int res;
00560
00561 res = ast_unregister_application(app);
00562
00563 STANDARD_HANGUP_LOCALUSERS;
00564
00565 return res;
00566 }
00567
00568 int load_module(void)
00569 {
00570 return ast_register_application(app, chanspy_exec, synopsis, desc);
00571 }
00572
00573 char *description(void)
00574 {
00575 return (char *) synopsis;
00576 }
00577
00578 int usecount(void)
00579 {
00580 int res;
00581 STANDARD_USECOUNT(res);
00582 return res;
00583 }
00584
00585 char *key()
00586 {
00587 return ASTERISK_GPL_KEY;
00588 }