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
00033
00034
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 354429 $")
00039
00040 #include <ctype.h>
00041 #include <errno.h>
00042
00043 #include "asterisk/paths.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/audiohook.h"
00047 #include "asterisk/features.h"
00048 #include "asterisk/app.h"
00049 #include "asterisk/utils.h"
00050 #include "asterisk/say.h"
00051 #include "asterisk/pbx.h"
00052 #include "asterisk/translate.h"
00053 #include "asterisk/manager.h"
00054 #include "asterisk/module.h"
00055 #include "asterisk/lock.h"
00056 #include "asterisk/options.h"
00057 #include "asterisk/autochan.h"
00058
00059 #define AST_NAME_STRLEN 256
00060 #define NUM_SPYGROUPS 128
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
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 static const char app_chan[] = "ChanSpy";
00345
00346 static const char app_ext[] = "ExtenSpy";
00347
00348 static const char app_dahdiscan[] = "DAHDIScan";
00349
00350 enum {
00351 OPTION_QUIET = (1 << 0),
00352 OPTION_BRIDGED = (1 << 1),
00353 OPTION_VOLUME = (1 << 2),
00354 OPTION_GROUP = (1 << 3),
00355 OPTION_RECORD = (1 << 4),
00356 OPTION_WHISPER = (1 << 5),
00357 OPTION_PRIVATE = (1 << 6),
00358 OPTION_READONLY = (1 << 7),
00359 OPTION_EXIT = (1 << 8),
00360 OPTION_ENFORCED = (1 << 9),
00361 OPTION_NOTECH = (1 << 10),
00362 OPTION_BARGE = (1 << 11),
00363 OPTION_NAME = (1 << 12),
00364 OPTION_DTMF_SWITCH_MODES = (1 << 13),
00365 OPTION_DTMF_EXIT = (1 << 14),
00366 OPTION_DTMF_CYCLE = (1 << 15),
00367 OPTION_DAHDI_SCAN = (1 << 16),
00368 OPTION_STOP = (1 << 17),
00369 OPTION_EXITONHANGUP = (1 << 18),
00370 };
00371
00372 enum {
00373 OPT_ARG_VOLUME = 0,
00374 OPT_ARG_GROUP,
00375 OPT_ARG_RECORD,
00376 OPT_ARG_ENFORCED,
00377 OPT_ARG_NAME,
00378 OPT_ARG_EXIT,
00379 OPT_ARG_CYCLE,
00380 OPT_ARG_ARRAY_SIZE,
00381 };
00382
00383 AST_APP_OPTIONS(spy_opts, {
00384 AST_APP_OPTION('b', OPTION_BRIDGED),
00385 AST_APP_OPTION('B', OPTION_BARGE),
00386 AST_APP_OPTION_ARG('c', OPTION_DTMF_CYCLE, OPT_ARG_CYCLE),
00387 AST_APP_OPTION('d', OPTION_DTMF_SWITCH_MODES),
00388 AST_APP_OPTION_ARG('e', OPTION_ENFORCED, OPT_ARG_ENFORCED),
00389 AST_APP_OPTION('E', OPTION_EXITONHANGUP),
00390 AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
00391 AST_APP_OPTION_ARG('n', OPTION_NAME, OPT_ARG_NAME),
00392 AST_APP_OPTION('o', OPTION_READONLY),
00393 AST_APP_OPTION('q', OPTION_QUIET),
00394 AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
00395 AST_APP_OPTION('s', OPTION_NOTECH),
00396 AST_APP_OPTION('S', OPTION_STOP),
00397 AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
00398 AST_APP_OPTION('w', OPTION_WHISPER),
00399 AST_APP_OPTION('W', OPTION_PRIVATE),
00400 AST_APP_OPTION_ARG('x', OPTION_DTMF_EXIT, OPT_ARG_EXIT),
00401 AST_APP_OPTION('X', OPTION_EXIT),
00402 });
00403
00404 struct chanspy_translation_helper {
00405
00406 struct ast_audiohook spy_audiohook;
00407 struct ast_audiohook whisper_audiohook;
00408 struct ast_audiohook bridge_whisper_audiohook;
00409 int fd;
00410 int volfactor;
00411 struct ast_flags flags;
00412 };
00413
00414 struct spy_dtmf_options {
00415 char exit;
00416 char cycle;
00417 char volume;
00418 };
00419
00420 static void *spy_alloc(struct ast_channel *chan, void *data)
00421 {
00422
00423 return data;
00424 }
00425
00426 static void spy_release(struct ast_channel *chan, void *data)
00427 {
00428
00429 }
00430
00431 static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
00432 {
00433 struct chanspy_translation_helper *csth = data;
00434 struct ast_frame *f, *cur;
00435 struct ast_format format_slin;
00436
00437 ast_format_set(&format_slin, AST_FORMAT_SLINEAR, 0);
00438
00439 ast_audiohook_lock(&csth->spy_audiohook);
00440 if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00441
00442 ast_audiohook_unlock(&csth->spy_audiohook);
00443 return -1;
00444 }
00445
00446 if (ast_test_flag(&csth->flags, OPTION_READONLY)) {
00447
00448 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_READ, &format_slin);
00449 } else {
00450 f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin);
00451 }
00452
00453 ast_audiohook_unlock(&csth->spy_audiohook);
00454
00455 if (!f)
00456 return 0;
00457
00458 for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00459 if (ast_write(chan, cur)) {
00460 ast_frfree(f);
00461 return -1;
00462 }
00463
00464 if (csth->fd) {
00465 if (write(csth->fd, cur->data.ptr, cur->datalen) < 0) {
00466 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
00467 }
00468 }
00469 }
00470
00471 ast_frfree(f);
00472
00473 return 0;
00474 }
00475
00476 static struct ast_generator spygen = {
00477 .alloc = spy_alloc,
00478 .release = spy_release,
00479 .generate = spy_generate,
00480 };
00481
00482 static int start_spying(struct ast_autochan *autochan, const char *spychan_name, struct ast_audiohook *audiohook)
00483 {
00484 int res = 0;
00485 struct ast_channel *peer = NULL;
00486
00487 ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, ast_channel_name(autochan->chan));
00488
00489 ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
00490 res = ast_audiohook_attach(autochan->chan, audiohook);
00491
00492 if (!res && ast_test_flag(autochan->chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(autochan->chan))) {
00493 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
00494 }
00495 return res;
00496 }
00497
00498 static void change_spy_mode(const char digit, struct ast_flags *flags)
00499 {
00500 if (digit == '4') {
00501 ast_clear_flag(flags, OPTION_WHISPER);
00502 ast_clear_flag(flags, OPTION_BARGE);
00503 } else if (digit == '5') {
00504 ast_clear_flag(flags, OPTION_BARGE);
00505 ast_set_flag(flags, OPTION_WHISPER);
00506 } else if (digit == '6') {
00507 ast_clear_flag(flags, OPTION_WHISPER);
00508 ast_set_flag(flags, OPTION_BARGE);
00509 }
00510 }
00511
00512 static int channel_spy(struct ast_channel *chan, struct ast_autochan *spyee_autochan,
00513 int *volfactor, int fd, struct spy_dtmf_options *user_options, struct ast_flags *flags,
00514 char *exitcontext)
00515 {
00516 struct chanspy_translation_helper csth;
00517 int running = 0, res, x = 0;
00518 char inp[24] = {0};
00519 char *name;
00520 struct ast_frame *f;
00521 struct ast_silence_generator *silgen = NULL;
00522 struct ast_autochan *spyee_bridge_autochan = NULL;
00523 const char *spyer_name;
00524 struct ast_channel *chans[] = { chan, spyee_autochan->chan };
00525
00526 ast_channel_lock(chan);
00527 spyer_name = ast_strdupa(ast_channel_name(chan));
00528 ast_channel_unlock(chan);
00529
00530
00531
00532 if (ast_check_hangup(chan) || ast_check_hangup(spyee_autochan->chan)) {
00533 return 0;
00534 }
00535
00536 ast_channel_lock(spyee_autochan->chan);
00537 name = ast_strdupa(ast_channel_name(spyee_autochan->chan));
00538 ast_channel_unlock(spyee_autochan->chan);
00539
00540 ast_verb(2, "Spying on channel %s\n", name);
00541 ast_manager_event_multichan(EVENT_FLAG_CALL, "ChanSpyStart", 2, chans,
00542 "SpyerChannel: %s\r\n"
00543 "SpyeeChannel: %s\r\n",
00544 spyer_name, name);
00545
00546 memset(&csth, 0, sizeof(csth));
00547 ast_copy_flags(&csth.flags, flags, AST_FLAGS_ALL);
00548
00549
00550
00551
00552 ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy", 0);
00553
00554 if (start_spying(spyee_autochan, spyer_name, &csth.spy_audiohook)) {
00555 ast_audiohook_destroy(&csth.spy_audiohook);
00556 return 0;
00557 }
00558
00559 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00560
00561
00562
00563 ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy", 0);
00564
00565 if (start_spying(spyee_autochan, spyer_name, &csth.whisper_audiohook)) {
00566 ast_log(LOG_WARNING, "Unable to attach whisper audiohook to spyee %s. Whisper mode disabled!\n", name);
00567 }
00568 }
00569
00570 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00571
00572
00573
00574 ast_audiohook_init(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "Chanspy", 0);
00575
00576 if ((spyee_bridge_autochan = ast_autochan_setup(ast_bridged_channel(spyee_autochan->chan)))) {
00577 ast_channel_lock(spyee_bridge_autochan->chan);
00578 if (start_spying(spyee_bridge_autochan, spyer_name, &csth.bridge_whisper_audiohook)) {
00579 ast_log(LOG_WARNING, "Unable to attach barge audiohook on spyee %s. Barge mode disabled!\n", name);
00580 }
00581 ast_channel_unlock(spyee_bridge_autochan->chan);
00582 }
00583 }
00584
00585 ast_channel_lock(chan);
00586 ast_set_flag(chan, AST_FLAG_END_DTMF_ONLY);
00587 ast_channel_unlock(chan);
00588
00589 csth.volfactor = *volfactor;
00590
00591 if (csth.volfactor) {
00592 csth.spy_audiohook.options.read_volume = csth.volfactor;
00593 csth.spy_audiohook.options.write_volume = csth.volfactor;
00594 }
00595
00596 csth.fd = fd;
00597
00598 if (ast_test_flag(flags, OPTION_PRIVATE))
00599 silgen = ast_channel_start_silence_generator(chan);
00600 else
00601 ast_activate_generator(chan, &spygen, &csth);
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 while (ast_waitfor(chan, -1) > -1 && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
00618 if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
00619 running = -1;
00620 break;
00621 }
00622
00623 if (ast_test_flag(flags, OPTION_BARGE) && f->frametype == AST_FRAME_VOICE) {
00624 ast_audiohook_lock(&csth.whisper_audiohook);
00625 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00626 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00627 ast_audiohook_write_frame(&csth.bridge_whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00628 ast_audiohook_unlock(&csth.whisper_audiohook);
00629 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00630 ast_frfree(f);
00631 continue;
00632 } else if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
00633 ast_audiohook_lock(&csth.whisper_audiohook);
00634 ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
00635 ast_audiohook_unlock(&csth.whisper_audiohook);
00636 ast_frfree(f);
00637 continue;
00638 }
00639
00640 res = (f->frametype == AST_FRAME_DTMF) ? f->subclass.integer : 0;
00641 ast_frfree(f);
00642 if (!res)
00643 continue;
00644
00645 if (x == sizeof(inp))
00646 x = 0;
00647
00648 if (res < 0) {
00649 running = -1;
00650 break;
00651 }
00652
00653 if (ast_test_flag(flags, OPTION_EXIT)) {
00654 char tmp[2];
00655 tmp[0] = res;
00656 tmp[1] = '\0';
00657 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00658 ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
00659 pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
00660 running = -2;
00661 break;
00662 } else {
00663 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00664 }
00665 } else if (res >= '0' && res <= '9') {
00666 if (ast_test_flag(flags, OPTION_DTMF_SWITCH_MODES)) {
00667 change_spy_mode(res, flags);
00668 } else {
00669 inp[x++] = res;
00670 }
00671 }
00672
00673 if (res == user_options->cycle) {
00674 running = 0;
00675 break;
00676 } else if (res == user_options->exit) {
00677 running = -2;
00678 break;
00679 } else if (res == user_options->volume) {
00680 if (!ast_strlen_zero(inp)) {
00681 running = atoi(inp);
00682 break;
00683 }
00684
00685 (*volfactor)++;
00686 if (*volfactor > 4)
00687 *volfactor = -4;
00688 ast_verb(3, "Setting spy volume on %s to %d\n", ast_channel_name(chan), *volfactor);
00689
00690 csth.volfactor = *volfactor;
00691 csth.spy_audiohook.options.read_volume = csth.volfactor;
00692 csth.spy_audiohook.options.write_volume = csth.volfactor;
00693 }
00694 }
00695
00696 if (ast_test_flag(flags, OPTION_PRIVATE))
00697 ast_channel_stop_silence_generator(chan, silgen);
00698 else
00699 ast_deactivate_generator(chan);
00700
00701 ast_channel_lock(chan);
00702 ast_clear_flag(chan, AST_FLAG_END_DTMF_ONLY);
00703 ast_channel_unlock(chan);
00704
00705 if (ast_test_flag(flags, OPTION_WHISPER | OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00706 ast_audiohook_lock(&csth.whisper_audiohook);
00707 ast_audiohook_detach(&csth.whisper_audiohook);
00708 ast_audiohook_unlock(&csth.whisper_audiohook);
00709 ast_audiohook_destroy(&csth.whisper_audiohook);
00710 }
00711
00712 if (ast_test_flag(flags, OPTION_BARGE | OPTION_DTMF_SWITCH_MODES)) {
00713 ast_audiohook_lock(&csth.bridge_whisper_audiohook);
00714 ast_audiohook_detach(&csth.bridge_whisper_audiohook);
00715 ast_audiohook_unlock(&csth.bridge_whisper_audiohook);
00716 ast_audiohook_destroy(&csth.bridge_whisper_audiohook);
00717 }
00718
00719 ast_audiohook_lock(&csth.spy_audiohook);
00720 ast_audiohook_detach(&csth.spy_audiohook);
00721 ast_audiohook_unlock(&csth.spy_audiohook);
00722 ast_audiohook_destroy(&csth.spy_audiohook);
00723
00724 if (spyee_bridge_autochan) {
00725 ast_autochan_destroy(spyee_bridge_autochan);
00726 }
00727
00728 ast_verb(2, "Done Spying on channel %s\n", name);
00729 ast_manager_event(chan, EVENT_FLAG_CALL, "ChanSpyStop", "SpyeeChannel: %s\r\n", name);
00730
00731 return running;
00732 }
00733
00734 static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
00735 struct ast_autochan *autochan, struct ast_channel *chan)
00736 {
00737 struct ast_channel *next;
00738 struct ast_autochan *autochan_store;
00739 const size_t pseudo_len = strlen("DAHDI/pseudo");
00740
00741 if (!iter) {
00742 return NULL;
00743 }
00744
00745 redo:
00746 if (!(next = ast_channel_iterator_next(iter))) {
00747 return NULL;
00748 }
00749
00750 if (!strncmp(ast_channel_name(next), "DAHDI/pseudo", pseudo_len)) {
00751 goto redo;
00752 } else if (next == chan) {
00753 goto redo;
00754 }
00755
00756 autochan_store = ast_autochan_setup(next);
00757 ast_channel_unref(next);
00758
00759 return autochan_store;
00760 }
00761
00762 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
00763 int volfactor, const int fd, struct spy_dtmf_options *user_options,
00764 const char *mygroup, const char *myenforced, const char *spec, const char *exten,
00765 const char *context, const char *mailbox, const char *name_context)
00766 {
00767 char nameprefix[AST_NAME_STRLEN];
00768 char peer_name[AST_NAME_STRLEN + 5];
00769 char exitcontext[AST_MAX_CONTEXT] = "";
00770 signed char zero_volume = 0;
00771 int waitms;
00772 int res;
00773 char *ptr;
00774 int num_spyed_upon = 1;
00775 struct ast_channel_iterator *iter = NULL;
00776
00777 if (ast_test_flag(flags, OPTION_EXIT)) {
00778 const char *c;
00779 ast_channel_lock(chan);
00780 if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
00781 ast_copy_string(exitcontext, c, sizeof(exitcontext));
00782 } else if (!ast_strlen_zero(chan->macrocontext)) {
00783 ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
00784 } else {
00785 ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
00786 }
00787 ast_channel_unlock(chan);
00788 }
00789
00790 if (chan->_state != AST_STATE_UP)
00791 ast_answer(chan);
00792
00793 ast_set_flag(chan, AST_FLAG_SPYING);
00794
00795 waitms = 100;
00796
00797 for (;;) {
00798 struct ast_autochan *autochan = NULL, *next_autochan = NULL;
00799 struct ast_channel *prev = NULL;
00800
00801 if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
00802 res = ast_streamfile(chan, "beep", ast_channel_language(chan));
00803 if (!res)
00804 res = ast_waitstream(chan, "");
00805 else if (res < 0) {
00806 ast_clear_flag(chan, AST_FLAG_SPYING);
00807 break;
00808 }
00809 if (!ast_strlen_zero(exitcontext)) {
00810 char tmp[2];
00811 tmp[0] = res;
00812 tmp[1] = '\0';
00813 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
00814 goto exit;
00815 else
00816 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00817 }
00818 }
00819
00820
00821 if (!ast_strlen_zero(spec)) {
00822 iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
00823 } else if (!ast_strlen_zero(exten)) {
00824 iter = ast_channel_iterator_by_exten_new(exten, context);
00825 } else {
00826 iter = ast_channel_iterator_all_new();
00827 }
00828
00829 if (!iter) {
00830 res = -1;
00831 goto exit;
00832 }
00833
00834 res = ast_waitfordigit(chan, waitms);
00835 if (res < 0) {
00836 iter = ast_channel_iterator_destroy(iter);
00837 ast_clear_flag(chan, AST_FLAG_SPYING);
00838 break;
00839 }
00840 if (!ast_strlen_zero(exitcontext)) {
00841 char tmp[2];
00842 tmp[0] = res;
00843 tmp[1] = '\0';
00844 if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
00845 iter = ast_channel_iterator_destroy(iter);
00846 goto exit;
00847 } else {
00848 ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
00849 }
00850 }
00851
00852
00853 waitms = 100;
00854 num_spyed_upon = 0;
00855
00856 for (autochan = next_channel(iter, autochan, chan);
00857 autochan;
00858 prev = autochan->chan, ast_autochan_destroy(autochan),
00859 autochan = next_autochan ? next_autochan :
00860 next_channel(iter, autochan, chan), next_autochan = NULL) {
00861 int igrp = !mygroup;
00862 int ienf = !myenforced;
00863 char *s;
00864
00865 if (autochan->chan == prev) {
00866 ast_autochan_destroy(autochan);
00867 break;
00868 }
00869
00870 if (ast_check_hangup(chan)) {
00871 ast_autochan_destroy(autochan);
00872 break;
00873 }
00874
00875 if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
00876 continue;
00877 }
00878
00879 if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
00880 continue;
00881 }
00882
00883 if (mygroup) {
00884 int num_groups = 0;
00885 int num_mygroups = 0;
00886 char dup_group[512];
00887 char dup_mygroup[512];
00888 char *groups[NUM_SPYGROUPS];
00889 char *mygroups[NUM_SPYGROUPS];
00890 const char *group = NULL;
00891 int x;
00892 int y;
00893 ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
00894 num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
00895 ARRAY_LEN(mygroups));
00896
00897
00898
00899 if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
00900 group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
00901 } else {
00902 group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
00903 }
00904
00905 if (!ast_strlen_zero(group)) {
00906 ast_copy_string(dup_group, group, sizeof(dup_group));
00907 num_groups = ast_app_separate_args(dup_group, ':', groups,
00908 ARRAY_LEN(groups));
00909 }
00910
00911 for (y = 0; y < num_mygroups; y++) {
00912 for (x = 0; x < num_groups; x++) {
00913 if (!strcmp(mygroups[y], groups[x])) {
00914 igrp = 1;
00915 break;
00916 }
00917 }
00918 }
00919 }
00920
00921 if (!igrp) {
00922 continue;
00923 }
00924 if (myenforced) {
00925 char ext[AST_CHANNEL_NAME + 3];
00926 char buffer[512];
00927 char *end;
00928
00929 snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);
00930
00931 ast_copy_string(ext + 1, ast_channel_name(autochan->chan), sizeof(ext) - 1);
00932 if ((end = strchr(ext, '-'))) {
00933 *end++ = ':';
00934 *end = '\0';
00935 }
00936
00937 ext[0] = ':';
00938
00939 if (strcasestr(buffer, ext)) {
00940 ienf = 1;
00941 }
00942 }
00943
00944 if (!ienf) {
00945 continue;
00946 }
00947
00948 strcpy(peer_name, "spy-");
00949 strncat(peer_name, ast_channel_name(autochan->chan), AST_NAME_STRLEN - 4 - 1);
00950 ptr = strchr(peer_name, '/');
00951 *ptr++ = '\0';
00952 ptr = strsep(&ptr, "-");
00953
00954 for (s = peer_name; s < ptr; s++)
00955 *s = tolower(*s);
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 int num;
00965 if (!ast_test_flag(flags, OPTION_NOTECH)) {
00966 if (ast_fileexists(peer_name, NULL, NULL) > 0) {
00967 res = ast_streamfile(chan, peer_name, ast_channel_language(chan));
00968 if (!res) {
00969 res = ast_waitstream(chan, "");
00970 }
00971 if (res) {
00972 ast_autochan_destroy(autochan);
00973 break;
00974 }
00975 } else {
00976 res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan));
00977 }
00978 }
00979 if ((num = atoi(ptr))) {
00980 ast_say_digits(chan, num, "", ast_channel_language(chan));
00981 }
00982 }
00983 }
00984
00985 res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
00986 num_spyed_upon++;
00987
00988 if (res == -1) {
00989 ast_autochan_destroy(autochan);
00990 iter = ast_channel_iterator_destroy(iter);
00991 goto exit;
00992 } else if (res == -2) {
00993 res = 0;
00994 ast_autochan_destroy(autochan);
00995 iter = ast_channel_iterator_destroy(iter);
00996 goto exit;
00997 } else if (res > 1 && spec) {
00998 struct ast_channel *next;
00999
01000 snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
01001
01002 if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
01003 next_autochan = ast_autochan_setup(next);
01004 next = ast_channel_unref(next);
01005 } else {
01006
01007 if (!ast_check_hangup(autochan->chan)) {
01008 next_autochan = ast_autochan_setup(autochan->chan);
01009 } else {
01010
01011 next_autochan = NULL;
01012 }
01013 }
01014 } else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
01015 iter = ast_channel_iterator_destroy(iter);
01016 goto exit;
01017 }
01018 }
01019
01020 iter = ast_channel_iterator_destroy(iter);
01021
01022 if (res == -1 || ast_check_hangup(chan))
01023 break;
01024 if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
01025 break;
01026 }
01027 }
01028 exit:
01029
01030 ast_clear_flag(chan, AST_FLAG_SPYING);
01031
01032 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
01033
01034 return res;
01035 }
01036
01037 static int chanspy_exec(struct ast_channel *chan, const char *data)
01038 {
01039 char *myenforced = NULL;
01040 char *mygroup = NULL;
01041 char *recbase = NULL;
01042 int fd = 0;
01043 struct ast_flags flags;
01044 struct spy_dtmf_options user_options = {
01045 .cycle = '*',
01046 .volume = '#',
01047 .exit = '\0',
01048 };
01049 struct ast_format oldwf;
01050 int volfactor = 0;
01051 int res;
01052 char *mailbox = NULL;
01053 char *name_context = NULL;
01054 AST_DECLARE_APP_ARGS(args,
01055 AST_APP_ARG(spec);
01056 AST_APP_ARG(options);
01057 );
01058 char *opts[OPT_ARG_ARRAY_SIZE];
01059 char *parse = ast_strdupa(data);
01060
01061 AST_STANDARD_APP_ARGS(args, parse);
01062 ast_format_clear(&oldwf);
01063
01064 if (args.spec && !strcmp(args.spec, "all"))
01065 args.spec = NULL;
01066
01067 if (args.options) {
01068 char tmp;
01069 ast_app_parse_options(spy_opts, &flags, opts, args.options);
01070 if (ast_test_flag(&flags, OPTION_GROUP))
01071 mygroup = opts[OPT_ARG_GROUP];
01072
01073 if (ast_test_flag(&flags, OPTION_RECORD) &&
01074 !(recbase = opts[OPT_ARG_RECORD]))
01075 recbase = "chanspy";
01076
01077 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
01078 tmp = opts[OPT_ARG_EXIT][0];
01079 if (strchr("0123456789*#", tmp) && tmp != '\0') {
01080 user_options.exit = tmp;
01081 } else {
01082 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
01083 }
01084 }
01085
01086 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
01087 tmp = opts[OPT_ARG_CYCLE][0];
01088 if (strchr("0123456789*#", tmp) && tmp != '\0') {
01089 user_options.cycle = tmp;
01090 } else {
01091 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
01092 }
01093 }
01094
01095 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
01096 int vol;
01097
01098 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
01099 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
01100 else
01101 volfactor = vol;
01102 }
01103
01104 if (ast_test_flag(&flags, OPTION_PRIVATE))
01105 ast_set_flag(&flags, OPTION_WHISPER);
01106
01107 if (ast_test_flag(&flags, OPTION_ENFORCED))
01108 myenforced = opts[OPT_ARG_ENFORCED];
01109
01110 if (ast_test_flag(&flags, OPTION_NAME)) {
01111 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
01112 char *delimiter;
01113 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
01114 mailbox = opts[OPT_ARG_NAME];
01115 *delimiter++ = '\0';
01116 name_context = delimiter;
01117 } else {
01118 mailbox = opts[OPT_ARG_NAME];
01119 }
01120 }
01121 }
01122 } else {
01123 ast_clear_flag(&flags, AST_FLAGS_ALL);
01124 }
01125
01126 ast_format_copy(&oldwf, &chan->writeformat);
01127 if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
01128 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01129 return -1;
01130 }
01131
01132 if (recbase) {
01133 char filename[PATH_MAX];
01134
01135 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
01136 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
01137 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
01138 fd = 0;
01139 }
01140 }
01141
01142 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, myenforced, args.spec, NULL, NULL, mailbox, name_context);
01143
01144 if (fd)
01145 close(fd);
01146
01147 if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
01148 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01149
01150 if (ast_test_flag(&flags, OPTION_EXITONHANGUP)) {
01151 ast_verb(3, "Stopped spying due to the spied-on channel hanging up.\n");
01152 }
01153
01154 return res;
01155 }
01156
01157 static int extenspy_exec(struct ast_channel *chan, const char *data)
01158 {
01159 char *ptr, *exten = NULL;
01160 char *mygroup = NULL;
01161 char *recbase = NULL;
01162 int fd = 0;
01163 struct ast_flags flags;
01164 struct spy_dtmf_options user_options = {
01165 .cycle = '*',
01166 .volume = '#',
01167 .exit = '\0',
01168 };
01169 struct ast_format oldwf;
01170 int volfactor = 0;
01171 int res;
01172 char *mailbox = NULL;
01173 char *name_context = NULL;
01174 AST_DECLARE_APP_ARGS(args,
01175 AST_APP_ARG(context);
01176 AST_APP_ARG(options);
01177 );
01178 char *parse = ast_strdupa(data);
01179
01180 AST_STANDARD_APP_ARGS(args, parse);
01181 ast_format_clear(&oldwf);
01182
01183 if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
01184 exten = args.context;
01185 *ptr++ = '\0';
01186 args.context = ptr;
01187 }
01188 if (ast_strlen_zero(args.context))
01189 args.context = ast_strdupa(chan->context);
01190
01191 if (args.options) {
01192 char *opts[OPT_ARG_ARRAY_SIZE];
01193 char tmp;
01194
01195 ast_app_parse_options(spy_opts, &flags, opts, args.options);
01196 if (ast_test_flag(&flags, OPTION_GROUP))
01197 mygroup = opts[OPT_ARG_GROUP];
01198
01199 if (ast_test_flag(&flags, OPTION_RECORD) &&
01200 !(recbase = opts[OPT_ARG_RECORD]))
01201 recbase = "chanspy";
01202
01203 if (ast_test_flag(&flags, OPTION_DTMF_EXIT) && opts[OPT_ARG_EXIT]) {
01204 tmp = opts[OPT_ARG_EXIT][0];
01205 if (strchr("0123456789*#", tmp) && tmp != '\0') {
01206 user_options.exit = tmp;
01207 } else {
01208 ast_log(LOG_NOTICE, "Argument for option 'x' must be a valid DTMF digit.");
01209 }
01210 }
01211
01212 if (ast_test_flag(&flags, OPTION_DTMF_CYCLE) && opts[OPT_ARG_CYCLE]) {
01213 tmp = opts[OPT_ARG_CYCLE][0];
01214 if (strchr("0123456789*#", tmp) && tmp != '\0') {
01215 user_options.cycle = tmp;
01216 } else {
01217 ast_log(LOG_NOTICE, "Argument for option 'c' must be a valid DTMF digit.");
01218 }
01219 }
01220
01221 if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
01222 int vol;
01223
01224 if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
01225 ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
01226 else
01227 volfactor = vol;
01228 }
01229
01230 if (ast_test_flag(&flags, OPTION_PRIVATE))
01231 ast_set_flag(&flags, OPTION_WHISPER);
01232
01233 if (ast_test_flag(&flags, OPTION_NAME)) {
01234 if (!ast_strlen_zero(opts[OPT_ARG_NAME])) {
01235 char *delimiter;
01236 if ((delimiter = strchr(opts[OPT_ARG_NAME], '@'))) {
01237 mailbox = opts[OPT_ARG_NAME];
01238 *delimiter++ = '\0';
01239 name_context = delimiter;
01240 } else {
01241 mailbox = opts[OPT_ARG_NAME];
01242 }
01243 }
01244 }
01245
01246 } else {
01247 ast_clear_flag(&flags, AST_FLAGS_ALL);
01248 }
01249
01250 oldwf = chan->writeformat;
01251 if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
01252 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01253 return -1;
01254 }
01255
01256 if (recbase) {
01257 char filename[PATH_MAX];
01258
01259 snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
01260 if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
01261 ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
01262 fd = 0;
01263 }
01264 }
01265
01266
01267 res = common_exec(chan, &flags, volfactor, fd, &user_options, mygroup, NULL, NULL, exten, args.context, mailbox, name_context);
01268
01269 if (fd)
01270 close(fd);
01271
01272 if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
01273 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01274
01275 return res;
01276 }
01277
01278 static int dahdiscan_exec(struct ast_channel *chan, const char *data)
01279 {
01280 const char *spec = "DAHDI";
01281 struct ast_flags flags;
01282 struct spy_dtmf_options user_options = {
01283 .cycle = '#',
01284 .volume = '\0',
01285 .exit = '*',
01286 };
01287 struct ast_format oldwf;
01288 int res;
01289 char *mygroup = NULL;
01290
01291 ast_clear_flag(&flags, AST_FLAGS_ALL);
01292 ast_format_clear(&oldwf);
01293 if (!ast_strlen_zero(data)) {
01294 mygroup = ast_strdupa(data);
01295 }
01296 ast_set_flag(&flags, OPTION_DTMF_EXIT);
01297 ast_set_flag(&flags, OPTION_DTMF_CYCLE);
01298 ast_set_flag(&flags, OPTION_DAHDI_SCAN);
01299
01300 ast_format_copy(&oldwf, &chan->writeformat);
01301 if (ast_set_write_format_by_id(chan, AST_FORMAT_SLINEAR) < 0) {
01302 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01303 return -1;
01304 }
01305
01306 res = common_exec(chan, &flags, 0, 0, &user_options, mygroup, NULL, spec, NULL, NULL, NULL, NULL);
01307
01308 if (oldwf.id && ast_set_write_format(chan, &oldwf) < 0)
01309 ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
01310
01311 return res;
01312 }
01313
01314 static int unload_module(void)
01315 {
01316 int res = 0;
01317
01318 res |= ast_unregister_application(app_chan);
01319 res |= ast_unregister_application(app_ext);
01320 res |= ast_unregister_application(app_dahdiscan);
01321
01322 return res;
01323 }
01324
01325 static int load_module(void)
01326 {
01327 int res = 0;
01328
01329 res |= ast_register_application_xml(app_chan, chanspy_exec);
01330 res |= ast_register_application_xml(app_ext, extenspy_exec);
01331 res |= ast_register_application_xml(app_dahdiscan, dahdiscan_exec);
01332
01333 return res;
01334 }
01335
01336 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");