|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package POE::Filter::IRCv3;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 $POE::Filter::IRCv3::VERSION = '1.002002';  | 
| 
3
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
67474
 | 
 use strict; use warnings;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
    | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
10
 | 
 use Carp;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
294
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Not mandatory, but handy for POE apps, in which case POE is presumably  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # installed already; we can do all POE::Filter-y things, this only matters for  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ->isa('POE::Filter') ->  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BEGIN {  | 
| 
11
 | 
2
 | 
  
 50
  
 | 
 
 | 
  
2
  
 | 
 
 | 
5
 | 
   if (eval { require POE::Filter; 1 }) {  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1173
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1047
 | 
    | 
| 
12
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1294
 | 
     our @ISA = 'POE::Filter';  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =for Pod::Coverage COLONIFY DEBUG BUFFER SPCHR  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub COLONIFY () { 0 }  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DEBUG    () { 1 }  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub BUFFER   () { 2 }  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub SPCHR    () { "\x20" }  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our %CharToEscapedTag = (  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ';'  => '\:',  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ' '  => '\s',  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   "\\" => '\\',  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   "\r" => '\r',  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   "\n" => '\n',  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   "\a" => '\a',  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our %EscapedTagToChar = reverse %CharToEscapedTag;  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
39
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
966
 | 
   my ($class, %params) = @_;  | 
| 
40
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
   $params{uc $_} = $params{$_} for keys %params;  | 
| 
41
 | 
4
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
69
 | 
   bless [  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ($params{'COLONIFY'} || 0),  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ($params{'DEBUG'}    || $ENV{POE_FILTER_IRC_DEBUG} || 0),  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     []      # BUFFER  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ], $class  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub clone {  | 
| 
49
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
1
 | 
   my ($self) = @_;  | 
| 
50
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   my $nself = [@$self];  | 
| 
51
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   $nself->[BUFFER] = [];  | 
| 
52
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
   bless $nself, ref $self  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
4
 | 
  
100
  
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
868
 | 
 sub debug    { defined $_[1] ? $_[0]->[DEBUG] = $_[1] : $_[0]->[DEBUG] }  | 
| 
56
 | 
2
 | 
  
100
  
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
974
 | 
 sub colonify { defined $_[1] ? $_[0]->[COLONIFY] = $_[1] : $_[0]->[COLONIFY] }  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
377
 | 
 sub get_one_start { push @{ $_[0]->[BUFFER] }, $_ for @{ $_[1] }; }  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
59
 | 
1
 | 
  
 50
  
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
2
 | 
 sub get_pending   { @{ $_[0]->[BUFFER] } ? [ @{ $_[0]->[BUFFER] } ] : () }  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get {  | 
| 
62
 | 
39
 | 
 
 | 
 
 | 
  
39
  
 | 
  
1
  
 | 
63207
 | 
   my @events;  | 
| 
63
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
   for my $raw_line (@{ $_[1] }) {  | 
| 
 
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
    | 
| 
64
 | 
39
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
154
 | 
     warn " >> '$raw_line'\n" if $_[0]->[DEBUG];  | 
| 
65
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
105
 | 
     if ( my $event = parse_one_line($raw_line) ) {  | 
| 
66
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
129
 | 
       push @events, $event;  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # carp here because caller provided lines:  | 
| 
69
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
419
 | 
       carp "Received malformed IRC input: $raw_line";  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   \@events  | 
| 
73
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
274
 | 
 }  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get_one {  | 
| 
76
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
1373
 | 
   my ($self) = @_;  | 
| 
77
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   my @events;  | 
| 
78
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   if ( my $raw_line = shift @{ $self->[BUFFER] } ) {  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
79
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     warn " >> '$raw_line'\n" if $self->[DEBUG];  | 
| 
80
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     if ( my $event = parse_one_line($raw_line) ) {  | 
| 
81
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
       push @events, $event;  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # ..but warn here because who knows where the buffer came from:  | 
| 
84
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       warn "Received malformed IRC input: $raw_line\n";  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   \@events  | 
| 
88
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
 }  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
91
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1485
 | 
 use bytes;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
92
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
80
 | 
 no warnings 'substr';  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2109
 | 
    | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub put {  | 
| 
95
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
60932
 | 
   my ($self, $events) = @_;  | 
| 
96
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
   my $raw_lines = [];  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
   for my $event (@$events) {  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
100
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
77
 | 
     if ( ref $event eq 'HASH' ) {  | 
| 
101
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
       my $raw_line;  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       ## FIXME this gets glacially slow ->  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #  y// over string for escapes first and then loop?  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       #    | 
| 
106
 | 
21
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
103
 | 
       if ( exists $event->{tags} && (my @tags = %{ $event->{tags} }) ) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
    | 
| 
107
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
           $raw_line .= '@';  | 
| 
108
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
           while (my ($thistag, $thisval) = splice @tags, 0, 2) {  | 
| 
109
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
             $raw_line .= $thistag;  | 
| 
110
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
             if (defined $thisval) {  | 
| 
111
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
               $raw_line .= '=';  | 
| 
112
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
               my $tag_pos = 0;  | 
| 
113
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
               my $len = length $thisval;  | 
| 
114
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
               while ($tag_pos < $len) {  | 
| 
115
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
                 my $ch = substr $thisval, $tag_pos++, 1;  | 
| 
116
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
                 $raw_line .= exists $CharToEscapedTag{$ch} ?  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   $CharToEscapedTag{$ch} : $ch  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               }  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
120
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
30
 | 
             $raw_line .= ';' if @tags;  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
122
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
           $raw_line .= ' ';  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
125
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
106
 | 
       $raw_line .= ':' . $event->{prefix} . ' ' if $event->{prefix};  | 
| 
126
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
       $raw_line .= $event->{command};  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
128
 | 
21
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
93
 | 
       if ( $event->{params} && (my @params = @{ $event->{params} }) ) {  | 
| 
 
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
120
 | 
    | 
| 
129
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
           $raw_line .= ' ';  | 
| 
130
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
           my $param = shift @params;  | 
| 
131
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
104
 | 
           while (@params) {  | 
| 
132
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
             $raw_line .= $param . ' ';  | 
| 
133
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
             $param = shift @params;  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
135
 | 
17
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
150
 | 
           $raw_line .= ':'  | 
| 
 
 | 
 
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if (index($param, SPCHR) != -1)  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             or (index($param, ':') == 0)  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             or (  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               defined $event->{colonify} ?  | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               $event->{colonify} : $self->[COLONIFY]  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             );  | 
| 
142
 | 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
           $raw_line .= $param;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
145
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51
 | 
       push @$raw_lines, $raw_line;  | 
| 
146
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
98
 | 
       warn " << '$raw_line'\n" if $self->[DEBUG];  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
148
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       carp "($self) non-HASH passed to put(): '$event'";  | 
| 
149
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       push @$raw_lines, $event if ref $event eq 'SCALAR';  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $raw_lines  | 
| 
155
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
 }  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
158
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub parse_one_line {  | 
| 
159
 | 
42
 | 
 
 | 
 
 | 
  
42
  
 | 
  
1
  
 | 
881
 | 
   my $raw_line = $_[0];  | 
| 
160
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
   my %event = ( raw_line => $raw_line );  | 
| 
161
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
   my $pos = 0;  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ## We cheat a little; the spec is fuzzy when it comes to CR, LF, and NUL  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ## bytes. Theoretically they're not allowed inside messages, but  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ## that's really an implementation detail (and the spec agrees).  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ## We just stick to SPCHR (\x20) here.  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
168
 | 
42
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
145
 | 
   if ( substr($raw_line, 0, 1) eq '@' ) {  | 
| 
169
 | 
21
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     return unless (my $nextsp = index($raw_line, SPCHR)) > 0;  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Tag parser cheats and uses split, at the moment:  | 
| 
171
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
112
 | 
     for ( split /;/, substr $raw_line, 1, ($nextsp - 1) ) {  | 
| 
172
 | 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
72
 | 
           my ($thistag, $thisval) = split /=/;  | 
| 
173
 | 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
           my $realval;  | 
| 
174
 | 
41
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
66
 | 
           if (defined $thisval) {  | 
| 
175
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
             my $tag_pos = 0;  | 
| 
176
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
             my $len = length $thisval;  | 
| 
177
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
51
 | 
             while ($tag_pos < $len) {  | 
| 
178
 | 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
112
 | 
               my $ch = substr $thisval, $tag_pos++, 1;  | 
| 
179
 | 
130
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
148
 | 
               if ($ch eq "\\") {  | 
| 
180
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
19
 | 
                 my $pair = $ch . (substr($thisval, $tag_pos++, 1) || '');  | 
| 
181
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
33
 | 
                 $realval .= exists $EscapedTagToChar{$pair} ?  | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   $EscapedTagToChar{$pair} : substr $pair, 1, 1;  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               } else {  | 
| 
184
 | 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
181
 | 
                 $realval .= $ch  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               }  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
188
 | 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
           $event{tags}->{$thistag} = $realval  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
190
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
     $pos = $nextsp + 1;  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
193
 | 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
138
 | 
   $pos++ while substr($raw_line, $pos, 1) eq SPCHR;  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
195
 | 
42
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
118
 | 
   if ( substr($raw_line, $pos, 1) eq ':' ) {  | 
| 
196
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
     my $nextsp;  | 
| 
197
 | 
26
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
242
 | 
     ($nextsp = index $raw_line, SPCHR, $pos) > 0 and length(  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $event{prefix} = substr $raw_line, ($pos + 1), ($nextsp - $pos - 1)  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ) or return;  | 
| 
200
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
     $pos = $nextsp + 1;  | 
| 
201
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
118
 | 
     $pos++ while substr($raw_line, $pos, 1) eq SPCHR;  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
204
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
   my $nextsp_maybe;  | 
| 
205
 | 
39
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
136
 | 
   if ( ($nextsp_maybe = index $raw_line, SPCHR, $pos) == -1 ) {  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # No more spaces; do we have anything..?  | 
| 
207
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     my $cmd = substr $raw_line, $pos;  | 
| 
208
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
33
 | 
     $event{command} = uc( length $cmd ? $cmd : return );  | 
| 
209
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
     return \%event  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $event{command} = uc(   | 
| 
213
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
130
 | 
     substr($raw_line, $pos, ($nextsp_maybe - $pos) )  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
215
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
   $pos = $nextsp_maybe + 1;  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
217
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
116
 | 
   $pos++ while substr($raw_line, $pos, 1) eq SPCHR;  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
219
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
   my $maxlen = length $raw_line;  | 
| 
220
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
116
 | 
   PARAM: while ( $pos < $maxlen ) {  | 
| 
221
 | 
54
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
133
 | 
     if ( substr($raw_line, $pos, 1) eq ':' ) {  | 
| 
222
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
       push @{ $event{params} }, substr $raw_line, ($pos + 1);  | 
| 
 
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
    | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       last PARAM  | 
| 
224
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
     }  | 
| 
225
 | 
33
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
107
 | 
     if ( (my $nextsp = index $raw_line, SPCHR, $pos) == -1 ) {  | 
| 
226
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
       push @{ $event{params} }, substr $raw_line, $pos;  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       last PARAM  | 
| 
228
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     } else {  | 
| 
229
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
       push @{ $event{params} }, substr $raw_line, $pos, ($nextsp - $pos);  | 
| 
 
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
    | 
| 
230
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
       $pos = $nextsp + 1;  | 
| 
231
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
       $pos++ while substr($raw_line, $pos, 1) eq SPCHR;  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       next PARAM  | 
| 
233
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
71
 | 
     }  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
236
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
152
 | 
   \%event  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
240
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
16
 | 
 no bytes;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 print  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   qq[ let's try this again -without- the part where we beat you to],  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   qq[ death with a six foot plush toy of sexual harassment panda\n ]  | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 unless caller; 1;  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 POE::Filter::IRCv3 - Fast IRCv3.2 parser for POE or stand-alone use  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $filter = POE::Filter::IRCv3->new(colonify => 1);  | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Raw lines parsed to hashes:  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $array_of_refs  = $filter->get(   | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     [   | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       ':prefix COMMAND foo :bar',  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       '@foo=bar;baz :prefix COMMAND foo :bar',  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ]  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Hashes deparsed to raw lines:  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $array_of_lines = $filter->put(   | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     [  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         prefix  => 'prefix',  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         command => 'COMMAND',  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         params  => [  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           'foo',  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           'bar'  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ],  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       },  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       {  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         prefix  => 'prefix',  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         command => 'COMMAND',  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         params  => [  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           'foo',  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           'bar'  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ],  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         tags => {  | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           foo => 'bar',  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           baz => undef,  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         },  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       },  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ]   | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Stacked with a line filter, suitable for Wheel usage, etc:  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $ircd = POE::Filter::IRCv3->new(colonify => 1);  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $line = POE::Filter::Line->new(  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     InputRegexp   => '\015?\012',  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     OutputLiteral => "\015\012",  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $stacked = POE::Filter::Stackable->new(  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Filters => [ $line, $ircd ],  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Functional parser interface:  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $event = POE::Filter::IRCv3::parse_one_line(  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ':foo PRIVMSG #bar :baz quux'  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A L for IRC traffic with support for IRCv3.2 message tags.  | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Does not rely on regular expressions for parsing.  Benchmarks show this  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 approach is generally faster on the most common IRC strings.  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Like any proper L, there are no POE-specific bits involved here  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 -- the filter can be used stand-alone to parse lines of IRC traffic (also see  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L).   | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In fact, you do not need L installed -- if L is not  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 available, it is left out of C<@ISA> and the filter will continue working  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 normally.  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 POE / Object interface  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 new  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Construct a new Filter; if the B option is true,   | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the last parameter will always have a colon prepended.  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 (This setting can also be retrieved or changed on-the-fly by calling   | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 B as a method, or changed for specific events by passing a   | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 B option via events passed to L.)  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 get_one_start, get_one, get_pending  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Implement the interface described in L.  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 See L.  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 get  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $events = $filter->get( [ $line, $another, ... ] );  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   for my $event (@$events) {  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $cmd = $event->{command};  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ## See below for other keys available  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Takes an ARRAY of raw lines and returns an ARRAY of HASH-type references with   | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the following keys:  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head4 command  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The (uppercased) command or numeric.  | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head4 params  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 An ARRAY containing the event parameters.  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head4 prefix  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The sender prefix, if any.  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head4 tags  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A HASH of key => value pairs matching IRCv3.2 "message tags" -- see   | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L.  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Note that a tag can be present, but have an undefined value.  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 put  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $lines = $filter->put( [ $hash, $another_hash, ... ] );  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   for my $line (@$lines) {  | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ## Direct to socket, etc  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Takes an ARRAY of HASH-type references matching those described in L   | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 (documented above) and returns an ARRAY of raw IRC-formatted lines.  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head4 colonify  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In addition to the keys described in L, the B option can be   | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 specified for specific events. This controls whether or not the last   | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 parameter will be colon-prefixed even if it is a single word. (Yes, IRC is   | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 woefully inconsistent ...)  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Specify as part of the event hash:  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $filter->put([ { %event, colonify => 1 } ]);  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 clone  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Copy the filter object (with a cleared buffer).  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 debug  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Turn on/off debug output, which will display every input/output line (and  | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 possibly other data in the future).  | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This is enabled by default at construction time if the environment variable  | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 C is a true value.  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 Functional interface  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head3 parse_one_line  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If the filter is being used as a stand-alone IRC parser and speed is of the  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 essence, you can skip method resolution & queue handling by calling the parse  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 function directly using the fully-qualified name:  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $ev = POE::Filter::IRCv3::parse_one_line( $line );  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The function takes a single line and returns a HASH whose structure is  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 described in the documentation for L, above.  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If the given line cannot be parsed, the function returns false (rather than  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 throwing an exception, as L would).  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 There is currently no functional interface to message string composition  | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 (L).  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 AUTHOR  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Jon Portnoy   | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Licensed under the same terms as Perl.  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Original implementations were derived from L,   | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 which is copyright Chris Williams and Jonathan Steinert. This codebase has  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 diverged significantly.  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Major thanks to the C<#ircv3> crew on irc.atheme.org, especially C and  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 C, for various bits of inspiration.  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SEE ALSO  | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  |