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