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