File Coverage

blib/lib/IO/Socket/CLI.pm
Criterion Covered Total %
statement 101 153 66.0
branch 38 72 52.7
condition 10 23 43.4
subroutine 18 27 66.6
pod 17 17 100.0
total 184 292 63.0


line stmt bran cond sub pod time code
1             package IO::Socket::CLI;
2              
3             =head1 NAME
4              
5             IO::Socket::CLI - CLI for IO::Socket::INET6 and IO::Socket::SSL
6              
7             =head1 VERSION
8              
9             Version 0.04
10              
11             =head1 SYNOPSIS
12              
13             use IO::Socket::CLI;
14             @ISA = ("IO::Socket::CLI");
15              
16             =head1 DESCRIPTION
17              
18             C provides a command-line interface to L and
19             L.
20              
21             =for comment
22             =head1 EXPORT
23             None by default.
24              
25             =cut
26              
27 1     1   30288 use 5.006;
  1         5  
  1         55  
28 1     1   7 use strict;
  1         1  
  1         41  
29 1     1   6 use warnings;
  1         7  
  1         53  
30 1     1   1556 use IO::Socket::SSL;
  1         120126  
  1         8  
31 1     1   1366 use IO::Socket::INET6;
  1         5514  
  1         9  
32 1     1   920 use Carp;
  1         3  
  1         80  
33              
34             BEGIN {
35 1     1   7 use Exporter ();
  1         3  
  1         111  
36 1     1   2 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
37 1         2 $VERSION = '0.04';
38 1         15 @ISA = qw(Exporter);
39 1         2 @EXPORT = qw(); # qw( );
40 1         2 @EXPORT_OK = qw(); # ( @{ $EXPORT_TAGS{'all'} } );
41 1         1880 %EXPORT_TAGS = (); # ( 'all' => [ qw( ) ] );
42             }
43              
44             # defaults
45             my $DEBUG = 0; # boolean?
46             my $DELAY = 10; # number of milliseconds between each attempt at reading the response from the server.
47             my $TIMEOUT = 5; # number of seconds to wait for a response from server before returning an empty list.
48             my $PRINT_RESPONSE = 1; # boolean
49             my $PREPEND = 1; # boolean
50             our $SSL = 0; # boolean
51             my $HOST = '127.0.0.1'; # IP or domain
52             our $PORT = '143'; # port
53             our $BYE = qr'^\* BYE( |\r?$)'; # string server sends when it hangs up.
54              
55             =head1 METHODS
56              
57             =over 2
58              
59             =item new(...)
60              
61             Creates a new IO::Socket::CLI object, returning its reference. Has the following options:
62              
63             =over 2
64              
65             =item HOST
66              
67             Hostname or IP address. Default is C<'127.0.0.1'>.
68              
69             =item PORT
70              
71             Port of the service. Default is C<'143'>.
72              
73             =item SSL
74              
75             Boolean value for if an SSL connection. Default is C<0>.
76              
77             =item BYE
78              
79             String server sends when it hangs up. Default is C.
80              
81             =item TIMEOUT
82              
83             Timeout in seconds for reading from the socket before returning an empty list. Default is C<5>.
84              
85             =item DELAY
86              
87             Delay in milliseconds between read attempts if nothing is returned. Default is C<10>.
88              
89             =item PRINT_RESPONSE
90              
91             Boolean value for if to automatically print the server response on L. Default is C<1>.
92              
93             =item PREPEND
94              
95             Boolean value for if to pretend client commands and server responses with C<"C: "> and C<"S: ">, respectively. Default is C<1>.
96              
97             =item DEBUG
98              
99             Boolean value for if to give verbose debugging info. Default is C<0>.
100              
101             =back
102              
103             =cut
104              
105             sub new {
106 1     1 1 2454 my $this = shift;
107 1   33     13 my $class = ref($this) || $this;
108 1         4 my $self = {};
109 1 50       11 my $args = (ref($_[0]) eq 'HASH') ? $_[0] : {@_};
110              
111 1 50       8 $self->{_HOST} = ($args->{HOST}) ? $args->{HOST} : $HOST;
112 1 50       7 $self->{_PORT} = ($args->{PORT}) ? $args->{PORT} : $PORT;
113 1 50       12 $self->{_BYE} = ($args->{BYE}) ? $args->{BYE} : $BYE;
114 1 50       7 $self->{_DELAY} = ($args->{DELAY}) ? $args->{DELAY} : $DELAY;
115 1 50       5 $self->{_TIMEOUT} = ($args->{TIMEOUT}) ? $args->{TIMEOUT} : $TIMEOUT;
116 1 50       45 $self->{_PRINT_RESPONSE} = (defined $args->{PRINT_RESPONSE}) ? $args->{PRINT_RESPONSE} : $PRINT_RESPONSE;
117 1 50       7 $self->{_PREPEND} = (defined $args->{PREPEND}) ? $args->{PREPEND} : $PREPEND;
118 1 50       7 $self->{_DEBUG} = (defined $args->{DEBUG}) ? $args->{DEBUG} : $DEBUG;
119 1 50       6 $self->{_SSL} = (defined $args->{SSL}) ? $args->{SSL} : $SSL;
120 1   50     16 $self->{_SOCKET} = IO::Socket::INET6->new(PeerAddr => $self->{_HOST},
121             PeerPort => $self->{_PORT},
122             Blocking => 0) ||
123             die "Can't bind : $@\n";
124              
125 1 50       1593 ($self->{_SSL}) and IO::Socket::SSL->start_SSL($self->{_SOCKET});
126 1 50       12 $self->{_OPEN} = ($self->{_SOCKET}->connected()) ? 1 : 0;
127 1         20 $self->{_COMMAND} = '';
128 1         4 $self->{_SERVER_RESPONSE} = [];
129              
130 1         3 bless ($self, $class);
131 1         6 return $self;
132             }
133              
134             =item read()
135              
136             Reads the response from the server, returning it as a list. Tries every
137             C milliseconds until C seconds. Optionally prints the
138             response to C if C.
139              
140             =cut
141              
142             sub read {
143 0     0 1 0 my $self = shift;
144 0         0 my $i = 0;
145 0         0 my $max_i = $self->{_TIMEOUT} / ($self->{_DELAY} / 1000);
146              
147 0         0 do {
148 0         0 select(undef, undef, undef, $self->{_DELAY} / 1000);
149 0         0 @{$self->{_SERVER_RESPONSE}} = $self->{_SOCKET}->getlines;
  0         0  
150 0         0 $i++;
151 0   0     0 } while (!@{$self->{_SERVER_RESPONSE}} && $i < $max_i);
152              
153 0 0 0     0 if ($DEBUG || $self->{_DEBUG}) {
154 0         0 print STDOUT "D: response took roughly " . ($i * $self->{_DELAY}) . " milliseconds\n";
155             }
156              
157 0 0       0 $self->print_resp() if ($self->{_PRINT_RESPONSE});
158              
159 0         0 return @{$self->{_SERVER_RESPONSE}};
  0         0  
160             }
161              
162             =item response()
163              
164             Returns the last stored response from the server as a list.
165              
166             =cut
167              
168             sub response {
169 0     0 1 0 my $self = shift;
170 0         0 return @{$self->{_SERVER_RESPONSE}};
  0         0  
171             }
172              
173             =item print_resp()
174              
175             Prints each line of server response to C, optionally prepending with C<"S: "> if C.
176              
177             =cut
178              
179             sub print_resp {
180 0     0 1 0 my $self = shift;
181 0         0 foreach (@{$self->{_SERVER_RESPONSE}}) {
  0         0  
182 0 0       0 print STDOUT "" . (($self->{_PREPEND}) ? "S: " : "") . "$_";
183             }
184             }
185              
186             =item is_open()
187              
188             Returns if the server hung up according to the last server response.
189              
190             =cut
191              
192             sub is_open {
193 0     0 1 0 my $self = shift;
194 0         0 my $bye = $self->{_BYE};
195 0 0       0 $self->{_OPEN} = ($self->{_SOCKET}->connected()) ? 1 : 0;
196 0         0 foreach (@{$self->{_SERVER_RESPONSE}}) {
  0         0  
197 0 0       0 $self->{_OPEN} = 0 if (/$bye/);
198 0         0 last;
199             }
200 0         0 return $self->{_OPEN};
201             }
202              
203             =item send($command)
204              
205             Sends C<$command> to the server. Optionally echoes C<$command> if C.
206              
207             =cut
208              
209             sub send($) {
210 0     0 1 0 my $self = shift;
211 0         0 chomp (my $command = shift);
212 0         0 $self->{_COMMAND} = $command;
213 0 0       0 print STDOUT "" . ($self->{_PREPEND} ? "C: " : "") . "$command\r\n" if ($self->{_PRINT_RESPONSE});
    0          
214 0         0 $self->{_SOCKET}->syswrite("$command\r\n");
215             }
216              
217             =item prompt()
218              
219             Reads command from C and sends it to the server.
220              
221             =cut
222              
223             sub prompt {
224 0     0 1 0 my $self = shift;
225 0 0       0 print STDOUT "C: " if ($self->{_PREPEND}); # client prompt
226 0         0 chomp(my $command = );
227 0         0 $self->{_COMMAND} = $command;
228 0         0 $self->{_SOCKET}->syswrite("$command\r\n");
229             }
230              
231             =item command()
232              
233             Returns last command sent.
234              
235             =cut
236              
237             sub command() {
238 0     0 1 0 my $self = shift;
239 0         0 return $self->{_COMMAND};
240             }
241              
242             =item print_response(), print_response($boolean)
243              
244             Optionally turns C on/off. Returns value.
245              
246             =cut
247              
248             sub print_response {
249 4     4 1 4596 my $self = shift;
250 4 100       17 if (@_) {
251 3         4 my $boolean = shift;
252 3 100 66     23 if ($boolean and $boolean != 1) {
253 2         383 carp "warning: valid settings for print_response() are 0 or 1 -- setting to $PRINT_RESPONSE";
254 2         79 $boolean = $PRINT_RESPONSE;
255             }
256 3         10 $self->{_PRINT_RESPONSE} = $boolean;
257             }
258 4         23 return $self->{_PRINT_RESPONSE};
259             }
260              
261             =item prepend(), prepend($boolean)
262              
263             Optionally turns C on/off. Returns value.
264              
265             =cut
266              
267             sub prepend {
268 4     4 1 8 my $self = shift;
269 4 100       161 if (@_) {
270 3         5 my $boolean = shift;
271 3 100 66     24 if ($boolean and $boolean != 1) {
272 2         411 carp "warning: valid settings for prepend() are 0 or 1 -- setting to $PREPEND";
273 2         175 $boolean = $PREPEND;
274             }
275 3         9 $self->{_PREPEND} = $boolean;
276             }
277 4         22 return $self->{_PREPEND};
278             }
279              
280             =item timeout(), timeout($seconds)
281              
282             Optionally sets C in seconds. Must be non-negative. Returns value.
283              
284             =cut
285              
286             sub timeout {
287 4     4 1 9 my $self = shift;
288 4 100       15 if (@_) {
289 3         5 my $seconds = shift;
290 3 100       84 if ($seconds < 0) {
291 1         212 carp "warning: timeout() must be non-negative -- setting to $TIMEOUT";
292 1         49 $seconds = $TIMEOUT;
293             }
294 3         9 $self->{_TIMEOUT} = $seconds;
295             }
296 4         20 return $self->{_TIMEOUT};
297             }
298              
299             =item delay(), delay($milliseconds)
300              
301             Optionally sets C in milliseconds. Must be positive. Returns value.
302              
303             =cut
304              
305             sub delay {
306 4     4 1 10 my $self = shift;
307 4 100       15 if (@_) {
308 3         6 my $milliseconds = shift;
309 3 100       10 if ($milliseconds < 1) {
310 2         299 carp "warning: delay() must be positive -- setting to $DELAY";
311 2         74 $milliseconds = $DELAY;
312             }
313 3         7 $self->{_DELAY} = $milliseconds;
314             }
315 4         19 return $self->{_DELAY};
316             }
317              
318             =item bye(), bye($bye)
319              
320             Optionally sets C. Must be a regexp-like quote: C. Returns value.
321              
322             =cut
323              
324             sub bye {
325 3     3 1 9 my $self = shift;
326 3 100       15 if (@_) {
327 2         4 my $bye = shift;
328 2 100       16 unless ($bye =~ /\(\?(?:-xism|\^):.*\)/) {
329 1         429 carp "warning: bye() must be a regexp-like quote: qr/STRING/ -- setting to '$BYE' instead of '$bye'";
330 1         59 $bye = $BYE;
331             }
332 2         8 $self->{_BYE} = $bye;
333             }
334 3         36 return $self->{_BYE};
335             }
336              
337             =item debug(), debug($boolean)
338              
339             Optionally turns debugging info/verbosity on/off. Returns value.
340              
341             =cut
342              
343             sub debug {
344 5     5 1 11 my $self = shift;
345 5 100       18 if (@_) {
346 4         6 my $boolean = shift;
347 4 100 100     29 if ($boolean and $boolean != 1) {
348 2         259 carp "warning: valid settings for debug() are 0 or 1 -- setting to 1";
349 2         391 $boolean = 1;
350             }
351 4         10 $self->{_DEBUG} = $boolean;
352             }
353 5         26 return $self->{_DEBUG};
354             }
355              
356             #sub debug {
357             # my $self = shift;
358             # confess 'error: thing->debug($level)' unless @_ == 1;
359             # my $level = shift;
360             # if (ref($self)) {
361             # $self->{_DEBUG} = $level; # just myself
362             # } else {
363             # $DEBUG = $level; # whole class
364             # }
365             #}
366              
367             =item socket()
368              
369             Returns the underlying socket.
370              
371             =cut
372              
373             sub socket {
374 0     0 1 0 my $self = shift;
375 0         0 return $self->{_SOCKET};
376             }
377              
378             =item errstr()
379              
380             Returns C from the socket. Only for SSL - returns C otherwise.
381              
382             =cut
383              
384             sub errstr {
385 0     0 1 0 my $self = shift;
386 0 0       0 if ($self->{_SSL}) {
387 0         0 return $self->{_SOCKET}->errstr();
388             } else {
389 0         0 return undef;
390             }
391             }
392              
393             =item close()
394              
395             Closes the socket. Returns true on success. This method needs to be overridden for SSL connections.
396              
397             =cut
398              
399             sub close {
400 1     1 1 20 my $self = shift;
401 1         20 return $self->{_SOCKET}->close();
402 0 0       0 if ($self->{_SSL}) {
403 0         0 return $self->{_SOCKET}->stop_SSL(SSL_ctx_free => 1);
404             } else {
405 0         0 return $self->{_SOCKET}->close();
406             }
407             }
408              
409             # object destructor
410             sub DESTROY {
411 1     1   6195 my $self = shift;
412 1 50 33     20 if ($DEBUG || $self->{"_DEBUG"}) {
413 0         0 carp "Destroying $self " . $self->{_HOST} . ":" . $self->{_PORT};
414             }
415 1         6 $self->close();
416             }
417              
418             # class destructor
419             sub END {
420 1 50   1   200 if ($DEBUG) {
421 0         0 print STDOUT "class destroyed.\n";
422             }
423             }
424              
425             =back
426              
427             =head1 BUGS
428              
429             Does not verify SSL connections. Has not been tried with STARTTLS.
430              
431             =head1 SUPPORT
432              
433             =over 2
434              
435             =item * CPAN Bug Tracker
436              
437             L
438              
439             =item * Code, Pull Requests, alternative Issues Tracker
440              
441             L
442              
443             =back
444              
445             =head1 COPYRIGHT AND LICENSE
446              
447             Copyright (C) 2012 by Ashley Willis Eashleyw@cpan.orgE
448              
449             This library is free software; you can redistribute it and/or modify
450             it under the same terms as Perl itself, either Perl version 5.12.4 or,
451             at your option, any later version of Perl 5 you may have available.
452              
453             =head1 SEE ALSO
454              
455             L, L, L, L
456              
457             =cut
458              
459             1;