File Coverage

blib/lib/POE/Filter/MSN.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             package POE::Filter::MSN;
2 1     1   174271 use strict;
  1         4  
  1         35  
3              
4 1     1   6 use POE qw(Component::Client::MSN::Command);
  1         2  
  1         6  
5              
6             use vars qw($Debug);
7             $Debug = 0;
8              
9             sub Dumper { require Data::Dumper; local $Data::Dumper::Indent = 1; Data::Dumper::Dumper(@_) }
10              
11             sub new {
12             my $class = shift;
13             my %opts = @_;
14             my $o = {
15             buffer => '',
16             get_state => 'line',
17             put_state => 'line',
18             body_info => {},
19             ftp => 0,
20             };
21             foreach (keys %opts) {
22             $o->{$_} = $opts{$_};
23             }
24             bless($o, $class);
25             }
26              
27             sub get {
28             my ($self, $stream) = @_;
29              
30             # Accumulate data in a framing buffer.
31             $self->{buffer} .= join('', @$stream);
32              
33            
34             my $many = [];
35             while (1) {
36             my $input = $self->get_one([]);
37             if ($input) {
38             push(@$many,@$input);
39             } else {
40             last;
41             }
42             }
43              
44             return $many;
45             }
46              
47             sub get_one_start {
48             my ($self, $stream) = @_;
49              
50             $Debug && do {
51             open(FH,">>/tmp/proto.log");
52             print FH join('', @$stream);
53             close(FH);
54             };
55             # Accumulate data in a framing buffer.
56             $self->{buffer} .= join('', @$stream);
57             }
58              
59             sub get_one {
60             my($self, $stream) = @_;
61            
62             return [] if ($self->{finish});
63            
64             my @commands;
65             if ($self->{get_state} eq 'line') {
66             return [] unless($self->{buffer} =~ m/\r\n/s);
67              
68             while (1) {
69             # warn "buffer length is".length($self->{buffer})."\n";
70             if ($self->{ftp} == 1 && $self->{buffer} =~ s/^(.{3})\r\n//) {
71             # print STDERR "got [TFR]\n";
72             $self->{put_state} = 'msftp';
73             my $command = POE::Component::Client::MSN::Command->new($1);
74             if ($command->name eq 'TFR') {
75             $self->{body_info} = {
76             command => $command,
77             file_length => $self->{file_size},
78             };
79             # print STDERR "file len: ".$self->{file_size}."\n";
80             delete $self->{file_size};
81             }
82             push @commands, $command;
83             return \@commands;
84             }
85            
86             if ($self->{buffer} =~ s/^(.{3}) (?:(\d+) )?(.*?)\r\n//) {
87             # print STDERR "got [$1] [$2] [$3]\n";
88             #while ($self->{buffer} =~ s/^(.{3}) (?:(\d+) )?(.*?)\r\n//){
89             my $command = POE::Component::Client::MSN::Command->new($1, $3, $2);
90             if ($command->name eq 'MSG') {
91             # switch to body
92             $self->{get_state} = 'body';
93             $self->{body_info} = {
94             command => $command,
95             length => $command->args->[2],
96             };
97             last;
98             } elsif ($self->{ftp} == 1 && $command->name eq 'FIL') {
99             # switch to body
100             $command->name("file_data_stream");
101             $self->{body_info} = {
102             command => $command,
103             file_length => $command->data,
104             bytes_read => 0,
105             total_bytes_read => 0,
106             };
107             # print STDERR "file len: ".$command->data."\n";
108             push @commands, $command;
109             return \@commands;
110             } else {
111             push @commands, $command;
112             }
113             } else {
114             #return [];
115             last;
116             }
117             }
118             }
119              
120             if ($self->{get_state} eq 'body') {
121             if (length($self->{buffer}) < $self->{body_info}->{length}) {
122             # not enough bytes
123             $Debug and warn Dumper \@commands;
124             return \@commands;
125             }
126             my $message = substr($self->{buffer}, 0, $self->{body_info}->{length}, '');
127             my $command = $self->{body_info}->{command};
128             $command->message($message);
129             push @commands, $command;
130            
131             # switch to line by line
132             $self->{get_state} = 'line';
133             $Debug and warn "GET: ", Dumper \@commands;
134             return \@commands;
135             } elsif ($self->{get_state} eq 'msftp-head') {
136             my @d = unpack('C*', $self->{buffer});
137            
138             #print STDERR "ftp head: ".scalar(@d)."\n";
139              
140             if (scalar(@d) == 0 && $self->{body_info}->{total_bytes_read} == $self->{body_info}->{file_length}) {
141             #print STDERR "EOF!!\n";
142             $self->{get_state} = 'line';
143             return [{ eof => 1, stream => ''}];
144             }
145              
146             # poe locks up here if length of $d is 0
147             return [] unless ($#d > 1); # not enough head bytes read
148            
149             if ($d[0] == 1 && $d[1] == 0 && $d[2] == 0) {
150             #print STDERR "EOF!\n";
151             $self->{buffer} = substr($self->{buffer},3);
152             $self->{get_state} = 'line';
153             return [{ eof => 1, stream => ''}];
154             }
155            
156             shift(@d); #don't need the first byte
157            
158             # lenth of body = byte1 + (byte2 * 256)
159             $self->{body_info}->{length} = shift(@d) + (shift(@d) * 256);
160             # $self->{body_info}->{length} = unpack('S',substr($self->{buffer},1,2));
161             $self->{body_info}->{bytes_read} = 0;
162             #print STDERR "got body len: ".$self->{body_info}->{length}."\n";
163              
164             # cut the buffer
165             $self->{buffer} = substr($self->{buffer},3);
166            
167             $self->{get_state} = 'msftp-body';
168             }
169              
170             if ($self->{get_state} eq 'msftp-body') {
171             # do this?
172             return [] if (length($self->{buffer}) < $self->{body_info}->{length});
173              
174             # $Debug and warn "stream data bytes read:".$self->{body_info}->{bytes_read}."\n";
175             ## if ($self->{body_info}->{bytes_read} < $self->{body_info}->{length}) {
176             # if (length($self->{buffer}) < $self->{body_info}->{length}) {
177             # # the complete body has not been read
178             # push(@commands,{ stream => $self->{buffer} });
179             # $self->{body_info}->{bytes_read} += length($self->{buffer});
180             # $self->{body_info}->{total_bytes_read} += length($self->{buffer}); # doesn't get reset
181             #print STDERR "ftp body:".$self->{body_info}->{bytes_read}." which is ".$self->{body_info}->{total_bytes_read}." out of ".$self->{body_info}->{file_length}."\n";
182             # $self->{buffer} = '';
183             # # not enough bytes
184             # #$Debug and warn Dumper \@commands;
185             # return \@commands;
186             # }
187              
188             if ($self->{body_info}->{bytes_read} == $self->{body_info}->{length}) {
189             #print STDERR "Forced EOF with ".length($self->{buffer})." bytes in the buffer\n";
190             push(@commands,{ eof => 1, stream => '' });
191             # switch to line by line
192             $self->{get_state} = 'line';
193             return \@commands;
194             }
195             my $data = substr($self->{buffer}, 0, $self->{body_info}->{length}, '');
196             $self->{body_info}->{bytes_read} += length($data);
197             $self->{body_info}->{total_bytes_read} += length($data); # doesn't get reset
198             #print STDERR "ftp: ".$self->{body_info}->{total_bytes_read}." bytes\n";
199             #print STDERR "ftp body:".$self->{body_info}->{bytes_read}." which is ".$self->{body_info}->{total_bytes_read}." out of ".$self->{body_info}->{file_length}."\n";
200             push(@commands,{ stream => $data });
201             if ($self->{body_info}->{total_bytes_read} == $self->{body_info}->{file_length}) {
202             #print STDERR "forced EOF with ".length($self->{buffer})." bytes in the buffer\n";
203             push(@commands,{ eof => 1, stream => '' });
204             # switch to line by line
205             $self->{get_state} = 'line';
206             } else {
207             # switch to the header
208             $self->{get_state} = 'msftp-head';
209             }
210             return \@commands
211             }
212            
213             $Debug and warn "GET: ", Dumper \@commands;
214             return \@commands;
215             }
216              
217             sub put {
218             my($self, $commands) = @_;
219             return [ map $self->_put($_), @$commands ];
220             }
221              
222             sub _put {
223             my($self, $command) = @_;
224             # $Debug and warn "PUT: ", Dumper $command."\r\n";
225             if ($self->{ftp} == 1) {
226             # MSNFTP doesn't have transactions
227             if (ref($command) && exists($command->{name_only})) {
228             if ($command->name eq 'TFR') {
229             $self->{get_state} = 'msftp-head';
230             }
231             $Debug and warn "PUT: ".$command->name.($command->no_newline ? '' : "\r\n");
232             return $command->name.($command->no_newline ? '' : "\r\n");
233             } else {
234             if ($self->{put_state} eq 'msftp') {
235             my @data;
236             # make header and send data
237             if ($command->{eof}) {
238             my @header = qw(1 0 0);
239             push(@data,pack('C*', @header));
240             } else {
241             my @header = "0";
242             #push(@header,pack('S',length($command->{stream})));
243             my $x = pack "S", length($command->{stream});
244             push(@header,ord(substr($x,0,1)));
245             push(@header,ord(substr($x,1,1)));
246             push(@data,pack('C*', @header));
247             push(@data,$command->{stream});
248             }
249             return join('',@data);
250             } else {
251             $Debug and warn "PUT: ".sprintf "%s %s%s",$command->name, $command->data, ($command->no_newline ? '' : "\r\n");
252             return sprintf "%s %s%s",$command->name, $command->data, ($command->no_newline ? '' : "\r\n");
253             }
254             }
255             } else {
256             # this shouldn't happen, but fix it
257             if ($self->{put_state} eq 'msftp') {
258             $self->{put_state} = 'line';
259             }
260             $Debug and warn "PUT: ".sprintf "%s %d %s%s",$command->name, $command->transaction, $command->data, ($command->no_newline ? '' : "\r\n");
261             return sprintf "%s %d %s%s",$command->name, $command->transaction, $command->data, ($command->no_newline ? '' : "\r\n");
262              
263             }
264             }
265              
266             sub get_pending {
267             my $self = shift;
268             return [ $self->{buffer} ] if length $self->{buffer};
269             return undef;
270             }
271              
272             1;
273