1 # Net::Cmd.pm $Id: //depot/libnet/Net/Cmd.pm#34 $
3 # Copyright (c) 1995-2006 Graham Barr <gbarr@pobox.com>. All rights reserved.
4 # This program is free software; you can redistribute it and/or
5 # modify it under the same terms as Perl itself.
13 use vars qw(@ISA @EXPORT $VERSION);
19 require Convert::EBCDIC;
20 # Convert::EBCDIC->import;
24 my $doUTF8 = eval { require utf8 };
28 @EXPORT = qw(CMD_INFO CMD_OK CMD_MORE CMD_REJECT CMD_ERROR CMD_PENDING);
39 my $tr = $^O eq 'os390' ? Convert::EBCDIC->new() : undef;
45 unless (exists ${*$cmd}{'net_cmd_asciipeer'})
48 my $ebcdicstr = $tr->toebcdic($string);
49 ${*$cmd}{'net_cmd_asciipeer'} = $string !~ /^\d+/ && $ebcdicstr =~ /^\d+/;
52 ${*$cmd}{'net_cmd_asciipeer'}
53 ? $tr->toebcdic($_[0])
60 ${*$cmd}{'net_cmd_asciipeer'}
76 my %spc = ( $pkg , "");
78 while ($pkg = shift @do)
80 next if defined $done{$pkg};
84 my $v = defined ${"${pkg}::VERSION"}
85 ? "(" . ${"${pkg}::VERSION"} . ")"
89 $cmd->debug_print(1,"${spc}${pkg}${v}\n");
93 @spc{@{"${pkg}::ISA"}} = (" " . $spc{$pkg}) x @{"${pkg}::ISA"};
94 unshift(@do, @{"${pkg}::ISA"});
101 @_ == 1 or @_ == 2 or croak 'usage: $obj->debug([LEVEL])';
103 my($cmd,$level) = @_;
104 my $pkg = ref($cmd) || $cmd;
109 $oldval = ${*$cmd}{'net_cmd_debug'} || 0;
113 $oldval = $debug{$pkg} || 0;
119 $level = $debug{$pkg} || 0
120 unless defined $level;
123 if($level && !exists $debug{$pkg});
127 ${*$cmd}{'net_cmd_debug'} = $level;
131 $debug{$pkg} = $level;
139 @_ == 1 or croak 'usage: $obj->message()';
143 wantarray ? @{${*$cmd}{'net_cmd_resp'}}
144 : join("", @{${*$cmd}{'net_cmd_resp'}});
147 sub debug_text { $_[2] }
151 my($cmd,$out,$text) = @_;
152 print STDERR $cmd,($out ? '>>> ' : '<<< '), $cmd->debug_text($out,$text);
157 @_ == 1 or croak 'usage: $obj->code()';
161 ${*$cmd}{'net_cmd_code'} = "000"
162 unless exists ${*$cmd}{'net_cmd_code'};
164 ${*$cmd}{'net_cmd_code'};
169 @_ == 1 or croak 'usage: $obj->status()';
173 substr(${*$cmd}{'net_cmd_code'},0,1);
178 @_ == 3 or croak 'usage: $obj->set_status(CODE, MESSAGE)';
181 my($code,$resp) = @_;
186 (${*$cmd}{'net_cmd_code'},${*$cmd}{'net_cmd_resp'}) = ($code, $resp);
195 unless (defined fileno($cmd))
197 $cmd->set_status("599", "Connection closed");
203 if(exists ${*$cmd}{'net_cmd_last_ch'});
207 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
209 my $str = join(" ", map { /\n/ ? do { my $n = $_; $n =~ tr/\n/ /; $n } : $_; } @_);
210 $str = $cmd->toascii($str) if $tr;
213 my $len = length $str;
217 unless (defined($swlen = syswrite($cmd,$str,$len)) && $swlen == $len);
219 $cmd->debug_print(1,$str)
222 ${*$cmd}{'net_cmd_resp'} = []; # the response
223 ${*$cmd}{'net_cmd_code'} = "000"; # Made this one up :-)
231 @_ == 1 or croak 'usage: $obj->ok()';
233 my $code = $_[0]->code;
234 0 < $code && $code < 400;
241 ${*$cmd}{'net_cmd_resp'} = [ 'Unsupported command' ];
242 ${*$cmd}{'net_cmd_code'} = 580;
250 ${*$cmd}{'net_cmd_lines'} ||= [];
252 return shift @{${*$cmd}{'net_cmd_lines'}}
253 if scalar(@{${*$cmd}{'net_cmd_lines'}});
255 my $partial = defined(${*$cmd}{'net_cmd_partial'})
256 ? ${*$cmd}{'net_cmd_partial'} : "";
257 my $fd = fileno($cmd);
267 until(scalar(@{${*$cmd}{'net_cmd_lines'}}))
269 my $timeout = $cmd->timeout || undef;
272 my $select_ret = select($rout=$rin, undef, undef, $timeout);
275 unless (sysread($cmd, $buf="", 1024))
277 carp(ref($cmd) . ": Unexpected EOF on command channel")
283 substr($buf,0,0) = $partial; ## prepend from last sysread
285 my @buf = split(/\015?\012/, $buf, -1); ## break into lines
289 push(@{${*$cmd}{'net_cmd_lines'}}, map { "$_\n" } @buf);
294 my $msg = $select_ret ? "Error or Interrupted: $!" : "Timeout";
295 carp("$cmd: $msg") if($cmd->debug);
300 ${*$cmd}{'net_cmd_partial'} = $partial;
304 foreach my $ln (@{${*$cmd}{'net_cmd_lines'}})
306 $ln = $cmd->toebcdic($ln);
310 shift @{${*$cmd}{'net_cmd_lines'}};
317 ${*$cmd}{'net_cmd_lines'} ||= [];
318 unshift(@{${*$cmd}{'net_cmd_lines'}}, $str);
324 unless $_[1] =~ s/^(\d\d\d)(.?)//o;
331 my($code,$more) = (undef) x 2;
333 ${*$cmd}{'net_cmd_resp'} ||= [];
337 my $str = $cmd->getline();
340 unless defined($str);
342 $cmd->debug_print(0,$str)
345 ($code,$more) = $cmd->parse_response($str);
346 unless(defined $code)
348 $cmd->ungetline($str);
352 ${*$cmd}{'net_cmd_code'} = $code;
354 push(@{${*$cmd}{'net_cmd_resp'}},$str);
370 my $str = $cmd->getline() or return undef;
372 $cmd->debug_print(0,$str)
373 if ($cmd->debug & 4);
375 last if($str =~ /^\.\r?\n/o);
395 my $arr = @_ == 1 && ref($_[0]) ? $_[0] : \@_;
396 my $line = join("" ,@$arr);
398 utf8::encode($line) if $doUTF8;
400 return 0 unless defined(fileno($cmd));
402 my $last_ch = ${*$cmd}{'net_cmd_last_ch'};
403 $last_ch = ${*$cmd}{'net_cmd_last_ch'} = "\012" unless defined $last_ch;
405 return 1 unless length $line;
408 foreach my $b (split(/\n/,$line)) {
409 $cmd->debug_print(1, "$b\n");
413 $line =~ tr/\r\n/\015\012/ unless "\r" eq "\015";
417 if ($last_ch eq "\015") {
418 $first_ch = "\012" if $line =~ s/^\012//;
420 elsif ($last_ch eq "\012") {
421 $first_ch = "." if $line =~ /^\./;
424 $line =~ s/\015?\012(\.?)/\015\012$1$1/sg;
426 substr($line,0,0) = $first_ch;
428 ${*$cmd}{'net_cmd_last_ch'} = substr($line,-1,1);
430 my $len = length($line);
433 vec($win,fileno($cmd),1) = 1;
434 my $timeout = $cmd->timeout || undef;
436 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
441 my $s = select(undef,$wout=$win, undef, $timeout);
442 if ((defined $s and $s > 0) or -f $cmd) # -f for testing on win32
444 my $w = syswrite($cmd, $line, $len, $offset);
447 carp("$cmd: $!") if $cmd->debug;
455 carp("$cmd: Timeout") if($cmd->debug);
466 my $arr = @_ == 1 && ref($_[0]) ? $_[0] : \@_;
467 my $line = join("" ,@$arr);
469 return 0 unless defined(fileno($cmd));
472 unless length($line);
477 print STDERR $b,join("\n$b",split(/\n/,$line)),"\n";
480 my $len = length($line);
483 vec($win,fileno($cmd),1) = 1;
484 my $timeout = $cmd->timeout || undef;
486 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
490 if (select(undef,$wout=$win, undef, $timeout) > 0)
492 my $w = syswrite($cmd, $line, $len, $offset);
495 carp("$cmd: $!") if $cmd->debug;
503 carp("$cmd: Timeout") if($cmd->debug);
515 return 0 unless defined(fileno($cmd));
517 my $ch = ${*$cmd}{'net_cmd_last_ch'};
523 elsif ($ch ne "\012") {
524 $tosend = "\015\012";
527 $tosend .= ".\015\012";
529 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
531 $cmd->debug_print(1, ".\n")
534 syswrite($cmd,$tosend, length $tosend);
536 delete ${*$cmd}{'net_cmd_last_ch'};
538 $cmd->response() == CMD_OK;
541 # read and write to tied filehandle
544 ${*$cmd}{'net_cmd_readbuf'} = '';
546 tie *$fh,ref($cmd),$cmd;
557 # Tied filehandle read. Reads requested data length, returning
558 # end-of-file when the dot is encountered.
561 my ($len,$offset) = @_[1,2];
562 return unless exists ${*$cmd}{'net_cmd_readbuf'};
564 while (!$done and length(${*$cmd}{'net_cmd_readbuf'}) < $len) {
565 ${*$cmd}{'net_cmd_readbuf'} .= $cmd->getline() or return;
566 $done++ if ${*$cmd}{'net_cmd_readbuf'} =~ s/^\.\r?\n\Z//m;
570 substr($_[0],$offset+0) = substr(${*$cmd}{'net_cmd_readbuf'},0,$len);
571 substr(${*$cmd}{'net_cmd_readbuf'},0,$len) = '';
572 delete ${*$cmd}{'net_cmd_readbuf'} if $done;
579 # in this context, we use the presence of readbuf to
580 # indicate that we have not yet reached the eof
581 return unless exists ${*$cmd}{'net_cmd_readbuf'};
582 my $line = $cmd->getline;
583 return if $line =~ /^\.\r?\n/;
589 my ($buf,$len,$offset) = @_;
590 $len ||= length ($buf);
592 return unless $cmd->datasend(substr($buf,$offset,$len));
593 ${*$cmd}{'net_cmd_sending'}++; # flag that we should call dataend()
599 my $r = exists(${*$cmd}{'net_cmd_sending'}) ? $cmd->dataend : 1;
600 delete ${*$cmd}{'net_cmd_readbuf'};
601 delete ${*$cmd}{'net_cmd_sending'};
612 Net::Cmd - Network Command class (as used by FTP, SMTP etc)
622 C<Net::Cmd> is a collection of methods that can be inherited by a sub class
623 of C<IO::Handle>. These methods implement the functionality required for a
624 command based protocol, for example FTP and SMTP.
628 These methods provide a user interface to the C<Net::Cmd> object.
632 =item debug ( VALUE )
634 Set the level of debug information for this object. If C<VALUE> is not given
635 then the current state is returned. Otherwise the state is changed to
636 C<VALUE> and the previous state returned.
639 may implement different levels of debug but a non-zero value results in
640 copies of all commands and responses also being sent to STDERR.
642 If C<VALUE> is C<undef> then the debug level will be set to the default
643 debug level for the class.
645 This method can also be called as a I<static> method to set/get the default
646 debug level for a given class.
650 Returns the text message returned from the last command
654 Returns the 3-digit code from the last command. If a command is pending
655 then the value 0 is returned
659 Returns non-zero if the last code value was greater than zero and
660 less than 400. This holds true for most command servers. Servers
661 where this does not hold may override this method.
665 Returns the most significant digit of the current status code. If a command
666 is pending then C<CMD_PENDING> is returned.
668 =item datasend ( DATA )
670 Send data to the remote server, converting LF to CRLF. Any line starting
671 with a '.' will be prefixed with another '.'.
672 C<DATA> may be an array or a reference to an array.
676 End the sending of data to the remote server. This is done by ensuring that
677 the data already sent ends with CRLF then sending '.CRLF' to end the
678 transmission. Once this data has been sent C<dataend> calls C<response> and
679 returns true if C<response> returns CMD_OK.
685 These methods are not intended to be called by the user, but used or
686 over-ridden by a sub-class of C<Net::Cmd>
690 =item debug_print ( DIR, TEXT )
692 Print debugging information. C<DIR> denotes the direction I<true> being
693 data being sent to the server. Calls C<debug_text> before printing to
696 =item debug_text ( TEXT )
698 This method is called to print debugging information. TEXT is
699 the text being sent. The method should return the text to be printed
701 This is primarily meant for the use of modules such as FTP where passwords
702 are sent, but we do not want to display them in the debugging information.
704 =item command ( CMD [, ARGS, ... ])
706 Send a command to the command server. All arguments a first joined with
707 a space character and CRLF is appended, this string is then sent to the
710 Returns undef upon failure
714 Sets the status code to 580 and the response text to 'Unsupported command'.
719 Obtain a response from the server. Upon success the most significant digit
720 of the status code is returned. Upon failure, timeout etc., I<undef> is
723 =item parse_response ( TEXT )
725 This method is called by C<response> as a method with one argument. It should
726 return an array of 2 values, the 3-digit status code and a flag which is true
727 when this is part of a multi-line response and this line is not the list.
731 Retrieve one line, delimited by CRLF, from the remote server. Returns I<undef>
734 B<NOTE>: If you do use this method for any reason, please remember to add
735 some C<debug_print> calls into your method.
737 =item ungetline ( TEXT )
739 Unget a line of text from the server.
741 =item rawdatasend ( DATA )
743 Send data to the remote server without performing any conversions. C<DATA>
746 =item read_until_dot ()
748 Read data from the remote server until a line consisting of a single '.'.
749 Any lines starting with '..' will have one of the '.'s removed.
751 Returns a reference to a list containing the lines, or I<undef> upon failure.
755 Returns a filehandle tied to the Net::Cmd object. After issuing a
756 command, you may read from this filehandle using read() or <>. The
757 filehandle will return EOF when the final dot is encountered.
758 Similarly, you may write to the filehandle in order to send data to
759 the server after issuing a command that expects data to be written.
761 See the Net::POP3 and Net::SMTP modules for examples of this.
767 C<Net::Cmd> exports six subroutines, five of these, C<CMD_INFO>, C<CMD_OK>,
768 C<CMD_MORE>, C<CMD_REJECT> and C<CMD_ERROR>, correspond to possible results
769 of C<response> and C<status>. The sixth is C<CMD_PENDING>.
773 Graham Barr <gbarr@pobox.com>
777 Copyright (c) 1995-2006 Graham Barr. All rights reserved.
778 This program is free software; you can redistribute it and/or modify
779 it under the same terms as Perl itself.