File Coverage

blib/lib/POE/Component/Client/Telnet.pm
Criterion Covered Total %
statement 27 177 15.2
branch 0 72 0.0
condition 0 11 0.0
subroutine 9 25 36.0
pod 4 12 33.3
total 40 297 13.4


line stmt bran cond sub pod time code
1             package POE::Component::Client::Telnet;
2              
3 1     1   28923 use POE 0.31;
  1         56250  
  1         7  
4 1     1   110226 use POE::Wheel::Run;
  1         38086  
  1         40  
5 1     1   15 use POE::Filter::Line;
  1         17  
  1         101  
6 1     1   1443 use POE::Filter::Reference;
  1         10843  
  1         30  
7 1     1   1746 use Net::Telnet;
  1         35833  
  1         65  
8 1     1   10 use Carp qw(carp croak);
  1         1  
  1         64  
9 1     1   5 use Devel::Symdump;
  1         3  
  1         32  
10 1     1   6 use vars qw($AUTOLOAD);
  1         2  
  1         46  
11              
12 1     1   6 use strict;
  1         1  
  1         2497  
13              
14             our $VERSION = '0.06';
15              
16             sub AUTOLOAD {
17 0     0     my $self = shift;
18 0           my $method = $AUTOLOAD;
19 0           $method =~ s/.*:://;
20 0 0         return unless $method =~ /[^A-Z]/;
21            
22 0 0         warn "autoload method $method" if ($self->{debug});
23            
24 0           my $hash = shift;
25 0 0         croak 'first param must be a hash ref of options' unless (ref($hash) eq 'HASH');
26            
27 0 0         $hash->{wantarray} = wantarray() unless (defined($hash->{wantarray}));
28 0           $poe_kernel->post($self->session_id() => $method => $hash => @_);
29             }
30              
31             sub spawn {
32 0     0 0   goto &new;
33             }
34              
35             sub new {
36 0     0 1   my $package = shift;
37 0 0         croak "$package needs an even number of parameters" if @_ & 1;
38 0           my %params = @_;
39              
40 0           foreach my $param ( keys %params ) {
41 0           $params{ lc $param } = delete ( $params{ $param } );
42             }
43              
44 0           my $options = delete ( $params{'options'} );
45 0   0       $params{package} ||= 'Net::Telnet';
46              
47             # map of commands to packages
48 0           $params{cmd_map} = {};
49              
50 0           my $self = bless(\%params, $package);
51              
52 0 0         if ($params{package} ne 'Net::Telnet') {
53 0           eval "use $params{package}";
54 0 0         die $@ if ($@);
55             }
56            
57 0           my @obj = Devel::Symdump->functions('Net::Telnet');
58 0           push(@obj,Devel::Symdump->functions($params{package}));
59            
60 0           foreach my $p (@obj) {
61 0           my ($pk,$sub) = ($p =~ m/^(.+)\:\:([^\:]+)/);
62            
63 0 0         next unless ($sub =~ /[^A-Z_0-9]$/);
64 0 0 0       next if ($sub =~ m/^_/ || $sub =~ m/(carp|croak|confess)$/);
65 0           my $o = $p;
66            
67 0 0         if (defined &$o) {
68 0           $self->{cmd_map}->{$sub} = $pk;
69             }
70             }
71            
72 0           $self->{session_id} = POE::Session->create(
73             object_states => [
74 0 0 0       $self => { (map { $_ => 'request' } keys %{$self->{cmd_map}}) },
  0            
75             $self => [ qw(_start shutdown wheel_close wheel_err wheel_out wheel_stderr) ],
76             ],
77             ( ( defined ( $options ) and ref ( $options ) eq 'HASH' ) ? ( options => $options ) : () ),
78             )->ID();
79              
80 0 0         warn "session $self->{session_id} created for $params{package}" if ($self->{debug});
81            
82 0           return $self;
83             }
84              
85             # POE related object methods
86              
87             sub _start {
88 0     0     my ($kernel,$self) = @_[KERNEL,OBJECT];
89              
90 0 0         if ( $self->{alias} ) {
91 0           $kernel->alias_set( $self->{alias} );
92             } else {
93 0           $kernel->refcount_increment( $self->{session_id} => __PACKAGE__ );
94             }
95              
96 0           $self->{wheel} = POE::Wheel::Run->new(
97             Program => \&process_requests,
98             CloseOnCall => 0,
99             StdinFilter => POE::Filter::Reference->new(),
100             StdoutFilter => POE::Filter::Reference->new(),
101             StderrFilter => POE::Filter::Line->new(),
102             StdoutEvent => 'wheel_out',
103             StderrEvent => 'wheel_stderr',
104             ErrorEvent => 'wheel_err',
105             CloseEvent => 'wheel_close',
106             );
107              
108             # adjust options
109 0 0         if ($self->{package} ne 'Net::Telnet') {
110 0           $self->{telnet_options} = [ (@{$self->{telnet_options}}, '_Package' => $self->{package}) ];
  0            
111             }
112              
113 0 0 0       if ($self->{telnet_options} && ref($self->{telnet_options}) eq 'ARRAY') {
114 0           $self->{wheel}->put($self->{telnet_options});
115             }
116              
117 0           undef;
118             }
119              
120             sub request {
121 0     0 0   my ($kernel,$self,$state,$sender) = (@_[KERNEL,OBJECT,STATE],$_[SENDER]->ID);
122            
123 0 0         warn "processing request $state\n" if ($self->{debug});
124             # Get the arguments
125 0           my $args;
126 0 0         if (ref($_[ARG0]) eq 'HASH') {
127 0           $args = { %{ $_[ARG0] } };
  0            
128             } else {
129 0           warn "first parameter must be a ref hash, trying to adjust. "
130             ."(fix this to get rid of this message)";
131 0           $args = { @_[ARG0 .. $#_ ] };
132             }
133            
134 0 0         if ($self->{wheel}) {
135 0           $args->{session} = $sender;
136 0           $args->{func} = $state;
137 0           $args->{state} = $state;
138 0           $args->{args} = [ @_[ ARG1 .. $#_ ] ];
139            
140             # if we have an event to report to...make sure we stay around
141 0 0         if ($args->{event}) {
142 0           $kernel->refcount_increment($sender => __PACKAGE__);
143             }
144            
145 0           $self->{wheel}->put($args);
146             }
147            
148 0           undef;
149             }
150              
151             sub wheel_out {
152 0     0 0   my ($kernel,$self,$input) = @_[KERNEL,OBJECT,ARG0];
153              
154 0           delete $input->{func};
155            
156 0           my $session = delete $input->{session};
157 0           my $event = delete $input->{event};
158              
159 0 0         if ($event) {
160 0           $kernel->post($session => $event => $input);
161 0           $kernel->refcount_decrement($session => __PACKAGE__);
162             }
163            
164 0           undef;
165             }
166              
167             sub wheel_stderr {
168 0     0 0   my ($kernel,$self,$input) = @_[KERNEL,OBJECT,ARG0];
169              
170 0 0         warn "$input\n" if ($self->{debug});
171             }
172              
173             sub wheel_err {
174 0     0 0   my ($self, $operation, $errnum, $errstr, $wheel_id) = @_[OBJECT, ARG0..ARG3];
175            
176 0 0         warn "Wheel $wheel_id generated $operation error $errnum: $errstr\n" if ($self->{debug});
177             }
178              
179             sub wheel_close {
180 0     0 0   my $self = $_[OBJECT];
181            
182 0 0         warn "Wheel closed\n" if ($self->{debug});
183            
184 0           warn "$self->{package} Wheel closed, ieeeeeeee!\n";
185             }
186              
187             # Dual event and object methods
188              
189             sub shutdown {
190 0 0   0 0   unless (UNIVERSAL::isa($_[KERNEL],'POE::Kernel')) {
191 0 0         if ($poe_kernel) {
192 0           $poe_kernel->call(shift->session_id() => 'shutdown' => @_);
193             }
194 0           return;
195             }
196            
197 0           my ($kernel,$self) = @_[KERNEL,OBJECT];
198              
199             # remove alias or decrease ref count
200 0 0         if ($self->{alias}) {
201 0           $kernel->alias_remove($_) for $kernel->alias_list();
202             } else {
203 0           $kernel->refcount_decrement($self->session_id() => __PACKAGE__);
204             }
205            
206 0 0         if ($self->{wheel}) {
207 0           $self->{wheel}->shutdown_stdin;
208             }
209 0           undef;
210             }
211              
212              
213             # Object methods
214              
215             sub session_id {
216 0     0 1   shift->{session_id};
217             }
218              
219             sub yield {
220 0     0 1   my $self = shift;
221 0           $poe_kernel->post($self->session_id() => @_);
222             }
223              
224             sub call {
225 0     0 1   my $self = shift;
226 0           $poe_kernel->call($self->session_id() => @_);
227             }
228              
229             sub DESTROY {
230 0 0   0     if (UNIVERSAL::isa($_[0],__PACKAGE__)) {
231 0           $_[0]->shutdown();
232             }
233             }
234              
235             # Main Wheel::Run process sub
236              
237             sub process_requests {
238 0     0 0   binmode(STDIN);
239 0           binmode(STDOUT);
240              
241 0           my $raw;
242 0           my $size = 4096;
243 0           my $filter = POE::Filter::Reference->new();
244              
245             # telnet object
246 0           my $t;
247              
248             # there's room for other callbacks
249 0           my %callbacks = (
250             option_callback => undef,
251             );
252            
253             READ:
254 0           while ( sysread ( STDIN, $raw, $size ) ) {
255 0           my $requests = $filter->get([$raw]);
256              
257 0 0         unless ($t) {
258 0           my $arg = shift(@{$requests});
  0            
259 0 0         if (ref($arg) eq 'ARRAY') {
260 0           my $package = 'Net::Telnet';
261 0           my %args = ( @$arg );
262 0 0         if ($args{_Package}) {
263 0           $package = delete $args{'_Package'};
264 0           eval "use $package";
265 0 0         if ($@) {
266 0           die "$@\n";
267             }
268             }
269 0           $t = $package->new(%args);
270             } else {
271 0           $t = Net::Telnet->new();
272 0           unshift(@{$requests},$arg);
  0            
273             }
274             }
275            
276 0           foreach my $req (@{$requests}) {
  0            
277 0           my $func = $req->{func};
278            
279 0 0         if ($func eq 'option_callback') {
280 0 0         if (@{$req->{args}}) {
  0            
281             # set the callback event
282 0           $callbacks{$func} = $req->{args}->[0];
283             # TODO allow unsetting event? Net::Telnet doesn't allow it...
284             # then set a coderef to post that back
285             $t->$func(sub {
286             # $obj, $option, $is_remote, $is_enabled, $was_enabled, $buf_position
287 0     0     shift; # don't need and can't send the object
288 0           $req->{result} = [ @_ ];
289 0           $req->{event} = $callbacks{$func};
290 0           my $rep = $filter->put( [ $req ] );
291 0           print STDOUT @$rep;
292 0           });
293             } else {
294 0           $req->{result} = $callbacks{$func};
295 0           my $rep = $filter->put( [ $req ] );
296 0           print STDOUT @$rep;
297             }
298 0           next;
299             }
300              
301 0           my @result;
302 0           eval {
303 0           @result = $t->$func(@{$req->{args}});
  0            
304             };
305 0 0         if ($@) {
306 0           $req->{error} = $@;
307 0           @result = undef;
308             }
309            
310 0 0         if ($req->{wantarray}) {
311 0           $req->{result} = \@result;
312             } else {
313 0           $req->{result} = $result[0];
314             }
315            
316 0           my $replies = $filter->put( [ $req ] );
317 0           print STDOUT @$replies;
318             }
319             }
320             }
321              
322             1;
323              
324             __END__