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