-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathspy.pl
173 lines (151 loc) · 4.64 KB
/
spy.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#
# spy.pl - Enables two cooperating irssi users to share one user's view of a
# channel.
#
# This is probably a bit evil. Only use your powers for good.
#
# Glenn Willen ([email protected])
use Irssi;
use POSIX;
use Data::Dumper;
use vars qw($VERSION %IRSSI);
$VERSION = "0.01";
%IRSSI = (
authors => "Glenn Willen",
contact => "gwillen\@nerdnet.org",
name => "spy",
description => "Enables two cooperating irssi users to share one user's view of a channel.",
license => "Public Domain",
url => "http://irssi.org/",
changed => "Fri May 11 00:00:00 EST 2012"
);
$hdr = "xIRCSPYx";
$overhead = length($hdr);
$linemax = 400 - $overhead;
$timeout = 10;
$min_send_interval = 5;
$buf = "";
$maxtimer = undef;
$mintimer = undef;
$lockout = 0;
@data = ();
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
sub find_server_by_network($) {
my ($net) = @_;
foreach my $s (Irssi::servers()) {
if (lc($s->{'chatnet'}) eq lc($net)) {
return $s;
}
}
return undef;
}
sub cmd_debug {
my ($data, $server, $witem) = @_;
print(eval($data));
}
sub allow_send() {
$lockout = 0;
# We should really check if we missed a send, and do it now if we did. I
# _think_ the other timer should always catch us, but I'm not certain.
}
sub flush_buf() {
if ($lockout) {
return; # Toon soon since last send -- we're locked out.
}
my $send = substr($buf, 0, $linemax);
$buf = substr($buf, $linemax);
my $copynetwork = trim(Irssi::settings_get_str('copy_network'));
my $copytarget = trim(Irssi::settings_get_str('copy_to_user'));
return if $copytarget eq "";
$server = find_server_by_network($copynetwork);
$server->command("MSG $copytarget $hdr$send");
$lockout = 1;
$mintimer = Irssi::timeout_add_once($min_send_interval * 1000, \&allow_send, undef);
if ($buf ne "") {
# Still text to send; restart the clock.
$maxtimer = Irssi::timeout_add_once($timeout * 1000, \&flush_buf, undef);
}
}
sub copy_msg($) {
my ($copy) = @_;
$copy = length($copy) . ":$copy;";
if ($buf eq "") {
# Start the clock.
$maxtimer = Irssi::timeout_add_once($timeout * 1000, \&flush_buf, undef);
}
$buf .= $copy;
if (length $buf >= $linemax) {
flush_buf();
}
}
sub print_text {
my ($textdest, $text, $stripped) = @_;
my $copychannel = trim(Irssi::settings_get_str('copy_channel'));
return if $copychannel eq "";
if ($textdest->{'target'} eq $copychannel) {
copy_msg($stripped);
}
@data = @_;
}
sub message_own_private {
my ($server, $msg, $target, $orig_target) = @_;
if (substr($msg, 0, length($hdr)) eq $hdr) {
# We're sending an encoded message.
Irssi::signal_stop();
}
}
$recv_buf = {};
sub message_private {
my ($server, $msg, $nick, $address) = @_;
if (substr($msg, 0, length($hdr)) eq $hdr) {
# It's an encoded message.
Irssi::signal_stop();
$msg = substr($msg, length($hdr));
$recv_buf->{$nick} = "" if !defined $recv_buf->{$nick};
$recv_buf->{$nick} .= $msg;
my $window = Irssi::window_find_name("spy-$nick");
if (!$window) {
my $saved = Irssi::active_win()->{refnum};
Irssi::command("window new hide");
Irssi::command("window name spy-$nick");
$window = Irssi::window_find_name("spy-$nick");
Irssi::command("window $saved");
}
while ($recv_buf->{$nick} and $recv_buf->{$nick} !~ /^[0-9]+:/) {
print "FRAMING ERROR: buffer starts with junk: $recv_buf->{$nick}";
print "Flushing buffer to next semicolon";
my ($flush, $keep) = split(";", $recv_buf->{$nick}, 2);
$window->print("<FRAMING ERROR>$flush", MSGLEVEL_PUBLIC);
$recv_buf->{$nick} = $keep;
}
my ($len, $rest) = split(":", $recv_buf->{$nick}, 2);
if (length($rest) < $len+1) {
# We don't have a full line yet, don't try to process it. Wait for more.
return;
}
while (defined $rest) {
my $body = substr($rest, 0, $len);
$window->print($body, MSGLEVEL_PUBLIC);
my $semi = substr($rest, $len, 1);
if ($semi ne ";") {
print "FRAMING ERROR: Missing semicolon after message in buffer";
}
$recv_buf->{$nick} = substr($rest, $len+1);
($len, $rest) = split(":", $recv_buf->{$nick}, 2);
}
}
}
Irssi::command_bind('debug', 'cmd_debug');
Irssi::settings_add_str('spy', 'copy_network', 'Freenode');
Irssi::settings_add_str('spy', 'copy_channel', '');
Irssi::settings_add_str('spy', 'copy_to_user', '');
Irssi::signal_add_last('print text', 'print_text');
Irssi::signal_add_last('message private', 'message_private');
Irssi::signal_add_last('message own_private', 'message_own_private');
# vim:set ts=4 sw=4 et: