xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Net/FTP.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gate# Net::FTP.pm
2*0Sstevel@tonic-gate#
3*0Sstevel@tonic-gate# Copyright (c) 1995-8 Graham Barr <gbarr@pobox.com>. All rights reserved.
4*0Sstevel@tonic-gate# This program is free software; you can redistribute it and/or
5*0Sstevel@tonic-gate# modify it under the same terms as Perl itself.
6*0Sstevel@tonic-gate#
7*0Sstevel@tonic-gate# Documentation (at end) improved 1996 by Nathan Torkington <gnat@frii.com>.
8*0Sstevel@tonic-gate
9*0Sstevel@tonic-gatepackage Net::FTP;
10*0Sstevel@tonic-gate
11*0Sstevel@tonic-gaterequire 5.001;
12*0Sstevel@tonic-gate
13*0Sstevel@tonic-gateuse strict;
14*0Sstevel@tonic-gateuse vars qw(@ISA $VERSION);
15*0Sstevel@tonic-gateuse Carp;
16*0Sstevel@tonic-gate
17*0Sstevel@tonic-gateuse Socket 1.3;
18*0Sstevel@tonic-gateuse IO::Socket;
19*0Sstevel@tonic-gateuse Time::Local;
20*0Sstevel@tonic-gateuse Net::Cmd;
21*0Sstevel@tonic-gateuse Net::Config;
22*0Sstevel@tonic-gateuse Fcntl qw(O_WRONLY O_RDONLY O_APPEND O_CREAT O_TRUNC);
23*0Sstevel@tonic-gate# use AutoLoader qw(AUTOLOAD);
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate$VERSION = "2.72"; # $Id: //depot/libnet/Net/FTP.pm#80 $
26*0Sstevel@tonic-gate@ISA     = qw(Exporter Net::Cmd IO::Socket::INET);
27*0Sstevel@tonic-gate
28*0Sstevel@tonic-gate# Someday I will "use constant", when I am not bothered to much about
29*0Sstevel@tonic-gate# compatability with older releases of perl
30*0Sstevel@tonic-gate
31*0Sstevel@tonic-gateuse vars qw($TELNET_IAC $TELNET_IP $TELNET_DM);
32*0Sstevel@tonic-gate($TELNET_IAC,$TELNET_IP,$TELNET_DM) = (255,244,242);
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gate# Name is too long for AutoLoad, it clashes with pasv_xfer
35*0Sstevel@tonic-gatesub pasv_xfer_unique {
36*0Sstevel@tonic-gate    my($sftp,$sfile,$dftp,$dfile) = @_;
37*0Sstevel@tonic-gate    $sftp->pasv_xfer($sfile,$dftp,$dfile,1);
38*0Sstevel@tonic-gate}
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gateBEGIN {
41*0Sstevel@tonic-gate  # make a constant so code is fast'ish
42*0Sstevel@tonic-gate  my $is_os390 = $^O eq 'os390';
43*0Sstevel@tonic-gate  *trEBCDIC = sub () { $is_os390 }
44*0Sstevel@tonic-gate}
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gate1;
47*0Sstevel@tonic-gate# Having problems with AutoLoader
48*0Sstevel@tonic-gate#__END__
49*0Sstevel@tonic-gate
50*0Sstevel@tonic-gatesub new
51*0Sstevel@tonic-gate{
52*0Sstevel@tonic-gate my $pkg  = shift;
53*0Sstevel@tonic-gate my $peer = shift;
54*0Sstevel@tonic-gate my %arg  = @_;
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate my $host = $peer;
57*0Sstevel@tonic-gate my $fire = undef;
58*0Sstevel@tonic-gate my $fire_type = undef;
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate if(exists($arg{Firewall}) || Net::Config->requires_firewall($peer))
61*0Sstevel@tonic-gate  {
62*0Sstevel@tonic-gate   $fire = $arg{Firewall}
63*0Sstevel@tonic-gate	|| $ENV{FTP_FIREWALL}
64*0Sstevel@tonic-gate	|| $NetConfig{ftp_firewall}
65*0Sstevel@tonic-gate	|| undef;
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate   if(defined $fire)
68*0Sstevel@tonic-gate    {
69*0Sstevel@tonic-gate     $peer = $fire;
70*0Sstevel@tonic-gate     delete $arg{Port};
71*0Sstevel@tonic-gate	 $fire_type = $arg{FirewallType}
72*0Sstevel@tonic-gate	 || $ENV{FTP_FIREWALL_TYPE}
73*0Sstevel@tonic-gate	 || $NetConfig{firewall_type}
74*0Sstevel@tonic-gate	 || undef;
75*0Sstevel@tonic-gate    }
76*0Sstevel@tonic-gate  }
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate my $ftp = $pkg->SUPER::new(PeerAddr => $peer,
79*0Sstevel@tonic-gate			    PeerPort => $arg{Port} || 'ftp(21)',
80*0Sstevel@tonic-gate			    LocalAddr => $arg{'LocalAddr'},
81*0Sstevel@tonic-gate			    Proto    => 'tcp',
82*0Sstevel@tonic-gate			    Timeout  => defined $arg{Timeout}
83*0Sstevel@tonic-gate						? $arg{Timeout}
84*0Sstevel@tonic-gate						: 120
85*0Sstevel@tonic-gate			   ) or return undef;
86*0Sstevel@tonic-gate
87*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_host'}     = $host;		# Remote hostname
88*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_type'}     = 'A';		# ASCII/binary/etc mode
89*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_blksize'}  = abs($arg{'BlockSize'} || 10240);
90*0Sstevel@tonic-gate
91*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_localaddr'} = $arg{'LocalAddr'};
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_firewall'} = $fire
94*0Sstevel@tonic-gate	if(defined $fire);
95*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_firewall_type'} = $fire_type
96*0Sstevel@tonic-gate	if(defined $fire_type);
97*0Sstevel@tonic-gate
98*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_passive'} = int
99*0Sstevel@tonic-gate	exists $arg{Passive}
100*0Sstevel@tonic-gate	    ? $arg{Passive}
101*0Sstevel@tonic-gate	    : exists $ENV{FTP_PASSIVE}
102*0Sstevel@tonic-gate		? $ENV{FTP_PASSIVE}
103*0Sstevel@tonic-gate		: defined $fire
104*0Sstevel@tonic-gate		    ? $NetConfig{ftp_ext_passive}
105*0Sstevel@tonic-gate		    : $NetConfig{ftp_int_passive};	# Whew! :-)
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate $ftp->hash(exists $arg{Hash} ? $arg{Hash} : 0, 1024);
108*0Sstevel@tonic-gate
109*0Sstevel@tonic-gate $ftp->autoflush(1);
110*0Sstevel@tonic-gate
111*0Sstevel@tonic-gate $ftp->debug(exists $arg{Debug} ? $arg{Debug} : undef);
112*0Sstevel@tonic-gate
113*0Sstevel@tonic-gate unless ($ftp->response() == CMD_OK)
114*0Sstevel@tonic-gate  {
115*0Sstevel@tonic-gate   $ftp->close();
116*0Sstevel@tonic-gate   $@ = $ftp->message;
117*0Sstevel@tonic-gate   undef $ftp;
118*0Sstevel@tonic-gate  }
119*0Sstevel@tonic-gate
120*0Sstevel@tonic-gate $ftp;
121*0Sstevel@tonic-gate}
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate##
124*0Sstevel@tonic-gate## User interface methods
125*0Sstevel@tonic-gate##
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gatesub hash {
128*0Sstevel@tonic-gate    my $ftp = shift;		# self
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gate    my($h,$b) = @_;
131*0Sstevel@tonic-gate    unless($h) {
132*0Sstevel@tonic-gate      delete ${*$ftp}{'net_ftp_hash'};
133*0Sstevel@tonic-gate      return [\*STDERR,0];
134*0Sstevel@tonic-gate    }
135*0Sstevel@tonic-gate    ($h,$b) = (ref($h)? $h : \*STDERR, $b || 1024);
136*0Sstevel@tonic-gate    select((select($h), $|=1)[0]);
137*0Sstevel@tonic-gate    $b = 512 if $b < 512;
138*0Sstevel@tonic-gate    ${*$ftp}{'net_ftp_hash'} = [$h, $b];
139*0Sstevel@tonic-gate}
140*0Sstevel@tonic-gate
141*0Sstevel@tonic-gatesub quit
142*0Sstevel@tonic-gate{
143*0Sstevel@tonic-gate my $ftp = shift;
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate $ftp->_QUIT;
146*0Sstevel@tonic-gate $ftp->close;
147*0Sstevel@tonic-gate}
148*0Sstevel@tonic-gate
149*0Sstevel@tonic-gatesub DESTROY {}
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gatesub ascii  { shift->type('A',@_); }
152*0Sstevel@tonic-gatesub binary { shift->type('I',@_); }
153*0Sstevel@tonic-gate
154*0Sstevel@tonic-gatesub ebcdic
155*0Sstevel@tonic-gate{
156*0Sstevel@tonic-gate carp "TYPE E is unsupported, shall default to I";
157*0Sstevel@tonic-gate shift->type('E',@_);
158*0Sstevel@tonic-gate}
159*0Sstevel@tonic-gate
160*0Sstevel@tonic-gatesub byte
161*0Sstevel@tonic-gate{
162*0Sstevel@tonic-gate carp "TYPE L is unsupported, shall default to I";
163*0Sstevel@tonic-gate shift->type('L',@_);
164*0Sstevel@tonic-gate}
165*0Sstevel@tonic-gate
166*0Sstevel@tonic-gate# Allow the user to send a command directly, BE CAREFUL !!
167*0Sstevel@tonic-gate
168*0Sstevel@tonic-gatesub quot
169*0Sstevel@tonic-gate{
170*0Sstevel@tonic-gate my $ftp = shift;
171*0Sstevel@tonic-gate my $cmd = shift;
172*0Sstevel@tonic-gate
173*0Sstevel@tonic-gate $ftp->command( uc $cmd, @_);
174*0Sstevel@tonic-gate $ftp->response();
175*0Sstevel@tonic-gate}
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gatesub site
178*0Sstevel@tonic-gate{
179*0Sstevel@tonic-gate my $ftp = shift;
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate $ftp->command("SITE", @_);
182*0Sstevel@tonic-gate $ftp->response();
183*0Sstevel@tonic-gate}
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gatesub mdtm
186*0Sstevel@tonic-gate{
187*0Sstevel@tonic-gate my $ftp  = shift;
188*0Sstevel@tonic-gate my $file = shift;
189*0Sstevel@tonic-gate
190*0Sstevel@tonic-gate # Server Y2K bug workaround
191*0Sstevel@tonic-gate #
192*0Sstevel@tonic-gate # sigh; some idiotic FTP servers use ("19%d",tm.tm_year) instead of
193*0Sstevel@tonic-gate # ("%d",tm.tm_year+1900).  This results in an extra digit in the
194*0Sstevel@tonic-gate # string returned. To account for this we allow an optional extra
195*0Sstevel@tonic-gate # digit in the year. Then if the first two digits are 19 we use the
196*0Sstevel@tonic-gate # remainder, otherwise we subtract 1900 from the whole year.
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate $ftp->_MDTM($file) && $ftp->message =~ /((\d\d)(\d\d\d?))(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/
199*0Sstevel@tonic-gate    ? timegm($8,$7,$6,$5,$4-1,$2 eq '19' ? $3 : ($1-1900))
200*0Sstevel@tonic-gate    : undef;
201*0Sstevel@tonic-gate}
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gatesub size {
204*0Sstevel@tonic-gate  my $ftp  = shift;
205*0Sstevel@tonic-gate  my $file = shift;
206*0Sstevel@tonic-gate  my $io;
207*0Sstevel@tonic-gate  if($ftp->supported("SIZE")) {
208*0Sstevel@tonic-gate    return $ftp->_SIZE($file)
209*0Sstevel@tonic-gate	? ($ftp->message =~ /(\d+)\s*$/)[0]
210*0Sstevel@tonic-gate	: undef;
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate elsif($ftp->supported("STAT")) {
213*0Sstevel@tonic-gate   my @msg;
214*0Sstevel@tonic-gate   return undef
215*0Sstevel@tonic-gate       unless $ftp->_STAT($file) && (@msg = $ftp->message) == 3;
216*0Sstevel@tonic-gate   my $line;
217*0Sstevel@tonic-gate   foreach $line (@msg) {
218*0Sstevel@tonic-gate     return (split(/\s+/,$line))[4]
219*0Sstevel@tonic-gate	 if $line =~ /^[-rwxSsTt]{10}/
220*0Sstevel@tonic-gate   }
221*0Sstevel@tonic-gate }
222*0Sstevel@tonic-gate else {
223*0Sstevel@tonic-gate   my @files = $ftp->dir($file);
224*0Sstevel@tonic-gate   if(@files) {
225*0Sstevel@tonic-gate     return (split(/\s+/,$1))[4]
226*0Sstevel@tonic-gate	 if $files[0] =~ /^([-rwxSsTt]{10}.*)$/;
227*0Sstevel@tonic-gate   }
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate undef;
230*0Sstevel@tonic-gate}
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gatesub login {
233*0Sstevel@tonic-gate  my($ftp,$user,$pass,$acct) = @_;
234*0Sstevel@tonic-gate  my($ok,$ruser,$fwtype);
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate  unless (defined $user) {
237*0Sstevel@tonic-gate    require Net::Netrc;
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate    my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'});
240*0Sstevel@tonic-gate
241*0Sstevel@tonic-gate    ($user,$pass,$acct) = $rc->lpa()
242*0Sstevel@tonic-gate	 if ($rc);
243*0Sstevel@tonic-gate   }
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate  $user ||= "anonymous";
246*0Sstevel@tonic-gate  $ruser = $user;
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate  $fwtype = ${*$ftp}{'net_ftp_firewall_type'}
249*0Sstevel@tonic-gate  || $NetConfig{'ftp_firewall_type'}
250*0Sstevel@tonic-gate  || 0;
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate  if ($fwtype && defined ${*$ftp}{'net_ftp_firewall'}) {
253*0Sstevel@tonic-gate    if ($fwtype == 1 || $fwtype == 7) {
254*0Sstevel@tonic-gate      $user .= '@' . ${*$ftp}{'net_ftp_host'};
255*0Sstevel@tonic-gate    }
256*0Sstevel@tonic-gate    else {
257*0Sstevel@tonic-gate      require Net::Netrc;
258*0Sstevel@tonic-gate
259*0Sstevel@tonic-gate      my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'});
260*0Sstevel@tonic-gate
261*0Sstevel@tonic-gate      my($fwuser,$fwpass,$fwacct) = $rc ? $rc->lpa() : ();
262*0Sstevel@tonic-gate
263*0Sstevel@tonic-gate      if ($fwtype == 5) {
264*0Sstevel@tonic-gate	$user = join('@',$user,$fwuser,${*$ftp}{'net_ftp_host'});
265*0Sstevel@tonic-gate	$pass = $pass . '@' . $fwpass;
266*0Sstevel@tonic-gate      }
267*0Sstevel@tonic-gate      else {
268*0Sstevel@tonic-gate	if ($fwtype == 2) {
269*0Sstevel@tonic-gate	  $user .= '@' . ${*$ftp}{'net_ftp_host'};
270*0Sstevel@tonic-gate	}
271*0Sstevel@tonic-gate	elsif ($fwtype == 6) {
272*0Sstevel@tonic-gate	  $fwuser .= '@' . ${*$ftp}{'net_ftp_host'};
273*0Sstevel@tonic-gate	}
274*0Sstevel@tonic-gate
275*0Sstevel@tonic-gate	$ok = $ftp->_USER($fwuser);
276*0Sstevel@tonic-gate
277*0Sstevel@tonic-gate	return 0 unless $ok == CMD_OK || $ok == CMD_MORE;
278*0Sstevel@tonic-gate
279*0Sstevel@tonic-gate	$ok = $ftp->_PASS($fwpass || "");
280*0Sstevel@tonic-gate
281*0Sstevel@tonic-gate	return 0 unless $ok == CMD_OK || $ok == CMD_MORE;
282*0Sstevel@tonic-gate
283*0Sstevel@tonic-gate	$ok = $ftp->_ACCT($fwacct)
284*0Sstevel@tonic-gate	  if defined($fwacct);
285*0Sstevel@tonic-gate
286*0Sstevel@tonic-gate	if ($fwtype == 3) {
287*0Sstevel@tonic-gate          $ok = $ftp->command("SITE",${*$ftp}{'net_ftp_host'})->response;
288*0Sstevel@tonic-gate	}
289*0Sstevel@tonic-gate	elsif ($fwtype == 4) {
290*0Sstevel@tonic-gate          $ok = $ftp->command("OPEN",${*$ftp}{'net_ftp_host'})->response;
291*0Sstevel@tonic-gate	}
292*0Sstevel@tonic-gate
293*0Sstevel@tonic-gate	return 0 unless $ok == CMD_OK || $ok == CMD_MORE;
294*0Sstevel@tonic-gate      }
295*0Sstevel@tonic-gate    }
296*0Sstevel@tonic-gate  }
297*0Sstevel@tonic-gate
298*0Sstevel@tonic-gate  $ok = $ftp->_USER($user);
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate  # Some dumb firewalls don't prefix the connection messages
301*0Sstevel@tonic-gate  $ok = $ftp->response()
302*0Sstevel@tonic-gate	 if ($ok == CMD_OK && $ftp->code == 220 && $user =~ /\@/);
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate  if ($ok == CMD_MORE) {
305*0Sstevel@tonic-gate    unless(defined $pass) {
306*0Sstevel@tonic-gate      require Net::Netrc;
307*0Sstevel@tonic-gate
308*0Sstevel@tonic-gate      my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'}, $ruser);
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gate      ($ruser,$pass,$acct) = $rc->lpa()
311*0Sstevel@tonic-gate	 if ($rc);
312*0Sstevel@tonic-gate
313*0Sstevel@tonic-gate      $pass = '-anonymous@'
314*0Sstevel@tonic-gate         if (!defined $pass && (!defined($ruser) || $ruser =~ /^anonymous/o));
315*0Sstevel@tonic-gate    }
316*0Sstevel@tonic-gate
317*0Sstevel@tonic-gate    $ok = $ftp->_PASS($pass || "");
318*0Sstevel@tonic-gate  }
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate  $ok = $ftp->_ACCT($acct)
321*0Sstevel@tonic-gate	 if (defined($acct) && ($ok == CMD_MORE || $ok == CMD_OK));
322*0Sstevel@tonic-gate
323*0Sstevel@tonic-gate  if ($fwtype == 7 && $ok == CMD_OK && defined ${*$ftp}{'net_ftp_firewall'}) {
324*0Sstevel@tonic-gate    my($f,$auth,$resp) = _auth_id($ftp);
325*0Sstevel@tonic-gate    $ftp->authorize($auth,$resp) if defined($resp);
326*0Sstevel@tonic-gate  }
327*0Sstevel@tonic-gate
328*0Sstevel@tonic-gate  $ok == CMD_OK;
329*0Sstevel@tonic-gate}
330*0Sstevel@tonic-gate
331*0Sstevel@tonic-gatesub account
332*0Sstevel@tonic-gate{
333*0Sstevel@tonic-gate @_ == 2 or croak 'usage: $ftp->account( ACCT )';
334*0Sstevel@tonic-gate my $ftp = shift;
335*0Sstevel@tonic-gate my $acct = shift;
336*0Sstevel@tonic-gate $ftp->_ACCT($acct) == CMD_OK;
337*0Sstevel@tonic-gate}
338*0Sstevel@tonic-gate
339*0Sstevel@tonic-gatesub _auth_id {
340*0Sstevel@tonic-gate my($ftp,$auth,$resp) = @_;
341*0Sstevel@tonic-gate
342*0Sstevel@tonic-gate unless(defined $resp)
343*0Sstevel@tonic-gate  {
344*0Sstevel@tonic-gate   require Net::Netrc;
345*0Sstevel@tonic-gate
346*0Sstevel@tonic-gate   $auth ||= eval { (getpwuid($>))[0] } || $ENV{NAME};
347*0Sstevel@tonic-gate
348*0Sstevel@tonic-gate   my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'}, $auth)
349*0Sstevel@tonic-gate        || Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'});
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate   ($auth,$resp) = $rc->lpa()
352*0Sstevel@tonic-gate     if ($rc);
353*0Sstevel@tonic-gate  }
354*0Sstevel@tonic-gate  ($ftp,$auth,$resp);
355*0Sstevel@tonic-gate}
356*0Sstevel@tonic-gate
357*0Sstevel@tonic-gatesub authorize
358*0Sstevel@tonic-gate{
359*0Sstevel@tonic-gate @_ >= 1 || @_ <= 3 or croak 'usage: $ftp->authorize( [AUTH [, RESP]])';
360*0Sstevel@tonic-gate
361*0Sstevel@tonic-gate my($ftp,$auth,$resp) = &_auth_id;
362*0Sstevel@tonic-gate
363*0Sstevel@tonic-gate my $ok = $ftp->_AUTH($auth || "");
364*0Sstevel@tonic-gate
365*0Sstevel@tonic-gate $ok = $ftp->_RESP($resp || "")
366*0Sstevel@tonic-gate	if ($ok == CMD_MORE);
367*0Sstevel@tonic-gate
368*0Sstevel@tonic-gate $ok == CMD_OK;
369*0Sstevel@tonic-gate}
370*0Sstevel@tonic-gate
371*0Sstevel@tonic-gatesub rename
372*0Sstevel@tonic-gate{
373*0Sstevel@tonic-gate @_ == 3 or croak 'usage: $ftp->rename(FROM, TO)';
374*0Sstevel@tonic-gate
375*0Sstevel@tonic-gate my($ftp,$from,$to) = @_;
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate $ftp->_RNFR($from)
378*0Sstevel@tonic-gate    && $ftp->_RNTO($to);
379*0Sstevel@tonic-gate}
380*0Sstevel@tonic-gate
381*0Sstevel@tonic-gatesub type
382*0Sstevel@tonic-gate{
383*0Sstevel@tonic-gate my $ftp = shift;
384*0Sstevel@tonic-gate my $type = shift;
385*0Sstevel@tonic-gate my $oldval = ${*$ftp}{'net_ftp_type'};
386*0Sstevel@tonic-gate
387*0Sstevel@tonic-gate return $oldval
388*0Sstevel@tonic-gate	unless (defined $type);
389*0Sstevel@tonic-gate
390*0Sstevel@tonic-gate return undef
391*0Sstevel@tonic-gate	unless ($ftp->_TYPE($type,@_));
392*0Sstevel@tonic-gate
393*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_type'} = join(" ",$type,@_);
394*0Sstevel@tonic-gate
395*0Sstevel@tonic-gate $oldval;
396*0Sstevel@tonic-gate}
397*0Sstevel@tonic-gate
398*0Sstevel@tonic-gatesub alloc
399*0Sstevel@tonic-gate{
400*0Sstevel@tonic-gate my $ftp = shift;
401*0Sstevel@tonic-gate my $size = shift;
402*0Sstevel@tonic-gate my $oldval = ${*$ftp}{'net_ftp_allo'};
403*0Sstevel@tonic-gate
404*0Sstevel@tonic-gate return $oldval
405*0Sstevel@tonic-gate	unless (defined $size);
406*0Sstevel@tonic-gate
407*0Sstevel@tonic-gate return undef
408*0Sstevel@tonic-gate	unless ($ftp->_ALLO($size,@_));
409*0Sstevel@tonic-gate
410*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_allo'} = join(" ",$size,@_);
411*0Sstevel@tonic-gate
412*0Sstevel@tonic-gate $oldval;
413*0Sstevel@tonic-gate}
414*0Sstevel@tonic-gate
415*0Sstevel@tonic-gatesub abort
416*0Sstevel@tonic-gate{
417*0Sstevel@tonic-gate my $ftp = shift;
418*0Sstevel@tonic-gate
419*0Sstevel@tonic-gate send($ftp,pack("CCC", $TELNET_IAC, $TELNET_IP, $TELNET_IAC),MSG_OOB);
420*0Sstevel@tonic-gate
421*0Sstevel@tonic-gate $ftp->command(pack("C",$TELNET_DM) . "ABOR");
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_dataconn'}->close()
424*0Sstevel@tonic-gate    if defined ${*$ftp}{'net_ftp_dataconn'};
425*0Sstevel@tonic-gate
426*0Sstevel@tonic-gate $ftp->response();
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate $ftp->status == CMD_OK;
429*0Sstevel@tonic-gate}
430*0Sstevel@tonic-gate
431*0Sstevel@tonic-gatesub get
432*0Sstevel@tonic-gate{
433*0Sstevel@tonic-gate my($ftp,$remote,$local,$where) = @_;
434*0Sstevel@tonic-gate
435*0Sstevel@tonic-gate my($loc,$len,$buf,$resp,$data);
436*0Sstevel@tonic-gate local *FD;
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gate my $localfd = ref($local) || ref(\$local) eq "GLOB";
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate ($local = $remote) =~ s#^.*/##
441*0Sstevel@tonic-gate	unless(defined $local);
442*0Sstevel@tonic-gate
443*0Sstevel@tonic-gate croak("Bad remote filename '$remote'\n")
444*0Sstevel@tonic-gate	if $remote =~ /[\r\n]/s;
445*0Sstevel@tonic-gate
446*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_rest'} = $where
447*0Sstevel@tonic-gate	if ($where);
448*0Sstevel@tonic-gate
449*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_port'};
450*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_pasv'};
451*0Sstevel@tonic-gate
452*0Sstevel@tonic-gate $data = $ftp->retr($remote) or
453*0Sstevel@tonic-gate	return undef;
454*0Sstevel@tonic-gate
455*0Sstevel@tonic-gate if($localfd)
456*0Sstevel@tonic-gate  {
457*0Sstevel@tonic-gate   $loc = $local;
458*0Sstevel@tonic-gate  }
459*0Sstevel@tonic-gate else
460*0Sstevel@tonic-gate  {
461*0Sstevel@tonic-gate   $loc = \*FD;
462*0Sstevel@tonic-gate
463*0Sstevel@tonic-gate   unless(sysopen($loc, $local, O_CREAT | O_WRONLY | ($where ? O_APPEND : O_TRUNC)))
464*0Sstevel@tonic-gate    {
465*0Sstevel@tonic-gate     carp "Cannot open Local file $local: $!\n";
466*0Sstevel@tonic-gate     $data->abort;
467*0Sstevel@tonic-gate     return undef;
468*0Sstevel@tonic-gate    }
469*0Sstevel@tonic-gate  }
470*0Sstevel@tonic-gate
471*0Sstevel@tonic-gate if($ftp->type eq 'I' && !binmode($loc))
472*0Sstevel@tonic-gate  {
473*0Sstevel@tonic-gate   carp "Cannot binmode Local file $local: $!\n";
474*0Sstevel@tonic-gate   $data->abort;
475*0Sstevel@tonic-gate   close($loc) unless $localfd;
476*0Sstevel@tonic-gate   return undef;
477*0Sstevel@tonic-gate  }
478*0Sstevel@tonic-gate
479*0Sstevel@tonic-gate $buf = '';
480*0Sstevel@tonic-gate my($count,$hashh,$hashb,$ref) = (0);
481*0Sstevel@tonic-gate
482*0Sstevel@tonic-gate ($hashh,$hashb) = @$ref
483*0Sstevel@tonic-gate   if($ref = ${*$ftp}{'net_ftp_hash'});
484*0Sstevel@tonic-gate
485*0Sstevel@tonic-gate my $blksize = ${*$ftp}{'net_ftp_blksize'};
486*0Sstevel@tonic-gate local $\; # Just in case
487*0Sstevel@tonic-gate
488*0Sstevel@tonic-gate while(1)
489*0Sstevel@tonic-gate  {
490*0Sstevel@tonic-gate   last unless $len = $data->read($buf,$blksize);
491*0Sstevel@tonic-gate
492*0Sstevel@tonic-gate   if (trEBCDIC && $ftp->type ne 'I')
493*0Sstevel@tonic-gate    {
494*0Sstevel@tonic-gate     $buf = $ftp->toebcdic($buf);
495*0Sstevel@tonic-gate     $len = length($buf);
496*0Sstevel@tonic-gate    }
497*0Sstevel@tonic-gate
498*0Sstevel@tonic-gate   if($hashh) {
499*0Sstevel@tonic-gate    $count += $len;
500*0Sstevel@tonic-gate    print $hashh "#" x (int($count / $hashb));
501*0Sstevel@tonic-gate    $count %= $hashb;
502*0Sstevel@tonic-gate   }
503*0Sstevel@tonic-gate   unless(print $loc $buf)
504*0Sstevel@tonic-gate    {
505*0Sstevel@tonic-gate     carp "Cannot write to Local file $local: $!\n";
506*0Sstevel@tonic-gate     $data->abort;
507*0Sstevel@tonic-gate     close($loc)
508*0Sstevel@tonic-gate        unless $localfd;
509*0Sstevel@tonic-gate     return undef;
510*0Sstevel@tonic-gate    }
511*0Sstevel@tonic-gate  }
512*0Sstevel@tonic-gate
513*0Sstevel@tonic-gate print $hashh "\n" if $hashh;
514*0Sstevel@tonic-gate
515*0Sstevel@tonic-gate unless ($localfd)
516*0Sstevel@tonic-gate  {
517*0Sstevel@tonic-gate   unless (close($loc))
518*0Sstevel@tonic-gate    {
519*0Sstevel@tonic-gate     carp "Cannot close file $local (perhaps disk space) $!\n";
520*0Sstevel@tonic-gate     return undef;
521*0Sstevel@tonic-gate    }
522*0Sstevel@tonic-gate  }
523*0Sstevel@tonic-gate
524*0Sstevel@tonic-gate unless ($data->close()) # implied $ftp->response
525*0Sstevel@tonic-gate  {
526*0Sstevel@tonic-gate   carp "Unable to close datastream";
527*0Sstevel@tonic-gate   return undef;
528*0Sstevel@tonic-gate  }
529*0Sstevel@tonic-gate
530*0Sstevel@tonic-gate return $local;
531*0Sstevel@tonic-gate}
532*0Sstevel@tonic-gate
533*0Sstevel@tonic-gatesub cwd
534*0Sstevel@tonic-gate{
535*0Sstevel@tonic-gate @_ == 1 || @_ == 2 or croak 'usage: $ftp->cwd( [ DIR ] )';
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate my($ftp,$dir) = @_;
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate $dir = "/" unless defined($dir) && $dir =~ /\S/;
540*0Sstevel@tonic-gate
541*0Sstevel@tonic-gate $dir eq ".."
542*0Sstevel@tonic-gate    ? $ftp->_CDUP()
543*0Sstevel@tonic-gate    : $ftp->_CWD($dir);
544*0Sstevel@tonic-gate}
545*0Sstevel@tonic-gate
546*0Sstevel@tonic-gatesub cdup
547*0Sstevel@tonic-gate{
548*0Sstevel@tonic-gate @_ == 1 or croak 'usage: $ftp->cdup()';
549*0Sstevel@tonic-gate $_[0]->_CDUP;
550*0Sstevel@tonic-gate}
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gatesub pwd
553*0Sstevel@tonic-gate{
554*0Sstevel@tonic-gate @_ == 1 || croak 'usage: $ftp->pwd()';
555*0Sstevel@tonic-gate my $ftp = shift;
556*0Sstevel@tonic-gate
557*0Sstevel@tonic-gate $ftp->_PWD();
558*0Sstevel@tonic-gate $ftp->_extract_path;
559*0Sstevel@tonic-gate}
560*0Sstevel@tonic-gate
561*0Sstevel@tonic-gate# rmdir( $ftp, $dir, [ $recurse ] )
562*0Sstevel@tonic-gate#
563*0Sstevel@tonic-gate# Removes $dir on remote host via FTP.
564*0Sstevel@tonic-gate# $ftp is handle for remote host
565*0Sstevel@tonic-gate#
566*0Sstevel@tonic-gate# If $recurse is TRUE, the directory and deleted recursively.
567*0Sstevel@tonic-gate# This means all of its contents and subdirectories.
568*0Sstevel@tonic-gate#
569*0Sstevel@tonic-gate# Initial version contributed by Dinkum Software
570*0Sstevel@tonic-gate#
571*0Sstevel@tonic-gatesub rmdir
572*0Sstevel@tonic-gate{
573*0Sstevel@tonic-gate    @_ == 2 || @_ == 3 or croak('usage: $ftp->rmdir( DIR [, RECURSE ] )');
574*0Sstevel@tonic-gate
575*0Sstevel@tonic-gate    # Pick off the args
576*0Sstevel@tonic-gate    my ($ftp, $dir, $recurse) = @_ ;
577*0Sstevel@tonic-gate    my $ok;
578*0Sstevel@tonic-gate
579*0Sstevel@tonic-gate    return $ok
580*0Sstevel@tonic-gate	if $ok = $ftp->_RMD( $dir ) or !$recurse;
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gate    # Try to delete the contents
583*0Sstevel@tonic-gate    # Get a list of all the files in the directory
584*0Sstevel@tonic-gate    my $filelist = $ftp->ls($dir);
585*0Sstevel@tonic-gate
586*0Sstevel@tonic-gate    return undef
587*0Sstevel@tonic-gate	unless $filelist && @$filelist; # failed, it is probably not a directory
588*0Sstevel@tonic-gate
589*0Sstevel@tonic-gate    # Go thru and delete each file or the directory
590*0Sstevel@tonic-gate    my $file;
591*0Sstevel@tonic-gate    foreach $file (map { m,/, ? $_ : "$dir/$_" } @$filelist)
592*0Sstevel@tonic-gate    {
593*0Sstevel@tonic-gate	next  # successfully deleted the file
594*0Sstevel@tonic-gate	    if $ftp->delete($file);
595*0Sstevel@tonic-gate
596*0Sstevel@tonic-gate	# Failed to delete it, assume its a directory
597*0Sstevel@tonic-gate	# Recurse and ignore errors, the final rmdir() will
598*0Sstevel@tonic-gate	# fail on any errors here
599*0Sstevel@tonic-gate	return $ok
600*0Sstevel@tonic-gate	    unless $ok = $ftp->rmdir($file, 1) ;
601*0Sstevel@tonic-gate    }
602*0Sstevel@tonic-gate
603*0Sstevel@tonic-gate    # Directory should be empty
604*0Sstevel@tonic-gate    # Try to remove the directory again
605*0Sstevel@tonic-gate    # Pass results directly to caller
606*0Sstevel@tonic-gate    # If any of the prior deletes failed, this
607*0Sstevel@tonic-gate    # rmdir() will fail because directory is not empty
608*0Sstevel@tonic-gate    return $ftp->_RMD($dir) ;
609*0Sstevel@tonic-gate}
610*0Sstevel@tonic-gate
611*0Sstevel@tonic-gatesub restart
612*0Sstevel@tonic-gate{
613*0Sstevel@tonic-gate  @_ == 2 || croak 'usage: $ftp->restart( BYTE_OFFSET )';
614*0Sstevel@tonic-gate
615*0Sstevel@tonic-gate  my($ftp,$where) = @_;
616*0Sstevel@tonic-gate
617*0Sstevel@tonic-gate  ${*$ftp}{'net_ftp_rest'} = $where;
618*0Sstevel@tonic-gate
619*0Sstevel@tonic-gate  return undef;
620*0Sstevel@tonic-gate}
621*0Sstevel@tonic-gate
622*0Sstevel@tonic-gate
623*0Sstevel@tonic-gatesub mkdir
624*0Sstevel@tonic-gate{
625*0Sstevel@tonic-gate @_ == 2 || @_ == 3 or croak 'usage: $ftp->mkdir( DIR [, RECURSE ] )';
626*0Sstevel@tonic-gate
627*0Sstevel@tonic-gate my($ftp,$dir,$recurse) = @_;
628*0Sstevel@tonic-gate
629*0Sstevel@tonic-gate $ftp->_MKD($dir) || $recurse or
630*0Sstevel@tonic-gate    return undef;
631*0Sstevel@tonic-gate
632*0Sstevel@tonic-gate my $path = $dir;
633*0Sstevel@tonic-gate
634*0Sstevel@tonic-gate unless($ftp->ok)
635*0Sstevel@tonic-gate  {
636*0Sstevel@tonic-gate   my @path = split(m#(?=/+)#, $dir);
637*0Sstevel@tonic-gate
638*0Sstevel@tonic-gate   $path = "";
639*0Sstevel@tonic-gate
640*0Sstevel@tonic-gate   while(@path)
641*0Sstevel@tonic-gate    {
642*0Sstevel@tonic-gate     $path .= shift @path;
643*0Sstevel@tonic-gate
644*0Sstevel@tonic-gate     $ftp->_MKD($path);
645*0Sstevel@tonic-gate
646*0Sstevel@tonic-gate     $path = $ftp->_extract_path($path);
647*0Sstevel@tonic-gate    }
648*0Sstevel@tonic-gate
649*0Sstevel@tonic-gate   # If the creation of the last element was not successful, see if we
650*0Sstevel@tonic-gate   # can cd to it, if so then return path
651*0Sstevel@tonic-gate
652*0Sstevel@tonic-gate   unless($ftp->ok)
653*0Sstevel@tonic-gate    {
654*0Sstevel@tonic-gate     my($status,$message) = ($ftp->status,$ftp->message);
655*0Sstevel@tonic-gate     my $pwd = $ftp->pwd;
656*0Sstevel@tonic-gate
657*0Sstevel@tonic-gate     if($pwd && $ftp->cwd($dir))
658*0Sstevel@tonic-gate      {
659*0Sstevel@tonic-gate       $path = $dir;
660*0Sstevel@tonic-gate       $ftp->cwd($pwd);
661*0Sstevel@tonic-gate      }
662*0Sstevel@tonic-gate     else
663*0Sstevel@tonic-gate      {
664*0Sstevel@tonic-gate       undef $path;
665*0Sstevel@tonic-gate      }
666*0Sstevel@tonic-gate     $ftp->set_status($status,$message);
667*0Sstevel@tonic-gate    }
668*0Sstevel@tonic-gate  }
669*0Sstevel@tonic-gate
670*0Sstevel@tonic-gate $path;
671*0Sstevel@tonic-gate}
672*0Sstevel@tonic-gate
673*0Sstevel@tonic-gatesub delete
674*0Sstevel@tonic-gate{
675*0Sstevel@tonic-gate @_ == 2 || croak 'usage: $ftp->delete( FILENAME )';
676*0Sstevel@tonic-gate
677*0Sstevel@tonic-gate $_[0]->_DELE($_[1]);
678*0Sstevel@tonic-gate}
679*0Sstevel@tonic-gate
680*0Sstevel@tonic-gatesub put        { shift->_store_cmd("stor",@_) }
681*0Sstevel@tonic-gatesub put_unique { shift->_store_cmd("stou",@_) }
682*0Sstevel@tonic-gatesub append     { shift->_store_cmd("appe",@_) }
683*0Sstevel@tonic-gate
684*0Sstevel@tonic-gatesub nlst { shift->_data_cmd("NLST",@_) }
685*0Sstevel@tonic-gatesub list { shift->_data_cmd("LIST",@_) }
686*0Sstevel@tonic-gatesub retr { shift->_data_cmd("RETR",@_) }
687*0Sstevel@tonic-gatesub stor { shift->_data_cmd("STOR",@_) }
688*0Sstevel@tonic-gatesub stou { shift->_data_cmd("STOU",@_) }
689*0Sstevel@tonic-gatesub appe { shift->_data_cmd("APPE",@_) }
690*0Sstevel@tonic-gate
691*0Sstevel@tonic-gatesub _store_cmd
692*0Sstevel@tonic-gate{
693*0Sstevel@tonic-gate my($ftp,$cmd,$local,$remote) = @_;
694*0Sstevel@tonic-gate my($loc,$sock,$len,$buf);
695*0Sstevel@tonic-gate local *FD;
696*0Sstevel@tonic-gate
697*0Sstevel@tonic-gate my $localfd = ref($local) || ref(\$local) eq "GLOB";
698*0Sstevel@tonic-gate
699*0Sstevel@tonic-gate unless(defined $remote)
700*0Sstevel@tonic-gate  {
701*0Sstevel@tonic-gate   croak 'Must specify remote filename with stream input'
702*0Sstevel@tonic-gate	if $localfd;
703*0Sstevel@tonic-gate
704*0Sstevel@tonic-gate   require File::Basename;
705*0Sstevel@tonic-gate   $remote = File::Basename::basename($local);
706*0Sstevel@tonic-gate  }
707*0Sstevel@tonic-gate if( defined ${*$ftp}{'net_ftp_allo'} )
708*0Sstevel@tonic-gate  {
709*0Sstevel@tonic-gate   delete ${*$ftp}{'net_ftp_allo'};
710*0Sstevel@tonic-gate  } else
711*0Sstevel@tonic-gate  {
712*0Sstevel@tonic-gate   # if the user hasn't already invoked the alloc method since the last
713*0Sstevel@tonic-gate   # _store_cmd call, figure out if the local file is a regular file(not
714*0Sstevel@tonic-gate   # a pipe, or device) and if so get the file size from stat, and send
715*0Sstevel@tonic-gate   # an ALLO command before sending the STOR, STOU, or APPE command.
716*0Sstevel@tonic-gate   my $size = -f $local && -s _; # no ALLO if sending data from a pipe
717*0Sstevel@tonic-gate   $ftp->_ALLO($size) if $size;
718*0Sstevel@tonic-gate  }
719*0Sstevel@tonic-gate croak("Bad remote filename '$remote'\n")
720*0Sstevel@tonic-gate	if $remote =~ /[\r\n]/s;
721*0Sstevel@tonic-gate
722*0Sstevel@tonic-gate if($localfd)
723*0Sstevel@tonic-gate  {
724*0Sstevel@tonic-gate   $loc = $local;
725*0Sstevel@tonic-gate  }
726*0Sstevel@tonic-gate else
727*0Sstevel@tonic-gate  {
728*0Sstevel@tonic-gate   $loc = \*FD;
729*0Sstevel@tonic-gate
730*0Sstevel@tonic-gate   unless(sysopen($loc, $local, O_RDONLY))
731*0Sstevel@tonic-gate    {
732*0Sstevel@tonic-gate     carp "Cannot open Local file $local: $!\n";
733*0Sstevel@tonic-gate     return undef;
734*0Sstevel@tonic-gate    }
735*0Sstevel@tonic-gate  }
736*0Sstevel@tonic-gate
737*0Sstevel@tonic-gate if($ftp->type eq 'I' && !binmode($loc))
738*0Sstevel@tonic-gate  {
739*0Sstevel@tonic-gate   carp "Cannot binmode Local file $local: $!\n";
740*0Sstevel@tonic-gate   return undef;
741*0Sstevel@tonic-gate  }
742*0Sstevel@tonic-gate
743*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_port'};
744*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_pasv'};
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gate $sock = $ftp->_data_cmd($cmd, $remote) or
747*0Sstevel@tonic-gate	return undef;
748*0Sstevel@tonic-gate
749*0Sstevel@tonic-gate $remote = ($ftp->message =~ /FILE:\s*(.*)/)[0]
750*0Sstevel@tonic-gate   if 'STOU' eq uc $cmd;
751*0Sstevel@tonic-gate
752*0Sstevel@tonic-gate my $blksize = ${*$ftp}{'net_ftp_blksize'};
753*0Sstevel@tonic-gate
754*0Sstevel@tonic-gate my($count,$hashh,$hashb,$ref) = (0);
755*0Sstevel@tonic-gate
756*0Sstevel@tonic-gate ($hashh,$hashb) = @$ref
757*0Sstevel@tonic-gate   if($ref = ${*$ftp}{'net_ftp_hash'});
758*0Sstevel@tonic-gate
759*0Sstevel@tonic-gate while(1)
760*0Sstevel@tonic-gate  {
761*0Sstevel@tonic-gate   last unless $len = read($loc,$buf="",$blksize);
762*0Sstevel@tonic-gate
763*0Sstevel@tonic-gate   if (trEBCDIC && $ftp->type ne 'I')
764*0Sstevel@tonic-gate    {
765*0Sstevel@tonic-gate     $buf = $ftp->toascii($buf);
766*0Sstevel@tonic-gate     $len = length($buf);
767*0Sstevel@tonic-gate    }
768*0Sstevel@tonic-gate
769*0Sstevel@tonic-gate   if($hashh) {
770*0Sstevel@tonic-gate    $count += $len;
771*0Sstevel@tonic-gate    print $hashh "#" x (int($count / $hashb));
772*0Sstevel@tonic-gate    $count %= $hashb;
773*0Sstevel@tonic-gate   }
774*0Sstevel@tonic-gate
775*0Sstevel@tonic-gate   my $wlen;
776*0Sstevel@tonic-gate   unless(defined($wlen = $sock->write($buf,$len)) && $wlen == $len)
777*0Sstevel@tonic-gate    {
778*0Sstevel@tonic-gate     $sock->abort;
779*0Sstevel@tonic-gate     close($loc)
780*0Sstevel@tonic-gate	unless $localfd;
781*0Sstevel@tonic-gate     print $hashh "\n" if $hashh;
782*0Sstevel@tonic-gate     return undef;
783*0Sstevel@tonic-gate    }
784*0Sstevel@tonic-gate  }
785*0Sstevel@tonic-gate
786*0Sstevel@tonic-gate print $hashh "\n" if $hashh;
787*0Sstevel@tonic-gate
788*0Sstevel@tonic-gate close($loc)
789*0Sstevel@tonic-gate	unless $localfd;
790*0Sstevel@tonic-gate
791*0Sstevel@tonic-gate $sock->close() or
792*0Sstevel@tonic-gate	return undef;
793*0Sstevel@tonic-gate
794*0Sstevel@tonic-gate if ('STOU' eq uc $cmd and $ftp->message =~ m/unique\s+file\s*name\s*:\s*(.*)\)|"(.*)"/)
795*0Sstevel@tonic-gate  {
796*0Sstevel@tonic-gate   require File::Basename;
797*0Sstevel@tonic-gate   $remote = File::Basename::basename($+)
798*0Sstevel@tonic-gate  }
799*0Sstevel@tonic-gate
800*0Sstevel@tonic-gate return $remote;
801*0Sstevel@tonic-gate}
802*0Sstevel@tonic-gate
803*0Sstevel@tonic-gatesub port
804*0Sstevel@tonic-gate{
805*0Sstevel@tonic-gate @_ == 1 || @_ == 2 or croak 'usage: $ftp->port([PORT])';
806*0Sstevel@tonic-gate
807*0Sstevel@tonic-gate my($ftp,$port) = @_;
808*0Sstevel@tonic-gate my $ok;
809*0Sstevel@tonic-gate
810*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_intern_port'};
811*0Sstevel@tonic-gate
812*0Sstevel@tonic-gate unless(defined $port)
813*0Sstevel@tonic-gate  {
814*0Sstevel@tonic-gate   # create a Listen socket at same address as the command socket
815*0Sstevel@tonic-gate
816*0Sstevel@tonic-gate   ${*$ftp}{'net_ftp_listen'} ||= IO::Socket::INET->new(Listen    => 5,
817*0Sstevel@tonic-gate				    	    	        Proto     => 'tcp',
818*0Sstevel@tonic-gate							Timeout   => $ftp->timeout,
819*0Sstevel@tonic-gate							LocalAddr => $ftp->sockhost,
820*0Sstevel@tonic-gate				    	    	       );
821*0Sstevel@tonic-gate
822*0Sstevel@tonic-gate   my $listen = ${*$ftp}{'net_ftp_listen'};
823*0Sstevel@tonic-gate
824*0Sstevel@tonic-gate   my($myport, @myaddr) = ($listen->sockport, split(/\./,$listen->sockhost));
825*0Sstevel@tonic-gate
826*0Sstevel@tonic-gate   $port = join(',', @myaddr, $myport >> 8, $myport & 0xff);
827*0Sstevel@tonic-gate
828*0Sstevel@tonic-gate   ${*$ftp}{'net_ftp_intern_port'} = 1;
829*0Sstevel@tonic-gate  }
830*0Sstevel@tonic-gate
831*0Sstevel@tonic-gate $ok = $ftp->_PORT($port);
832*0Sstevel@tonic-gate
833*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_port'} = $port;
834*0Sstevel@tonic-gate
835*0Sstevel@tonic-gate $ok;
836*0Sstevel@tonic-gate}
837*0Sstevel@tonic-gate
838*0Sstevel@tonic-gatesub ls  { shift->_list_cmd("NLST",@_); }
839*0Sstevel@tonic-gatesub dir { shift->_list_cmd("LIST",@_); }
840*0Sstevel@tonic-gate
841*0Sstevel@tonic-gatesub pasv
842*0Sstevel@tonic-gate{
843*0Sstevel@tonic-gate @_ == 1 or croak 'usage: $ftp->pasv()';
844*0Sstevel@tonic-gate
845*0Sstevel@tonic-gate my $ftp = shift;
846*0Sstevel@tonic-gate
847*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_intern_port'};
848*0Sstevel@tonic-gate
849*0Sstevel@tonic-gate $ftp->_PASV && $ftp->message =~ /(\d+(,\d+)+)/
850*0Sstevel@tonic-gate    ? ${*$ftp}{'net_ftp_pasv'} = $1
851*0Sstevel@tonic-gate    : undef;
852*0Sstevel@tonic-gate}
853*0Sstevel@tonic-gate
854*0Sstevel@tonic-gatesub unique_name
855*0Sstevel@tonic-gate{
856*0Sstevel@tonic-gate my $ftp = shift;
857*0Sstevel@tonic-gate ${*$ftp}{'net_ftp_unique'} || undef;
858*0Sstevel@tonic-gate}
859*0Sstevel@tonic-gate
860*0Sstevel@tonic-gatesub supported {
861*0Sstevel@tonic-gate    @_ == 2 or croak 'usage: $ftp->supported( CMD )';
862*0Sstevel@tonic-gate    my $ftp = shift;
863*0Sstevel@tonic-gate    my $cmd = uc shift;
864*0Sstevel@tonic-gate    my $hash = ${*$ftp}{'net_ftp_supported'} ||= {};
865*0Sstevel@tonic-gate
866*0Sstevel@tonic-gate    return $hash->{$cmd}
867*0Sstevel@tonic-gate        if exists $hash->{$cmd};
868*0Sstevel@tonic-gate
869*0Sstevel@tonic-gate    return $hash->{$cmd} = 0
870*0Sstevel@tonic-gate	unless $ftp->_HELP($cmd);
871*0Sstevel@tonic-gate
872*0Sstevel@tonic-gate    my $text = $ftp->message;
873*0Sstevel@tonic-gate    if($text =~ /following\s+commands/i) {
874*0Sstevel@tonic-gate	$text =~ s/^.*\n//;
875*0Sstevel@tonic-gate        while($text =~ /(\*?)(\w+)(\*?)/sg) {
876*0Sstevel@tonic-gate            $hash->{"\U$2"} = !length("$1$3");
877*0Sstevel@tonic-gate        }
878*0Sstevel@tonic-gate    }
879*0Sstevel@tonic-gate    else {
880*0Sstevel@tonic-gate	$hash->{$cmd} = $text !~ /unimplemented/i;
881*0Sstevel@tonic-gate    }
882*0Sstevel@tonic-gate
883*0Sstevel@tonic-gate    $hash->{$cmd} ||= 0;
884*0Sstevel@tonic-gate}
885*0Sstevel@tonic-gate
886*0Sstevel@tonic-gate##
887*0Sstevel@tonic-gate## Deprecated methods
888*0Sstevel@tonic-gate##
889*0Sstevel@tonic-gate
890*0Sstevel@tonic-gatesub lsl
891*0Sstevel@tonic-gate{
892*0Sstevel@tonic-gate carp "Use of Net::FTP::lsl deprecated, use 'dir'"
893*0Sstevel@tonic-gate    if $^W;
894*0Sstevel@tonic-gate goto &dir;
895*0Sstevel@tonic-gate}
896*0Sstevel@tonic-gate
897*0Sstevel@tonic-gatesub authorise
898*0Sstevel@tonic-gate{
899*0Sstevel@tonic-gate carp "Use of Net::FTP::authorise deprecated, use 'authorize'"
900*0Sstevel@tonic-gate    if $^W;
901*0Sstevel@tonic-gate goto &authorize;
902*0Sstevel@tonic-gate}
903*0Sstevel@tonic-gate
904*0Sstevel@tonic-gate
905*0Sstevel@tonic-gate##
906*0Sstevel@tonic-gate## Private methods
907*0Sstevel@tonic-gate##
908*0Sstevel@tonic-gate
909*0Sstevel@tonic-gatesub _extract_path
910*0Sstevel@tonic-gate{
911*0Sstevel@tonic-gate my($ftp, $path) = @_;
912*0Sstevel@tonic-gate
913*0Sstevel@tonic-gate # This tries to work both with and without the quote doubling
914*0Sstevel@tonic-gate # convention (RFC 959 requires it, but the first 3 servers I checked
915*0Sstevel@tonic-gate # didn't implement it).  It will fail on a server which uses a quote in
916*0Sstevel@tonic-gate # the message which isn't a part of or surrounding the path.
917*0Sstevel@tonic-gate $ftp->ok &&
918*0Sstevel@tonic-gate    $ftp->message =~ /(?:^|\s)\"(.*)\"(?:$|\s)/ &&
919*0Sstevel@tonic-gate    ($path = $1) =~ s/\"\"/\"/g;
920*0Sstevel@tonic-gate
921*0Sstevel@tonic-gate $path;
922*0Sstevel@tonic-gate}
923*0Sstevel@tonic-gate
924*0Sstevel@tonic-gate##
925*0Sstevel@tonic-gate## Communication methods
926*0Sstevel@tonic-gate##
927*0Sstevel@tonic-gate
928*0Sstevel@tonic-gatesub _dataconn
929*0Sstevel@tonic-gate{
930*0Sstevel@tonic-gate my $ftp = shift;
931*0Sstevel@tonic-gate my $data = undef;
932*0Sstevel@tonic-gate my $pkg = "Net::FTP::" . $ftp->type;
933*0Sstevel@tonic-gate
934*0Sstevel@tonic-gate eval "require " . $pkg;
935*0Sstevel@tonic-gate
936*0Sstevel@tonic-gate $pkg =~ s/ /_/g;
937*0Sstevel@tonic-gate
938*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_dataconn'};
939*0Sstevel@tonic-gate
940*0Sstevel@tonic-gate if(defined ${*$ftp}{'net_ftp_pasv'})
941*0Sstevel@tonic-gate  {
942*0Sstevel@tonic-gate   my @port = split(/,/,${*$ftp}{'net_ftp_pasv'});
943*0Sstevel@tonic-gate
944*0Sstevel@tonic-gate   $data = $pkg->new(PeerAddr => join(".",@port[0..3]),
945*0Sstevel@tonic-gate    	    	     PeerPort => $port[4] * 256 + $port[5],
946*0Sstevel@tonic-gate		     LocalAddr => ${*$ftp}{'net_ftp_localaddr'},
947*0Sstevel@tonic-gate    	    	     Proto    => 'tcp'
948*0Sstevel@tonic-gate    	    	    );
949*0Sstevel@tonic-gate  }
950*0Sstevel@tonic-gate elsif(defined ${*$ftp}{'net_ftp_listen'})
951*0Sstevel@tonic-gate  {
952*0Sstevel@tonic-gate   $data = ${*$ftp}{'net_ftp_listen'}->accept($pkg);
953*0Sstevel@tonic-gate   close(delete ${*$ftp}{'net_ftp_listen'});
954*0Sstevel@tonic-gate  }
955*0Sstevel@tonic-gate
956*0Sstevel@tonic-gate if($data)
957*0Sstevel@tonic-gate  {
958*0Sstevel@tonic-gate   ${*$data} = "";
959*0Sstevel@tonic-gate   $data->timeout($ftp->timeout);
960*0Sstevel@tonic-gate   ${*$ftp}{'net_ftp_dataconn'} = $data;
961*0Sstevel@tonic-gate   ${*$data}{'net_ftp_cmd'} = $ftp;
962*0Sstevel@tonic-gate   ${*$data}{'net_ftp_blksize'} = ${*$ftp}{'net_ftp_blksize'};
963*0Sstevel@tonic-gate  }
964*0Sstevel@tonic-gate
965*0Sstevel@tonic-gate $data;
966*0Sstevel@tonic-gate}
967*0Sstevel@tonic-gate
968*0Sstevel@tonic-gatesub _list_cmd
969*0Sstevel@tonic-gate{
970*0Sstevel@tonic-gate my $ftp = shift;
971*0Sstevel@tonic-gate my $cmd = uc shift;
972*0Sstevel@tonic-gate
973*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_port'};
974*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_pasv'};
975*0Sstevel@tonic-gate
976*0Sstevel@tonic-gate my $data = $ftp->_data_cmd($cmd,@_);
977*0Sstevel@tonic-gate
978*0Sstevel@tonic-gate return
979*0Sstevel@tonic-gate	unless(defined $data);
980*0Sstevel@tonic-gate
981*0Sstevel@tonic-gate require Net::FTP::A;
982*0Sstevel@tonic-gate bless $data, "Net::FTP::A"; # Force ASCII mode
983*0Sstevel@tonic-gate
984*0Sstevel@tonic-gate my $databuf = '';
985*0Sstevel@tonic-gate my $buf = '';
986*0Sstevel@tonic-gate my $blksize = ${*$ftp}{'net_ftp_blksize'};
987*0Sstevel@tonic-gate
988*0Sstevel@tonic-gate while($data->read($databuf,$blksize)) {
989*0Sstevel@tonic-gate   $buf .= $databuf;
990*0Sstevel@tonic-gate }
991*0Sstevel@tonic-gate
992*0Sstevel@tonic-gate my $list = [ split(/\n/,$buf) ];
993*0Sstevel@tonic-gate
994*0Sstevel@tonic-gate $data->close();
995*0Sstevel@tonic-gate
996*0Sstevel@tonic-gate if (trEBCDIC)
997*0Sstevel@tonic-gate  {
998*0Sstevel@tonic-gate   for (@$list) { $_ = $ftp->toebcdic($_) }
999*0Sstevel@tonic-gate  }
1000*0Sstevel@tonic-gate
1001*0Sstevel@tonic-gate wantarray ? @{$list}
1002*0Sstevel@tonic-gate           : $list;
1003*0Sstevel@tonic-gate}
1004*0Sstevel@tonic-gate
1005*0Sstevel@tonic-gatesub _data_cmd
1006*0Sstevel@tonic-gate{
1007*0Sstevel@tonic-gate my $ftp = shift;
1008*0Sstevel@tonic-gate my $cmd = uc shift;
1009*0Sstevel@tonic-gate my $ok = 1;
1010*0Sstevel@tonic-gate my $where = delete ${*$ftp}{'net_ftp_rest'} || 0;
1011*0Sstevel@tonic-gate my $arg;
1012*0Sstevel@tonic-gate
1013*0Sstevel@tonic-gate for $arg (@_) {
1014*0Sstevel@tonic-gate   croak("Bad argument '$arg'\n")
1015*0Sstevel@tonic-gate	if $arg =~ /[\r\n]/s;
1016*0Sstevel@tonic-gate }
1017*0Sstevel@tonic-gate
1018*0Sstevel@tonic-gate if(${*$ftp}{'net_ftp_passive'} &&
1019*0Sstevel@tonic-gate     !defined ${*$ftp}{'net_ftp_pasv'} &&
1020*0Sstevel@tonic-gate     !defined ${*$ftp}{'net_ftp_port'})
1021*0Sstevel@tonic-gate  {
1022*0Sstevel@tonic-gate   my $data = undef;
1023*0Sstevel@tonic-gate
1024*0Sstevel@tonic-gate   $ok = defined $ftp->pasv;
1025*0Sstevel@tonic-gate   $ok = $ftp->_REST($where)
1026*0Sstevel@tonic-gate	if $ok && $where;
1027*0Sstevel@tonic-gate
1028*0Sstevel@tonic-gate   if($ok)
1029*0Sstevel@tonic-gate    {
1030*0Sstevel@tonic-gate     $ftp->command($cmd,@_);
1031*0Sstevel@tonic-gate     $data = $ftp->_dataconn();
1032*0Sstevel@tonic-gate     $ok = CMD_INFO == $ftp->response();
1033*0Sstevel@tonic-gate     if($ok)
1034*0Sstevel@tonic-gate      {
1035*0Sstevel@tonic-gate       $data->reading
1036*0Sstevel@tonic-gate         if $data && $cmd =~ /RETR|LIST|NLST/;
1037*0Sstevel@tonic-gate       return $data
1038*0Sstevel@tonic-gate      }
1039*0Sstevel@tonic-gate     $data->_close
1040*0Sstevel@tonic-gate	if $data;
1041*0Sstevel@tonic-gate    }
1042*0Sstevel@tonic-gate   return undef;
1043*0Sstevel@tonic-gate  }
1044*0Sstevel@tonic-gate
1045*0Sstevel@tonic-gate $ok = $ftp->port
1046*0Sstevel@tonic-gate    unless (defined ${*$ftp}{'net_ftp_port'} ||
1047*0Sstevel@tonic-gate            defined ${*$ftp}{'net_ftp_pasv'});
1048*0Sstevel@tonic-gate
1049*0Sstevel@tonic-gate $ok = $ftp->_REST($where)
1050*0Sstevel@tonic-gate    if $ok && $where;
1051*0Sstevel@tonic-gate
1052*0Sstevel@tonic-gate return undef
1053*0Sstevel@tonic-gate    unless $ok;
1054*0Sstevel@tonic-gate
1055*0Sstevel@tonic-gate $ftp->command($cmd,@_);
1056*0Sstevel@tonic-gate
1057*0Sstevel@tonic-gate return 1
1058*0Sstevel@tonic-gate    if(defined ${*$ftp}{'net_ftp_pasv'});
1059*0Sstevel@tonic-gate
1060*0Sstevel@tonic-gate $ok = CMD_INFO == $ftp->response();
1061*0Sstevel@tonic-gate
1062*0Sstevel@tonic-gate return $ok
1063*0Sstevel@tonic-gate    unless exists ${*$ftp}{'net_ftp_intern_port'};
1064*0Sstevel@tonic-gate
1065*0Sstevel@tonic-gate if($ok) {
1066*0Sstevel@tonic-gate   my $data = $ftp->_dataconn();
1067*0Sstevel@tonic-gate
1068*0Sstevel@tonic-gate   $data->reading
1069*0Sstevel@tonic-gate         if $data && $cmd =~ /RETR|LIST|NLST/;
1070*0Sstevel@tonic-gate
1071*0Sstevel@tonic-gate   return $data;
1072*0Sstevel@tonic-gate }
1073*0Sstevel@tonic-gate
1074*0Sstevel@tonic-gate
1075*0Sstevel@tonic-gate close(delete ${*$ftp}{'net_ftp_listen'});
1076*0Sstevel@tonic-gate
1077*0Sstevel@tonic-gate return undef;
1078*0Sstevel@tonic-gate}
1079*0Sstevel@tonic-gate
1080*0Sstevel@tonic-gate##
1081*0Sstevel@tonic-gate## Over-ride methods (Net::Cmd)
1082*0Sstevel@tonic-gate##
1083*0Sstevel@tonic-gate
1084*0Sstevel@tonic-gatesub debug_text { $_[2] =~ /^(pass|resp|acct)/i ? "$1 ....\n" : $_[2]; }
1085*0Sstevel@tonic-gate
1086*0Sstevel@tonic-gatesub command
1087*0Sstevel@tonic-gate{
1088*0Sstevel@tonic-gate my $ftp = shift;
1089*0Sstevel@tonic-gate
1090*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_port'};
1091*0Sstevel@tonic-gate $ftp->SUPER::command(@_);
1092*0Sstevel@tonic-gate}
1093*0Sstevel@tonic-gate
1094*0Sstevel@tonic-gatesub response
1095*0Sstevel@tonic-gate{
1096*0Sstevel@tonic-gate my $ftp = shift;
1097*0Sstevel@tonic-gate my $code = $ftp->SUPER::response();
1098*0Sstevel@tonic-gate
1099*0Sstevel@tonic-gate delete ${*$ftp}{'net_ftp_pasv'}
1100*0Sstevel@tonic-gate    if ($code != CMD_MORE && $code != CMD_INFO);
1101*0Sstevel@tonic-gate
1102*0Sstevel@tonic-gate $code;
1103*0Sstevel@tonic-gate}
1104*0Sstevel@tonic-gate
1105*0Sstevel@tonic-gatesub parse_response
1106*0Sstevel@tonic-gate{
1107*0Sstevel@tonic-gate return ($1, $2 eq "-")
1108*0Sstevel@tonic-gate    if $_[1] =~ s/^(\d\d\d)(.?)//o;
1109*0Sstevel@tonic-gate
1110*0Sstevel@tonic-gate my $ftp = shift;
1111*0Sstevel@tonic-gate
1112*0Sstevel@tonic-gate # Darn MS FTP server is a load of CRAP !!!!
1113*0Sstevel@tonic-gate return ()
1114*0Sstevel@tonic-gate	unless ${*$ftp}{'net_cmd_code'} + 0;
1115*0Sstevel@tonic-gate
1116*0Sstevel@tonic-gate (${*$ftp}{'net_cmd_code'},1);
1117*0Sstevel@tonic-gate}
1118*0Sstevel@tonic-gate
1119*0Sstevel@tonic-gate##
1120*0Sstevel@tonic-gate## Allow 2 servers to talk directly
1121*0Sstevel@tonic-gate##
1122*0Sstevel@tonic-gate
1123*0Sstevel@tonic-gatesub pasv_xfer {
1124*0Sstevel@tonic-gate    my($sftp,$sfile,$dftp,$dfile,$unique) = @_;
1125*0Sstevel@tonic-gate
1126*0Sstevel@tonic-gate    ($dfile = $sfile) =~ s#.*/##
1127*0Sstevel@tonic-gate	unless(defined $dfile);
1128*0Sstevel@tonic-gate
1129*0Sstevel@tonic-gate    my $port = $sftp->pasv or
1130*0Sstevel@tonic-gate	return undef;
1131*0Sstevel@tonic-gate
1132*0Sstevel@tonic-gate    $dftp->port($port) or
1133*0Sstevel@tonic-gate	return undef;
1134*0Sstevel@tonic-gate
1135*0Sstevel@tonic-gate    return undef
1136*0Sstevel@tonic-gate	unless($unique ? $dftp->stou($dfile) : $dftp->stor($dfile));
1137*0Sstevel@tonic-gate
1138*0Sstevel@tonic-gate    unless($sftp->retr($sfile) && $sftp->response == CMD_INFO) {
1139*0Sstevel@tonic-gate	$sftp->retr($sfile);
1140*0Sstevel@tonic-gate	$dftp->abort;
1141*0Sstevel@tonic-gate	$dftp->response();
1142*0Sstevel@tonic-gate	return undef;
1143*0Sstevel@tonic-gate    }
1144*0Sstevel@tonic-gate
1145*0Sstevel@tonic-gate    $dftp->pasv_wait($sftp);
1146*0Sstevel@tonic-gate}
1147*0Sstevel@tonic-gate
1148*0Sstevel@tonic-gatesub pasv_wait
1149*0Sstevel@tonic-gate{
1150*0Sstevel@tonic-gate @_ == 2 or croak 'usage: $ftp->pasv_wait(NON_PASV_FTP)';
1151*0Sstevel@tonic-gate
1152*0Sstevel@tonic-gate my($ftp, $non_pasv) = @_;
1153*0Sstevel@tonic-gate my($file,$rin,$rout);
1154*0Sstevel@tonic-gate
1155*0Sstevel@tonic-gate vec($rin='',fileno($ftp),1) = 1;
1156*0Sstevel@tonic-gate select($rout=$rin, undef, undef, undef);
1157*0Sstevel@tonic-gate
1158*0Sstevel@tonic-gate $ftp->response();
1159*0Sstevel@tonic-gate $non_pasv->response();
1160*0Sstevel@tonic-gate
1161*0Sstevel@tonic-gate return undef
1162*0Sstevel@tonic-gate	unless $ftp->ok() && $non_pasv->ok();
1163*0Sstevel@tonic-gate
1164*0Sstevel@tonic-gate return $1
1165*0Sstevel@tonic-gate	if $ftp->message =~ /unique file name:\s*(\S*)\s*\)/;
1166*0Sstevel@tonic-gate
1167*0Sstevel@tonic-gate return $1
1168*0Sstevel@tonic-gate	if $non_pasv->message =~ /unique file name:\s*(\S*)\s*\)/;
1169*0Sstevel@tonic-gate
1170*0Sstevel@tonic-gate return 1;
1171*0Sstevel@tonic-gate}
1172*0Sstevel@tonic-gate
1173*0Sstevel@tonic-gatesub cmd { shift->command(@_)->response() }
1174*0Sstevel@tonic-gate
1175*0Sstevel@tonic-gate########################################
1176*0Sstevel@tonic-gate#
1177*0Sstevel@tonic-gate# RFC959 commands
1178*0Sstevel@tonic-gate#
1179*0Sstevel@tonic-gate
1180*0Sstevel@tonic-gatesub _ABOR { shift->command("ABOR")->response()	 == CMD_OK }
1181*0Sstevel@tonic-gatesub _ALLO { shift->command("ALLO",@_)->response() == CMD_OK}
1182*0Sstevel@tonic-gatesub _CDUP { shift->command("CDUP")->response()	 == CMD_OK }
1183*0Sstevel@tonic-gatesub _NOOP { shift->command("NOOP")->response()	 == CMD_OK }
1184*0Sstevel@tonic-gatesub _PASV { shift->command("PASV")->response()	 == CMD_OK }
1185*0Sstevel@tonic-gatesub _QUIT { shift->command("QUIT")->response()	 == CMD_OK }
1186*0Sstevel@tonic-gatesub _DELE { shift->command("DELE",@_)->response() == CMD_OK }
1187*0Sstevel@tonic-gatesub _CWD  { shift->command("CWD", @_)->response() == CMD_OK }
1188*0Sstevel@tonic-gatesub _PORT { shift->command("PORT",@_)->response() == CMD_OK }
1189*0Sstevel@tonic-gatesub _RMD  { shift->command("RMD", @_)->response() == CMD_OK }
1190*0Sstevel@tonic-gatesub _MKD  { shift->command("MKD", @_)->response() == CMD_OK }
1191*0Sstevel@tonic-gatesub _PWD  { shift->command("PWD", @_)->response() == CMD_OK }
1192*0Sstevel@tonic-gatesub _TYPE { shift->command("TYPE",@_)->response() == CMD_OK }
1193*0Sstevel@tonic-gatesub _RNTO { shift->command("RNTO",@_)->response() == CMD_OK }
1194*0Sstevel@tonic-gatesub _RESP { shift->command("RESP",@_)->response() == CMD_OK }
1195*0Sstevel@tonic-gatesub _MDTM { shift->command("MDTM",@_)->response() == CMD_OK }
1196*0Sstevel@tonic-gatesub _SIZE { shift->command("SIZE",@_)->response() == CMD_OK }
1197*0Sstevel@tonic-gatesub _HELP { shift->command("HELP",@_)->response() == CMD_OK }
1198*0Sstevel@tonic-gatesub _STAT { shift->command("STAT",@_)->response() == CMD_OK }
1199*0Sstevel@tonic-gatesub _APPE { shift->command("APPE",@_)->response() == CMD_INFO }
1200*0Sstevel@tonic-gatesub _LIST { shift->command("LIST",@_)->response() == CMD_INFO }
1201*0Sstevel@tonic-gatesub _NLST { shift->command("NLST",@_)->response() == CMD_INFO }
1202*0Sstevel@tonic-gatesub _RETR { shift->command("RETR",@_)->response() == CMD_INFO }
1203*0Sstevel@tonic-gatesub _STOR { shift->command("STOR",@_)->response() == CMD_INFO }
1204*0Sstevel@tonic-gatesub _STOU { shift->command("STOU",@_)->response() == CMD_INFO }
1205*0Sstevel@tonic-gatesub _RNFR { shift->command("RNFR",@_)->response() == CMD_MORE }
1206*0Sstevel@tonic-gatesub _REST { shift->command("REST",@_)->response() == CMD_MORE }
1207*0Sstevel@tonic-gatesub _USER { shift->command("user",@_)->response() } # A certain brain dead firewall :-)
1208*0Sstevel@tonic-gatesub _PASS { shift->command("PASS",@_)->response() }
1209*0Sstevel@tonic-gatesub _ACCT { shift->command("ACCT",@_)->response() }
1210*0Sstevel@tonic-gatesub _AUTH { shift->command("AUTH",@_)->response() }
1211*0Sstevel@tonic-gate
1212*0Sstevel@tonic-gatesub _SMNT { shift->unsupported(@_) }
1213*0Sstevel@tonic-gatesub _MODE { shift->unsupported(@_) }
1214*0Sstevel@tonic-gatesub _SYST { shift->unsupported(@_) }
1215*0Sstevel@tonic-gatesub _STRU { shift->unsupported(@_) }
1216*0Sstevel@tonic-gatesub _REIN { shift->unsupported(@_) }
1217*0Sstevel@tonic-gate
1218*0Sstevel@tonic-gate1;
1219*0Sstevel@tonic-gate
1220*0Sstevel@tonic-gate__END__
1221*0Sstevel@tonic-gate
1222*0Sstevel@tonic-gate=head1 NAME
1223*0Sstevel@tonic-gate
1224*0Sstevel@tonic-gateNet::FTP - FTP Client class
1225*0Sstevel@tonic-gate
1226*0Sstevel@tonic-gate=head1 SYNOPSIS
1227*0Sstevel@tonic-gate
1228*0Sstevel@tonic-gate    use Net::FTP;
1229*0Sstevel@tonic-gate
1230*0Sstevel@tonic-gate    $ftp = Net::FTP->new("some.host.name", Debug => 0)
1231*0Sstevel@tonic-gate      or die "Cannot connect to some.host.name: $@";
1232*0Sstevel@tonic-gate
1233*0Sstevel@tonic-gate    $ftp->login("anonymous",'-anonymous@')
1234*0Sstevel@tonic-gate      or die "Cannot login ", $ftp->message;
1235*0Sstevel@tonic-gate
1236*0Sstevel@tonic-gate    $ftp->cwd("/pub")
1237*0Sstevel@tonic-gate      or die "Cannot change working directory ", $ftp->message;
1238*0Sstevel@tonic-gate
1239*0Sstevel@tonic-gate    $ftp->get("that.file")
1240*0Sstevel@tonic-gate      or die "get failed ", $ftp->message;
1241*0Sstevel@tonic-gate
1242*0Sstevel@tonic-gate    $ftp->quit;
1243*0Sstevel@tonic-gate
1244*0Sstevel@tonic-gate=head1 DESCRIPTION
1245*0Sstevel@tonic-gate
1246*0Sstevel@tonic-gateC<Net::FTP> is a class implementing a simple FTP client in Perl as
1247*0Sstevel@tonic-gatedescribed in RFC959.  It provides wrappers for a subset of the RFC959
1248*0Sstevel@tonic-gatecommands.
1249*0Sstevel@tonic-gate
1250*0Sstevel@tonic-gate=head1 OVERVIEW
1251*0Sstevel@tonic-gate
1252*0Sstevel@tonic-gateFTP stands for File Transfer Protocol.  It is a way of transferring
1253*0Sstevel@tonic-gatefiles between networked machines.  The protocol defines a client
1254*0Sstevel@tonic-gate(whose commands are provided by this module) and a server (not
1255*0Sstevel@tonic-gateimplemented in this module).  Communication is always initiated by the
1256*0Sstevel@tonic-gateclient, and the server responds with a message and a status code (and
1257*0Sstevel@tonic-gatesometimes with data).
1258*0Sstevel@tonic-gate
1259*0Sstevel@tonic-gateThe FTP protocol allows files to be sent to or fetched from the
1260*0Sstevel@tonic-gateserver.  Each transfer involves a B<local file> (on the client) and a
1261*0Sstevel@tonic-gateB<remote file> (on the server).  In this module, the same file name
1262*0Sstevel@tonic-gatewill be used for both local and remote if only one is specified.  This
1263*0Sstevel@tonic-gatemeans that transferring remote file C</path/to/file> will try to put
1264*0Sstevel@tonic-gatethat file in C</path/to/file> locally, unless you specify a local file
1265*0Sstevel@tonic-gatename.
1266*0Sstevel@tonic-gate
1267*0Sstevel@tonic-gateThe protocol also defines several standard B<translations> which the
1268*0Sstevel@tonic-gatefile can undergo during transfer.  These are ASCII, EBCDIC, binary,
1269*0Sstevel@tonic-gateand byte.  ASCII is the default type, and indicates that the sender of
1270*0Sstevel@tonic-gatefiles will translate the ends of lines to a standard representation
1271*0Sstevel@tonic-gatewhich the receiver will then translate back into their local
1272*0Sstevel@tonic-gaterepresentation.  EBCDIC indicates the file being transferred is in
1273*0Sstevel@tonic-gateEBCDIC format.  Binary (also known as image) format sends the data as
1274*0Sstevel@tonic-gatea contiguous bit stream.  Byte format transfers the data as bytes, the
1275*0Sstevel@tonic-gatevalues of which remain the same regardless of differences in byte size
1276*0Sstevel@tonic-gatebetween the two machines (in theory - in practice you should only use
1277*0Sstevel@tonic-gatethis if you really know what you're doing).
1278*0Sstevel@tonic-gate
1279*0Sstevel@tonic-gate=head1 CONSTRUCTOR
1280*0Sstevel@tonic-gate
1281*0Sstevel@tonic-gate=over 4
1282*0Sstevel@tonic-gate
1283*0Sstevel@tonic-gate=item new (HOST [,OPTIONS])
1284*0Sstevel@tonic-gate
1285*0Sstevel@tonic-gateThis is the constructor for a new Net::FTP object. C<HOST> is the
1286*0Sstevel@tonic-gatename of the remote host to which an FTP connection is required.
1287*0Sstevel@tonic-gate
1288*0Sstevel@tonic-gateC<OPTIONS> are passed in a hash like fashion, using key and value pairs.
1289*0Sstevel@tonic-gatePossible options are:
1290*0Sstevel@tonic-gate
1291*0Sstevel@tonic-gateB<Firewall> - The name of a machine which acts as an FTP firewall. This can be
1292*0Sstevel@tonic-gateoverridden by an environment variable C<FTP_FIREWALL>. If specified, and the
1293*0Sstevel@tonic-gategiven host cannot be directly connected to, then the
1294*0Sstevel@tonic-gateconnection is made to the firewall machine and the string C<@hostname> is
1295*0Sstevel@tonic-gateappended to the login identifier. This kind of setup is also refered to
1296*0Sstevel@tonic-gateas an ftp proxy.
1297*0Sstevel@tonic-gate
1298*0Sstevel@tonic-gateB<FirewallType> - The type of firewall running on the machine indicated by
1299*0Sstevel@tonic-gateB<Firewall>. This can be overridden by an environment variable
1300*0Sstevel@tonic-gateC<FTP_FIREWALL_TYPE>. For a list of permissible types, see the description of
1301*0Sstevel@tonic-gateftp_firewall_type in L<Net::Config>.
1302*0Sstevel@tonic-gate
1303*0Sstevel@tonic-gateB<BlockSize> - This is the block size that Net::FTP will use when doing
1304*0Sstevel@tonic-gatetransfers. (defaults to 10240)
1305*0Sstevel@tonic-gate
1306*0Sstevel@tonic-gateB<Port> - The port number to connect to on the remote machine for the
1307*0Sstevel@tonic-gateFTP connection
1308*0Sstevel@tonic-gate
1309*0Sstevel@tonic-gateB<Timeout> - Set a timeout value (defaults to 120)
1310*0Sstevel@tonic-gate
1311*0Sstevel@tonic-gateB<Debug> - debug level (see the debug method in L<Net::Cmd>)
1312*0Sstevel@tonic-gate
1313*0Sstevel@tonic-gateB<Passive> - If set to a non-zero value then all data transfers will be done
1314*0Sstevel@tonic-gateusing passive mode. This is not usually required except for some I<dumb>
1315*0Sstevel@tonic-gateservers, and some firewall configurations. This can also be set by the
1316*0Sstevel@tonic-gateenvironment variable C<FTP_PASSIVE>.
1317*0Sstevel@tonic-gate
1318*0Sstevel@tonic-gateB<Hash> - If given a reference to a file handle (e.g., C<\*STDERR>),
1319*0Sstevel@tonic-gateprint hash marks (#) on that filehandle every 1024 bytes.  This
1320*0Sstevel@tonic-gatesimply invokes the C<hash()> method for you, so that hash marks
1321*0Sstevel@tonic-gateare displayed for all transfers.  You can, of course, call C<hash()>
1322*0Sstevel@tonic-gateexplicitly whenever you'd like.
1323*0Sstevel@tonic-gate
1324*0Sstevel@tonic-gateB<LocalAddr> - Local address to use for all socket connections, this
1325*0Sstevel@tonic-gateargument will be passed to L<IO::Socket::INET>
1326*0Sstevel@tonic-gate
1327*0Sstevel@tonic-gateIf the constructor fails undef will be returned and an error message will
1328*0Sstevel@tonic-gatebe in $@
1329*0Sstevel@tonic-gate
1330*0Sstevel@tonic-gate=back
1331*0Sstevel@tonic-gate
1332*0Sstevel@tonic-gate=head1 METHODS
1333*0Sstevel@tonic-gate
1334*0Sstevel@tonic-gateUnless otherwise stated all methods return either a I<true> or I<false>
1335*0Sstevel@tonic-gatevalue, with I<true> meaning that the operation was a success. When a method
1336*0Sstevel@tonic-gatestates that it returns a value, failure will be returned as I<undef> or an
1337*0Sstevel@tonic-gateempty list.
1338*0Sstevel@tonic-gate
1339*0Sstevel@tonic-gate=over 4
1340*0Sstevel@tonic-gate
1341*0Sstevel@tonic-gate=item login ([LOGIN [,PASSWORD [, ACCOUNT] ] ])
1342*0Sstevel@tonic-gate
1343*0Sstevel@tonic-gateLog into the remote FTP server with the given login information. If
1344*0Sstevel@tonic-gateno arguments are given then the C<Net::FTP> uses the C<Net::Netrc>
1345*0Sstevel@tonic-gatepackage to lookup the login information for the connected host.
1346*0Sstevel@tonic-gateIf no information is found then a login of I<anonymous> is used.
1347*0Sstevel@tonic-gateIf no password is given and the login is I<anonymous> then I<anonymous@>
1348*0Sstevel@tonic-gatewill be used for password.
1349*0Sstevel@tonic-gate
1350*0Sstevel@tonic-gateIf the connection is via a firewall then the C<authorize> method will
1351*0Sstevel@tonic-gatebe called with no arguments.
1352*0Sstevel@tonic-gate
1353*0Sstevel@tonic-gate=item authorize ( [AUTH [, RESP]])
1354*0Sstevel@tonic-gate
1355*0Sstevel@tonic-gateThis is a protocol used by some firewall ftp proxies. It is used
1356*0Sstevel@tonic-gateto authorise the user to send data out.  If both arguments are not specified
1357*0Sstevel@tonic-gatethen C<authorize> uses C<Net::Netrc> to do a lookup.
1358*0Sstevel@tonic-gate
1359*0Sstevel@tonic-gate=item site (ARGS)
1360*0Sstevel@tonic-gate
1361*0Sstevel@tonic-gateSend a SITE command to the remote server and wait for a response.
1362*0Sstevel@tonic-gate
1363*0Sstevel@tonic-gateReturns most significant digit of the response code.
1364*0Sstevel@tonic-gate
1365*0Sstevel@tonic-gate=item ascii
1366*0Sstevel@tonic-gate
1367*0Sstevel@tonic-gateTransfer file in ASCII. CRLF translation will be done if required
1368*0Sstevel@tonic-gate
1369*0Sstevel@tonic-gate=item binary
1370*0Sstevel@tonic-gate
1371*0Sstevel@tonic-gateTransfer file in binary mode. No transformation will be done.
1372*0Sstevel@tonic-gate
1373*0Sstevel@tonic-gateB<Hint>: If both server and client machines use the same line ending for
1374*0Sstevel@tonic-gatetext files, then it will be faster to transfer all files in binary mode.
1375*0Sstevel@tonic-gate
1376*0Sstevel@tonic-gate=item rename ( OLDNAME, NEWNAME )
1377*0Sstevel@tonic-gate
1378*0Sstevel@tonic-gateRename a file on the remote FTP server from C<OLDNAME> to C<NEWNAME>. This
1379*0Sstevel@tonic-gateis done by sending the RNFR and RNTO commands.
1380*0Sstevel@tonic-gate
1381*0Sstevel@tonic-gate=item delete ( FILENAME )
1382*0Sstevel@tonic-gate
1383*0Sstevel@tonic-gateSend a request to the server to delete C<FILENAME>.
1384*0Sstevel@tonic-gate
1385*0Sstevel@tonic-gate=item cwd ( [ DIR ] )
1386*0Sstevel@tonic-gate
1387*0Sstevel@tonic-gateAttempt to change directory to the directory given in C<$dir>.  If
1388*0Sstevel@tonic-gateC<$dir> is C<"..">, the FTP C<CDUP> command is used to attempt to
1389*0Sstevel@tonic-gatemove up one directory. If no directory is given then an attempt is made
1390*0Sstevel@tonic-gateto change the directory to the root directory.
1391*0Sstevel@tonic-gate
1392*0Sstevel@tonic-gate=item cdup ()
1393*0Sstevel@tonic-gate
1394*0Sstevel@tonic-gateChange directory to the parent of the current directory.
1395*0Sstevel@tonic-gate
1396*0Sstevel@tonic-gate=item pwd ()
1397*0Sstevel@tonic-gate
1398*0Sstevel@tonic-gateReturns the full pathname of the current directory.
1399*0Sstevel@tonic-gate
1400*0Sstevel@tonic-gate=item restart ( WHERE )
1401*0Sstevel@tonic-gate
1402*0Sstevel@tonic-gateSet the byte offset at which to begin the next data transfer. Net::FTP simply
1403*0Sstevel@tonic-gaterecords this value and uses it when during the next data transfer. For this
1404*0Sstevel@tonic-gatereason this method will not return an error, but setting it may cause
1405*0Sstevel@tonic-gatea subsequent data transfer to fail.
1406*0Sstevel@tonic-gate
1407*0Sstevel@tonic-gate=item rmdir ( DIR [, RECURSE ])
1408*0Sstevel@tonic-gate
1409*0Sstevel@tonic-gateRemove the directory with the name C<DIR>. If C<RECURSE> is I<true> then
1410*0Sstevel@tonic-gateC<rmdir> will attempt to delete everything inside the directory.
1411*0Sstevel@tonic-gate
1412*0Sstevel@tonic-gate=item mkdir ( DIR [, RECURSE ])
1413*0Sstevel@tonic-gate
1414*0Sstevel@tonic-gateCreate a new directory with the name C<DIR>. If C<RECURSE> is I<true> then
1415*0Sstevel@tonic-gateC<mkdir> will attempt to create all the directories in the given path.
1416*0Sstevel@tonic-gate
1417*0Sstevel@tonic-gateReturns the full pathname to the new directory.
1418*0Sstevel@tonic-gate
1419*0Sstevel@tonic-gate=item ls ( [ DIR ] )
1420*0Sstevel@tonic-gate
1421*0Sstevel@tonic-gate=item alloc ( SIZE [, RECORD_SIZE] )
1422*0Sstevel@tonic-gate
1423*0Sstevel@tonic-gateThe alloc command allows you to give the ftp server a hint about the size
1424*0Sstevel@tonic-gateof the file about to be transfered using the ALLO ftp command. Some storage
1425*0Sstevel@tonic-gatesystems use this to make intelligent decisions about how to store the file.
1426*0Sstevel@tonic-gateThe C<SIZE> argument represents the size of the file in bytes. The
1427*0Sstevel@tonic-gateC<RECORD_SIZE> argument indicates a mazimum record or page size for files
1428*0Sstevel@tonic-gatesent with a record or page structure.
1429*0Sstevel@tonic-gate
1430*0Sstevel@tonic-gateThe size of the file will be determined, and sent to the server
1431*0Sstevel@tonic-gateautomatically for normal files so that this method need only be called if
1432*0Sstevel@tonic-gateyou are transfering data from a socket, named pipe, or other stream not
1433*0Sstevel@tonic-gateassociated with a normal file.
1434*0Sstevel@tonic-gate
1435*0Sstevel@tonic-gateGet a directory listing of C<DIR>, or the current directory.
1436*0Sstevel@tonic-gate
1437*0Sstevel@tonic-gateIn an array context, returns a list of lines returned from the server. In
1438*0Sstevel@tonic-gatea scalar context, returns a reference to a list.
1439*0Sstevel@tonic-gate
1440*0Sstevel@tonic-gate=item dir ( [ DIR ] )
1441*0Sstevel@tonic-gate
1442*0Sstevel@tonic-gateGet a directory listing of C<DIR>, or the current directory in long format.
1443*0Sstevel@tonic-gate
1444*0Sstevel@tonic-gateIn an array context, returns a list of lines returned from the server. In
1445*0Sstevel@tonic-gatea scalar context, returns a reference to a list.
1446*0Sstevel@tonic-gate
1447*0Sstevel@tonic-gate=item get ( REMOTE_FILE [, LOCAL_FILE [, WHERE]] )
1448*0Sstevel@tonic-gate
1449*0Sstevel@tonic-gateGet C<REMOTE_FILE> from the server and store locally. C<LOCAL_FILE> may be
1450*0Sstevel@tonic-gatea filename or a filehandle. If not specified, the file will be stored in
1451*0Sstevel@tonic-gatethe current directory with the same leafname as the remote file.
1452*0Sstevel@tonic-gate
1453*0Sstevel@tonic-gateIf C<WHERE> is given then the first C<WHERE> bytes of the file will
1454*0Sstevel@tonic-gatenot be transfered, and the remaining bytes will be appended to
1455*0Sstevel@tonic-gatethe local file if it already exists.
1456*0Sstevel@tonic-gate
1457*0Sstevel@tonic-gateReturns C<LOCAL_FILE>, or the generated local file name if C<LOCAL_FILE>
1458*0Sstevel@tonic-gateis not given. If an error was encountered undef is returned.
1459*0Sstevel@tonic-gate
1460*0Sstevel@tonic-gate=item put ( LOCAL_FILE [, REMOTE_FILE ] )
1461*0Sstevel@tonic-gate
1462*0Sstevel@tonic-gatePut a file on the remote server. C<LOCAL_FILE> may be a name or a filehandle.
1463*0Sstevel@tonic-gateIf C<LOCAL_FILE> is a filehandle then C<REMOTE_FILE> must be specified. If
1464*0Sstevel@tonic-gateC<REMOTE_FILE> is not specified then the file will be stored in the current
1465*0Sstevel@tonic-gatedirectory with the same leafname as C<LOCAL_FILE>.
1466*0Sstevel@tonic-gate
1467*0Sstevel@tonic-gateReturns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE>
1468*0Sstevel@tonic-gateis not given.
1469*0Sstevel@tonic-gate
1470*0Sstevel@tonic-gateB<NOTE>: If for some reason the transfer does not complete and an error is
1471*0Sstevel@tonic-gatereturned then the contents that had been transfered will not be remove
1472*0Sstevel@tonic-gateautomatically.
1473*0Sstevel@tonic-gate
1474*0Sstevel@tonic-gate=item put_unique ( LOCAL_FILE [, REMOTE_FILE ] )
1475*0Sstevel@tonic-gate
1476*0Sstevel@tonic-gateSame as put but uses the C<STOU> command.
1477*0Sstevel@tonic-gate
1478*0Sstevel@tonic-gateReturns the name of the file on the server.
1479*0Sstevel@tonic-gate
1480*0Sstevel@tonic-gate=item append ( LOCAL_FILE [, REMOTE_FILE ] )
1481*0Sstevel@tonic-gate
1482*0Sstevel@tonic-gateSame as put but appends to the file on the remote server.
1483*0Sstevel@tonic-gate
1484*0Sstevel@tonic-gateReturns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE>
1485*0Sstevel@tonic-gateis not given.
1486*0Sstevel@tonic-gate
1487*0Sstevel@tonic-gate=item unique_name ()
1488*0Sstevel@tonic-gate
1489*0Sstevel@tonic-gateReturns the name of the last file stored on the server using the
1490*0Sstevel@tonic-gateC<STOU> command.
1491*0Sstevel@tonic-gate
1492*0Sstevel@tonic-gate=item mdtm ( FILE )
1493*0Sstevel@tonic-gate
1494*0Sstevel@tonic-gateReturns the I<modification time> of the given file
1495*0Sstevel@tonic-gate
1496*0Sstevel@tonic-gate=item size ( FILE )
1497*0Sstevel@tonic-gate
1498*0Sstevel@tonic-gateReturns the size in bytes for the given file as stored on the remote server.
1499*0Sstevel@tonic-gate
1500*0Sstevel@tonic-gateB<NOTE>: The size reported is the size of the stored file on the remote server.
1501*0Sstevel@tonic-gateIf the file is subsequently transfered from the server in ASCII mode
1502*0Sstevel@tonic-gateand the remote server and local machine have different ideas about
1503*0Sstevel@tonic-gate"End Of Line" then the size of file on the local machine after transfer
1504*0Sstevel@tonic-gatemay be different.
1505*0Sstevel@tonic-gate
1506*0Sstevel@tonic-gate=item supported ( CMD )
1507*0Sstevel@tonic-gate
1508*0Sstevel@tonic-gateReturns TRUE if the remote server supports the given command.
1509*0Sstevel@tonic-gate
1510*0Sstevel@tonic-gate=item hash ( [FILEHANDLE_GLOB_REF],[ BYTES_PER_HASH_MARK] )
1511*0Sstevel@tonic-gate
1512*0Sstevel@tonic-gateCalled without parameters, or with the first argument false, hash marks
1513*0Sstevel@tonic-gateare suppressed.  If the first argument is true but not a reference to a
1514*0Sstevel@tonic-gatefile handle glob, then \*STDERR is used.  The second argument is the number
1515*0Sstevel@tonic-gateof bytes per hash mark printed, and defaults to 1024.  In all cases the
1516*0Sstevel@tonic-gatereturn value is a reference to an array of two:  the filehandle glob reference
1517*0Sstevel@tonic-gateand the bytes per hash mark.
1518*0Sstevel@tonic-gate
1519*0Sstevel@tonic-gate=back
1520*0Sstevel@tonic-gate
1521*0Sstevel@tonic-gateThe following methods can return different results depending on
1522*0Sstevel@tonic-gatehow they are called. If the user explicitly calls either
1523*0Sstevel@tonic-gateof the C<pasv> or C<port> methods then these methods will
1524*0Sstevel@tonic-gatereturn a I<true> or I<false> value. If the user does not
1525*0Sstevel@tonic-gatecall either of these methods then the result will be a
1526*0Sstevel@tonic-gatereference to a C<Net::FTP::dataconn> based object.
1527*0Sstevel@tonic-gate
1528*0Sstevel@tonic-gate=over 4
1529*0Sstevel@tonic-gate
1530*0Sstevel@tonic-gate=item nlst ( [ DIR ] )
1531*0Sstevel@tonic-gate
1532*0Sstevel@tonic-gateSend an C<NLST> command to the server, with an optional parameter.
1533*0Sstevel@tonic-gate
1534*0Sstevel@tonic-gate=item list ( [ DIR ] )
1535*0Sstevel@tonic-gate
1536*0Sstevel@tonic-gateSame as C<nlst> but using the C<LIST> command
1537*0Sstevel@tonic-gate
1538*0Sstevel@tonic-gate=item retr ( FILE )
1539*0Sstevel@tonic-gate
1540*0Sstevel@tonic-gateBegin the retrieval of a file called C<FILE> from the remote server.
1541*0Sstevel@tonic-gate
1542*0Sstevel@tonic-gate=item stor ( FILE )
1543*0Sstevel@tonic-gate
1544*0Sstevel@tonic-gateTell the server that you wish to store a file. C<FILE> is the
1545*0Sstevel@tonic-gatename of the new file that should be created.
1546*0Sstevel@tonic-gate
1547*0Sstevel@tonic-gate=item stou ( FILE )
1548*0Sstevel@tonic-gate
1549*0Sstevel@tonic-gateSame as C<stor> but using the C<STOU> command. The name of the unique
1550*0Sstevel@tonic-gatefile which was created on the server will be available via the C<unique_name>
1551*0Sstevel@tonic-gatemethod after the data connection has been closed.
1552*0Sstevel@tonic-gate
1553*0Sstevel@tonic-gate=item appe ( FILE )
1554*0Sstevel@tonic-gate
1555*0Sstevel@tonic-gateTell the server that we want to append some data to the end of a file
1556*0Sstevel@tonic-gatecalled C<FILE>. If this file does not exist then create it.
1557*0Sstevel@tonic-gate
1558*0Sstevel@tonic-gate=back
1559*0Sstevel@tonic-gate
1560*0Sstevel@tonic-gateIf for some reason you want to have complete control over the data connection,
1561*0Sstevel@tonic-gatethis includes generating it and calling the C<response> method when required,
1562*0Sstevel@tonic-gatethen the user can use these methods to do so.
1563*0Sstevel@tonic-gate
1564*0Sstevel@tonic-gateHowever calling these methods only affects the use of the methods above that
1565*0Sstevel@tonic-gatecan return a data connection. They have no effect on methods C<get>, C<put>,
1566*0Sstevel@tonic-gateC<put_unique> and those that do not require data connections.
1567*0Sstevel@tonic-gate
1568*0Sstevel@tonic-gate=over 4
1569*0Sstevel@tonic-gate
1570*0Sstevel@tonic-gate=item port ( [ PORT ] )
1571*0Sstevel@tonic-gate
1572*0Sstevel@tonic-gateSend a C<PORT> command to the server. If C<PORT> is specified then it is sent
1573*0Sstevel@tonic-gateto the server. If not, then a listen socket is created and the correct information
1574*0Sstevel@tonic-gatesent to the server.
1575*0Sstevel@tonic-gate
1576*0Sstevel@tonic-gate=item pasv ()
1577*0Sstevel@tonic-gate
1578*0Sstevel@tonic-gateTell the server to go into passive mode. Returns the text that represents the
1579*0Sstevel@tonic-gateport on which the server is listening, this text is in a suitable form to
1580*0Sstevel@tonic-gatesent to another ftp server using the C<port> method.
1581*0Sstevel@tonic-gate
1582*0Sstevel@tonic-gate=back
1583*0Sstevel@tonic-gate
1584*0Sstevel@tonic-gateThe following methods can be used to transfer files between two remote
1585*0Sstevel@tonic-gateservers, providing that these two servers can connect directly to each other.
1586*0Sstevel@tonic-gate
1587*0Sstevel@tonic-gate=over 4
1588*0Sstevel@tonic-gate
1589*0Sstevel@tonic-gate=item pasv_xfer ( SRC_FILE, DEST_SERVER [, DEST_FILE ] )
1590*0Sstevel@tonic-gate
1591*0Sstevel@tonic-gateThis method will do a file transfer between two remote ftp servers. If
1592*0Sstevel@tonic-gateC<DEST_FILE> is omitted then the leaf name of C<SRC_FILE> will be used.
1593*0Sstevel@tonic-gate
1594*0Sstevel@tonic-gate=item pasv_xfer_unique ( SRC_FILE, DEST_SERVER [, DEST_FILE ] )
1595*0Sstevel@tonic-gate
1596*0Sstevel@tonic-gateLike C<pasv_xfer> but the file is stored on the remote server using
1597*0Sstevel@tonic-gatethe STOU command.
1598*0Sstevel@tonic-gate
1599*0Sstevel@tonic-gate=item pasv_wait ( NON_PASV_SERVER )
1600*0Sstevel@tonic-gate
1601*0Sstevel@tonic-gateThis method can be used to wait for a transfer to complete between a passive
1602*0Sstevel@tonic-gateserver and a non-passive server. The method should be called on the passive
1603*0Sstevel@tonic-gateserver with the C<Net::FTP> object for the non-passive server passed as an
1604*0Sstevel@tonic-gateargument.
1605*0Sstevel@tonic-gate
1606*0Sstevel@tonic-gate=item abort ()
1607*0Sstevel@tonic-gate
1608*0Sstevel@tonic-gateAbort the current data transfer.
1609*0Sstevel@tonic-gate
1610*0Sstevel@tonic-gate=item quit ()
1611*0Sstevel@tonic-gate
1612*0Sstevel@tonic-gateSend the QUIT command to the remote FTP server and close the socket connection.
1613*0Sstevel@tonic-gate
1614*0Sstevel@tonic-gate=back
1615*0Sstevel@tonic-gate
1616*0Sstevel@tonic-gate=head2 Methods for the adventurous
1617*0Sstevel@tonic-gate
1618*0Sstevel@tonic-gateC<Net::FTP> inherits from C<Net::Cmd> so methods defined in C<Net::Cmd> may
1619*0Sstevel@tonic-gatebe used to send commands to the remote FTP server.
1620*0Sstevel@tonic-gate
1621*0Sstevel@tonic-gate=over 4
1622*0Sstevel@tonic-gate
1623*0Sstevel@tonic-gate=item quot (CMD [,ARGS])
1624*0Sstevel@tonic-gate
1625*0Sstevel@tonic-gateSend a command, that Net::FTP does not directly support, to the remote
1626*0Sstevel@tonic-gateserver and wait for a response.
1627*0Sstevel@tonic-gate
1628*0Sstevel@tonic-gateReturns most significant digit of the response code.
1629*0Sstevel@tonic-gate
1630*0Sstevel@tonic-gateB<WARNING> This call should only be used on commands that do not require
1631*0Sstevel@tonic-gatedata connections. Misuse of this method can hang the connection.
1632*0Sstevel@tonic-gate
1633*0Sstevel@tonic-gate=back
1634*0Sstevel@tonic-gate
1635*0Sstevel@tonic-gate=head1 THE dataconn CLASS
1636*0Sstevel@tonic-gate
1637*0Sstevel@tonic-gateSome of the methods defined in C<Net::FTP> return an object which will
1638*0Sstevel@tonic-gatebe derived from this class.The dataconn class itself is derived from
1639*0Sstevel@tonic-gatethe C<IO::Socket::INET> class, so any normal IO operations can be performed.
1640*0Sstevel@tonic-gateHowever the following methods are defined in the dataconn class and IO should
1641*0Sstevel@tonic-gatebe performed using these.
1642*0Sstevel@tonic-gate
1643*0Sstevel@tonic-gate=over 4
1644*0Sstevel@tonic-gate
1645*0Sstevel@tonic-gate=item read ( BUFFER, SIZE [, TIMEOUT ] )
1646*0Sstevel@tonic-gate
1647*0Sstevel@tonic-gateRead C<SIZE> bytes of data from the server and place it into C<BUFFER>, also
1648*0Sstevel@tonic-gateperforming any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
1649*0Sstevel@tonic-gategiven, the timeout value from the command connection will be used.
1650*0Sstevel@tonic-gate
1651*0Sstevel@tonic-gateReturns the number of bytes read before any <CRLF> translation.
1652*0Sstevel@tonic-gate
1653*0Sstevel@tonic-gate=item write ( BUFFER, SIZE [, TIMEOUT ] )
1654*0Sstevel@tonic-gate
1655*0Sstevel@tonic-gateWrite C<SIZE> bytes of data from C<BUFFER> to the server, also
1656*0Sstevel@tonic-gateperforming any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
1657*0Sstevel@tonic-gategiven, the timeout value from the command connection will be used.
1658*0Sstevel@tonic-gate
1659*0Sstevel@tonic-gateReturns the number of bytes written before any <CRLF> translation.
1660*0Sstevel@tonic-gate
1661*0Sstevel@tonic-gate=item bytes_read ()
1662*0Sstevel@tonic-gate
1663*0Sstevel@tonic-gateReturns the number of bytes read so far.
1664*0Sstevel@tonic-gate
1665*0Sstevel@tonic-gate=item abort ()
1666*0Sstevel@tonic-gate
1667*0Sstevel@tonic-gateAbort the current data transfer.
1668*0Sstevel@tonic-gate
1669*0Sstevel@tonic-gate=item close ()
1670*0Sstevel@tonic-gate
1671*0Sstevel@tonic-gateClose the data connection and get a response from the FTP server. Returns
1672*0Sstevel@tonic-gateI<true> if the connection was closed successfully and the first digit of
1673*0Sstevel@tonic-gatethe response from the server was a '2'.
1674*0Sstevel@tonic-gate
1675*0Sstevel@tonic-gate=back
1676*0Sstevel@tonic-gate
1677*0Sstevel@tonic-gate=head1 UNIMPLEMENTED
1678*0Sstevel@tonic-gate
1679*0Sstevel@tonic-gateThe following RFC959 commands have not been implemented:
1680*0Sstevel@tonic-gate
1681*0Sstevel@tonic-gate=over 4
1682*0Sstevel@tonic-gate
1683*0Sstevel@tonic-gate=item B<SMNT>
1684*0Sstevel@tonic-gate
1685*0Sstevel@tonic-gateMount a different file system structure without changing login or
1686*0Sstevel@tonic-gateaccounting information.
1687*0Sstevel@tonic-gate
1688*0Sstevel@tonic-gate=item B<HELP>
1689*0Sstevel@tonic-gate
1690*0Sstevel@tonic-gateAsk the server for "helpful information" (that's what the RFC says) on
1691*0Sstevel@tonic-gatethe commands it accepts.
1692*0Sstevel@tonic-gate
1693*0Sstevel@tonic-gate=item B<MODE>
1694*0Sstevel@tonic-gate
1695*0Sstevel@tonic-gateSpecifies transfer mode (stream, block or compressed) for file to be
1696*0Sstevel@tonic-gatetransferred.
1697*0Sstevel@tonic-gate
1698*0Sstevel@tonic-gate=item B<SYST>
1699*0Sstevel@tonic-gate
1700*0Sstevel@tonic-gateRequest remote server system identification.
1701*0Sstevel@tonic-gate
1702*0Sstevel@tonic-gate=item B<STAT>
1703*0Sstevel@tonic-gate
1704*0Sstevel@tonic-gateRequest remote server status.
1705*0Sstevel@tonic-gate
1706*0Sstevel@tonic-gate=item B<STRU>
1707*0Sstevel@tonic-gate
1708*0Sstevel@tonic-gateSpecifies file structure for file to be transferred.
1709*0Sstevel@tonic-gate
1710*0Sstevel@tonic-gate=item B<REIN>
1711*0Sstevel@tonic-gate
1712*0Sstevel@tonic-gateReinitialize the connection, flushing all I/O and account information.
1713*0Sstevel@tonic-gate
1714*0Sstevel@tonic-gate=back
1715*0Sstevel@tonic-gate
1716*0Sstevel@tonic-gate=head1 REPORTING BUGS
1717*0Sstevel@tonic-gate
1718*0Sstevel@tonic-gateWhen reporting bugs/problems please include as much information as possible.
1719*0Sstevel@tonic-gateIt may be difficult for me to reproduce the problem as almost every setup
1720*0Sstevel@tonic-gateis different.
1721*0Sstevel@tonic-gate
1722*0Sstevel@tonic-gateA small script which yields the problem will probably be of help. It would
1723*0Sstevel@tonic-gatealso be useful if this script was run with the extra options C<Debug => 1>
1724*0Sstevel@tonic-gatepassed to the constructor, and the output sent with the bug report. If you
1725*0Sstevel@tonic-gatecannot include a small script then please include a Debug trace from a
1726*0Sstevel@tonic-gaterun of your program which does yield the problem.
1727*0Sstevel@tonic-gate
1728*0Sstevel@tonic-gate=head1 AUTHOR
1729*0Sstevel@tonic-gate
1730*0Sstevel@tonic-gateGraham Barr <gbarr@pobox.com>
1731*0Sstevel@tonic-gate
1732*0Sstevel@tonic-gate=head1 SEE ALSO
1733*0Sstevel@tonic-gate
1734*0Sstevel@tonic-gateL<Net::Netrc>
1735*0Sstevel@tonic-gateL<Net::Cmd>
1736*0Sstevel@tonic-gate
1737*0Sstevel@tonic-gateftp(1), ftpd(8), RFC 959
1738*0Sstevel@tonic-gatehttp://www.cis.ohio-state.edu/htbin/rfc/rfc959.html
1739*0Sstevel@tonic-gate
1740*0Sstevel@tonic-gate=head1 USE EXAMPLES
1741*0Sstevel@tonic-gate
1742*0Sstevel@tonic-gateFor an example of the use of Net::FTP see
1743*0Sstevel@tonic-gate
1744*0Sstevel@tonic-gate=over 4
1745*0Sstevel@tonic-gate
1746*0Sstevel@tonic-gate=item http://www.csh.rit.edu/~adam/Progs/
1747*0Sstevel@tonic-gate
1748*0Sstevel@tonic-gateC<autoftp> is a program that can retrieve, send, or list files via
1749*0Sstevel@tonic-gatethe FTP protocol in a non-interactive manner.
1750*0Sstevel@tonic-gate
1751*0Sstevel@tonic-gate=back
1752*0Sstevel@tonic-gate
1753*0Sstevel@tonic-gate=head1 CREDITS
1754*0Sstevel@tonic-gate
1755*0Sstevel@tonic-gateHenry Gabryjelski <henryg@WPI.EDU> - for the suggestion of creating directories
1756*0Sstevel@tonic-gaterecursively.
1757*0Sstevel@tonic-gate
1758*0Sstevel@tonic-gateNathan Torkington <gnat@frii.com> - for some input on the documentation.
1759*0Sstevel@tonic-gate
1760*0Sstevel@tonic-gateRoderick Schertler <roderick@gate.net> - for various inputs
1761*0Sstevel@tonic-gate
1762*0Sstevel@tonic-gate=head1 COPYRIGHT
1763*0Sstevel@tonic-gate
1764*0Sstevel@tonic-gateCopyright (c) 1995-1998 Graham Barr. All rights reserved.
1765*0Sstevel@tonic-gateThis program is free software; you can redistribute it and/or modify it
1766*0Sstevel@tonic-gateunder the same terms as Perl itself.
1767*0Sstevel@tonic-gate
1768*0Sstevel@tonic-gate=for html <hr>
1769*0Sstevel@tonic-gate
1770*0Sstevel@tonic-gateI<$Id: //depot/libnet/Net/FTP.pm#80 $>
1771*0Sstevel@tonic-gate
1772*0Sstevel@tonic-gate=cut
1773