home *** CD-ROM | disk | FTP | other *** search
/ Inter.Net 55-2 / Inter.Net 55-2.iso / Mandrake / mdkinst / usr / lib / perl5 / site_perl / 5.005 / i386-linux / Net / FTP.pm < prev    next >
Encoding:
Perl POD Document  |  2000-01-12  |  18.1 KB  |  969 lines

  1. # Net::FTP.pm
  2. #
  3. # Copyright (c) 1995-8 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.
  6. #
  7. # Documentation (at end) improved 1996 by Nathan Torkington <gnat@frii.com>.
  8.  
  9. package Net::FTP;
  10.  
  11. require 5.001;
  12.  
  13. use strict;
  14. use vars qw(@ISA $VERSION);
  15. use Carp;
  16.  
  17. use Socket 1.3;
  18. use IO::Socket;
  19. use Time::Local;
  20. use Net::Cmd;
  21. use Net::Config;
  22. # use AutoLoader qw(AUTOLOAD);
  23.  
  24. $VERSION = "2.40"; # $Id: //depot/libnet/Net/FTP.pm#25$
  25. @ISA     = qw(Exporter Net::Cmd IO::Socket::INET);
  26.  
  27. # Someday I will "use constant", when I am not bothered to much about
  28. # compatability with older releases of perl
  29.  
  30. use vars qw($TELNET_IAC $TELNET_IP $TELNET_DM);
  31. ($TELNET_IAC,$TELNET_IP,$TELNET_DM) = (255,244,242);
  32.  
  33. # Name is too long for AutoLoad, it clashes with pasv_xfer
  34. sub pasv_xfer_unique {
  35.     my($sftp,$sfile,$dftp,$dfile) = @_;
  36.     $sftp->pasv_xfer($sfile,$dftp,$dfile,1);
  37. }
  38.  
  39. 1;
  40. # Having problems with AutoLoader
  41. #__END__
  42.  
  43. sub new
  44. {
  45.  my $pkg  = shift;
  46.  my $peer = shift;
  47.  my %arg  = @_; 
  48.  
  49.  my $host = $peer;
  50.  my $fire = undef;
  51.  
  52.  # Should I use Net::Ping here ?? --GMB
  53.  if(exists($arg{Firewall}) || !defined(inet_aton($peer)))
  54.   {
  55.    $fire = $arg{Firewall}
  56.     || $ENV{FTP_FIREWALL}
  57.     || $NetConfig{ftp_firewall}
  58.     || undef;
  59.  
  60.    if(defined $fire)
  61.     {
  62.      $peer = $fire;
  63.      delete $arg{Port};
  64.     }
  65.   }
  66.  
  67.  my $ftp = $pkg->SUPER::new(PeerAddr => $peer, 
  68.                 PeerPort => $arg{Port} || 'ftp(21)',
  69.                 Proto    => 'tcp',
  70.                 Timeout  => defined $arg{Timeout}
  71.                         ? $arg{Timeout}
  72.                         : 120
  73.                ) or return undef;
  74.  
  75.  ${*$ftp}{'net_ftp_host'}     = $host;        # Remote hostname
  76.  ${*$ftp}{'net_ftp_type'}     = 'A';        # ASCII/binary/etc mode
  77.  
  78.  ${*$ftp}{'net_ftp_firewall'} = $fire
  79.     if(defined $fire);
  80.  
  81.  ${*$ftp}{'net_ftp_passive'} = int
  82.     exists $arg{Passive}
  83.         ? $arg{Passive}
  84.         : exists $ENV{FTP_PASSIVE}
  85.         ? $ENV{FTP_PASSIVE}
  86.         : defined $fire
  87.             ? $NetConfig{ftp_ext_passive}
  88.             : $NetConfig{ftp_int_passive};    # Whew! :-)
  89.  
  90.  $ftp->autoflush(1);
  91.  
  92.  $ftp->debug(exists $arg{Debug} ? $arg{Debug} : undef);
  93.  
  94.  unless ($ftp->response() == CMD_OK)
  95.   {
  96.    $ftp->close();
  97.    $@ = $ftp->message;
  98.    undef $ftp;
  99.   }
  100.  
  101.  $ftp;
  102. }
  103.  
  104. ##
  105. ## User interface methods
  106. ##
  107.  
  108. sub quit
  109. {
  110.  my $ftp = shift;
  111.  
  112.  $ftp->_QUIT;
  113.  $ftp->close;
  114. }
  115.  
  116. sub DESTROY
  117. {
  118.  my $ftp = shift;
  119.  defined(fileno($ftp)) && $ftp->quit
  120. }
  121.  
  122. sub ascii  { shift->type('A',@_); }
  123. sub binary { shift->type('I',@_); }
  124.  
  125. sub ebcdic
  126. {
  127.  carp "TYPE E is unsupported, shall default to I";
  128.  shift->type('E',@_);
  129. }
  130.  
  131. sub byte
  132. {
  133.  carp "TYPE L is unsupported, shall default to I";
  134.  shift->type('L',@_);
  135. }
  136.  
  137. # Allow the user to send a command directly, BE CAREFUL !!
  138.  
  139. sub quot
  140.  my $ftp = shift;
  141.  my $cmd = shift;
  142.  
  143.  $ftp->command( uc $cmd, @_);
  144.  $ftp->response();
  145. }
  146.  
  147. sub site
  148. {
  149.  my $ftp = shift;
  150.  
  151.  $ftp->command("SITE", @_);
  152.  $ftp->response();
  153. }
  154.  
  155. sub mdtm
  156. {
  157.  my $ftp  = shift;
  158.  my $file = shift;
  159.  
  160.  $ftp->_MDTM($file) && $ftp->message =~ /(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/
  161.     ? timegm($6,$5,$4,$3,$2-1,$1 - 1900)
  162.     : undef;
  163. }
  164.  
  165. sub size
  166. {
  167.  my $ftp  = shift;
  168.  my $file = shift;
  169.  my $io;
  170.  if($ftp->supported("SIZE")) {
  171.     return $ftp->_SIZE($file)
  172.         ? ($ftp->message =~ /(\d+)/)[0]
  173.         : undef;
  174.  }
  175.  elsif($ftp->supported("STAT")) {
  176.     my @msg;
  177.     return undef
  178.         unless $ftp->_STAT($file) && (@msg = $ftp->message) == 3;
  179.     my $line;
  180.     foreach $line (@msg) {
  181.         return (split(/\s+/,$line))[4]
  182.         if $line =~ /^[-rw]{10}/
  183.     }
  184.  }
  185.  elsif($io = $ftp->list($file)) {
  186.     my $line;
  187.     $io->read($line,1024);
  188.     $io->close;
  189.     return (split(/\s+/,$1))[4]
  190.         if $line =~ /^([-rw]{10}.*)\n/s;
  191.  }
  192.  undef;
  193. }
  194.  
  195. sub login
  196. {
  197.  my($ftp,$user,$pass,$acct) = @_;
  198.  my($ok,$ruser);
  199.  
  200.  unless (defined $user)
  201.   {
  202.    require Net::Netrc;
  203.  
  204.    my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'});
  205.  
  206.    ($user,$pass,$acct) = $rc->lpa()
  207.     if ($rc);
  208.   }
  209.  
  210.  $user ||= "anonymous";
  211.  $ruser = $user;
  212.  
  213.  if(defined ${*$ftp}{'net_ftp_firewall'})
  214.   {
  215.    $user .= "@" . ${*$ftp}{'net_ftp_host'};
  216.   }
  217.  
  218.  $ok = $ftp->_USER($user);
  219.  
  220.  # Some dumb firewalls don't prefix the connection messages
  221.  $ok = $ftp->response()
  222.     if($ok == CMD_OK && $ftp->code == 220 && $user =~ /\@/);
  223.  
  224.  if ($ok == CMD_MORE)
  225.   {
  226.    unless(defined $pass)
  227.     {
  228.      require Net::Netrc;
  229.  
  230.      my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'}, $ruser);
  231.  
  232.      ($ruser,$pass,$acct) = $rc->lpa()
  233.     if ($rc);
  234.  
  235.      $pass = "-" . (eval { (getpwuid($>))[0] } || $ENV{NAME} ) . '@'
  236.         if (!defined $pass && (!defined($ruser) || $ruser =~ /^anonymous/o));
  237.     }
  238.  
  239.    $ok = $ftp->_PASS($pass || "");
  240.   }
  241.  
  242.  $ok = $ftp->_ACCT($acct || "")
  243.     if ($ok == CMD_MORE);
  244.  
  245.  $ftp->authorize()
  246.     if($ok == CMD_OK && defined ${*$ftp}{'net_ftp_firewall'});
  247.  
  248.  $ok == CMD_OK;
  249. }
  250.  
  251. sub account
  252. {
  253.  @_ == 2 or croak 'usage: $ftp->account( ACCT )';
  254.  my $ftp = shift;
  255.  my $acct = shift;
  256.  $ftp->_ACCT($acct) == CMD_OK;
  257. }
  258.  
  259. sub authorize
  260. {
  261.  @_ >= 1 || @_ <= 3 or croak 'usage: $ftp->authorize( [AUTH [, RESP]])';
  262.  
  263.  my($ftp,$auth,$resp) = @_;
  264.  
  265.  unless(defined $resp)
  266.   {
  267.    require Net::Netrc;
  268.  
  269.    $auth ||= eval { (getpwuid($>))[0] } || $ENV{NAME};
  270.  
  271.    my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'}, $auth)
  272.         || Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'});
  273.  
  274.    ($auth,$resp) = $rc->lpa()
  275.      if($rc);
  276.   }
  277.  
  278.  my $ok = $ftp->_AUTH($auth || "");
  279.  
  280.  $ok = $ftp->_RESP($resp || "")
  281.     if ($ok == CMD_MORE);
  282.  
  283.  $ok == CMD_OK;
  284. }
  285.  
  286. sub rename
  287. {
  288.  @_ == 3 or croak 'usage: $ftp->rename(FROM, TO)';
  289.  
  290.  my($ftp,$from,$to) = @_;
  291.  
  292.  $ftp->_RNFR($from)
  293.     && $ftp->_RNTO($to);
  294. }
  295.  
  296. sub type
  297. {
  298.  my $ftp = shift;
  299.  my $type = shift;
  300.  my $oldval = ${*$ftp}{'net_ftp_type'};
  301.  
  302.  return $oldval
  303.     unless (defined $type);
  304.  
  305.  return undef
  306.     unless ($ftp->_TYPE($type,@_));
  307.  
  308.  ${*$ftp}{'net_ftp_type'} = join(" ",$type,@_);
  309.  
  310.  $oldval;
  311. }
  312.  
  313. sub abort
  314. {
  315.  my $ftp = shift;
  316.  
  317.  send($ftp,pack("CCC", $TELNET_IAC, $TELNET_IP, $TELNET_IAC),MSG_OOB);
  318.  
  319.  $ftp->command(pack("C",$TELNET_DM) . "ABOR");
  320.  
  321.  ${*$ftp}{'net_ftp_dataconn'}->close()
  322.     if defined ${*$ftp}{'net_ftp_dataconn'};
  323.  
  324.  $ftp->response();
  325.  
  326.  $ftp->status == CMD_OK;
  327. }
  328.  
  329. sub get
  330. {
  331.  my($ftp,$remote,$local,$where) = @_;
  332.  
  333.  my($loc,$len,$buf,$resp,$localfd,$data);
  334.  local *FD;
  335.  
  336.  $localfd = ref($local) ? fileno($local)
  337.             : undef;
  338.  
  339.  ($local = $remote) =~ s#^.*/##
  340.     unless(defined $local);
  341.  
  342.  croak("Bad remote filename '$remote'\n")
  343.     if $remote =~ /[\s\r\n]/s;
  344.  
  345.  ${*$ftp}{'net_ftp_rest'} = $where
  346.     if ($where);
  347.  
  348.  delete ${*$ftp}{'net_ftp_port'};
  349.  delete ${*$ftp}{'net_ftp_pasv'};
  350.  
  351.  $data = $ftp->retr($remote) or
  352.     return undef;
  353.  
  354.  if(defined $localfd)
  355.   {
  356.    $loc = $local;
  357.   }
  358.  else
  359.   {
  360.    $loc = \*FD;
  361.  
  362.    unless(($where) ? open($loc,">>$local") : open($loc,">$local"))
  363.     {
  364.      carp "Cannot open Local file $local: $!\n";
  365.      $data->abort;
  366.      return undef;
  367.     }
  368.   }
  369.  
  370.  if($ftp->type eq 'I' && !binmode($loc))
  371.   {
  372.    carp "Cannot binmode Local file $local: $!\n";
  373.    $data->abort;
  374.    return undef;
  375.   }
  376.  
  377.  $buf = '';
  378.  my $swlen;
  379.  
  380.  do
  381.   {
  382.    $len = $data->read($buf,1024);
  383.   }
  384.  while($len && defined($swlen = syswrite($loc,$buf,$len)) && $swlen == $len);
  385.  
  386.  close($loc)
  387.     unless defined $localfd;
  388.  
  389.  $data->close(); # implied $ftp->response
  390.  
  391.  return $local;
  392. }
  393.  
  394. sub cwd
  395. {
  396.  @_ == 2 || @_ == 3 or croak 'usage: $ftp->cwd( [ DIR ] )';
  397.  
  398.  my($ftp,$dir) = @_;
  399.  
  400.  $dir ||= "/";
  401.  
  402.  $dir eq ".."
  403.     ? $ftp->_CDUP()
  404.     : $ftp->_CWD($dir);
  405. }
  406.  
  407. sub cdup
  408. {
  409.  @_ == 1 or croak 'usage: $ftp->cdup()';
  410.  $_[0]->_CDUP;
  411. }
  412.  
  413. sub pwd
  414. {
  415.  @_ == 1 || croak 'usage: $ftp->pwd()';
  416.  my $ftp = shift;
  417.  
  418.  $ftp->_PWD();
  419.  $ftp->_extract_path;
  420. }
  421.  
  422. sub rmdir
  423. {
  424.  @_ == 2 || croak 'usage: $ftp->rmdir( DIR )';
  425.  
  426.  $_[0]->_RMD($_[1]);
  427. }
  428.  
  429. sub mkdir
  430. {
  431.  @_ == 2 || @_ == 3 or croak 'usage: $ftp->mkdir( DIR [, RECURSE ] )';
  432.  
  433.  my($ftp,$dir,$recurse) = @_;
  434.  
  435.  $ftp->_MKD($dir) || $recurse or
  436.     return undef;
  437.  
  438.  my $path = $dir;
  439.  
  440.  unless($ftp->ok)
  441.   {
  442.    my @path = split(m#(?=/+)#, $dir);
  443.  
  444.    $path = "";
  445.  
  446.    while(@path)
  447.     {
  448.      $path .= shift @path;
  449.  
  450.      $ftp->_MKD($path);
  451.  
  452.      $path = $ftp->_extract_path($path);
  453.     }
  454.  
  455.    # If the creation of the last element was not sucessful, see if we
  456.    # can cd to it, if so then return path
  457.  
  458.    unless($ftp->ok)
  459.     {
  460.      my($status,$message) = ($ftp->status,$ftp->message);
  461.      my $pwd = $ftp->pwd;
  462.      
  463.      if($pwd && $ftp->cd($dir))
  464.       {
  465.        $path = $dir;
  466.        $ftp->cd($pwd);
  467.       }
  468.      else
  469.       {
  470.        undef $path;
  471.       }
  472.      $ftp->set_status($status,$message);
  473.     }
  474.   }
  475.  
  476.  $path;
  477. }
  478.  
  479. sub delete
  480. {
  481.  @_ == 2 || croak 'usage: $ftp->delete( FILENAME )';
  482.  
  483.  $_[0]->_DELE($_[1]);
  484. }
  485.  
  486. sub put        { shift->_store_cmd("stor",@_) }
  487. sub put_unique { shift->_store_cmd("stou",@_) }
  488. sub append     { shift->_store_cmd("appe",@_) }
  489.  
  490. sub nlst { shift->_data_cmd("NLST",@_) }
  491. sub list { shift->_data_cmd("LIST",@_) }
  492. sub retr { shift->_data_cmd("RETR",@_) }
  493. sub stor { shift->_data_cmd("STOR",@_) }
  494. sub stou { shift->_data_cmd("STOU",@_) }
  495. sub appe { shift->_data_cmd("APPE",@_) }
  496.  
  497. sub _store_cmd 
  498. {
  499.  my($ftp,$cmd,$local,$remote) = @_;
  500.  my($loc,$sock,$len,$buf,$localfd);
  501.  local *FD;
  502.  
  503.  $localfd = ref($local) ? fileno($local)
  504.             : undef;
  505.  
  506.  unless(defined $remote)
  507.   {
  508.    croak 'Must specify remote filename with stream input'
  509.     if defined $localfd;
  510.  
  511.    require File::Basename;
  512.    $remote = File::Basename::basename($local);
  513.   }
  514.  
  515.  croak("Bad remote filename '$remote'\n")
  516.     if $remote =~ /[\s\r\n]/s;
  517.  
  518.  if(defined $localfd)
  519.   {
  520.    $loc = $local;
  521.   }
  522.  else
  523.   {
  524.    $loc = \*FD;
  525.  
  526.    unless(open($loc,"<$local"))
  527.     {
  528.      carp "Cannot open Local file $local: $!\n";
  529.      return undef;
  530.     }
  531.   }
  532.  
  533.  if($ftp->type eq 'I' && !binmode($loc))
  534.   {
  535.    carp "Cannot binmode Local file $local: $!\n";
  536.    return undef;
  537.   }
  538.  
  539.  delete ${*$ftp}{'net_ftp_port'};
  540.  delete ${*$ftp}{'net_ftp_pasv'};
  541.  
  542.  $sock = $ftp->_data_cmd($cmd, $remote) or 
  543.     return undef;
  544.  
  545.  while(1)
  546.   {
  547.    last unless $len = sysread($loc,$buf="",1024);
  548.  
  549.    my $wlen;
  550.    unless(defined($wlen = $sock->write($buf,$len)) && $wlen == $len)
  551.     {
  552.      $sock->abort;
  553.      close($loc)
  554.     unless defined $localfd;
  555.      return undef;
  556.     }
  557.   }
  558.  
  559.  $sock->close();
  560.  
  561.  close($loc)
  562.     unless defined $localfd;
  563.  
  564.  ($remote) = $ftp->message =~ /unique file name:\s*(\S*)\s*\)/
  565.     if ('STOU' eq uc $cmd);
  566.  
  567.  return $remote;
  568. }
  569.  
  570. sub port
  571. {
  572.  @_ == 1 || @_ == 2 or croak 'usage: $ftp->port([PORT])';
  573.  
  574.  my($ftp,$port) = @_;
  575.  my $ok;
  576.  
  577.  delete ${*$ftp}{'net_ftp_intern_port'};
  578.  
  579.  unless(defined $port)
  580.   {
  581.    # create a Listen socket at same address as the command socket
  582.  
  583.    ${*$ftp}{'net_ftp_listen'} ||= IO::Socket::INET->new(Listen    => 5,
  584.                                         Proto     => 'tcp',
  585.                                         LocalAddr => $ftp->sockhost, 
  586.                                        );
  587.   
  588.    my $listen = ${*$ftp}{'net_ftp_listen'};
  589.  
  590.    my($myport, @myaddr) = ($listen->sockport, split(/\./,$listen->sockhost));
  591.  
  592.    $port = join(',', @myaddr, $myport >> 8, $myport & 0xff);
  593.  
  594.    ${*$ftp}{'net_ftp_intern_port'} = 1;
  595.   }
  596.  
  597.  $ok = $ftp->_PORT($port);
  598.  
  599.  ${*$ftp}{'net_ftp_port'} = $port;
  600.  
  601.  $ok;
  602. }
  603.  
  604. sub ls  { shift->_list_cmd("NLST",@_); }
  605. sub dir { shift->_list_cmd("LIST",@_); }
  606.  
  607. sub pasv
  608. {
  609.  @_ == 1 or croak 'usage: $ftp->pasv()';
  610.  
  611.  my $ftp = shift;
  612.  
  613.  delete ${*$ftp}{'net_ftp_intern_port'};
  614.  
  615.  $ftp->_PASV && $ftp->message =~ /(\d+(,\d+)+)/
  616.     ? ${*$ftp}{'net_ftp_pasv'} = $1
  617.     : undef;    
  618. }
  619.  
  620. sub unique_name
  621. {
  622.  my $ftp = shift;
  623.  ${*$ftp}{'net_ftp_unique'} || undef;
  624. }
  625.  
  626. sub supported {
  627.     @_ == 2 or croak 'usage: $ftp->supported( CMD )';
  628.     my $ftp = shift;
  629.     my $cmd = uc shift;
  630.     my $hash = ${*$ftp}{'net_ftp_supported'} ||= {};
  631.  
  632.     return $hash->{$cmd}
  633.         if exists $hash->{$cmd};
  634.  
  635.     my $ok = $ftp->_HELP($cmd) &&
  636.         $ftp->message !~ /unimplemented/i;
  637.  
  638.     $hash->{$cmd} = $ok;
  639. }
  640.  
  641. ##
  642. ## Depreciated methods
  643. ##
  644.  
  645. sub lsl
  646. {
  647.  carp "Use of Net::FTP::lsl depreciated, use 'dir'"
  648.     if $^W;
  649.  goto &dir;
  650. }
  651.  
  652. sub authorise
  653. {
  654.  carp "Use of Net::FTP::authorise depreciated, use 'authorize'"
  655.     if $^W;
  656.  goto &authorize;
  657. }
  658.  
  659.  
  660. ##
  661. ## Private methods
  662. ##
  663.  
  664. sub _extract_path
  665. {
  666.  my($ftp, $path) = @_;
  667.  
  668.  # This tries to work both with and without the quote doubling
  669.  # convention (RFC 959 requires it, but the first 3 servers I checked
  670.  # didn't implement it).  It will fail on a server which uses a quote in
  671.  # the message which isn't a part of or surrounding the path.
  672.  $ftp->ok &&
  673.     $ftp->message =~ /(?:^|\s)\"(.*)\"(?:$|\s)/ &&
  674.     ($path = $1) =~ s/\"\"/\"/g;
  675.  
  676.  $path;
  677. }
  678.  
  679. ##
  680. ## Communication methods
  681. ##
  682.  
  683. sub _dataconn
  684. {
  685.  my $ftp = shift;
  686.  my $data = undef;
  687.  my $pkg = "Net::FTP::" . $ftp->type;
  688.  
  689.  eval "require " . $pkg;
  690.  
  691.  $pkg =~ s/ /_/g;
  692.  
  693.  delete ${*$ftp}{'net_ftp_dataconn'};
  694.  
  695.  if(defined ${*$ftp}{'net_ftp_pasv'})
  696.   {
  697.    my @port = split(/,/,${*$ftp}{'net_ftp_pasv'});
  698.  
  699.    $data = $pkg->new(PeerAddr => join(".",@port[0..3]),
  700.                      PeerPort => $port[4] * 256 + $port[5],
  701.                      Proto    => 'tcp'
  702.                     );
  703.   }
  704.  elsif(defined ${*$ftp}{'net_ftp_listen'})
  705.   {
  706.    $data = ${*$ftp}{'net_ftp_listen'}->accept($pkg);
  707.    close(delete ${*$ftp}{'net_ftp_listen'});
  708.   }
  709.  
  710.  if($data)
  711.   {
  712.    ${*$data} = "";
  713.    $data->timeout($ftp->timeout);
  714.    ${*$ftp}{'net_ftp_dataconn'} = $data;
  715.    ${*$data}{'net_ftp_cmd'} = $ftp;
  716.   }
  717.  
  718.  $data;
  719. }
  720.  
  721. sub _list_cmd
  722. {
  723.  my $ftp = shift;
  724.  my $cmd = uc shift;
  725.  
  726.  delete ${*$ftp}{'net_ftp_port'};
  727.  delete ${*$ftp}{'net_ftp_pasv'};
  728.  
  729.  my $data = $ftp->_data_cmd($cmd,@_);
  730.  
  731.  return undef
  732.     unless(defined $data);
  733.  
  734.  require Net::FTP::A;
  735.  bless $data, "Net::FTP::A"; # Force ASCII mode
  736.  
  737.  my $databuf = '';
  738.  my $buf = '';
  739.  
  740.  while($data->read($databuf,1024))
  741.   {
  742.    $buf .= $databuf;
  743.   }
  744.  
  745.  my $list = [ split(/\n/,$buf) ];
  746.  
  747.  $data->close();
  748.  
  749.  wantarray ? @{$list}
  750.            : $list;
  751. }
  752.  
  753. sub _data_cmd
  754. {
  755.  my $ftp = shift;
  756.  my $cmd = uc shift;
  757.  my $ok = 1;
  758.  my $where = delete ${*$ftp}{'net_ftp_rest'} || 0;
  759.  my $arg;
  760.  
  761.  for $arg (@_) {
  762.    croak("Bad argument '$arg'\n")
  763.     if $arg =~ /[\r\n]/s;
  764.  }
  765.  
  766.  if(${*$ftp}{'net_ftp_passive'} &&
  767.      !defined ${*$ftp}{'net_ftp_pasv'} &&
  768.      !defined ${*$ftp}{'net_ftp_port'})
  769.   {
  770.    my $data = undef;
  771.  
  772.    $ok = defined $ftp->pasv;
  773.    $ok = $ftp->_REST($where)
  774.     if $ok && $where;
  775.  
  776.    if($ok)
  777.     {
  778.      $ftp->command($cmd,@_);
  779.      $data = $ftp->_dataconn();
  780.      $ok = CMD_INFO == $ftp->response();
  781.      if($ok) 
  782.       {
  783.        $data->reading
  784.          if $data && $cmd =~ /RETR|LIST|NLST/;
  785.        return $data
  786.       }
  787.      $data->_close
  788.     if $data;
  789.     }
  790.    return undef;
  791.   }
  792.  
  793.  $ok = $ftp->port
  794.     unless (defined ${*$ftp}{'net_ftp_port'} ||
  795.             defined ${*$ftp}{'net_ftp_pasv'});
  796.  
  797.  $ok = $ftp->_REST($where)
  798.     if $ok && $where;
  799.  
  800.  return undef
  801.     unless $ok;
  802.  
  803.  $ftp->command($cmd,@_);
  804.  
  805.  return 1
  806.     if(defined ${*$ftp}{'net_ftp_pasv'});
  807.  
  808.  $ok = CMD_INFO == $ftp->response();
  809.  
  810.  return $ok 
  811.     unless exists ${*$ftp}{'net_ftp_intern_port'};
  812.  
  813.  if($ok) {
  814.    my $data = $ftp->_dataconn();
  815.  
  816.    $data->reading
  817.          if $data && $cmd =~ /RETR|LIST|NLST/;
  818.  
  819.    return $data;
  820.  }
  821.  
  822.  
  823.  close(delete ${*$ftp}{'net_ftp_listen'});
  824.  
  825.  return undef;
  826. }
  827.  
  828. ##
  829. ## Over-ride methods (Net::Cmd)
  830. ##
  831.  
  832. sub debug_text { $_[2] =~ /^(pass|resp)/i ? "$1 ....\n" : $_[2]; }
  833.  
  834. sub command
  835. {
  836.  my $ftp = shift;
  837.  
  838.  delete ${*$ftp}{'net_ftp_port'};
  839.  $ftp->SUPER::command(@_);
  840. }
  841.  
  842. sub response
  843. {
  844.  my $ftp = shift;
  845.  my $code = $ftp->SUPER::response();
  846.  
  847.  delete ${*$ftp}{'net_ftp_pasv'}
  848.     if ($code != CMD_MORE && $code != CMD_INFO);
  849.  
  850.  $code;
  851. }
  852.  
  853. sub parse_response
  854. {
  855.  return ($1, $2 eq "-")
  856.     if $_[1] =~ s/^(\d\d\d)(.?)//o;
  857.  
  858.  my $ftp = shift;
  859.  
  860.  # Darn MS FTP server is a load of CRAP !!!!
  861.  return ()
  862.     unless ${*$ftp}{'net_cmd_code'} + 0;
  863.  
  864.  (${*$ftp}{'net_cmd_code'},1);
  865. }
  866.  
  867. ##
  868. ## Allow 2 servers to talk directly
  869. ##
  870.  
  871. sub pasv_xfer {
  872.     my($sftp,$sfile,$dftp,$dfile,$unique) = @_;
  873.  
  874.     ($dfile = $sfile) =~ s#.*/##
  875.     unless(defined $dfile);
  876.  
  877.     my $port = $sftp->pasv or
  878.     return undef;
  879.  
  880.     $dftp->port($port) or
  881.     return undef;
  882.  
  883.     return undef
  884.     unless($unique ? $dftp->stou($dfile) : $dftp->stor($dfile));
  885.  
  886.     unless($sftp->retr($sfile) && $sftp->response == CMD_INFO) {
  887.     $sftp->retr($sfile);
  888.     $dftp->abort;
  889.     $dftp->response();
  890.     return undef;
  891.     }
  892.  
  893.     $dftp->pasv_wait($sftp);
  894. }
  895.  
  896. sub pasv_wait
  897. {
  898.  @_ == 2 or croak 'usage: $ftp->pasv_wait(NON_PASV_FTP)';
  899.  
  900.  my($ftp, $non_pasv) = @_;
  901.  my($file,$rin,$rout);
  902.  
  903.  vec($rin,fileno($ftp),1) = 1;
  904.  select($rout=$rin, undef, undef, undef);
  905.  
  906.  $ftp->response();
  907.  $non_pasv->response();
  908.  
  909.  return undef
  910.     unless $ftp->ok() && $non_pasv->ok();
  911.  
  912.  return $1
  913.     if $ftp->message =~ /unique file name:\s*(\S*)\s*\)/;
  914.  
  915.  return $1
  916.     if $non_pasv->message =~ /unique file name:\s*(\S*)\s*\)/;
  917.  
  918.  return 1;
  919. }
  920.  
  921. sub cmd { shift->command(@_)->response() }
  922.  
  923. ########################################
  924. #
  925. # RFC959 commands
  926. #
  927.  
  928. sub _ABOR { shift->command("ABOR")->response()     == CMD_OK }
  929. sub _CDUP { shift->command("CDUP")->response()     == CMD_OK }
  930. sub _NOOP { shift->command("NOOP")->response()     == CMD_OK }
  931. sub _PASV { shift->command("PASV")->response()     == CMD_OK }
  932. sub _QUIT { shift->command("QUIT")->response()     == CMD_OK }
  933. sub _DELE { shift->command("DELE",@_)->response() == CMD_OK }
  934. sub _CWD  { shift->command("CWD", @_)->response() == CMD_OK }
  935. sub _PORT { shift->command("PORT",@_)->response() == CMD_OK }
  936. sub _RMD  { shift->command("RMD", @_)->response() == CMD_OK }
  937. sub _MKD  { shift->command("MKD", @_)->response() == CMD_OK }
  938. sub _PWD  { shift->command("PWD", @_)->response() == CMD_OK }
  939. sub _TYPE { shift->command("TYPE",@_)->response() == CMD_OK }
  940. sub _RNTO { shift->command("RNTO",@_)->response() == CMD_OK }
  941. sub _ACCT { shift->command("ACCT",@_)->response() == CMD_OK }
  942. sub _RESP { shift->command("RESP",@_)->response() == CMD_OK }
  943. sub _MDTM { shift->command("MDTM",@_)->response() == CMD_OK }
  944. sub _SIZE { shift->command("SIZE",@_)->response() == CMD_OK }
  945. sub _HELP { shift->command("HELP",@_)->response() == CMD_OK }
  946. sub _STAT { shift->command("STAT",@_)->response() == CMD_OK }
  947. sub _APPE { shift->command("APPE",@_)->response() == CMD_INFO }
  948. sub _LIST { shift->command("LIST",@_)->response() == CMD_INFO }
  949. sub _NLST { shift->command("NLST",@_)->response() == CMD_INFO }
  950. sub _RETR { shift->command("RETR",@_)->response() == CMD_INFO }
  951. sub _STOR { shift->command("STOR",@_)->response() == CMD_INFO }
  952. sub _STOU { shift->command("STOU",@_)->response() == CMD_INFO }
  953. sub _RNFR { shift->command("RNFR",@_)->response() == CMD_MORE }
  954. sub _REST { shift->command("REST",@_)->response() == CMD_MORE }
  955. sub _USER { shift->command("user",@_)->response() } # A certain brain dead firewall :-)
  956. sub _PASS { shift->command("PASS",@_)->response() }
  957. sub _AUTH { shift->command("AUTH",@_)->response() }
  958.  
  959. sub _ALLO { shift->unsupported(@_) }
  960. sub _SMNT { shift->unsupported(@_) }
  961. sub _MODE { shift->unsupported(@_) }
  962. sub _SYST { shift->unsupported(@_) }
  963. sub _STRU { shift->unsupported(@_) }
  964. sub _REIN { shift->unsupported(@_) }
  965.  
  966. 1;
  967.  
  968.