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