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