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