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