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