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