File Coverage

blib/lib/POE/Filter/CTCP/P10.pm
Criterion Covered Total %
statement 16 89 17.9
branch 0 40 0.0
condition 0 3 0.0
subroutine 5 12 41.6
pod 4 4 100.0
total 25 148 16.8


line stmt bran cond sub pod time code
1             # $Id: Filter-CTCP.pm,v 1.3 1999/12/12 11:48:07 dennis Exp $
2             #
3             # POE::Filter::CTCP, by Dennis Taylor
4             #
5             # This module may be used, modified, and distributed under the same
6             # terms as Perl itself. Please see the license that came with your Perl
7             # distribution for details.
8             #
9              
10             package POE::Filter::CTCP::P10;
11              
12 1     1   6 use strict;
  1         2  
  1         28  
13 1     1   4 use Carp;
  1         2  
  1         42  
14 1     1   6 use File::Basename ();
  1         2  
  1         14  
15 1     1   4 use POE::Filter::IRC::P10;
  1         1  
  1         937  
16              
17              
18             # Create a new, empty POE::Filter::CTCP::P10 object.
19             sub new {
20 1     1 1 3 my $class = shift;
21 1         3 my %args = @_;
22              
23 1         4 my $self = { 'irc_filter' => POE::Filter::IRC::P10->new() };
24 1         4 bless $self, $class;
25             }
26              
27              
28             # Set/clear the 'debug' flag.
29             sub debug {
30 0     0 1   my $self = shift;
31 0 0         $self->{'debug'} = $_[0] if @_;
32 0           return( $self->{'debug'} );
33             }
34              
35              
36             # For each line of raw CTCP input data that we're fed, spit back the
37             # appropriate CTCP and normal message events.
38             sub get {
39 0     0 1   my ($self, $lineref) = @_;
40 0           my ($who, $type, $where, $ctcp, $text, $name, $args);
41 0           my $events = [];
42              
43             LINE:
44 0           foreach my $line (@$lineref) {
45 0           ($who, $type, $where, $ctcp, $text) = _ctcp_dequote( $line );
46              
47 0           foreach (@$ctcp) {
48             ($name, $args) = $_ =~ /^(\w+)(?: (.*))?/
49 0 0         or do { warn "Received malformed CTCP message: \"$_\""; next LINE; };
  0            
  0            
50 0 0         if (lc $name eq 'dcc') {
51             $args =~ /^(\w+) (\S+) (\d+) (\d+)(?: (\d+))?$/
52 0 0         or do { warn "Received malformed DCC request: \"$_\""; next LINE; };
  0            
  0            
53 0           my $basename = File::Basename::basename( $2 );
54 0           push @$events, { name => 'dcc_request',
55             args => [ $who, uc $1, $4, { open => undef,
56             nick => $who,
57             type => uc $1,
58             file => $basename,
59             size => $5,
60             done => 0,
61             addr => $3,
62             port => $4,
63             }, $basename, $5 ]
64             };
65              
66             } else {
67 0 0         push @$events, { name => $type . '_' . lc $name,
68             args => [ $who, [split /,/, $where],
69             (defined $args ? $args : '') ]
70             };
71             }
72             }
73              
74 0 0 0       if ($text and @$text > 0) {
75 0 0         $line =~ /^(\S+ +\w+ +\S+ +)/ or warn "What the heck? \"$line\"";
76 0           $text = $1 . ':' . join '', @$text;
77 0           $text =~ s/\cP/^P/g;
78 0 0         warn "CTCP: $text\n" if $self->{'debug'};
79 0           push @$events, @{$self->{irc_filter}->get( [$text] )};
  0            
80             }
81             }
82              
83 0           return $events;
84             }
85              
86              
87             # For each line of text we're fed, spit back a CTCP-quoted version of
88             # that line.
89             sub put {
90 0     0 1   my ($self, $lineref) = @_;
91 0           my $quoted = [];
92              
93 0           foreach my $line (@$lineref) {
94 0           push @$quoted, _ctcp_quote( $line );
95             }
96              
97 0           return $quoted;
98             }
99              
100              
101             # Quotes a string in a low-level, protocol-safe, utterly brain-dead
102             # fashion. Returns the quoted string.
103             sub _low_quote {
104 0     0     my $line = shift;
105 0           my %enquote = ("\012" => 'n', "\015" => 'r', "\0" => '0', "\cP" => "\cP");
106              
107 0 0         unless (defined $line) {
108 0           die "Not enough arguments to POE::Filter::CTCP->_low_quote";
109             }
110              
111 0 0         if ($line =~ tr/[\012\015\0\cP]//) { # quote \n, \r, ^P, and \0.
112 0           $line =~ s/([\012\015\0\cP])/\cP$enquote{$1}/g;
113             }
114              
115 0           return $line;
116             }
117              
118              
119             # Does low-level dequoting on CTCP messages. I hate this protocol.
120             # Yes, I copied this whole section out of Net::IRC.
121             sub _low_dequote {
122 0     0     my $line = shift;
123 0           my %dequote = (n => "\012", r => "\015", 0 => "\0", "\cP" => "\cP");
124              
125 0 0         unless (defined $line) {
126 0           die "Not enough arguments to POE::Filter::CTCP->_low_dequote";
127             }
128              
129             # Thanks to Abigail (abigail@foad.org) for this clever bit.
130 0 0         if ($line =~ tr/\cP//) { # dequote \n, \r, ^P, and \0.
131 0           $line =~ s/\cP([nr0\cP])/$dequote{$1}/g;
132             }
133              
134 0           return $line;
135             }
136              
137              
138             # Properly CTCP-quotes a message. Whoop.
139             sub _ctcp_quote {
140 0     0     my $line = shift;
141              
142 0           $line = _low_quote( $line );
143             # $line =~ s/\\/\\\\/g;
144 0           $line =~ s/\001/\\a/g;
145              
146 0           return "\001" . $line . "\001";
147             }
148              
149              
150             # Splits a message into CTCP and text chunks. This is gross. Most of
151             # this is also stolen from Net::IRC, but I wrote that too, so it's
152             # used with permission. ;-)
153             sub _ctcp_dequote {
154 0     0     my $line = shift;
155 0           my (@chunks, $ctcp, $text, $who, $type, $where, $msg);
156              
157             # CHUNG! CHUNG! CHUNG!
158              
159 0 0         unless (defined $line) {
160 0           die "Not enough arguments to POE::Filter::CTCP->_ctcp_dequote";
161             }
162              
163             # Strip out any low-level quoting in the text.
164 0           $line = _low_dequote( $line );
165              
166             # Filter misplaced \001s before processing... (Thanks, tchrist!)
167 0 0         substr($line, rindex($line, "\001"), 1) = '\\a'
168             unless ($line =~ tr/\001//) % 2 == 0;
169              
170 0 0         return unless $line =~ tr/\001//;
171              
172 0 0         ($who, $type, $where, $msg) = ($line =~ /^(\S+) +(\w+) +(\S+) +:?(.*)$/)
173             or return;
174 0           @chunks = split /\001/, $msg;
175 0 0         shift @chunks unless length $chunks[0]; # FIXME: Is this safe?
176              
177 0           foreach (@chunks) {
178             # Dequote unnecessarily quoted chars, and convert escaped \'s and ^A's.
179 0           s/\\([^\\a])/$1/g;
180 0           s/\\\\/\\/g;
181 0           s/\\a/\001/g;
182             }
183              
184             # If the line begins with a control-A, the first chunk is a CTCP
185             # message. Otherwise, it starts with text and alternates with CTCP
186             # messages. Really stupid protocol.
187              
188 0 0         if ($msg =~ /^\001/) {
189 0           push @$ctcp, shift @chunks;
190             }
191              
192 0           while (@chunks) {
193 0           push @$text, shift @chunks;
194 0 0         push @$ctcp, shift @chunks if @chunks;
195             }
196              
197             # Is this a CTCP request or reply?
198 0 0         if ($type eq 'P') {
199 0           $type = 'ctcp';
200             } else {
201 0           $type = 'ctcpreply';
202             }
203              
204 0           return ($who, $type, $where, $ctcp, $text);
205             }
206              
207              
208             1;
209              
210             __END__