| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package POE::Filter::IRC::Compat; |
|
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:HINRIK'; |
|
3
|
|
|
|
|
|
|
$POE::Filter::IRC::Compat::VERSION = '6.92'; |
|
4
|
80
|
|
|
80
|
|
80424
|
use strict; |
|
|
80
|
|
|
|
|
468
|
|
|
|
80
|
|
|
|
|
2854
|
|
|
5
|
80
|
|
|
80
|
|
457
|
use warnings FATAL => 'all'; |
|
|
80
|
|
|
|
|
170
|
|
|
|
80
|
|
|
|
|
3194
|
|
|
6
|
80
|
|
|
80
|
|
467
|
use Carp; |
|
|
80
|
|
|
|
|
215
|
|
|
|
80
|
|
|
|
|
5256
|
|
|
7
|
80
|
|
|
80
|
|
585
|
use POE::Filter::IRCD; |
|
|
80
|
|
|
|
|
173
|
|
|
|
80
|
|
|
|
|
2603
|
|
|
8
|
80
|
|
|
80
|
|
556
|
use File::Basename qw(fileparse); |
|
|
80
|
|
|
|
|
419
|
|
|
|
80
|
|
|
|
|
9306
|
|
|
9
|
80
|
|
|
80
|
|
602
|
use base qw(POE::Filter); |
|
|
80
|
|
|
|
|
194
|
|
|
|
80
|
|
|
|
|
287689
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
my %irc_cmds = ( |
|
12
|
|
|
|
|
|
|
qr/^\d{3}$/ => sub { |
|
13
|
|
|
|
|
|
|
my ($self, $event, $line) = @_; |
|
14
|
|
|
|
|
|
|
$event->{args}->[0] = _decolon( $line->{prefix} ); |
|
15
|
|
|
|
|
|
|
shift @{ $line->{params} }; |
|
16
|
|
|
|
|
|
|
if ( $line->{params}->[0] && $line->{params}->[0] =~ /\x20/ ) { |
|
17
|
|
|
|
|
|
|
$event->{args}->[1] = $line->{params}->[0]; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
else { |
|
20
|
|
|
|
|
|
|
$event->{args}->[1] = join(' ', ( map { /\x20/ ? ":$_" : $_ } @{ $line->{params} } ) ); |
|
21
|
|
|
|
|
|
|
} |
|
22
|
|
|
|
|
|
|
$event->{args}->[2] = $line->{params}; |
|
23
|
|
|
|
|
|
|
}, |
|
24
|
|
|
|
|
|
|
qr/^cap$/ => sub { |
|
25
|
|
|
|
|
|
|
my ($self, $event, $line) = @_; |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
for (my $i = 0; ; $i++) { |
|
28
|
|
|
|
|
|
|
last if !defined $line->{params}[$i+1]; |
|
29
|
|
|
|
|
|
|
$event->{args}[$i] = $line->{params}[$i+1]; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
}, |
|
32
|
|
|
|
|
|
|
qr/^notice$/ => sub { |
|
33
|
|
|
|
|
|
|
my ($self, $event, $line) = @_; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
if (defined $line->{prefix} && $line->{prefix} =~ /!/) { |
|
36
|
|
|
|
|
|
|
$event->{args} = [ |
|
37
|
|
|
|
|
|
|
_decolon( $line->{prefix} ), |
|
38
|
|
|
|
|
|
|
[split /,/, $line->{params}->[0]], |
|
39
|
|
|
|
|
|
|
($self->{identifymsg} |
|
40
|
|
|
|
|
|
|
? _split_idmsg($line->{params}->[1]) |
|
41
|
|
|
|
|
|
|
: $line->{params}->[1] |
|
42
|
|
|
|
|
|
|
), |
|
43
|
|
|
|
|
|
|
]; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
else { |
|
46
|
|
|
|
|
|
|
$event->{name} = 'snotice'; |
|
47
|
|
|
|
|
|
|
$event->{args} = [ |
|
48
|
|
|
|
|
|
|
$line->{params}->[1], |
|
49
|
|
|
|
|
|
|
$line->{params}->[0], |
|
50
|
|
|
|
|
|
|
(defined $line->{prefix} ? _decolon($line->{prefix}) : ()), |
|
51
|
|
|
|
|
|
|
]; |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
}, |
|
54
|
|
|
|
|
|
|
qr/^privmsg$/ => sub { |
|
55
|
|
|
|
|
|
|
my ($self, $event, $line) = @_; |
|
56
|
|
|
|
|
|
|
if ( grep { index( $line->{params}->[0], $_ ) >= 0 } @{ $self->{chantypes} } ) { |
|
57
|
|
|
|
|
|
|
$event->{args} = [ |
|
58
|
|
|
|
|
|
|
_decolon( $line->{prefix} ), |
|
59
|
|
|
|
|
|
|
[split /,/, $line->{params}->[0]], |
|
60
|
|
|
|
|
|
|
($self->{identifymsg} |
|
61
|
|
|
|
|
|
|
? _split_idmsg($line->{params}->[1]) |
|
62
|
|
|
|
|
|
|
: $line->{params}->[1] |
|
63
|
|
|
|
|
|
|
), |
|
64
|
|
|
|
|
|
|
]; |
|
65
|
|
|
|
|
|
|
$event->{name} = 'public'; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
else { |
|
68
|
|
|
|
|
|
|
$event->{args} = [ |
|
69
|
|
|
|
|
|
|
_decolon( $line->{prefix} ), |
|
70
|
|
|
|
|
|
|
[split /,/, $line->{params}->[0]], |
|
71
|
|
|
|
|
|
|
($self->{identifymsg} |
|
72
|
|
|
|
|
|
|
? _split_idmsg($line->{params}->[1]) |
|
73
|
|
|
|
|
|
|
: $line->{params}->[1] |
|
74
|
|
|
|
|
|
|
), |
|
75
|
|
|
|
|
|
|
]; |
|
76
|
|
|
|
|
|
|
$event->{name} = 'msg'; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
}, |
|
79
|
|
|
|
|
|
|
qr/^invite$/ => sub { |
|
80
|
|
|
|
|
|
|
my ($self, $event, $line) = @_; |
|
81
|
|
|
|
|
|
|
shift( @{ $line->{params} } ); |
|
82
|
|
|
|
|
|
|
unshift( @{ $line->{params} }, _decolon( $line->{prefix} || '' ) ) if $line->{prefix}; |
|
83
|
|
|
|
|
|
|
$event->{args} = $line->{params}; |
|
84
|
|
|
|
|
|
|
}, |
|
85
|
|
|
|
|
|
|
); |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# the magic cookie jar |
|
88
|
|
|
|
|
|
|
my %dcc_types = ( |
|
89
|
|
|
|
|
|
|
qr/^(?:CHAT|SEND)$/ => sub { |
|
90
|
|
|
|
|
|
|
my ($nick, $type, $args) = @_; |
|
91
|
|
|
|
|
|
|
my ($file, $addr, $port, $size); |
|
92
|
|
|
|
|
|
|
return if !(($file, $addr, $port, $size) = $args =~ /^(".+"|[^ ]+) +(\d+) +(\d+)(?: +(\d+))?/); |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
if ($file =~ s/^"//) { |
|
95
|
|
|
|
|
|
|
$file =~ s/"$//; |
|
96
|
|
|
|
|
|
|
$file =~ s/\\"/"/g; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
$file = fileparse($file); |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
return ( |
|
101
|
|
|
|
|
|
|
$port, |
|
102
|
|
|
|
|
|
|
{ |
|
103
|
|
|
|
|
|
|
nick => $nick, |
|
104
|
|
|
|
|
|
|
type => $type, |
|
105
|
|
|
|
|
|
|
file => $file, |
|
106
|
|
|
|
|
|
|
size => $size, |
|
107
|
|
|
|
|
|
|
addr => $addr, |
|
108
|
|
|
|
|
|
|
port => $port, |
|
109
|
|
|
|
|
|
|
}, |
|
110
|
|
|
|
|
|
|
$file, |
|
111
|
|
|
|
|
|
|
$size, |
|
112
|
|
|
|
|
|
|
$addr, |
|
113
|
|
|
|
|
|
|
); |
|
114
|
|
|
|
|
|
|
}, |
|
115
|
|
|
|
|
|
|
qr/^(?:ACCEPT|RESUME)$/ => sub { |
|
116
|
|
|
|
|
|
|
my ($nick, $type, $args) = @_; |
|
117
|
|
|
|
|
|
|
my ($file, $port, $position); |
|
118
|
|
|
|
|
|
|
return if !(($file, $port, $position) = $args =~ /^(".+"|[^ ]+) +(\d+) +(\d+)/); |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
$file =~ s/^"|"$//g; |
|
121
|
|
|
|
|
|
|
$file = fileparse($file); |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
return ( |
|
124
|
|
|
|
|
|
|
$port, |
|
125
|
|
|
|
|
|
|
{ |
|
126
|
|
|
|
|
|
|
nick => $nick, |
|
127
|
|
|
|
|
|
|
type => $type, |
|
128
|
|
|
|
|
|
|
file => $file, |
|
129
|
|
|
|
|
|
|
size => $position, |
|
130
|
|
|
|
|
|
|
port => $port, |
|
131
|
|
|
|
|
|
|
}, |
|
132
|
|
|
|
|
|
|
$file, |
|
133
|
|
|
|
|
|
|
$position, |
|
134
|
|
|
|
|
|
|
); |
|
135
|
|
|
|
|
|
|
}, |
|
136
|
|
|
|
|
|
|
); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub new { |
|
139
|
124
|
|
|
124
|
1
|
781
|
my ($package, %self) = @_; |
|
140
|
|
|
|
|
|
|
|
|
141
|
124
|
|
|
|
|
855
|
$self{lc $_} = delete $self{$_} for keys %self; |
|
142
|
124
|
|
|
|
|
451
|
$self{BUFFER} = [ ]; |
|
143
|
124
|
|
|
|
|
518
|
$self{_ircd} = POE::Filter::IRCD->new(); |
|
144
|
124
|
50
|
|
|
|
2840
|
$self{chantypes} = [ '#', '&' ] if ref $self{chantypes} ne 'ARRAY'; |
|
145
|
|
|
|
|
|
|
|
|
146
|
124
|
|
|
|
|
736
|
return bless \%self, $package; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub clone { |
|
150
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
|
151
|
0
|
|
|
|
|
0
|
my $nself = { }; |
|
152
|
0
|
|
|
|
|
0
|
$nself->{$_} = $self->{$_} for keys %{ $self }; |
|
|
0
|
|
|
|
|
0
|
|
|
153
|
0
|
|
|
|
|
0
|
$nself->{BUFFER} = [ ]; |
|
154
|
0
|
|
|
|
|
0
|
return bless $nself, ref $self; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Set/clear the 'debug' flag. |
|
158
|
|
|
|
|
|
|
sub debug { |
|
159
|
0
|
|
|
0
|
1
|
0
|
my ($self, $flag) = @_; |
|
160
|
0
|
0
|
|
|
|
0
|
if (defined $flag) { |
|
161
|
0
|
|
|
|
|
0
|
$self->{debug} = $flag; |
|
162
|
0
|
|
|
|
|
0
|
$self->{_ircd}->debug($flag); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
0
|
|
|
|
|
0
|
return $self->{debug}; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub chantypes { |
|
168
|
180
|
|
|
180
|
1
|
520
|
my ($self, $ref) = @_; |
|
169
|
180
|
50
|
33
|
|
|
950
|
return if ref $ref ne 'ARRAY' || !@{ $ref }; |
|
|
180
|
|
|
|
|
842
|
|
|
170
|
180
|
|
|
|
|
566
|
$self->{chantypes} = $ref; |
|
171
|
180
|
|
|
|
|
470
|
return 1; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub identifymsg { |
|
175
|
91
|
|
|
91
|
1
|
259
|
my ($self, $switch) = @_; |
|
176
|
91
|
|
|
|
|
254
|
$self->{identifymsg} = $switch; |
|
177
|
91
|
|
|
|
|
226
|
return; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub _split_idmsg { |
|
181
|
0
|
|
|
0
|
|
0
|
my ($line) = @_; |
|
182
|
0
|
|
|
|
|
0
|
my ($identified, $msg) = split //, $line, 2; |
|
183
|
0
|
0
|
|
|
|
0
|
$identified = $identified eq '+' ? 1 : 0; |
|
184
|
0
|
|
|
|
|
0
|
return $msg, $identified; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub get_one { |
|
188
|
3317
|
|
|
3317
|
1
|
46167
|
my ($self) = @_; |
|
189
|
3317
|
100
|
|
|
|
5197
|
my $line = shift @{ $self->{BUFFER} } or return [ ]; |
|
|
3317
|
|
|
|
|
10636
|
|
|
190
|
|
|
|
|
|
|
|
|
191
|
2611
|
50
|
33
|
|
|
18365
|
if (ref $line ne 'HASH' || !$line->{command} || !$line->{params}) { |
|
|
|
|
33
|
|
|
|
|
|
192
|
0
|
0
|
|
|
|
0
|
warn "Received line '$line' that is not IRC protocol\n" if $self->{debug}; |
|
193
|
0
|
|
|
|
|
0
|
return [ ]; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
2611
|
100
|
100
|
|
|
7664
|
if ($line->{command} =~ /^PRIVMSG|NOTICE$/ && $line->{params}->[1] =~ tr/\001//) { |
|
197
|
34
|
|
|
|
|
167
|
return $self->_get_ctcp($line); |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
my $event = { |
|
201
|
|
|
|
|
|
|
name => lc $line->{command}, |
|
202
|
|
|
|
|
|
|
raw_line => $line->{raw_line}, |
|
203
|
2577
|
|
|
|
|
9537
|
}; |
|
204
|
|
|
|
|
|
|
|
|
205
|
2577
|
|
|
|
|
9996
|
for my $cmd (keys %irc_cmds) { |
|
206
|
7659
|
100
|
|
|
|
91536
|
if ($event->{name} =~ $cmd) { |
|
207
|
2130
|
|
|
|
|
7950
|
$irc_cmds{$cmd}->($self, $event, $line); |
|
208
|
2130
|
|
|
|
|
10852
|
return [ $event ]; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# default |
|
213
|
447
|
100
|
50
|
|
|
1830
|
unshift( @{ $line->{params} }, _decolon( $line->{prefix} || '' ) ) if $line->{prefix}; |
|
|
356
|
|
|
|
|
1841
|
|
|
214
|
447
|
|
|
|
|
1179
|
$event->{args} = $line->{params}; |
|
215
|
447
|
|
|
|
|
2025
|
return [ $event ]; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub get_one_start { |
|
219
|
2611
|
|
|
2611
|
1
|
8907263
|
my ($self, $lines) = @_; |
|
220
|
2611
|
|
|
|
|
4530
|
push @{ $self->{BUFFER} }, @$lines; |
|
|
2611
|
|
|
|
|
6135
|
|
|
221
|
2611
|
|
|
|
|
5626
|
return; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub put { |
|
225
|
27
|
|
|
27
|
1
|
92
|
my ($self, $lineref) = @_; |
|
226
|
27
|
|
|
|
|
62
|
my $quoted = [ ]; |
|
227
|
27
|
|
|
|
|
117
|
push @$quoted, _ctcp_quote($_) for @$lineref; |
|
228
|
27
|
|
|
|
|
112
|
return $quoted; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Properly CTCP-quotes a message. Whoop. |
|
232
|
|
|
|
|
|
|
sub _ctcp_quote { |
|
233
|
27
|
|
|
27
|
|
58
|
my ($line) = @_; |
|
234
|
|
|
|
|
|
|
|
|
235
|
27
|
|
|
|
|
175
|
$line = _low_quote( $line ); |
|
236
|
|
|
|
|
|
|
#$line =~ s/\\/\\\\/g; |
|
237
|
27
|
|
|
|
|
84
|
$line =~ s/\001/\\a/g; |
|
238
|
|
|
|
|
|
|
|
|
239
|
27
|
|
|
|
|
138
|
return "\001$line\001"; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Splits a message into CTCP and text chunks. This is gross. Most of |
|
243
|
|
|
|
|
|
|
# this is also stolen from Net::IRC, but I (fimm) wrote that too, so it's |
|
244
|
|
|
|
|
|
|
# used with permission. ;-) |
|
245
|
|
|
|
|
|
|
sub _ctcp_dequote { |
|
246
|
34
|
|
|
34
|
|
84
|
my ($msg) = @_; |
|
247
|
34
|
|
|
|
|
68
|
my (@chunks, $ctcp, $text); |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# CHUNG! CHUNG! CHUNG! |
|
250
|
|
|
|
|
|
|
|
|
251
|
34
|
50
|
|
|
|
116
|
if (!defined $msg) { |
|
252
|
0
|
|
|
|
|
0
|
croak 'Not enough arguments to POE::Filter::IRC::Compat::_ctcp_dequote'; |
|
253
|
|
|
|
|
|
|
} |
|
254
|
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
# Strip out any low-level quoting in the text. |
|
256
|
34
|
|
|
|
|
130
|
$msg = _low_dequote( $msg ); |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Filter misplaced \001s before processing... (Thanks, tchrist!) |
|
259
|
34
|
100
|
|
|
|
161
|
substr($msg, rindex($msg, "\001"), 1, '\\a') |
|
260
|
|
|
|
|
|
|
if ($msg =~ tr/\001//) % 2 != 0; |
|
261
|
|
|
|
|
|
|
|
|
262
|
34
|
100
|
|
|
|
126
|
return if $msg !~ tr/\001//; |
|
263
|
|
|
|
|
|
|
|
|
264
|
33
|
|
|
|
|
147
|
@chunks = split /\001/, $msg; |
|
265
|
33
|
50
|
|
|
|
128
|
shift @chunks if !length $chunks[0]; # FIXME: Is this safe? |
|
266
|
|
|
|
|
|
|
|
|
267
|
33
|
|
|
|
|
136
|
for (@chunks) { |
|
268
|
|
|
|
|
|
|
# Dequote unnecessarily quoted chars, and convert escaped \'s and ^A's. |
|
269
|
35
|
|
|
|
|
108
|
s/\\([^\\a])/$1/g; |
|
270
|
35
|
|
|
|
|
78
|
s/\\\\/\\/g; |
|
271
|
35
|
|
|
|
|
104
|
s/\\a/\001/g; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# If the line begins with a control-A, the first chunk is a CTCP |
|
275
|
|
|
|
|
|
|
# message. Otherwise, it starts with text and alternates with CTCP |
|
276
|
|
|
|
|
|
|
# messages. Really stupid protocol. |
|
277
|
33
|
50
|
|
|
|
193
|
if ($msg =~ /^\001/) { |
|
278
|
33
|
|
|
|
|
102
|
push @$ctcp, shift @chunks; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
33
|
|
|
|
|
112
|
while (@chunks) { |
|
282
|
1
|
|
|
|
|
3
|
push @$text, shift @chunks; |
|
283
|
1
|
50
|
|
|
|
3
|
push @$ctcp, shift @chunks if @chunks; |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
|
|
286
|
33
|
|
|
|
|
110
|
return ($ctcp, $text); |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub _decolon { |
|
290
|
2481
|
|
|
2481
|
|
5032
|
my ($line) = @_; |
|
291
|
|
|
|
|
|
|
|
|
292
|
2481
|
|
|
|
|
5047
|
$line =~ s/^://; |
|
293
|
2481
|
|
|
|
|
8405
|
return $line; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
## no critic (Subroutines::ProhibitExcessComplexity) |
|
297
|
|
|
|
|
|
|
sub _get_ctcp { |
|
298
|
34
|
|
|
34
|
|
97
|
my ($self, $line) = @_; |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# Is this a CTCP request or reply? |
|
301
|
34
|
100
|
|
|
|
279
|
my $ctcp_type = $line->{command} eq 'PRIVMSG' ? 'ctcp' : 'ctcpreply'; |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# CAPAP IDENTIFY-MSG is only applied to ACTIONs |
|
304
|
34
|
|
|
|
|
131
|
my ($msg, $identified) = ($line->{params}->[1], undef); |
|
305
|
34
|
50
|
33
|
|
|
159
|
($msg, $identified) = _split_idmsg($msg) if $self->{identifymsg} && $msg =~ /^.ACTION/; |
|
306
|
|
|
|
|
|
|
|
|
307
|
34
|
|
|
|
|
78
|
my $events = [ ]; |
|
308
|
34
|
|
|
|
|
150
|
my ($ctcp, $text) = _ctcp_dequote($msg); |
|
309
|
|
|
|
|
|
|
|
|
310
|
34
|
100
|
|
|
|
111
|
if (!defined $ctcp) { |
|
311
|
1
|
50
|
|
|
|
6
|
warn "Received malformed CTCP message: $msg\n" if $self->{debug}; |
|
312
|
1
|
|
|
|
|
6
|
return $events; |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
33
|
100
|
|
|
|
190
|
my $nick = defined $line->{prefix} ? (split /!/, $line->{prefix})[0] : undef; |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# We only process the first CTCP. The only people who send multiple ones |
|
318
|
|
|
|
|
|
|
# are those who are trying to flood our outgoing queue anyway (e.g. by |
|
319
|
|
|
|
|
|
|
# having us reply to 20 VERSION requests at a time). |
|
320
|
33
|
|
|
|
|
94
|
my ($name, $args); |
|
321
|
33
|
|
|
|
|
102
|
CTCP: for my $string ($ctcp->[0]) { |
|
322
|
33
|
50
|
|
|
|
273
|
if (!(($name, $args) = $string =~ /^(\w+)(?: +(.*))?/)) { |
|
323
|
|
|
|
|
|
|
defined $nick |
|
324
|
0
|
0
|
|
|
|
0
|
? do { warn "Received malformed CTCP message from $nick: $string\n" if $self->{debug} } |
|
325
|
0
|
0
|
|
|
|
0
|
: do { warn "Trying to send malformed CTCP message: $string\n" if $self->{debug} } |
|
|
0
|
0
|
|
|
|
0
|
|
|
326
|
|
|
|
|
|
|
; |
|
327
|
0
|
|
|
|
|
0
|
last CTCP; |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
|
|
330
|
33
|
100
|
|
|
|
136
|
if (lc $name eq 'dcc') { |
|
331
|
11
|
|
|
|
|
26
|
my ($dcc_type, $rest); |
|
332
|
|
|
|
|
|
|
|
|
333
|
11
|
50
|
|
|
|
98
|
if (!(($dcc_type, $rest) = $args =~ /^(\w+) +(.+)/)) { |
|
334
|
|
|
|
|
|
|
defined $nick |
|
335
|
0
|
0
|
|
|
|
0
|
? do { warn "Received malformed DCC request from $nick: $args\n" if $self->{debug} } |
|
336
|
0
|
0
|
|
|
|
0
|
: do { warn "Trying to send malformed DCC request: $args\n" if $self->{debug} } |
|
|
0
|
0
|
|
|
|
0
|
|
|
337
|
|
|
|
|
|
|
; |
|
338
|
0
|
|
|
|
|
0
|
last CTCP; |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
} |
|
341
|
11
|
|
|
|
|
43
|
$dcc_type = uc $dcc_type; |
|
342
|
|
|
|
|
|
|
|
|
343
|
11
|
|
|
|
|
103
|
my ($handler) = grep { $dcc_type =~ /$_/ } keys %dcc_types; |
|
|
22
|
|
|
|
|
854
|
|
|
344
|
11
|
50
|
|
|
|
59
|
if (!$handler) { |
|
345
|
0
|
0
|
|
|
|
0
|
warn "Unhandled DCC $dcc_type request: $rest\n" if $self->{debug}; |
|
346
|
0
|
|
|
|
|
0
|
last CTCP; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
|
|
349
|
11
|
|
|
|
|
82
|
my @dcc_args = $dcc_types{$handler}->($nick, $dcc_type, $rest); |
|
350
|
11
|
50
|
|
|
|
76
|
if (!@dcc_args) { |
|
351
|
|
|
|
|
|
|
defined $nick |
|
352
|
0
|
0
|
|
|
|
0
|
? do { warn "Received malformed DCC $dcc_type request from $nick: $rest\n" if $self->{debug} } |
|
353
|
0
|
0
|
|
|
|
0
|
: do { warn "Trying to send malformed DCC $dcc_type request: $rest\n" if $self->{debug} } |
|
|
0
|
0
|
|
|
|
0
|
|
|
354
|
|
|
|
|
|
|
; |
|
355
|
0
|
|
|
|
|
0
|
last CTCP; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
push @$events, { |
|
359
|
|
|
|
|
|
|
name => 'dcc_request', |
|
360
|
|
|
|
|
|
|
args => [ |
|
361
|
|
|
|
|
|
|
$line->{prefix}, |
|
362
|
|
|
|
|
|
|
$dcc_type, |
|
363
|
|
|
|
|
|
|
@dcc_args, |
|
364
|
|
|
|
|
|
|
], |
|
365
|
|
|
|
|
|
|
raw_line => $line->{raw_line}, |
|
366
|
11
|
|
|
|
|
145
|
}; |
|
367
|
|
|
|
|
|
|
} |
|
368
|
|
|
|
|
|
|
else { |
|
369
|
|
|
|
|
|
|
push @$events, { |
|
370
|
|
|
|
|
|
|
name => $ctcp_type . '_' . lc $name, |
|
371
|
|
|
|
|
|
|
args => [ |
|
372
|
|
|
|
|
|
|
$line->{prefix}, |
|
373
|
|
|
|
|
|
|
[split /,/, $line->{params}->[0]], |
|
374
|
|
|
|
|
|
|
(defined $args ? $args : ''), |
|
375
|
|
|
|
|
|
|
(defined $identified ? $identified : () ), |
|
376
|
|
|
|
|
|
|
], |
|
377
|
|
|
|
|
|
|
raw_line => $line->{raw_line}, |
|
378
|
22
|
100
|
|
|
|
248
|
}; |
|
|
|
50
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# XXX: I'm not quite sure what this is for, but on FreeNode it adds an |
|
383
|
|
|
|
|
|
|
# extra bogus event and displays a debug message, so I have disabled it. |
|
384
|
|
|
|
|
|
|
# FreeNode precedes PRIVMSG and CTCP ACTION messages with '+' or '-'. |
|
385
|
|
|
|
|
|
|
#if ($text && @$text) { |
|
386
|
|
|
|
|
|
|
# my $what; |
|
387
|
|
|
|
|
|
|
# ($what) = $line->{raw_line} =~ /^(:[^ ]+ +\w+ +[^ ]+ +)/ |
|
388
|
|
|
|
|
|
|
# or warn "What the heck? '".$line->{raw_line}."'\n" if $self->{debug}; |
|
389
|
|
|
|
|
|
|
# $text = (defined $what ? $what : '') . ':' . join '', @$text; |
|
390
|
|
|
|
|
|
|
# $text =~ s/\cP/^P/g; |
|
391
|
|
|
|
|
|
|
# warn "CTCP: $text\n" if $self->{debug}; |
|
392
|
|
|
|
|
|
|
# push @$events, @{ $self->{_ircd}->get([$text]) }; |
|
393
|
|
|
|
|
|
|
#} |
|
394
|
|
|
|
|
|
|
|
|
395
|
33
|
|
|
|
|
211
|
return $events; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# Quotes a string in a low-level, protocol-safe, utterly brain-dead |
|
399
|
|
|
|
|
|
|
# fashion. Returns the quoted string. |
|
400
|
|
|
|
|
|
|
sub _low_quote { |
|
401
|
27
|
|
|
27
|
|
77
|
my ($line) = @_; |
|
402
|
27
|
|
|
|
|
369
|
my %enquote = ("\012" => 'n', "\015" => 'r', "\0" => '0', "\cP" => "\cP"); |
|
403
|
|
|
|
|
|
|
|
|
404
|
27
|
50
|
|
|
|
113
|
if (!defined $line) { |
|
405
|
0
|
|
|
|
|
0
|
croak 'Not enough arguments to POE::Filter::IRC::Compat->_low_quote'; |
|
406
|
|
|
|
|
|
|
} |
|
407
|
|
|
|
|
|
|
|
|
408
|
27
|
50
|
|
|
|
141
|
if ($line =~ tr/[\012\015\0\cP]//) { # quote \n, \r, ^P, and \0. |
|
409
|
0
|
|
|
|
|
0
|
$line =~ s/([\012\015\0\cP])/\cP$enquote{$1}/g; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
|
|
412
|
27
|
|
|
|
|
104
|
return $line; |
|
413
|
|
|
|
|
|
|
} |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# Does low-level dequoting on CTCP messages. I hate this protocol. |
|
416
|
|
|
|
|
|
|
# Yes, I copied this whole section out of Net::IRC. |
|
417
|
|
|
|
|
|
|
sub _low_dequote { |
|
418
|
34
|
|
|
34
|
|
81
|
my ($line) = @_; |
|
419
|
34
|
|
|
|
|
327
|
my %dequote = (n => "\012", r => "\015", 0 => "\0", "\cP" => "\cP"); |
|
420
|
|
|
|
|
|
|
|
|
421
|
34
|
50
|
|
|
|
147
|
if (!defined $line) { |
|
422
|
0
|
|
|
|
|
0
|
croak 'Not enough arguments to POE::Filter::IRC::Compat->_low_dequote'; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
# dequote \n, \r, ^P, and \0. |
|
426
|
|
|
|
|
|
|
# Thanks to Abigail (abigail@foad.org) for this clever bit. |
|
427
|
34
|
50
|
|
|
|
140
|
if ($line =~ tr/\cP//) { |
|
428
|
0
|
|
|
|
|
0
|
$line =~ s/\cP([nr0\cP])/$dequote{$1}/g; |
|
429
|
|
|
|
|
|
|
} |
|
430
|
|
|
|
|
|
|
|
|
431
|
34
|
|
|
|
|
127
|
return $line; |
|
432
|
|
|
|
|
|
|
} |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
1; |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=encoding utf8 |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=head1 NAME |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
POE::Filter::IRC::Compat - A filter which converts L |
|
441
|
|
|
|
|
|
|
output into L events |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
my $filter = POE::Filter::IRC::Compat->new(); |
|
446
|
|
|
|
|
|
|
my @events = @{ $filter->get( [ @lines ] ) }; |
|
447
|
|
|
|
|
|
|
my @msgs = @{ $filter->put( [ @messages ] ) }; |
|
448
|
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
POE::Filter::IRC::Compat is a L that converts |
|
452
|
|
|
|
|
|
|
L output into the L |
|
453
|
|
|
|
|
|
|
compatible event references. Basically a hack, so I could replace |
|
454
|
|
|
|
|
|
|
L with something that was more |
|
455
|
|
|
|
|
|
|
generic. |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
Among other things, it converts normal text into thoroughly CTCP-quoted |
|
458
|
|
|
|
|
|
|
messages, and transmogrifies CTCP-quoted messages into their normal, |
|
459
|
|
|
|
|
|
|
sane components. Rather what you'd expect a filter to do. |
|
460
|
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
A note: the CTCP protocol sucks bollocks. If I ever meet the fellow who |
|
462
|
|
|
|
|
|
|
came up with it, I'll shave their head and tattoo obscenities on it. |
|
463
|
|
|
|
|
|
|
Just read the "specification" (F in this distribution) |
|
464
|
|
|
|
|
|
|
and you'll hopefully see what I mean. Quote this, quote that, quote this |
|
465
|
|
|
|
|
|
|
again, all in different and weird ways... and who the hell needs to send |
|
466
|
|
|
|
|
|
|
mixed CTCP and text messages? WTF? It looks like it's practically complexity |
|
467
|
|
|
|
|
|
|
for complexity's sake -- and don't even get me started on the design of the |
|
468
|
|
|
|
|
|
|
DCC protocol! Anyhow, enough ranting. Onto the rest of the docs... |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head1 METHODS |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=head2 C |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
Returns a POE::Filter::IRC::Compat object. Takes no arguments. |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=head2 C |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Makes a copy of the filter, and clears the copy's buffer. |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=head2 C |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Takes an arrayref of L hashrefs and produces an arrayref of |
|
483
|
|
|
|
|
|
|
L compatible event hashrefs. Yay. |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=head2 C, C |
|
486
|
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
These perform a similar function as C but enable the filter to work with |
|
488
|
|
|
|
|
|
|
L. |
|
489
|
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head2 C |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Takes an array reference of CTCP messages to be properly quoted. This |
|
493
|
|
|
|
|
|
|
doesn't support CTCPs embedded in normal messages, which is a |
|
494
|
|
|
|
|
|
|
brain-dead hack in the protocol, so do it yourself if you really need |
|
495
|
|
|
|
|
|
|
it. Returns an array reference of the quoted lines for sending. |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head2 C |
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Takes an optinal true/false value which enables/disables debugging |
|
500
|
|
|
|
|
|
|
accordingly. Returns the debug status. |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
=head2 C |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
Takes an arrayref of possible channel prefix indicators. |
|
505
|
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
=head2 C |
|
507
|
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
Takes a boolean to turn on/off the support for CAPAB IDENTIFY-MSG. |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head1 AUTHOR |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Chris 'BinGOs' Williams |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
515
|
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
L |
|
517
|
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
L |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
L |
|
521
|
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
=cut |