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: 224179 $")
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 if (ast_test_flag(chan, OPTION_READONLY)) {
00205
00206 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, AST_FORMAT_SLINEAR);
00207 } else {
00208 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
00209 }
00210
00211 ast_audiohook_unlock(&csth->spy_audiohook);
00212
00213 if (!f)
00214 return 0;
00215
00216 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00217 if (ast_write(chan, cur)) {
00218 ast_frfree(f);
00219 return -1;
00220 }
00221
00222 if (csth->fd) {
00223 if (write(csth->fd, cur->data, cur->datalen) < 0) {
00224 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00225 }
00226 }
00227 }
00228
00229 ast_frfree(f);
00230
00231 return 0;
00232 }
00233
00234 static struct ast_generator spygen = {
00235 .alloc = spy_alloc,
00236 .release = spy_release,
00237 .generate = spy_generate,
00238 };
00239
00240 static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
00241 {
00242 int res = 0;
00243 struct ast_channel *peer = NULL;
00244
00245 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
00246
00247 ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
00248 res = ast_audiohook_attach(chan, audiohook);
00249
00250 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
00251 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00252 }
00253 return res;
00254 }
00255
00256 struct chanspy_ds {
00257 struct ast_channel *chan;
00258 char unique_id[20];
00259 ast_mutex_t lock;
00260 };
00261
00262 static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
00263 int *volfactor, int fd, const struct ast_flags *flags, char *exitcontext)
00264 {
00265 struct chanspy_translation_helper csth;
00266 int running = 0, res, x = 0;
00267 char inp[24] = {0};
00268 char *name;
00269 struct ast_frame *f;
00270 struct ast_silence_generator *silgen = NULL;
00271 struct ast_channel *spyee = NULL;
00272 const char *spyer_name;
00273
00274 ast_channel_lock(chan);
00275 spyer_name = ast_strdupa(chan->name);
00276 ast_channel_unlock(chan);
00277
00278 ast_mutex_lock(&spyee_chanspy_ds->lock);
00279 while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) {
00280
00281
00282 DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock);
00283 }
00284 ast_mutex_unlock(&spyee_chanspy_ds->lock);
00285
00286 if (!spyee)
00287 return 0;
00288
00289
00290
00291 if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
00292 ast_channel_unlock(spyee);
00293 return 0;
00294 }
00295
00296 name = ast_strdupa(spyee->name);
00297 ast_verb(2, "Spying on channel %s\n", name);
00298
00299 memset(&csth, 0, sizeof(csth));
00300
00301 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
00302
00303 if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
00304 ast_audiohook_destroy(&csth.spy_audiohook);
00305 ast_channel_unlock(spyee);
00306 return 0;
00307 }
00308
00309 if (ast_test_flag(flags, OPTION_WHISPER)) {
00310 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
00311 start_spying(spyee, spyer_name, &csth.whisper_audiohook);
00312 }
00313
00314 ast_channel_unlock(spyee);
00315 spyee = NULL;
00316
00317 csth.volfactor = *volfactor;
00318
00319 if (csth.volfactor) {
00320 csth.spy_audiohook.options.read_volume = csth.volfactor;
00321 csth.spy_audiohook.options.write_volume = csth.volfactor;
00322 }
00323
00324 csth.fd = fd;
00325
00326 if (ast_test_flag(flags, OPTION_PRIVATE))
00327 silgen = ast_channel_start_silence_generator(chan);
00328 else
00329 ast_activate_generator(chan, &spygen, &csth);
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00346 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00347 running = -1;
00348 break;
00349 }
00350
00351 if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
00352 ast_audiohook_lock(&csth.whisper_audiohook);
00353 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00354 ast_audiohook_unlock(&csth.whisper_audiohook);
00355 ast_frfree(f);
00356 continue;
00357 }
00358
00359 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
00360 ast_frfree(f);
00361 if (!res)
00362 continue;
00363
00364 if (x == sizeof(inp))
00365 x = 0;
00366
00367 if (res < 0) {
00368 running = -1;
00369 break;
00370 }
00371
00372 if (ast_test_flag(flags, OPTION_EXIT)) {
00373 char tmp[2];
00374 tmp[0] = res;
00375 tmp[1] = '\0';
00376 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00377 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
00378 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
00379 running = -2;
00380 break;
00381 } else {
00382 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00383 }
00384 } else if (res >= '0' && res <= '9') {
00385 inp[x++] = res;
00386 }
00387
00388 if (res == '*') {
00389 running = 0;
00390 break;
00391 } else if (res == '#') {
00392 if (!ast_strlen_zero(inp)) {
00393 running = atoi(inp);
00394 break;
00395 }
00396
00397 (*volfactor)++;
00398 if (*volfactor > 4)
00399 *volfactor = -4;
00400 ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
00401
00402 csth.volfactor = *volfactor;
00403 csth.spy_audiohook.options.read_volume = csth.volfactor;
00404 csth.spy_audiohook.options.write_volume = csth.volfactor;
00405 }
00406 }
00407
00408 if (ast_test_flag(flags, OPTION_PRIVATE))
00409 ast_channel_stop_silence_generator(chan, silgen);
00410 else
00411 ast_deactivate_generator(chan);
00412
00413 if (ast_test_flag(flags, OPTION_WHISPER)) {
00414 ast_audiohook_lock(&csth.whisper_audiohook);
00415 ast_audiohook_detach(&csth.whisper_audiohook);
00416 ast_audiohook_unlock(&csth.whisper_audiohook);
00417 ast_audiohook_destroy(&csth.whisper_audiohook);
00418 }
00419
00420 ast_audiohook_lock(&csth.spy_audiohook);
00421 ast_audiohook_detach(&csth.spy_audiohook);
00422 ast_audiohook_unlock(&csth.spy_audiohook);
00423 ast_audiohook_destroy(&csth.spy_audiohook);
00424
00425 ast_verb(2, "Done Spying on channel %s\n", name);
00426
00427 return running;
00428 }
00429
00430
00431
00432
00433
00434 static void chanspy_ds_destroy(void *data)
00435 {
00436 struct chanspy_ds *chanspy_ds = data;
00437
00438
00439
00440
00441
00442 ast_mutex_lock(&chanspy_ds->lock);
00443 chanspy_ds->chan = NULL;
00444 ast_mutex_unlock(&chanspy_ds->lock);
00445 }
00446
00447 static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
00448 {
00449 struct chanspy_ds *chanspy_ds = data;
00450
00451 ast_mutex_lock(&chanspy_ds->lock);
00452 chanspy_ds->chan = new_chan;
00453 ast_mutex_unlock(&chanspy_ds->lock);
00454 }
00455
00456 static const struct ast_datastore_info chanspy_ds_info = {
00457 .type = "chanspy",
00458 .destroy = chanspy_ds_destroy,
00459 .chan_fixup = chanspy_ds_chan_fixup,
00460 };
00461
00462 static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
00463 {
00464 struct ast_channel *chan;
00465
00466 if (!chanspy_ds) {
00467 return NULL;
00468 }
00469
00470 ast_mutex_lock(&chanspy_ds->lock);
00471 while ((chan = chanspy_ds->chan)) {
00472 struct ast_datastore *datastore;
00473
00474 if (ast_channel_trylock(chan)) {
00475 DEADLOCK_AVOIDANCE(&chanspy_ds->lock);
00476 continue;
00477 }
00478 if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
00479 ast_channel_datastore_remove(chan, datastore);
00480
00481 chanspy_ds_destroy(datastore->data);
00482 datastore->data = NULL;
00483 ast_channel_datastore_free(datastore);
00484 }
00485 ast_channel_unlock(chan);
00486 break;
00487 }
00488 ast_mutex_unlock(&chanspy_ds->lock);
00489
00490 return NULL;
00491 }
00492
00493
00494 static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
00495 {
00496 struct ast_datastore *datastore = NULL;
00497
00498 ast_mutex_lock(&chanspy_ds->lock);
00499
00500 if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
00501 ast_mutex_unlock(&chanspy_ds->lock);
00502 chanspy_ds = chanspy_ds_free(chanspy_ds);
00503 ast_channel_unlock(chan);
00504 return NULL;
00505 }
00506
00507 chanspy_ds->chan = chan;
00508 datastore->data = chanspy_ds;
00509 ast_channel_datastore_add(chan, datastore);
00510
00511 return chanspy_ds;
00512 }
00513
00514 static struct chanspy_ds *next_channel(struct ast_channel *chan,
00515 const struct ast_channel *last, const char *spec,
00516 const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
00517 {
00518 struct ast_channel *next;
00519 const size_t pseudo_len = strlen("DAHDI/pseudo");
00520
00521 redo:
00522 if (!ast_strlen_zero(spec))
00523 next = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
00524
00525 else if (!ast_strlen_zero(exten))
00526 next = ast_walk_channel_by_exten_locked(last, exten, context);
00527 else
00528 next = ast_channel_walk_locked(last);
00529
00530 if (!next)
00531 return NULL;
00532
00533 if (!strncmp(next->name, "DAHDI/pseudo", pseudo_len)) {
00534 last = next;
00535 ast_channel_unlock(next);
00536 goto redo;
00537 } else if (next == chan) {
00538 last = next;
00539 ast_channel_unlock(next);
00540 goto redo;
00541 }
00542
00543 return setup_chanspy_ds(next, chanspy_ds);
00544 }
00545
00546 static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
00547 int volfactor, const int fd, const char *mygroup, const char *myenforced,
00548 const char *spec, const char *exten, const char *context)
00549 {
00550 char nameprefix[AST_NAME_STRLEN];
00551 char peer_name[AST_NAME_STRLEN + 5];
00552 char exitcontext[AST_MAX_CONTEXT] = "";
00553 signed char zero_volume = 0;
00554 int waitms;
00555 int res;
00556 char *ptr;
00557 int num;
00558 int num_spyed_upon = 1;
00559 struct chanspy_ds chanspy_ds = { 0, };
00560
00561 if (ast_test_flag(flags, OPTION_EXIT)) {
00562 const char *c;
00563 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
00564 ast_copy_string(exitcontext, c, sizeof(exitcontext));
00565 else if (!ast_strlen_zero(chan->macrocontext))
00566 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00567 else
00568 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00569 }
00570
00571 ast_mutex_init(&chanspy_ds.lock);
00572
00573 snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
00574
00575 if (chan->_state != AST_STATE_UP)
00576 ast_answer(chan);
00577
00578 ast_set_flag(chan, AST_FLAG_SPYING);
00579
00580 waitms = 100;
00581
00582 for (;;) {
00583 struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
00584 struct ast_channel *prev = NULL, *peer = NULL;
00585
00586 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00587 res = ast_streamfile(chan, "beep", chan->language);
00588 if (!res)
00589 res = ast_waitstream(chan, "");
00590 else if (res < 0) {
00591 ast_clear_flag(chan, AST_FLAG_SPYING);
00592 break;
00593 }
00594 if (!ast_strlen_zero(exitcontext)) {
00595 char tmp[2];
00596 tmp[0] = res;
00597 tmp[1] = '\0';
00598 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00599 goto exit;
00600 else
00601 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00602 }
00603 }
00604
00605 res = ast_waitfordigit(chan, waitms);
00606 if (res < 0) {
00607 ast_clear_flag(chan, AST_FLAG_SPYING);
00608 break;
00609 }
00610 if (!ast_strlen_zero(exitcontext)) {
00611 char tmp[2];
00612 tmp[0] = res;
00613 tmp[1] = '\0';
00614 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00615 goto exit;
00616 else
00617 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00618 }
00619
00620
00621 waitms = 100;
00622 num_spyed_upon = 0;
00623
00624 for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
00625 peer_chanspy_ds;
00626 chanspy_ds_free(peer_chanspy_ds), prev = peer,
00627 peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
00628 next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
00629 int igrp = !mygroup;
00630 int ienf = !myenforced;
00631 char *s;
00632
00633 peer = peer_chanspy_ds->chan;
00634
00635 ast_mutex_unlock(&peer_chanspy_ds->lock);
00636
00637 if (peer == prev) {
00638 ast_channel_unlock(peer);
00639 chanspy_ds_free(peer_chanspy_ds);
00640 break;
00641 }
00642
00643 if (ast_check_hangup(chan)) {
00644 ast_channel_unlock(peer);
00645 chanspy_ds_free(peer_chanspy_ds);
00646 break;
00647 }
00648
00649 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
00650 ast_channel_unlock(peer);
00651 continue;
00652 }
00653
00654 if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
00655 ast_channel_unlock(peer);
00656 continue;
00657 }
00658
00659 if (mygroup) {
00660 int num_groups = 0;
00661 char dup_group[512];
00662 char *groups[25];
00663 const char *group;
00664 int x;
00665 if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
00666 ast_copy_string(dup_group, group, sizeof(dup_group));
00667 num_groups = ast_app_separate_args(dup_group, ':', groups,
00668 ARRAY_LEN(groups));
00669 }
00670
00671 for (x = 0; x < num_groups; x++) {
00672 if (!strcmp(mygroup, groups[x])) {
00673 igrp = 1;
00674 break;
00675 }
00676 }
00677 }
00678
00679 if (!igrp) {
00680 ast_channel_unlock(peer);
00681 continue;
00682 }
00683
00684 if (myenforced) {
00685 char ext[AST_CHANNEL_NAME + 3];
00686 char buffer[512];
00687 char *end;
00688
00689 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
00690
00691 ast_copy_string(ext + 1, peer->name, sizeof(ext) - 1);
00692 if ((end = strchr(ext, '-'))) {
00693 *end++ = ':';
00694 *end = '\0';
00695 }
00696
00697 ext[0] = ':';
00698
00699 if (strcasestr(buffer, ext)) {
00700 ienf = 1;
00701 }
00702 }
00703
00704 if (!ienf) {
00705 continue;
00706 }
00707
00708 strcpy(peer_name, "spy-");
00709 strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
00710 ptr = strchr(peer_name, '/');
00711 *ptr++ = '\0';
00712
00713 for (s = peer_name; s < ptr; s++)
00714 *s = tolower(*s);
00715
00716
00717
00718
00719 ast_channel_unlock(peer);
00720
00721 if (!ast_test_flag(flags, OPTION_QUIET)) {
00722 if (ast_fileexists(peer_name, NULL, NULL) != -1) {
00723 res = ast_streamfile(chan, peer_name, chan->language);
00724 if (!res)
00725 res = ast_waitstream(chan, "");
00726 if (res) {
00727 chanspy_ds_free(peer_chanspy_ds);
00728 break;
00729 }
00730 } else
00731 res = ast_say_character_str(chan, peer_name, "", chan->language);
00732 if ((num = atoi(ptr)))
00733 ast_say_digits(chan, atoi(ptr), "", chan->language);
00734 }
00735
00736 res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags, exitcontext);
00737 num_spyed_upon++;
00738
00739 if (res == -1) {
00740 chanspy_ds_free(peer_chanspy_ds);
00741 goto exit;
00742 } else if (res == -2) {
00743 res = 0;
00744 chanspy_ds_free(peer_chanspy_ds);
00745 goto exit;
00746 } else if (res > 1 && spec) {
00747 struct ast_channel *next;
00748
00749 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
00750
00751 if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
00752 peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
00753 next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
00754 } else {
00755
00756
00757 ast_mutex_lock(&peer_chanspy_ds->lock);
00758 if (peer_chanspy_ds->chan) {
00759 ast_channel_lock(peer_chanspy_ds->chan);
00760 next_chanspy_ds = peer_chanspy_ds;
00761 peer_chanspy_ds = NULL;
00762 } else {
00763
00764 ast_mutex_unlock(&peer_chanspy_ds->lock);
00765 next_chanspy_ds = NULL;
00766 }
00767 }
00768
00769 peer = NULL;
00770 }
00771 }
00772 if (res == -1 || ast_check_hangup(chan))
00773 break;
00774 }
00775 exit:
00776
00777 ast_clear_flag(chan, AST_FLAG_SPYING);
00778
00779 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
00780
00781 ast_mutex_lock(&chanspy_ds.lock);
00782 ast_mutex_unlock(&chanspy_ds.lock);
00783 ast_mutex_destroy(&chanspy_ds.lock);
00784
00785 return res;
00786 }
00787
00788 static int chanspy_exec(struct ast_channel *chan, void *data)
00789 {
00790 char *myenforced = NULL;
00791 char *mygroup = NULL;
00792 char *recbase = NULL;
00793 int fd = 0;
00794 struct ast_flags flags;
00795 int oldwf = 0;
00796 int volfactor = 0;
00797 int res;
00798 AST_DECLARE_APP_ARGS(args,
00799 AST_APP_ARG(spec);
00800 AST_APP_ARG(options);
00801 );
00802 char *opts[OPT_ARG_ARRAY_SIZE];
00803
00804 data = ast_strdupa(data);
00805 AST_STANDARD_APP_ARGS(args, data);
00806
00807 if (args.spec && !strcmp(args.spec, "all"))
00808 args.spec = NULL;
00809
00810 if (args.options) {
00811 ast_app_parse_options(spy_opts, &flags, opts, args.options);
00812 if (ast_test_flag(&flags, OPTION_GROUP))
00813 mygroup = opts[OPT_ARG_GROUP];
00814
00815 if (ast_test_flag(&flags, OPTION_RECORD) &&
00816 !(recbase = opts[OPT_ARG_RECORD]))
00817 recbase = "chanspy";
00818
00819 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00820 int vol;
00821
00822 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
00823 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00824 else
00825 volfactor = vol;
00826 }
00827
00828 if (ast_test_flag(&flags, OPTION_PRIVATE))
00829 ast_set_flag(&flags, OPTION_WHISPER);
00830
00831 if (ast_test_flag(&flags, OPTION_ENFORCED))
00832 myenforced = opts[OPT_ARG_ENFORCED];
00833
00834 } else
00835 ast_clear_flag(&flags, AST_FLAGS_ALL);
00836
00837 oldwf = chan->writeformat;
00838 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00839 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00840 return -1;
00841 }
00842
00843 if (recbase) {
00844 char filename[PATH_MAX];
00845
00846 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00847 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
00848 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00849 fd = 0;
00850 }
00851 }
00852
00853 res = common_exec(chan, &flags, volfactor, fd, mygroup, myenforced, args.spec, NULL, NULL);
00854
00855 if (fd)
00856 close(fd);
00857
00858 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00859 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00860
00861 return res;
00862 }
00863
00864 static int extenspy_exec(struct ast_channel *chan, void *data)
00865 {
00866 char *ptr, *exten = NULL;
00867 char *mygroup = NULL;
00868 char *recbase = NULL;
00869 int fd = 0;
00870 struct ast_flags flags;
00871 int oldwf = 0;
00872 int volfactor = 0;
00873 int res;
00874 AST_DECLARE_APP_ARGS(args,
00875 AST_APP_ARG(context);
00876 AST_APP_ARG(options);
00877 );
00878
00879 data = ast_strdupa(data);
00880
00881 AST_STANDARD_APP_ARGS(args, data);
00882 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
00883 exten = args.context;
00884 *ptr++ = '\0';
00885 args.context = ptr;
00886 }
00887
00888 if (ast_strlen_zero(args.context))
00889 args.context = ast_strdupa(chan->context);
00890
00891 if (args.options) {
00892 char *opts[OPT_ARG_ARRAY_SIZE];
00893
00894 ast_app_parse_options(spy_opts, &flags, opts, args.options);
00895 if (ast_test_flag(&flags, OPTION_GROUP))
00896 mygroup = opts[OPT_ARG_GROUP];
00897
00898 if (ast_test_flag(&flags, OPTION_RECORD) &&
00899 !(recbase = opts[OPT_ARG_RECORD]))
00900 recbase = "chanspy";
00901
00902 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
00903 int vol;
00904
00905 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
00906 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
00907 else
00908 volfactor = vol;
00909 }
00910
00911 if (ast_test_flag(&flags, OPTION_PRIVATE))
00912 ast_set_flag(&flags, OPTION_WHISPER);
00913 } else
00914 ast_clear_flag(&flags, AST_FLAGS_ALL);
00915
00916 oldwf = chan->writeformat;
00917 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
00918 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00919 return -1;
00920 }
00921
00922 if (recbase) {
00923 char filename[PATH_MAX];
00924
00925 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
00926 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
00927 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
00928 fd = 0;
00929 }
00930 }
00931
00932
00933 res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, NULL, exten, args.context);
00934
00935 if (fd)
00936 close(fd);
00937
00938 if (oldwf && ast_set_write_format(chan, oldwf) < 0)
00939 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
00940
00941 return res;
00942 }
00943
00944 static int unload_module(void)
00945 {
00946 int res = 0;
00947
00948 res |= ast_unregister_application(app_chan);
00949 res |= ast_unregister_application(app_ext);
00950
00951 return res;
00952 }
00953
00954 static int load_module(void)
00955 {
00956 int res = 0;
00957
00958 res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
00959 res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
00960
00961 return res;
00962 }
00963
00964 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");