[inseparable changes from patch from perl5.003_12 to perl5.003_13]
[p5sagit/p5-mst-13.2.git] / lib / Net / FTP.pm
CommitLineData
7e1af8bc 1# Net::FTP.pm
2#
3# Copyright (c) 1995 Graham Barr <Graham.Barr@tiuk.ti.com>. All rights
4# reserved. This program is free software; you can redistribute it and/or
5# modify it under the same terms as Perl itself.
5f05dabc 6
7package Net::FTP;
8
9=head1 NAME
10
11Net::FTP - FTP Client class
12
13=head1 SYNOPSIS
14
7e1af8bc 15 use Net::FTP;
16
17 $ftp = Net::FTP->new("some.host.name");
18 $ftp->login("anonymous","me@here.there");
19 $ftp->cwd("/pub");
20 $ftp->get("that.file");
21 $ftp->quit;
5f05dabc 22
23=head1 DESCRIPTION
24
25C<Net::FTP> is a class implementing a simple FTP client in Perl as described
26in RFC959
27
7e1af8bc 28C<Net::FTP> provides methods that will perform various operations. These methods
29could be split into groups depending the level of interface the user requires.
5f05dabc 30
7e1af8bc 31=head1 CONSTRUCTOR
5f05dabc 32
7e1af8bc 33=over 4
5f05dabc 34
7e1af8bc 35=item new (HOST [,OPTIONS])
5f05dabc 36
7e1af8bc 37This is the constructor for a new Net::SMTP object. C<HOST> is the
38name of the remote host to which a FTP connection is required.
5f05dabc 39
7e1af8bc 40C<OPTIONS> are passed in a hash like fasion, using key and value pairs.
41Possible options are:
42
43B<Firewall> - The name of a machine which acts as a FTP firewall. This can be
44overridden by an environment variable C<FTP_FIREWALL>. If specified, and the
45given host cannot be directly connected to, then the
46connection is made to the firwall machine and the string C<@hostname> is
47appended to the login identifier.
48
49B<Port> - The port number to connect to on the remote machine for the
50FTP connection
51
52B<Timeout> - Set a timeout value (defaults to 120)
53
54B<Debug> - Debug level
55
56B<Passive> - If set to I<true> then all data transfers will be done using
57passive mode. This is required for some I<dumb> servers.
58
59=back
5f05dabc 60
61=head1 METHODS
62
7e1af8bc 63Unless otherwise stated all methods return either a I<true> or I<false>
64value, with I<true> meaning that the operation was a success. When a method
65states that it returns a value, falure will be returned as I<undef> or an
66empty list.
67
68=over 4
69
70=item login ([LOGIN [,PASSWORD [, ACCOUNT] ] ])
71
72Log into the remote FTP server with the given login information. If
73no arguments are given then the C<Net::FTP> uses the C<Net::Netrc>
74package to lookup the login information for the connected host.
75If no information is found then a login of I<anonymous> is used.
76If no password is given and the login is I<anonymous> then the users
77Email address will be used for a password.
78
79If the connection is via a firewall then the C<authorize> method will
80be called with no arguments.
81
82=item authorize ( [AUTH [, RESP]])
83
84This is a protocol used by some firewall ftp proxies. It is used
85to authorise the user to send data out. If both arguments are not specified
86then C<authorize> uses C<Net::Netrc> to do a lookup.
87
88=item type (TYPE [, ARGS])
89
90This method will send the TYPE command to the remote FTP server
91to change the type of data transfer. The return value is the previous
92value.
93
94=item ascii ([ARGS]) binary([ARGS]) ebcdic([ARGS]) byte([ARGS])
95
96Synonyms for C<type> with the first arguments set correctly
97
98B<NOTE> ebcdic and byte are not fully supported.
99
100=item rename ( OLDNAME, NEWNAME )
101
102Rename a file on the remote FTP server from C<OLDNAME> to C<NEWNAME>. This
103is done by sending the RNFR and RNTO commands.
104
105=item delete ( FILENAME )
106
107Send a request to the server to delete C<FILENAME>.
108
109=item cwd ( [ DIR ] )
110
111Change the current working directory to C<DIR>, or / if not given.
112
113=item cdup ()
114
115Change directory to the parent of the current directory.
116
117=item pwd ()
118
119Returns the full pathname of the current directory.
120
121=item rmdir ( DIR )
122
123Remove the directory with the name C<DIR>.
124
125=item mkdir ( DIR [, RECURSE ])
126
127Create a new directory with the name C<DIR>. If C<RECURSE> is I<true> then
128C<mkdir> will attempt to create all the directories in the given path.
129
130Returns the full pathname to the new directory.
131
132=item ls ( [ DIR ] )
133
134Get a directory listing of C<DIR>, or the current directory.
135
136Returns a reference to a list of lines returned from the server.
137
138=item dir ( [ DIR ] )
139
140Get a directory listing of C<DIR>, or the current directory in long format.
141
142Returns a reference to a list of lines returned from the server.
143
144=item get ( REMOTE_FILE [, LOCAL_FILE ] )
145
146Get C<REMOTE_FILE> from the server and store locally. C<LOCAL_FILE> may be
147a filename or a filehandle. If not specified the the file will be stored in
148the current directory with the same leafname as the remote file.
149
150Returns C<LOCAL_FILE>, or the generated local file name if C<LOCAL_FILE>
151is not given.
152
153=item put ( LOCAL_FILE [, REMOTE_FILE ] )
154
155Put a file on the remote server. C<LOCAL_FILE> may be a name or a filehandle.
156If C<LOCAL_FILE> is a filehandle then C<REMOTE_FILE> must be specified. If
157C<REMOTE_FILE> is not specified then the file will be stored in the current
158directory with the same leafname as C<LOCAL_FILE>.
159
160Returns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE>
161is not given.
162
163=item put_unique ( LOCAL_FILE [, REMOTE_FILE ] )
164
165Same as put but uses the C<STOU> command.
166
167Returns the name of the file on the server.
168
169=item append ( LOCAL_FILE [, REMOTE_FILE ] )
170
171Same as put but appends to the file on the remote server.
172
173Returns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE>
174is not given.
175
176=item unique_name ()
177
178Returns the name of the last file stored on the server using the
179C<STOU> command.
180
181=item mdtm ( FILE )
182
183Returns the I<modification time> of the given file
184
185=item size ( FILE )
186
187Returns the size in bytes for the given file.
188
189=back
190
191The following methods can return different results depending on
192how they are called. If the user explicitly calls either
193of the C<pasv> or C<port> methods then these methods will
194return a I<true> or I<false> value. If the user does not
195call either of these methods then the result will be a
196reference to a C<Net::FTP::dataconn> based object.
197
198=over 4
199
200=item nlst ( [ DIR ] )
201
202Send a C<NLST> command to the server, with an optional parameter.
203
204=item list ( [ DIR ] )
205
206Same as C<nlst> but using the C<LIST> command
207
208=item retr ( FILE )
209
210Begin the retrieval of a file called C<FILE> from the remote server.
211
212=item stor ( FILE )
213
214Tell the server that you wish to store a file. C<FILE> is the
215name of the new file that should be created.
216
217=item stou ( FILE )
218
219Same as C<stor> but using the C<STOU> command. The name of the unique
220file which was created on the server will be avalaliable via the C<unique_name>
221method after the data connection has been closed.
222
223=item appe ( FILE )
224
225Tell the server that we want to append some data to the end of a file
226called C<FILE>. If this file does not exist then create it.
227
228=back
229
230If for some reason you want to have complete control over the data connection,
231this includes generating it and calling the C<response> method when required,
232then the user can use these methods to do so.
233
234However calling these methods only affects the use of the methods above that
235can return a data connection. They have no effect on methods C<get>, C<put>,
236C<put_unique> and those that do not require data connections.
237
238=over 4
239
240=item port ( [ PORT ] )
241
242Send a C<PORT> command to the server. If C<PORT> is specified then it is sent
243to the server. If not the a listen socket is created and the correct information
244sent to the server.
245
246=item pasv ()
247
248Tell the server to go into passive mode. Returns the text that represents the
249port on which the server is listening, this text is in a suitable form to
250sent to another ftp server using the C<port> method.
251
252=back
5f05dabc 253
7e1af8bc 254The following methods can be used to transfer files between two remote
255servers, providing that these two servers can connect directly to each other.
5f05dabc 256
7e1af8bc 257=over 4
5f05dabc 258
7e1af8bc 259=item pasv_xfer ( SRC_FILE, DEST_SERVER [, DEST_FILE ] )
260
261This method will do a file transfer between two remote ftp servers. If
262C<DEST_FILE> is omitted then the leaf name of C<SRC_FILE> will be used.
263
264=item pasv_wait ( NON_PASV_SERVER )
265
266This method can be used to wait for a transfer to complete between a passive
267server and a non-passive server. The method should be called on the passive
268server with the C<Net::FTP> object for the non-passive server passed as an
269argument.
270
271=item abort ()
272
273Abort the current data transfer.
274
275=item quit ()
276
277Send the QUIT command to the remote FTP server and close the socket connection.
278
279=back
280
281=head2 Methods for the adventurous
282
283C<Net::FTP> inherits from C<Net::Cmd> so methods defined in C<Net::Cmd> may
284be used to send commands to the remote FTP server.
285
286=over 4
287
288=item quot (CMD [,ARGS])
289
290Send a command, that Net::FTP does not directly support, to the remote
291server and wait for a response.
292
293Returns most significant digit of the response code.
294
295B<WARNING> This call should only be used on commands that do not require
296data connections. Misuse of this method can hang the connection.
297
298=back
299
300=head1 THE dataconn CLASS
301
302Some of the methods defined in C<Net::FTP> return an object which will
303be derived from this class.The dataconn class itself is derived from
304the C<IO::Socket::INET> class, so any normal IO operations can be performed.
305However the following methods are defined in the dataconn class and IO should
306be performed using these.
307
308=over 4
309
310=item read ( BUFFER, SIZE [, TIMEOUT ] )
311
312Read C<SIZE> bytes of data from the server and place it into C<BUFFER>, also
313performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
314given the the timeout value from the command connection will be used.
315
316Returns the number of bytes read before any <CRLF> translation.
317
318=item write ( BUFFER, SIZE [, TIMEOUT ] )
319
320Write C<SIZE> bytes of data from C<BUFFER> to the server, also
321performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not
322given the the timeout value from the command connection will be used.
323
324Returns the number of bytes written before any <CRLF> translation.
325
326=item abort ()
327
328Abort the current data transfer.
329
330=item close ()
331
332Close the data connection and get a response from the FTP server. Returns
333I<true> if the connection was closed sucessfully and the first digit of
334the response from the server was a '2'.
335
336=back
337
338=head1 AUTHOR
339
340Graham Barr <Graham.Barr@tiuk.ti.com>
341
342=head1 REVISION
343
344$Revision: 2.8 $
345$Date: 1996/09/05 06:53:58 $
346
347The VERSION is derived from the revision by changing each number after the
348first dot into a 2 digit number so
349
350 Revision 1.8 => VERSION 1.08
351 Revision 1.2.3 => VERSION 1.0203
352
353=head1 SEE ALSO
354
355L<Net::Netrc>
356L<Net::Cmd>
357
358=head1 CREDITS
359
360Henry Gabryjelski <henryg@WPI.EDU> - for the suggestion of creating directories
361recursively.
362
363=head1 COPYRIGHT
364
365Copyright (c) 1995 Graham Barr. All rights reserved. This program is free
366software; you can redistribute it and/or modify it under the same terms
367as Perl itself.
5f05dabc 368
369=cut
370
7e1af8bc 371require 5.001;
5f05dabc 372
7e1af8bc 373use strict;
374use vars qw(@ISA $VERSION);
375use Carp;
376
377use Socket 1.3;
378use IO::Socket;
379use Time::Local;
380use Net::Cmd;
381use Net::Telnet qw(TELNET_IAC TELNET_IP TELNET_DM);
382
383$VERSION = do{my @r=(q$Revision: 2.8 $=~/(\d+)/g);sprintf "%d."."%02d"x$#r,@r};
384@ISA = qw(Exporter Net::Cmd IO::Socket::INET);
385
386sub new
387{
5f05dabc 388 my $pkg = shift;
7e1af8bc 389 my $peer = shift;
5f05dabc 390 my %arg = @_;
7e1af8bc 391
392 my $host = $peer;
393 my $fire = undef;
394
395 unless(defined inet_aton($peer))
5f05dabc 396 {
7e1af8bc 397 $fire = $ENV{FTP_FIREWALL} || $arg{Firewall} || undef;
398 if(defined $fire)
399 {
400 $peer = $fire;
401 delete $arg{Port};
402 }
5f05dabc 403 }
404
7e1af8bc 405 my $ftp = $pkg->SUPER::new(PeerAddr => $peer,
406 PeerPort => $arg{Port} || 'ftp(21)',
407 Proto => 'tcp',
408 Timeout => defined $arg{Timeout}
409 ? $arg{Timeout}
410 : 120
411 ) or return undef;
5f05dabc 412
7e1af8bc 413 ${*$ftp}{'net_ftp_passive'} = $arg{Passive} || 0; # Always use pasv mode
414 ${*$ftp}{'net_ftp_host'} = $host; # Remote hostname
415 ${*$ftp}{'net_ftp_type'} = 'A'; # ASCII/binary/etc mode
5f05dabc 416
7e1af8bc 417 ${*$ftp}{'net_ftp_firewall'} = $fire
418 if defined $fire;
5f05dabc 419
7e1af8bc 420 $ftp->autoflush(1);
5f05dabc 421
7e1af8bc 422 $ftp->debug(exists $arg{Debug} ? $arg{Debug} : undef);
5f05dabc 423
7e1af8bc 424 unless ($ftp->response() == CMD_OK)
5f05dabc 425 {
7e1af8bc 426 $ftp->SUPER::close();
427 undef $ftp;
5f05dabc 428 }
429
7e1af8bc 430 $ftp;
5f05dabc 431}
432
7e1af8bc 433##
434## User interface methods
435##
5f05dabc 436
7e1af8bc 437sub quit
438{
439 my $ftp = shift;
5f05dabc 440
7e1af8bc 441 $ftp->_QUIT
442 && $ftp->SUPER::close;
5f05dabc 443}
444
7e1af8bc 445sub close
446{
447 my $ftp = shift;
5f05dabc 448
7e1af8bc 449 ref($ftp)
450 && defined fileno($ftp)
451 && $ftp->quit;
452}
5f05dabc 453
7e1af8bc 454sub DESTROY { shift->close }
5f05dabc 455
456sub ascii { shift->type('A',@_); }
5f05dabc 457sub binary { shift->type('I',@_); }
7e1af8bc 458
459sub ebcdic
460{
461 carp "TYPE E is unsupported, shall default to I";
462 shift->type('E',@_);
463}
464
465sub byte
466{
467 carp "TYPE L is unsupported, shall default to I";
468 shift->type('L',@_);
469}
5f05dabc 470
471# Allow the user to send a command directly, BE CAREFUL !!
472
7e1af8bc 473sub quot
474{
475 my $ftp = shift;
5f05dabc 476 my $cmd = shift;
477
7e1af8bc 478 $ftp->command( uc $cmd, @_);
479 $ftp->response();
5f05dabc 480}
481
7e1af8bc 482sub mdtm
483{
484 my $ftp = shift;
485 my $file = shift;
5f05dabc 486
7e1af8bc 487 return undef
488 unless $ftp->_MDTM($file);
5f05dabc 489
7e1af8bc 490 my @gt = reverse ($ftp->message =~ /(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/);
491 $gt[5] -= 1;
492 timegm(@gt);
493}
5f05dabc 494
7e1af8bc 495sub size
496{
497 my $ftp = shift;
498 my $file = shift;
499
500 $ftp->_SIZE($file)
501 ? ($ftp->message =~ /(\d+)/)[0]
502 : undef;
503}
504
505sub login
506{
507 my($ftp,$user,$pass,$acct) = @_;
508 my($ok,$ruser);
5f05dabc 509
7e1af8bc 510 unless (defined $user)
5f05dabc 511 {
512 require Net::Netrc;
7e1af8bc 513
514 my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'});
5f05dabc 515
516 ($user,$pass,$acct) = $rc->lpa()
7e1af8bc 517 if ($rc);
5f05dabc 518 }
519
7e1af8bc 520 $user ||= "anonymous";
521 $ruser = $user;
5f05dabc 522
7e1af8bc 523 if(defined ${*$ftp}{'net_ftp_firewall'})
524 {
525 $user .= "@" . ${*$ftp}{'net_ftp_host'};
526 }
5f05dabc 527
7e1af8bc 528 $ok = $ftp->_USER($user);
5f05dabc 529
7e1af8bc 530 # Some dumb firewall's don't prefix the connection messages
531 $ok = $ftp->response()
532 if($ok == CMD_OK && $ftp->code == 220 && $user =~ /\@/);
5f05dabc 533
7e1af8bc 534 if ($ok == CMD_MORE)
535 {
536 unless(defined $pass)
537 {
538 require Net::Netrc;
5f05dabc 539
7e1af8bc 540 my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_host'}, $ruser);
5f05dabc 541
7e1af8bc 542 ($ruser,$pass,$acct) = $rc->lpa()
543 if ($rc);
5f05dabc 544
7e1af8bc 545 $pass = "-" . (getpwuid($>))[0] . "@"
546 if (!defined $pass && $ruser =~ /^anonymous/o);
547 }
5f05dabc 548
7e1af8bc 549 $ok = $ftp->_PASS($pass || "");
550 }
5f05dabc 551
7e1af8bc 552 $ok = $ftp->_ACCT($acct || "")
553 if ($ok == CMD_MORE);
5f05dabc 554
7e1af8bc 555 $ftp->authorize()
556 if($ok == CMD_OK && defined ${*$ftp}{'net_ftp_firewall'});
5f05dabc 557
7e1af8bc 558 $ok == CMD_OK;
559}
5f05dabc 560
7e1af8bc 561sub authorize
562{
563 @_ >= 1 || @_ <= 3 or croak 'usage: $ftp->authorize( [AUTH [, RESP]])';
5f05dabc 564
7e1af8bc 565 my($ftp,$auth,$resp) = @_;
5f05dabc 566
7e1af8bc 567 unless(defined $resp)
568 {
569 require Net::Netrc;
5f05dabc 570
7e1af8bc 571 $auth ||= (getpwuid($>))[0];
5f05dabc 572
7e1af8bc 573 my $rc = Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'}, $auth)
574 || Net::Netrc->lookup(${*$ftp}{'net_ftp_firewall'});
5f05dabc 575
7e1af8bc 576 ($auth,$resp) = $rc->lpa()
577 if($rc);
578 }
579
580 my $ok = $ftp->_AUTH($auth || "");
581
582 $ok = $ftp->_RESP($resp || "")
583 if ($ok == CMD_MORE);
584
585 $ok == CMD_OK;
586}
587
588sub rename
589{
590 @_ == 3 or croak 'usage: $ftp->rename(FROM, TO)';
5f05dabc 591
7e1af8bc 592 my($ftp,$from,$to) = @_;
5f05dabc 593
7e1af8bc 594 $ftp->_RNFR($from)
595 && $ftp->_RNTO($to);
5f05dabc 596}
597
7e1af8bc 598sub type
599{
600 my $ftp = shift;
5f05dabc 601 my $type = shift;
7e1af8bc 602 my $oldval = ${*$ftp}{'net_ftp_type'};
5f05dabc 603
7e1af8bc 604 return $oldval
605 unless (defined $type);
5f05dabc 606
607 return undef
7e1af8bc 608 unless ($ftp->_TYPE($type,@_));
5f05dabc 609
7e1af8bc 610 ${*$ftp}{'net_ftp_type'} = join(" ",$type,@_);
611
612 $oldval;
5f05dabc 613}
614
7e1af8bc 615sub abort
616{
617 my $ftp = shift;
618
619 send($ftp,pack("CC",TELNET_IAC,TELNET_IP),0);
620 send($ftp,pack("C", TELNET_IAC),MSG_OOB);
621 send($ftp,pack("C", TELNET_DM),0);
622
623 $ftp->command("ABOR");
624
625 defined ${*$ftp}{'net_ftp_dataconn'}
626 ? ${*$ftp}{'net_ftp_dataconn'}->close()
627 : $ftp->response();
628
629 $ftp->response()
630 if $ftp->status == CMD_REJECT;
5f05dabc 631
7e1af8bc 632 $ftp->status == CMD_OK;
5f05dabc 633}
634
7e1af8bc 635sub get
636{
637 my($ftp,$remote,$local,$where) = @_;
638
5f05dabc 639 my($loc,$len,$buf,$resp,$localfd,$data);
640 local *FD;
641
642 $localfd = ref($local) ? fileno($local)
7e1af8bc 643 : undef;
644
645 ($local = $remote) =~ s#^.*/##
646 unless(defined $local);
647
648 ${*$ftp}{'net_ftp_rest'} = $where
649 if ($where);
5f05dabc 650
7e1af8bc 651 delete ${*$ftp}{'net_ftp_port'};
652 delete ${*$ftp}{'net_ftp_pasv'};
5f05dabc 653
7e1af8bc 654 $data = $ftp->retr($remote) or
655 return undef;
656
657 if(defined $localfd)
5f05dabc 658 {
659 $loc = $local;
660 }
661 else
662 {
663 $loc = \*FD;
664
665 unless(($where) ? open($loc,">>$local") : open($loc,">$local"))
666 {
667 carp "Cannot open Local file $local: $!\n";
7e1af8bc 668 $data->abort;
5f05dabc 669 return undef;
670 }
671 }
7e1af8bc 672 if ($ftp->binary && !binmode($loc))
673 {
674 carp "Cannot binmode Local file $local: $!\n";
675 return undef;
676 }
5f05dabc 677
678 $buf = '';
679
680 do
681 {
682 $len = $data->read($buf,1024);
683 }
684 while($len > 0 && syswrite($loc,$buf,$len) == $len);
685
686 close($loc)
7e1af8bc 687 unless defined $localfd;
5f05dabc 688
7e1af8bc 689 $data->close(); # implied $ftp->response
690
691 return $local;
692}
693
694sub cwd
695{
696 @_ == 2 || @_ == 3 or croak 'usage: $ftp->cwd( [ DIR ] )';
697
698 my($ftp,$dir) = @_;
699
700 $dir ||= "/";
701
702 $dir eq ".."
703 ? $ftp->_CDUP()
704 : $ftp->_CWD($dir);
705}
706
707sub cdup
708{
709 @_ == 1 or croak 'usage: $ftp->cdup()';
710 $_[0]->_CDUP;
5f05dabc 711}
712
7e1af8bc 713sub pwd
714{
715 @_ == 1 || croak 'usage: $ftp->pwd()';
716 my $ftp = shift;
717
718 $ftp->_PWD();
719 $ftp->_extract_path;
720}
721
722sub rmdir
723{
724 @_ == 2 || croak 'usage: $ftp->rmdir( DIR )';
725
726 $_[0]->_RMD($_[1]);
727}
728
729sub mkdir
730{
731 @_ == 2 || @_ == 3 or croak 'usage: $ftp->mkdir( DIR [, RECURSE ] )';
732
733 my($ftp,$dir,$recurse) = @_;
5f05dabc 734
7e1af8bc 735 $ftp->_MKD($dir) || $recurse or
736 return undef;
737
738 my $path = undef;
739 unless($ftp->ok)
740 {
741 my @path = split(m#(?=/+)#, $dir);
742
743 $path = "";
744
745 while(@path)
746 {
747 $path .= shift @path;
748
749 $ftp->_MKD($path);
750 $path = $ftp->_extract_path($path);
751
752 # 521 means directory already exists
753 last
754 unless $ftp->ok || $ftp->code == 521;
755 }
756 }
757
758 $ftp->_extract_path($path);
5f05dabc 759}
760
7e1af8bc 761sub delete
762{
763 @_ == 2 || croak 'usage: $ftp->delete( FILENAME )';
5f05dabc 764
7e1af8bc 765 $_[0]->_DELE($_[1]);
5f05dabc 766}
767
7e1af8bc 768sub put { shift->_store_cmd("stor",@_) }
769sub put_unique { shift->_store_cmd("stou",@_) }
770sub append { shift->_store_cmd("appe",@_) }
5f05dabc 771
7e1af8bc 772sub nlst { shift->_data_cmd("NLST",@_) }
773sub list { shift->_data_cmd("LIST",@_) }
774sub retr { shift->_data_cmd("RETR",@_) }
775sub stor { shift->_data_cmd("STOR",@_) }
776sub stou { shift->_data_cmd("STOU",@_) }
777sub appe { shift->_data_cmd("APPE",@_) }
5f05dabc 778
7e1af8bc 779sub _store_cmd
780{
781 my($ftp,$cmd,$local,$remote) = @_;
5f05dabc 782 my($loc,$sock,$len,$buf,$localfd);
783 local *FD;
784
785 $localfd = ref($local) ? fileno($local)
7e1af8bc 786 : undef;
5f05dabc 787
788 unless(defined $remote)
789 {
7e1af8bc 790 croak 'Must specify remote filename with stream input'
791 if defined $localfd;
5f05dabc 792
793 ($remote = $local) =~ s%.*/%%;
794 }
795
7e1af8bc 796 if(defined $localfd)
5f05dabc 797 {
798 $loc = $local;
799 }
800 else
801 {
802 $loc = \*FD;
803
804 unless(open($loc,"<$local"))
805 {
806 carp "Cannot open Local file $local: $!\n";
807 return undef;
808 }
7e1af8bc 809 if ($ftp->binary && !binmode($loc))
810 {
811 carp "Cannot binmode Local file $local: $!\n";
812 return undef;
813 }
5f05dabc 814 }
815
7e1af8bc 816 delete ${*$ftp}{'net_ftp_port'};
817 delete ${*$ftp}{'net_ftp_pasv'};
5f05dabc 818
7e1af8bc 819 $sock = $ftp->_data_cmd($cmd, $remote) or
5f05dabc 820 return undef;
821
822 do
823 {
7e1af8bc 824 $len = sysread($loc,$buf="",1024);
5f05dabc 825 }
826 while($len && $sock->write($buf,$len) == $len);
827
828 close($loc)
7e1af8bc 829 unless defined $localfd;
5f05dabc 830
831 $sock->close();
832
7e1af8bc 833 ($remote) = $ftp->message =~ /unique file name:\s*(\S*)\s*\)/
834 if ('STOU' eq uc $cmd);
5f05dabc 835
836 return $remote;
837}
838
7e1af8bc 839sub port
840{
841 @_ == 1 || @_ == 2 or croak 'usage: $ftp->port([PORT])';
842
843 my($ftp,$port) = @_;
5f05dabc 844 my $ok;
845
7e1af8bc 846 delete ${*$ftp}{'net_ftp_intern_port'};
847
5f05dabc 848 unless(defined $port)
849 {
5f05dabc 850 # create a Listen socket at same address as the command socket
851
7e1af8bc 852 ${*$ftp}{'net_ftp_listen'} ||= IO::Socket::INET->new(Listen => 5,
853 Proto => 'tcp',
854 LocalAddr => $ftp->sockhost,
855 );
5f05dabc 856
7e1af8bc 857 my $listen = ${*$ftp}{'net_ftp_listen'};
5f05dabc 858
859 my($myport, @myaddr) = ($listen->sockport, split(/\./,$listen->sockhost));
860
861 $port = join(',', @myaddr, $myport >> 8, $myport & 0xff);
7e1af8bc 862
863 ${*$ftp}{'net_ftp_intern_port'} = 1;
5f05dabc 864 }
865
7e1af8bc 866 $ok = $ftp->_PORT($port);
5f05dabc 867
7e1af8bc 868 ${*$ftp}{'net_ftp_port'} = $port;
5f05dabc 869
870 $ok;
871}
872
7e1af8bc 873sub ls { shift->_list_cmd("NLST",@_); }
874sub dir { shift->_list_cmd("LIST",@_); }
5f05dabc 875
7e1af8bc 876sub pasv
877{
878 @_ == 1 or croak 'usage: $ftp->pasv()';
5f05dabc 879
7e1af8bc 880 my $ftp = shift;
881
882 delete ${*$ftp}{'net_ftp_intern_port'};
5f05dabc 883
7e1af8bc 884 $ftp->_PASV && $ftp->message =~ /(\d+(,\d+)+)/
885 ? ${*$ftp}{'net_ftp_pasv'} = $1
886 : undef;
887}
5f05dabc 888
7e1af8bc 889sub unique_name
890{
891 my $ftp = shift;
892 ${*$ftp}{'net_ftp_unique'} || undef;
5f05dabc 893}
894
895##
7e1af8bc 896## Depreciated methods
5f05dabc 897##
898
7e1af8bc 899sub lsl
900{
901 carp "Use of Net::FTP::lsl depreciated, use 'dir'"
902 if $^W;
903 goto &dir;
5f05dabc 904}
905
7e1af8bc 906sub authorise
907{
908 carp "Use of Net::FTP::authorise depreciated, use 'authorize'"
909 if $^W;
910 goto &authorize;
911}
5f05dabc 912
5f05dabc 913
7e1af8bc 914##
915## Private methods
916##
5f05dabc 917
7e1af8bc 918sub _extract_path
919{
920 my($ftp, $path) = @_;
5f05dabc 921
7e1af8bc 922 $ftp->ok &&
923 $ftp->message =~ /\s\"(.*)\"\s/o &&
924 ($path = $1) =~ s/\"\"/\"/g;
5f05dabc 925
7e1af8bc 926 $path;
5f05dabc 927}
928
7e1af8bc 929##
930## Communication methods
931##
5f05dabc 932
7e1af8bc 933sub _dataconn
934{
935 my $ftp = shift;
936 my $data = undef;
937 my $pkg = "Net::FTP::" . $ftp->type;
5f05dabc 938
7e1af8bc 939 $pkg =~ s/ /_/g;
940
941 delete ${*$ftp}{'net_ftp_dataconn'};
5f05dabc 942
7e1af8bc 943 if(defined ${*$ftp}{'net_ftp_pasv'})
944 {
945 my @port = split(/,/,${*$ftp}{'net_ftp_pasv'});
5f05dabc 946
7e1af8bc 947 $data = $pkg->new(PeerAddr => join(".",@port[0..3]),
948 PeerPort => $port[4] * 256 + $port[5],
949 Proto => 'tcp'
950 );
951 }
952 elsif(defined ${*$ftp}{'net_ftp_listen'})
953 {
954 $data = ${*$ftp}{'net_ftp_listen'}->accept($pkg);
955 close(delete ${*$ftp}{'net_ftp_listen'});
956 }
957
958 if($data)
959 {
960 ${*$data} = "";
961 $data->timeout($ftp->timeout);
962 ${*$ftp}{'net_ftp_dataconn'} = $data;
963 ${*$data}{'net_ftp_cmd'} = $ftp;
964 }
965
966 $data;
5f05dabc 967}
968
7e1af8bc 969sub _list_cmd
970{
971 my $ftp = shift;
972 my $cmd = uc shift;
973
974 delete ${*$ftp}{'net_ftp_port'};
975 delete ${*$ftp}{'net_ftp_pasv'};
976
977 my $data = $ftp->_data_cmd($cmd,@_);
5f05dabc 978
979 return undef
980 unless(defined $data);
981
982 bless $data, "Net::FTP::A"; # Force ASCII mode
983
984 my $databuf = '';
985 my $buf = '';
986
7e1af8bc 987 while($data->read($databuf,1024))
988 {
5f05dabc 989 $buf .= $databuf;
7e1af8bc 990 }
5f05dabc 991
992 my $list = [ split(/\n/,$buf) ];
993
994 $data->close();
995
7e1af8bc 996 wantarray ? @{$list}
997 : $list;
5f05dabc 998}
999
7e1af8bc 1000sub _data_cmd
1001{
1002 my $ftp = shift;
5f05dabc 1003 my $cmd = uc shift;
1004 my $ok = 1;
7e1af8bc 1005 my $where = delete ${*$ftp}{'net_ftp_rest'} || 0;
5f05dabc 1006
7e1af8bc 1007 if(${*$ftp}{'net_ftp_passive'} &&
1008 !defined ${*$ftp}{'net_ftp_pasv'} &&
1009 !defined ${*$ftp}{'net_ftp_port'})
1010 {
1011 my $data = undef;
5f05dabc 1012
7e1af8bc 1013 $ok = defined $ftp->pasv;
1014 $ok = $ftp->_REST($where)
1015 if $ok && $where;
5f05dabc 1016
7e1af8bc 1017 if($ok)
1018 {
1019 $ftp->command($cmd,@_);
1020 $data = $ftp->_dataconn();
1021 $ok = CMD_INFO == $ftp->response();
1022 }
1023 return $ok ? $data
1024 : undef;
1025 }
5f05dabc 1026
7e1af8bc 1027 $ok = $ftp->port
1028 unless (defined ${*$ftp}{'net_ftp_port'} ||
1029 defined ${*$ftp}{'net_ftp_pasv'});
5f05dabc 1030
7e1af8bc 1031 $ok = $ftp->_REST($where)
1032 if $ok && $where;
5f05dabc 1033
7e1af8bc 1034 return undef
1035 unless $ok;
1036
1037 $ftp->command($cmd,@_);
1038
1039 return 1
1040 if(defined ${*$ftp}{'net_ftp_pasv'});
5f05dabc 1041
7e1af8bc 1042 $ok = CMD_INFO == $ftp->response();
5f05dabc 1043
7e1af8bc 1044 return $ok
1045 unless exists ${*$ftp}{'net_ftp_intern_port'};
1046
1047 $ok ? $ftp->_dataconn()
1048 : undef;
5f05dabc 1049}
1050
7e1af8bc 1051##
1052## Over-ride methods (Net::Cmd)
1053##
5f05dabc 1054
7e1af8bc 1055sub debug_text { $_[2] =~ /^(pass|resp)/i ? "$1 ....\n" : $_[2]; }
1056
1057sub command
1058{
1059 my $ftp = shift;
1060
1061 delete ${*$ftp}{'net_ftp_port'};
1062 $ftp->SUPER::command(@_);
5f05dabc 1063}
1064
7e1af8bc 1065sub response
1066{
1067 my $ftp = shift;
1068 my $code = $ftp->SUPER::response();
1069
1070 delete ${*$ftp}{'net_ftp_pasv'}
1071 if ($code != CMD_MORE && $code != CMD_INFO);
1072
1073 $code;
1074}
5f05dabc 1075
7e1af8bc 1076##
1077## Allow 2 servers to talk directly
1078##
5f05dabc 1079
7e1af8bc 1080sub pasv_xfer
1081{
1082 my($sftp,$sfile,$dftp,$dfile) = @_;
5f05dabc 1083
7e1af8bc 1084 ($dfile = $sfile) =~ s#.*/##
1085 unless(defined $dfile);
5f05dabc 1086
7e1af8bc 1087 my $port = $sftp->pasv or
1088 return undef;
5f05dabc 1089
7e1af8bc 1090 unless($dftp->port($port) && $sftp->retr($sfile) && $dftp->stou($dfile))
1091 {
1092 $sftp->abort;
1093 $dftp->abort;
1094 return undef;
1095 }
5f05dabc 1096
7e1af8bc 1097 $dftp->pasv_wait($sftp);
5f05dabc 1098}
1099
7e1af8bc 1100sub pasv_wait
1101{
1102 @_ == 2 or croak 'usage: $ftp->pasv_wait(NON_PASV_FTP)';
1103
1104 my($ftp, $non_pasv) = @_;
1105 my($file,$rin,$rout);
5f05dabc 1106
7e1af8bc 1107 vec($rin,fileno($ftp),1) = 1;
5f05dabc 1108 select($rout=$rin, undef, undef, undef);
1109
7e1af8bc 1110 $ftp->response();
5f05dabc 1111 $non_pasv->response();
1112
1113 return undef
7e1af8bc 1114 unless $ftp->ok() && $non_pasv->ok();
5f05dabc 1115
1116 return $1
7e1af8bc 1117 if $ftp->message =~ /unique file name:\s*(\S*)\s*\)/;
5f05dabc 1118
1119 return $1
1120 if $non_pasv->message =~ /unique file name:\s*(\S*)\s*\)/;
1121
1122 return 1;
1123}
1124
7e1af8bc 1125sub cmd { shift->command(@_)->responce() }
1126
1127########################################
1128#
1129# RFC959 commands
1130#
1131
1132sub _ABOR { shift->command("ABOR")->response() == CMD_OK }
1133sub _CDUP { shift->command("CDUP")->response() == CMD_OK }
1134sub _NOOP { shift->command("NOOP")->response() == CMD_OK }
1135sub _PASV { shift->command("PASV")->response() == CMD_OK }
1136sub _QUIT { shift->command("QUIT")->response() == CMD_OK }
1137sub _DELE { shift->command("DELE",@_)->response() == CMD_OK }
1138sub _CWD { shift->command("CWD", @_)->response() == CMD_OK }
1139sub _PORT { shift->command("PORT",@_)->response() == CMD_OK }
1140sub _RMD { shift->command("RMD", @_)->response() == CMD_OK }
1141sub _MKD { shift->command("MKD", @_)->response() == CMD_OK }
1142sub _PWD { shift->command("PWD", @_)->response() == CMD_OK }
1143sub _TYPE { shift->command("TYPE",@_)->response() == CMD_OK }
1144sub _RNTO { shift->command("RNTO",@_)->response() == CMD_OK }
1145sub _ACCT { shift->command("ACCT",@_)->response() == CMD_OK }
1146sub _RESP { shift->command("RESP",@_)->response() == CMD_OK }
1147sub _MDTM { shift->command("MDTM",@_)->response() == CMD_OK }
1148sub _SIZE { shift->command("SIZE",@_)->response() == CMD_OK }
1149sub _APPE { shift->command("APPE",@_)->response() == CMD_INFO }
1150sub _LIST { shift->command("LIST",@_)->response() == CMD_INFO }
1151sub _NLST { shift->command("NLST",@_)->response() == CMD_INFO }
1152sub _RETR { shift->command("RETR",@_)->response() == CMD_INFO }
1153sub _STOR { shift->command("STOR",@_)->response() == CMD_INFO }
1154sub _STOU { shift->command("STOU",@_)->response() == CMD_INFO }
1155sub _RNFR { shift->command("RNFR",@_)->response() == CMD_MORE }
1156sub _REST { shift->command("REST",@_)->response() == CMD_MORE }
1157sub _USER { shift->command("user",@_)->response() } # A certain brain dead firewall :-)
1158sub _PASS { shift->command("PASS",@_)->response() }
1159sub _AUTH { shift->command("AUTH",@_)->response() }
1160
1161sub _ALLO { shift->unsupported(@_) }
1162sub _SMNT { shift->unsupported(@_) }
1163sub _HELP { shift->unsupported(@_) }
1164sub _MODE { shift->unsupported(@_) }
1165sub _SITE { shift->unsupported(@_) }
1166sub _SYST { shift->unsupported(@_) }
1167sub _STAT { shift->unsupported(@_) }
1168sub _STRU { shift->unsupported(@_) }
1169sub _REIN { shift->unsupported(@_) }
5f05dabc 1170
7e1af8bc 1171##
1172## Generic data connection package
1173##
5f05dabc 1174
1175package Net::FTP::dataconn;
7e1af8bc 1176
5f05dabc 1177use Carp;
7e1af8bc 1178use vars qw(@ISA $timeout);
1179use Net::Cmd;
5f05dabc 1180
7e1af8bc 1181@ISA = qw(IO::Socket::INET);
5f05dabc 1182
7e1af8bc 1183sub abort
1184{
1185 my $data = shift;
1186 my $ftp = ${*$data}{'net_ftp_cmd'};
5f05dabc 1187
7e1af8bc 1188 $ftp->abort; # this will close me
1189}
5f05dabc 1190
7e1af8bc 1191sub close
1192{
1193 my $data = shift;
1194 my $ftp = ${*$data}{'net_ftp_cmd'};
5f05dabc 1195
7e1af8bc 1196 $data->SUPER::close();
5f05dabc 1197
7e1af8bc 1198 delete ${*$ftp}{'net_ftp_dataconn'}
1199 if exists ${*$ftp}{'net_ftp_dataconn'} &&
1200 $data == ${*$ftp}{'net_ftp_dataconn'};
5f05dabc 1201
7e1af8bc 1202 $ftp->response() == CMD_OK &&
1203 $ftp->message =~ /unique file name:\s*(\S*)\s*\)/ &&
1204 (${*$ftp}{'net_ftp_unique'} = $1);
5f05dabc 1205
7e1af8bc 1206 $ftp->status == CMD_OK;
5f05dabc 1207}
1208
7e1af8bc 1209sub _select
1210{
1211 my $data = shift;
5f05dabc 1212 local *timeout = \$_[0]; shift;
7e1af8bc 1213 my $rw = shift;
1214
5f05dabc 1215 my($rin,$win);
1216
1217 return 1 unless $timeout;
1218
1219 $rin = '';
7e1af8bc 1220 vec($rin,fileno($data),1) = 1;
5f05dabc 1221
1222 $win = $rw ? undef : $rin;
1223 $rin = undef unless $rw;
1224
1225 my $nfound = select($rin, $win, undef, $timeout);
1226
1227 croak "select: $!"
1228 if $nfound < 0;
1229
1230 return $nfound;
1231}
1232
7e1af8bc 1233sub can_read
1234{
1235 my $data = shift;
5f05dabc 1236 local *timeout = \$_[0];
1237
7e1af8bc 1238 $data->_select($timeout,1);
5f05dabc 1239}
1240
7e1af8bc 1241sub can_write
1242{
1243 my $data = shift;
5f05dabc 1244 local *timeout = \$_[0];
1245
7e1af8bc 1246 $data->_select($timeout,0);
5f05dabc 1247}
1248
7e1af8bc 1249sub cmd
1250{
1251 my $ftp = shift;
5f05dabc 1252
7e1af8bc 1253 ${*$ftp}{'net_ftp_cmd'};
5f05dabc 1254}
1255
1256
1257@Net::FTP::L::ISA = qw(Net::FTP::I);
1258@Net::FTP::E::ISA = qw(Net::FTP::I);
1259
7e1af8bc 1260##
1261## Package to read/write on ASCII data connections
1262##
1263
5f05dabc 1264package Net::FTP::A;
7e1af8bc 1265
1266use vars qw(@ISA $buf);
5f05dabc 1267use Carp;
1268
7e1af8bc 1269@ISA = qw(Net::FTP::dataconn);
5f05dabc 1270
7e1af8bc 1271sub read
1272{
1273 my $data = shift;
1274 local *buf = \$_[0]; shift;
1275 my $size = shift || croak 'read($buf,$size,[$offset])';
1276 my $offset = shift || 0;
1277 my $timeout = $data->timeout;
5f05dabc 1278
1279 croak "Bad offset"
1280 if($offset < 0);
1281
1282 $offset = length $buf
1283 if($offset > length $buf);
1284
7e1af8bc 1285 ${*$data} ||= "";
1286 my $l = 0;
1287
5f05dabc 1288 READ:
1289 {
7e1af8bc 1290 $data->can_read($timeout) or
5f05dabc 1291 croak "Timeout";
1292
7e1af8bc 1293 my $n = sysread($data, ${*$data}, $size, length ${*$data});
5f05dabc 1294
1295 return $n
1296 unless($n >= 0);
1297
7e1af8bc 1298 ${*$data} =~ s/(\015)?(?!\012)\Z//so;
1299 my $lf = $1 || "";
5f05dabc 1300
7e1af8bc 1301 ${*$data} =~ s/\015\012/\n/sgo;
5f05dabc 1302
7e1af8bc 1303 substr($buf,$offset) = ${*$data};
5f05dabc 1304
7e1af8bc 1305 $l += length(${*$data});
1306 $offset += length(${*$data});
5f05dabc 1307
7e1af8bc 1308 ${*$data} = $lf;
5f05dabc 1309
1310 redo READ
1311 if($l == 0 && $n > 0);
1312
1313 if($n == 0 && $l == 0)
1314 {
7e1af8bc 1315 substr($buf,$offset) = ${*$data};
1316 ${*$data} = "";
5f05dabc 1317 }
1318 }
1319
1320 return $l;
1321}
1322
7e1af8bc 1323sub write
1324{
1325 my $data = shift;
1326 local *buf = \$_[0]; shift;
1327 my $size = shift || croak 'write($buf,$size,[$timeout])';
1328 my $timeout = @_ ? shift : $data->timeout;
5f05dabc 1329
7e1af8bc 1330 $data->can_write($timeout) or
5f05dabc 1331 croak "Timeout";
1332
7e1af8bc 1333 # What is previous pkt ended in \015 or not ??
5f05dabc 1334
1335 my $tmp;
7e1af8bc 1336 ($tmp = $buf) =~ s/(?!\015)\012/\015\012/sg;
5f05dabc 1337
1338 my $len = $size + length($tmp) - length($buf);
7e1af8bc 1339 my $wrote = syswrite($data, $tmp, $len);
5f05dabc 1340
1341 if($wrote >= 0)
1342 {
1343 $wrote = $wrote == $len ? $size
1344 : $len - $wrote
1345 }
1346
1347 return $wrote;
1348}
1349
7e1af8bc 1350##
1351## Package to read/write on BINARY data connections
1352##
1353
5f05dabc 1354package Net::FTP::I;
7e1af8bc 1355
1356use vars qw(@ISA $buf);
5f05dabc 1357use Carp;
1358
7e1af8bc 1359@ISA = qw(Net::FTP::dataconn);
5f05dabc 1360
7e1af8bc 1361sub read
1362{
1363 my $data = shift;
1364 local *buf = \$_[0]; shift;
1365 my $size = shift || croak 'read($buf,$size,[$timeout])';
1366 my $timeout = @_ ? shift : $data->timeout;
5f05dabc 1367
7e1af8bc 1368 $data->can_read($timeout) or
5f05dabc 1369 croak "Timeout";
1370
7e1af8bc 1371 my $n = sysread($data, $buf, $size);
5f05dabc 1372
1373 $n;
1374}
1375
7e1af8bc 1376sub write
1377{
1378 my $data = shift;
1379 local *buf = \$_[0]; shift;
1380 my $size = shift || croak 'write($buf,$size,[$timeout])';
1381 my $timeout = @_ ? shift : $data->timeout;
5f05dabc 1382
7e1af8bc 1383 $data->can_write($timeout) or
5f05dabc 1384 croak "Timeout";
1385
7e1af8bc 1386 syswrite($data, $buf, $size);
5f05dabc 1387}
1388
5f05dabc 1389
13901;
1391