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