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