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;
21 # Convert::EBCDIC->import;
25 my $doUTF8 = eval { require utf8 };
29 @EXPORT = qw(CMD_INFO CMD_OK CMD_MORE CMD_REJECT CMD_ERROR CMD_PENDING);
41 my $tr = $^O eq 'os390' ? Convert::EBCDIC->new() : undef;
47 unless (exists ${*$cmd}{'net_cmd_asciipeer'}) {
49 my $ebcdicstr = $tr->toebcdic($string);
50 ${*$cmd}{'net_cmd_asciipeer'} = $string !~ /^\d+/ && $ebcdicstr =~ /^\d+/;
53 ${*$cmd}{'net_cmd_asciipeer'}
54 ? $tr->toebcdic($_[0])
61 ${*$cmd}{'net_cmd_asciipeer'}
79 while ($pkg = shift @do) {
80 next if defined $done{$pkg};
85 defined ${"${pkg}::VERSION"}
86 ? "(" . ${"${pkg}::VERSION"} . ")"
90 $cmd->debug_print(1, "${spc}${pkg}${v}\n");
92 if (@{"${pkg}::ISA"}) {
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;
108 $oldval = ${*$cmd}{'net_cmd_debug'} || 0;
111 $oldval = $debug{$pkg} || 0;
117 $level = $debug{$pkg} || 0
118 unless defined $level;
121 if ($level && !exists $debug{$pkg});
124 ${*$cmd}{'net_cmd_debug'} = $level;
127 $debug{$pkg} = $level;
135 @_ == 1 or croak 'usage: $obj->message()';
140 ? @{${*$cmd}{'net_cmd_resp'}}
141 : join("", @{${*$cmd}{'net_cmd_resp'}});
145 sub debug_text { $_[2] }
149 my ($cmd, $out, $text) = @_;
150 print STDERR $cmd, ($out ? '>>> ' : '<<< '), $cmd->debug_text($out, $text);
155 @_ == 1 or croak 'usage: $obj->code()';
159 ${*$cmd}{'net_cmd_code'} = "000"
160 unless exists ${*$cmd}{'net_cmd_code'};
162 ${*$cmd}{'net_cmd_code'};
167 @_ == 1 or croak 'usage: $obj->status()';
171 substr(${*$cmd}{'net_cmd_code'}, 0, 1);
176 @_ == 3 or croak 'usage: $obj->set_status(CODE, MESSAGE)';
179 my ($code, $resp) = @_;
184 (${*$cmd}{'net_cmd_code'}, ${*$cmd}{'net_cmd_resp'}) = ($code, $resp);
193 unless (defined fileno($cmd)) {
194 $cmd->set_status("599", "Connection closed");
200 if (exists ${*$cmd}{'net_cmd_last_ch'});
203 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
209 ? do { my $n = $_; $n =~ tr/\n/ /; $n }
213 $str = $cmd->toascii($str) if $tr;
216 my $len = length $str;
220 unless (defined($swlen = syswrite($cmd, $str, $len)) && $swlen == $len);
222 $cmd->debug_print(1, $str)
225 ${*$cmd}{'net_cmd_resp'} = []; # the response
226 ${*$cmd}{'net_cmd_code'} = "000"; # Made this one up :-)
234 @_ == 1 or croak 'usage: $obj->ok()';
236 my $code = $_[0]->code;
237 0 < $code && $code < 400;
244 ${*$cmd}{'net_cmd_resp'} = ['Unsupported command'];
245 ${*$cmd}{'net_cmd_code'} = 580;
253 ${*$cmd}{'net_cmd_lines'} ||= [];
255 return shift @{${*$cmd}{'net_cmd_lines'}}
256 if scalar(@{${*$cmd}{'net_cmd_lines'}});
258 my $partial = defined(${*$cmd}{'net_cmd_partial'}) ? ${*$cmd}{'net_cmd_partial'} : "";
259 my $fd = fileno($cmd);
265 vec($rin, $fd, 1) = 1;
269 until (scalar(@{${*$cmd}{'net_cmd_lines'}})) {
270 my $timeout = $cmd->timeout || undef;
273 my $select_ret = select($rout = $rin, undef, undef, $timeout);
274 if ($select_ret > 0) {
275 unless (sysread($cmd, $buf = "", 1024)) {
276 carp(ref($cmd) . ": Unexpected EOF on command channel")
282 substr($buf, 0, 0) = $partial; ## prepend from last sysread
284 my @buf = split(/\015?\012/, $buf, -1); ## break into lines
288 push(@{${*$cmd}{'net_cmd_lines'}}, map {"$_\n"} @buf);
292 my $msg = $select_ret ? "Error or Interrupted: $!" : "Timeout";
293 carp("$cmd: $msg") if ($cmd->debug);
298 ${*$cmd}{'net_cmd_partial'} = $partial;
301 foreach my $ln (@{${*$cmd}{'net_cmd_lines'}}) {
302 $ln = $cmd->toebcdic($ln);
306 shift @{${*$cmd}{'net_cmd_lines'}};
311 my ($cmd, $str) = @_;
313 ${*$cmd}{'net_cmd_lines'} ||= [];
314 unshift(@{${*$cmd}{'net_cmd_lines'}}, $str);
320 unless $_[1] =~ s/^(\d\d\d)(.?)//o;
327 my ($code, $more) = (undef) x 2;
329 ${*$cmd}{'net_cmd_resp'} ||= [];
332 my $str = $cmd->getline();
335 unless defined($str);
337 $cmd->debug_print(0, $str)
340 ($code, $more) = $cmd->parse_response($str);
341 unless (defined $code) {
342 $cmd->ungetline($str);
346 ${*$cmd}{'net_cmd_code'} = $code;
348 push(@{${*$cmd}{'net_cmd_resp'}}, $str);
363 my $str = $cmd->getline() or return undef;
365 $cmd->debug_print(0, $str)
366 if ($cmd->debug & 4);
368 last if ($str =~ /^\.\r?\n/o);
386 my $arr = @_ == 1 && ref($_[0]) ? $_[0] : \@_;
387 my $line = join("", @$arr);
390 # encode to individual utf8 bytes if
391 # $line is a string (in internal UTF-8)
392 utf8::encode($line) if utf8::is_utf8($line);
395 return 0 unless defined(fileno($cmd));
397 my $last_ch = ${*$cmd}{'net_cmd_last_ch'};
398 $last_ch = ${*$cmd}{'net_cmd_last_ch'} = "\012" unless defined $last_ch;
400 return 1 unless length $line;
403 foreach my $b (split(/\n/, $line)) {
404 $cmd->debug_print(1, "$b\n");
408 $line =~ tr/\r\n/\015\012/ unless "\r" eq "\015";
412 if ($last_ch eq "\015") {
413 $first_ch = "\012" if $line =~ s/^\012//;
415 elsif ($last_ch eq "\012") {
416 $first_ch = "." if $line =~ /^\./;
419 $line =~ s/\015?\012(\.?)/\015\012$1$1/sg;
421 substr($line, 0, 0) = $first_ch;
423 ${*$cmd}{'net_cmd_last_ch'} = substr($line, -1, 1);
425 my $len = length($line);
428 vec($win, fileno($cmd), 1) = 1;
429 my $timeout = $cmd->timeout || undef;
431 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
435 my $s = select(undef, $wout = $win, undef, $timeout);
436 if ((defined $s and $s > 0) or -f $cmd) # -f for testing on win32
438 my $w = syswrite($cmd, $line, $len, $offset);
439 unless (defined($w)) {
440 carp("$cmd: $!") if $cmd->debug;
447 carp("$cmd: Timeout") if ($cmd->debug);
458 my $arr = @_ == 1 && ref($_[0]) ? $_[0] : \@_;
459 my $line = join("", @$arr);
461 return 0 unless defined(fileno($cmd));
464 unless length($line);
468 print STDERR $b, join("\n$b", split(/\n/, $line)), "\n";
471 my $len = length($line);
474 vec($win, fileno($cmd), 1) = 1;
475 my $timeout = $cmd->timeout || undef;
477 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
480 if (select(undef, $wout = $win, undef, $timeout) > 0) {
481 my $w = syswrite($cmd, $line, $len, $offset);
482 unless (defined($w)) {
483 carp("$cmd: $!") if $cmd->debug;
490 carp("$cmd: Timeout") if ($cmd->debug);
502 return 0 unless defined(fileno($cmd));
504 my $ch = ${*$cmd}{'net_cmd_last_ch'};
510 elsif ($ch ne "\012") {
511 $tosend = "\015\012";
514 $tosend .= ".\015\012";
516 local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
518 $cmd->debug_print(1, ".\n")
521 syswrite($cmd, $tosend, length $tosend);
523 delete ${*$cmd}{'net_cmd_last_ch'};
525 $cmd->response() == CMD_OK;
528 # read and write to tied filehandle
531 ${*$cmd}{'net_cmd_readbuf'} = '';
533 tie *$fh, ref($cmd), $cmd;
544 # Tied filehandle read. Reads requested data length, returning
545 # end-of-file when the dot is encountered.
548 my ($len, $offset) = @_[1, 2];
549 return unless exists ${*$cmd}{'net_cmd_readbuf'};
551 while (!$done and length(${*$cmd}{'net_cmd_readbuf'}) < $len) {
552 ${*$cmd}{'net_cmd_readbuf'} .= $cmd->getline() or return;
553 $done++ if ${*$cmd}{'net_cmd_readbuf'} =~ s/^\.\r?\n\Z//m;
557 substr($_[0], $offset + 0) = substr(${*$cmd}{'net_cmd_readbuf'}, 0, $len);
558 substr(${*$cmd}{'net_cmd_readbuf'}, 0, $len) = '';
559 delete ${*$cmd}{'net_cmd_readbuf'} if $done;
568 # in this context, we use the presence of readbuf to
569 # indicate that we have not yet reached the eof
570 return unless exists ${*$cmd}{'net_cmd_readbuf'};
571 my $line = $cmd->getline;
572 return if $line =~ /^\.\r?\n/;
579 my ($buf, $len, $offset) = @_;
580 $len ||= length($buf);
582 return unless $cmd->datasend(substr($buf, $offset, $len));
583 ${*$cmd}{'net_cmd_sending'}++; # flag that we should call dataend()
590 my $r = exists(${*$cmd}{'net_cmd_sending'}) ? $cmd->dataend : 1;
591 delete ${*$cmd}{'net_cmd_readbuf'};
592 delete ${*$cmd}{'net_cmd_sending'};
603 Net::Cmd - Network Command class (as used by FTP, SMTP etc)
613 C<Net::Cmd> is a collection of methods that can be inherited by a sub class
614 of C<IO::Handle>. These methods implement the functionality required for a
615 command based protocol, for example FTP and SMTP.
619 These methods provide a user interface to the C<Net::Cmd> object.
623 =item debug ( VALUE )
625 Set the level of debug information for this object. If C<VALUE> is not given
626 then the current state is returned. Otherwise the state is changed to
627 C<VALUE> and the previous state returned.
630 may implement different levels of debug but a non-zero value results in
631 copies of all commands and responses also being sent to STDERR.
633 If C<VALUE> is C<undef> then the debug level will be set to the default
634 debug level for the class.
636 This method can also be called as a I<static> method to set/get the default
637 debug level for a given class.
641 Returns the text message returned from the last command
645 Returns the 3-digit code from the last command. If a command is pending
646 then the value 0 is returned
650 Returns non-zero if the last code value was greater than zero and
651 less than 400. This holds true for most command servers. Servers
652 where this does not hold may override this method.
656 Returns the most significant digit of the current status code. If a command
657 is pending then C<CMD_PENDING> is returned.
659 =item datasend ( DATA )
661 Send data to the remote server, converting LF to CRLF. Any line starting
662 with a '.' will be prefixed with another '.'.
663 C<DATA> may be an array or a reference to an array.
667 End the sending of data to the remote server. This is done by ensuring that
668 the data already sent ends with CRLF then sending '.CRLF' to end the
669 transmission. Once this data has been sent C<dataend> calls C<response> and
670 returns true if C<response> returns CMD_OK.
676 These methods are not intended to be called by the user, but used or
677 over-ridden by a sub-class of C<Net::Cmd>
681 =item debug_print ( DIR, TEXT )
683 Print debugging information. C<DIR> denotes the direction I<true> being
684 data being sent to the server. Calls C<debug_text> before printing to
687 =item debug_text ( TEXT )
689 This method is called to print debugging information. TEXT is
690 the text being sent. The method should return the text to be printed
692 This is primarily meant for the use of modules such as FTP where passwords
693 are sent, but we do not want to display them in the debugging information.
695 =item command ( CMD [, ARGS, ... ])
697 Send a command to the command server. All arguments a first joined with
698 a space character and CRLF is appended, this string is then sent to the
701 Returns undef upon failure
705 Sets the status code to 580 and the response text to 'Unsupported command'.
710 Obtain a response from the server. Upon success the most significant digit
711 of the status code is returned. Upon failure, timeout etc., I<undef> is
714 =item parse_response ( TEXT )
716 This method is called by C<response> as a method with one argument. It should
717 return an array of 2 values, the 3-digit status code and a flag which is true
718 when this is part of a multi-line response and this line is not the list.
722 Retrieve one line, delimited by CRLF, from the remote server. Returns I<undef>
725 B<NOTE>: If you do use this method for any reason, please remember to add
726 some C<debug_print> calls into your method.
728 =item ungetline ( TEXT )
730 Unget a line of text from the server.
732 =item rawdatasend ( DATA )
734 Send data to the remote server without performing any conversions. C<DATA>
737 =item read_until_dot ()
739 Read data from the remote server until a line consisting of a single '.'.
740 Any lines starting with '..' will have one of the '.'s removed.
742 Returns a reference to a list containing the lines, or I<undef> upon failure.
746 Returns a filehandle tied to the Net::Cmd object. After issuing a
747 command, you may read from this filehandle using read() or <>. The
748 filehandle will return EOF when the final dot is encountered.
749 Similarly, you may write to the filehandle in order to send data to
750 the server after issuing a command that expects data to be written.
752 See the Net::POP3 and Net::SMTP modules for examples of this.
758 C<Net::Cmd> exports six subroutines, five of these, C<CMD_INFO>, C<CMD_OK>,
759 C<CMD_MORE>, C<CMD_REJECT> and C<CMD_ERROR>, correspond to possible results
760 of C<response> and C<status>. The sixth is C<CMD_PENDING>.
764 Graham Barr <gbarr@pobox.com>
768 Copyright (c) 1995-2006 Graham Barr. All rights reserved.
769 This program is free software; you can redistribute it and/or modify
770 it under the same terms as Perl itself.