Commit | Line | Data |
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 | |
7 | package Net::FTP; |
8 | |
9 | =head1 NAME |
10 | |
11 | Net::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 | |
25 | C<Net::FTP> is a class implementing a simple FTP client in Perl as described |
26 | in RFC959 |
27 | |
7e1af8bc |
28 | C<Net::FTP> provides methods that will perform various operations. These methods |
29 | could 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 |
37 | This is the constructor for a new Net::SMTP object. C<HOST> is the |
38 | name of the remote host to which a FTP connection is required. |
5f05dabc |
39 | |
7e1af8bc |
40 | C<OPTIONS> are passed in a hash like fasion, using key and value pairs. |
41 | Possible options are: |
42 | |
43 | B<Firewall> - The name of a machine which acts as a FTP firewall. This can be |
44 | overridden by an environment variable C<FTP_FIREWALL>. If specified, and the |
45 | given host cannot be directly connected to, then the |
46 | connection is made to the firwall machine and the string C<@hostname> is |
47 | appended to the login identifier. |
48 | |
49 | B<Port> - The port number to connect to on the remote machine for the |
50 | FTP connection |
51 | |
52 | B<Timeout> - Set a timeout value (defaults to 120) |
53 | |
54 | B<Debug> - Debug level |
55 | |
56 | B<Passive> - If set to I<true> then all data transfers will be done using |
57 | passive mode. This is required for some I<dumb> servers. |
58 | |
59 | =back |
5f05dabc |
60 | |
61 | =head1 METHODS |
62 | |
7e1af8bc |
63 | Unless otherwise stated all methods return either a I<true> or I<false> |
64 | value, with I<true> meaning that the operation was a success. When a method |
65 | states that it returns a value, falure will be returned as I<undef> or an |
66 | empty list. |
67 | |
68 | =over 4 |
69 | |
70 | =item login ([LOGIN [,PASSWORD [, ACCOUNT] ] ]) |
71 | |
72 | Log into the remote FTP server with the given login information. If |
73 | no arguments are given then the C<Net::FTP> uses the C<Net::Netrc> |
74 | package to lookup the login information for the connected host. |
75 | If no information is found then a login of I<anonymous> is used. |
76 | If no password is given and the login is I<anonymous> then the users |
77 | Email address will be used for a password. |
78 | |
79 | If the connection is via a firewall then the C<authorize> method will |
80 | be called with no arguments. |
81 | |
82 | =item authorize ( [AUTH [, RESP]]) |
83 | |
84 | This is a protocol used by some firewall ftp proxies. It is used |
85 | to authorise the user to send data out. If both arguments are not specified |
86 | then C<authorize> uses C<Net::Netrc> to do a lookup. |
87 | |
88 | =item type (TYPE [, ARGS]) |
89 | |
90 | This method will send the TYPE command to the remote FTP server |
91 | to change the type of data transfer. The return value is the previous |
92 | value. |
93 | |
94 | =item ascii ([ARGS]) binary([ARGS]) ebcdic([ARGS]) byte([ARGS]) |
95 | |
96 | Synonyms for C<type> with the first arguments set correctly |
97 | |
98 | B<NOTE> ebcdic and byte are not fully supported. |
99 | |
100 | =item rename ( OLDNAME, NEWNAME ) |
101 | |
102 | Rename a file on the remote FTP server from C<OLDNAME> to C<NEWNAME>. This |
103 | is done by sending the RNFR and RNTO commands. |
104 | |
105 | =item delete ( FILENAME ) |
106 | |
107 | Send a request to the server to delete C<FILENAME>. |
108 | |
109 | =item cwd ( [ DIR ] ) |
110 | |
111 | Change the current working directory to C<DIR>, or / if not given. |
112 | |
113 | =item cdup () |
114 | |
115 | Change directory to the parent of the current directory. |
116 | |
117 | =item pwd () |
118 | |
119 | Returns the full pathname of the current directory. |
120 | |
121 | =item rmdir ( DIR ) |
122 | |
123 | Remove the directory with the name C<DIR>. |
124 | |
125 | =item mkdir ( DIR [, RECURSE ]) |
126 | |
127 | Create a new directory with the name C<DIR>. If C<RECURSE> is I<true> then |
128 | C<mkdir> will attempt to create all the directories in the given path. |
129 | |
130 | Returns the full pathname to the new directory. |
131 | |
132 | =item ls ( [ DIR ] ) |
133 | |
134 | Get a directory listing of C<DIR>, or the current directory. |
135 | |
136 | Returns a reference to a list of lines returned from the server. |
137 | |
138 | =item dir ( [ DIR ] ) |
139 | |
140 | Get a directory listing of C<DIR>, or the current directory in long format. |
141 | |
142 | Returns a reference to a list of lines returned from the server. |
143 | |
144 | =item get ( REMOTE_FILE [, LOCAL_FILE ] ) |
145 | |
146 | Get C<REMOTE_FILE> from the server and store locally. C<LOCAL_FILE> may be |
147 | a filename or a filehandle. If not specified the the file will be stored in |
148 | the current directory with the same leafname as the remote file. |
149 | |
150 | Returns C<LOCAL_FILE>, or the generated local file name if C<LOCAL_FILE> |
151 | is not given. |
152 | |
153 | =item put ( LOCAL_FILE [, REMOTE_FILE ] ) |
154 | |
155 | Put a file on the remote server. C<LOCAL_FILE> may be a name or a filehandle. |
156 | If C<LOCAL_FILE> is a filehandle then C<REMOTE_FILE> must be specified. If |
157 | C<REMOTE_FILE> is not specified then the file will be stored in the current |
158 | directory with the same leafname as C<LOCAL_FILE>. |
159 | |
160 | Returns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE> |
161 | is not given. |
162 | |
163 | =item put_unique ( LOCAL_FILE [, REMOTE_FILE ] ) |
164 | |
165 | Same as put but uses the C<STOU> command. |
166 | |
167 | Returns the name of the file on the server. |
168 | |
169 | =item append ( LOCAL_FILE [, REMOTE_FILE ] ) |
170 | |
171 | Same as put but appends to the file on the remote server. |
172 | |
173 | Returns C<REMOTE_FILE>, or the generated remote filename if C<REMOTE_FILE> |
174 | is not given. |
175 | |
176 | =item unique_name () |
177 | |
178 | Returns the name of the last file stored on the server using the |
179 | C<STOU> command. |
180 | |
181 | =item mdtm ( FILE ) |
182 | |
183 | Returns the I<modification time> of the given file |
184 | |
185 | =item size ( FILE ) |
186 | |
187 | Returns the size in bytes for the given file. |
188 | |
189 | =back |
190 | |
191 | The following methods can return different results depending on |
192 | how they are called. If the user explicitly calls either |
193 | of the C<pasv> or C<port> methods then these methods will |
194 | return a I<true> or I<false> value. If the user does not |
195 | call either of these methods then the result will be a |
196 | reference to a C<Net::FTP::dataconn> based object. |
197 | |
198 | =over 4 |
199 | |
200 | =item nlst ( [ DIR ] ) |
201 | |
202 | Send a C<NLST> command to the server, with an optional parameter. |
203 | |
204 | =item list ( [ DIR ] ) |
205 | |
206 | Same as C<nlst> but using the C<LIST> command |
207 | |
208 | =item retr ( FILE ) |
209 | |
210 | Begin the retrieval of a file called C<FILE> from the remote server. |
211 | |
212 | =item stor ( FILE ) |
213 | |
214 | Tell the server that you wish to store a file. C<FILE> is the |
215 | name of the new file that should be created. |
216 | |
217 | =item stou ( FILE ) |
218 | |
219 | Same as C<stor> but using the C<STOU> command. The name of the unique |
220 | file which was created on the server will be avalaliable via the C<unique_name> |
221 | method after the data connection has been closed. |
222 | |
223 | =item appe ( FILE ) |
224 | |
225 | Tell the server that we want to append some data to the end of a file |
226 | called C<FILE>. If this file does not exist then create it. |
227 | |
228 | =back |
229 | |
230 | If for some reason you want to have complete control over the data connection, |
231 | this includes generating it and calling the C<response> method when required, |
232 | then the user can use these methods to do so. |
233 | |
234 | However calling these methods only affects the use of the methods above that |
235 | can return a data connection. They have no effect on methods C<get>, C<put>, |
236 | C<put_unique> and those that do not require data connections. |
237 | |
238 | =over 4 |
239 | |
240 | =item port ( [ PORT ] ) |
241 | |
242 | Send a C<PORT> command to the server. If C<PORT> is specified then it is sent |
243 | to the server. If not the a listen socket is created and the correct information |
244 | sent to the server. |
245 | |
246 | =item pasv () |
247 | |
248 | Tell the server to go into passive mode. Returns the text that represents the |
249 | port on which the server is listening, this text is in a suitable form to |
250 | sent to another ftp server using the C<port> method. |
251 | |
252 | =back |
5f05dabc |
253 | |
7e1af8bc |
254 | The following methods can be used to transfer files between two remote |
255 | servers, 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 | |
261 | This method will do a file transfer between two remote ftp servers. If |
262 | C<DEST_FILE> is omitted then the leaf name of C<SRC_FILE> will be used. |
263 | |
264 | =item pasv_wait ( NON_PASV_SERVER ) |
265 | |
266 | This method can be used to wait for a transfer to complete between a passive |
267 | server and a non-passive server. The method should be called on the passive |
268 | server with the C<Net::FTP> object for the non-passive server passed as an |
269 | argument. |
270 | |
271 | =item abort () |
272 | |
273 | Abort the current data transfer. |
274 | |
275 | =item quit () |
276 | |
277 | Send the QUIT command to the remote FTP server and close the socket connection. |
278 | |
279 | =back |
280 | |
281 | =head2 Methods for the adventurous |
282 | |
283 | C<Net::FTP> inherits from C<Net::Cmd> so methods defined in C<Net::Cmd> may |
284 | be used to send commands to the remote FTP server. |
285 | |
286 | =over 4 |
287 | |
288 | =item quot (CMD [,ARGS]) |
289 | |
290 | Send a command, that Net::FTP does not directly support, to the remote |
291 | server and wait for a response. |
292 | |
293 | Returns most significant digit of the response code. |
294 | |
295 | B<WARNING> This call should only be used on commands that do not require |
296 | data connections. Misuse of this method can hang the connection. |
297 | |
298 | =back |
299 | |
300 | =head1 THE dataconn CLASS |
301 | |
302 | Some of the methods defined in C<Net::FTP> return an object which will |
303 | be derived from this class.The dataconn class itself is derived from |
304 | the C<IO::Socket::INET> class, so any normal IO operations can be performed. |
305 | However the following methods are defined in the dataconn class and IO should |
306 | be performed using these. |
307 | |
308 | =over 4 |
309 | |
310 | =item read ( BUFFER, SIZE [, TIMEOUT ] ) |
311 | |
312 | Read C<SIZE> bytes of data from the server and place it into C<BUFFER>, also |
313 | performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not |
314 | given the the timeout value from the command connection will be used. |
315 | |
316 | Returns the number of bytes read before any <CRLF> translation. |
317 | |
318 | =item write ( BUFFER, SIZE [, TIMEOUT ] ) |
319 | |
320 | Write C<SIZE> bytes of data from C<BUFFER> to the server, also |
321 | performing any <CRLF> translation necessary. C<TIMEOUT> is optional, if not |
322 | given the the timeout value from the command connection will be used. |
323 | |
324 | Returns the number of bytes written before any <CRLF> translation. |
325 | |
326 | =item abort () |
327 | |
328 | Abort the current data transfer. |
329 | |
330 | =item close () |
331 | |
332 | Close the data connection and get a response from the FTP server. Returns |
333 | I<true> if the connection was closed sucessfully and the first digit of |
334 | the response from the server was a '2'. |
335 | |
336 | =back |
337 | |
338 | =head1 AUTHOR |
339 | |
340 | Graham Barr <Graham.Barr@tiuk.ti.com> |
341 | |
342 | =head1 REVISION |
343 | |
344 | $Revision: 2.8 $ |
345 | $Date: 1996/09/05 06:53:58 $ |
346 | |
347 | The VERSION is derived from the revision by changing each number after the |
348 | first 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 | |
355 | L<Net::Netrc> |
356 | L<Net::Cmd> |
357 | |
358 | =head1 CREDITS |
359 | |
360 | Henry Gabryjelski <henryg@WPI.EDU> - for the suggestion of creating directories |
361 | recursively. |
362 | |
363 | =head1 COPYRIGHT |
364 | |
365 | Copyright (c) 1995 Graham Barr. All rights reserved. This program is free |
366 | software; you can redistribute it and/or modify it under the same terms |
367 | as Perl itself. |
5f05dabc |
368 | |
369 | =cut |
370 | |
7e1af8bc |
371 | require 5.001; |
5f05dabc |
372 | |
7e1af8bc |
373 | use strict; |
374 | use vars qw(@ISA $VERSION); |
375 | use Carp; |
376 | |
377 | use Socket 1.3; |
378 | use IO::Socket; |
379 | use Time::Local; |
380 | use Net::Cmd; |
381 | use 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 | |
386 | sub 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 |
437 | sub quit |
438 | { |
439 | my $ftp = shift; |
5f05dabc |
440 | |
7e1af8bc |
441 | $ftp->_QUIT |
442 | && $ftp->SUPER::close; |
5f05dabc |
443 | } |
444 | |
7e1af8bc |
445 | sub close |
446 | { |
447 | my $ftp = shift; |
5f05dabc |
448 | |
7e1af8bc |
449 | ref($ftp) |
450 | && defined fileno($ftp) |
451 | && $ftp->quit; |
452 | } |
5f05dabc |
453 | |
7e1af8bc |
454 | sub DESTROY { shift->close } |
5f05dabc |
455 | |
456 | sub ascii { shift->type('A',@_); } |
5f05dabc |
457 | sub binary { shift->type('I',@_); } |
7e1af8bc |
458 | |
459 | sub ebcdic |
460 | { |
461 | carp "TYPE E is unsupported, shall default to I"; |
462 | shift->type('E',@_); |
463 | } |
464 | |
465 | sub 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 |
473 | sub 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 |
482 | sub 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 |
495 | sub size |
496 | { |
497 | my $ftp = shift; |
498 | my $file = shift; |
499 | |
500 | $ftp->_SIZE($file) |
501 | ? ($ftp->message =~ /(\d+)/)[0] |
502 | : undef; |
503 | } |
504 | |
505 | sub 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 |
561 | sub 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 | |
588 | sub 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 |
598 | sub 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 |
615 | sub 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 |
635 | sub 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 | |
694 | sub 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 | |
707 | sub cdup |
708 | { |
709 | @_ == 1 or croak 'usage: $ftp->cdup()'; |
710 | $_[0]->_CDUP; |
5f05dabc |
711 | } |
712 | |
7e1af8bc |
713 | sub pwd |
714 | { |
715 | @_ == 1 || croak 'usage: $ftp->pwd()'; |
716 | my $ftp = shift; |
717 | |
718 | $ftp->_PWD(); |
719 | $ftp->_extract_path; |
720 | } |
721 | |
722 | sub rmdir |
723 | { |
724 | @_ == 2 || croak 'usage: $ftp->rmdir( DIR )'; |
725 | |
726 | $_[0]->_RMD($_[1]); |
727 | } |
728 | |
729 | sub 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 |
761 | sub delete |
762 | { |
763 | @_ == 2 || croak 'usage: $ftp->delete( FILENAME )'; |
5f05dabc |
764 | |
7e1af8bc |
765 | $_[0]->_DELE($_[1]); |
5f05dabc |
766 | } |
767 | |
7e1af8bc |
768 | sub put { shift->_store_cmd("stor",@_) } |
769 | sub put_unique { shift->_store_cmd("stou",@_) } |
770 | sub append { shift->_store_cmd("appe",@_) } |
5f05dabc |
771 | |
7e1af8bc |
772 | sub nlst { shift->_data_cmd("NLST",@_) } |
773 | sub list { shift->_data_cmd("LIST",@_) } |
774 | sub retr { shift->_data_cmd("RETR",@_) } |
775 | sub stor { shift->_data_cmd("STOR",@_) } |
776 | sub stou { shift->_data_cmd("STOU",@_) } |
777 | sub appe { shift->_data_cmd("APPE",@_) } |
5f05dabc |
778 | |
7e1af8bc |
779 | sub _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 |
839 | sub 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 |
873 | sub ls { shift->_list_cmd("NLST",@_); } |
874 | sub dir { shift->_list_cmd("LIST",@_); } |
5f05dabc |
875 | |
7e1af8bc |
876 | sub 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 |
889 | sub 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 |
899 | sub lsl |
900 | { |
901 | carp "Use of Net::FTP::lsl depreciated, use 'dir'" |
902 | if $^W; |
903 | goto &dir; |
5f05dabc |
904 | } |
905 | |
7e1af8bc |
906 | sub 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 |
918 | sub _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 |
933 | sub _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 |
969 | sub _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 |
1000 | sub _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 |
1055 | sub debug_text { $_[2] =~ /^(pass|resp)/i ? "$1 ....\n" : $_[2]; } |
1056 | |
1057 | sub command |
1058 | { |
1059 | my $ftp = shift; |
1060 | |
1061 | delete ${*$ftp}{'net_ftp_port'}; |
1062 | $ftp->SUPER::command(@_); |
5f05dabc |
1063 | } |
1064 | |
7e1af8bc |
1065 | sub 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 |
1080 | sub 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 |
1100 | sub 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 |
1125 | sub cmd { shift->command(@_)->responce() } |
1126 | |
1127 | ######################################## |
1128 | # |
1129 | # RFC959 commands |
1130 | # |
1131 | |
1132 | sub _ABOR { shift->command("ABOR")->response() == CMD_OK } |
1133 | sub _CDUP { shift->command("CDUP")->response() == CMD_OK } |
1134 | sub _NOOP { shift->command("NOOP")->response() == CMD_OK } |
1135 | sub _PASV { shift->command("PASV")->response() == CMD_OK } |
1136 | sub _QUIT { shift->command("QUIT")->response() == CMD_OK } |
1137 | sub _DELE { shift->command("DELE",@_)->response() == CMD_OK } |
1138 | sub _CWD { shift->command("CWD", @_)->response() == CMD_OK } |
1139 | sub _PORT { shift->command("PORT",@_)->response() == CMD_OK } |
1140 | sub _RMD { shift->command("RMD", @_)->response() == CMD_OK } |
1141 | sub _MKD { shift->command("MKD", @_)->response() == CMD_OK } |
1142 | sub _PWD { shift->command("PWD", @_)->response() == CMD_OK } |
1143 | sub _TYPE { shift->command("TYPE",@_)->response() == CMD_OK } |
1144 | sub _RNTO { shift->command("RNTO",@_)->response() == CMD_OK } |
1145 | sub _ACCT { shift->command("ACCT",@_)->response() == CMD_OK } |
1146 | sub _RESP { shift->command("RESP",@_)->response() == CMD_OK } |
1147 | sub _MDTM { shift->command("MDTM",@_)->response() == CMD_OK } |
1148 | sub _SIZE { shift->command("SIZE",@_)->response() == CMD_OK } |
1149 | sub _APPE { shift->command("APPE",@_)->response() == CMD_INFO } |
1150 | sub _LIST { shift->command("LIST",@_)->response() == CMD_INFO } |
1151 | sub _NLST { shift->command("NLST",@_)->response() == CMD_INFO } |
1152 | sub _RETR { shift->command("RETR",@_)->response() == CMD_INFO } |
1153 | sub _STOR { shift->command("STOR",@_)->response() == CMD_INFO } |
1154 | sub _STOU { shift->command("STOU",@_)->response() == CMD_INFO } |
1155 | sub _RNFR { shift->command("RNFR",@_)->response() == CMD_MORE } |
1156 | sub _REST { shift->command("REST",@_)->response() == CMD_MORE } |
1157 | sub _USER { shift->command("user",@_)->response() } # A certain brain dead firewall :-) |
1158 | sub _PASS { shift->command("PASS",@_)->response() } |
1159 | sub _AUTH { shift->command("AUTH",@_)->response() } |
1160 | |
1161 | sub _ALLO { shift->unsupported(@_) } |
1162 | sub _SMNT { shift->unsupported(@_) } |
1163 | sub _HELP { shift->unsupported(@_) } |
1164 | sub _MODE { shift->unsupported(@_) } |
1165 | sub _SITE { shift->unsupported(@_) } |
1166 | sub _SYST { shift->unsupported(@_) } |
1167 | sub _STAT { shift->unsupported(@_) } |
1168 | sub _STRU { shift->unsupported(@_) } |
1169 | sub _REIN { shift->unsupported(@_) } |
5f05dabc |
1170 | |
7e1af8bc |
1171 | ## |
1172 | ## Generic data connection package |
1173 | ## |
5f05dabc |
1174 | |
1175 | package Net::FTP::dataconn; |
7e1af8bc |
1176 | |
5f05dabc |
1177 | use Carp; |
7e1af8bc |
1178 | use vars qw(@ISA $timeout); |
1179 | use Net::Cmd; |
5f05dabc |
1180 | |
7e1af8bc |
1181 | @ISA = qw(IO::Socket::INET); |
5f05dabc |
1182 | |
7e1af8bc |
1183 | sub 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 |
1191 | sub 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 |
1209 | sub _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 |
1233 | sub can_read |
1234 | { |
1235 | my $data = shift; |
5f05dabc |
1236 | local *timeout = \$_[0]; |
1237 | |
7e1af8bc |
1238 | $data->_select($timeout,1); |
5f05dabc |
1239 | } |
1240 | |
7e1af8bc |
1241 | sub can_write |
1242 | { |
1243 | my $data = shift; |
5f05dabc |
1244 | local *timeout = \$_[0]; |
1245 | |
7e1af8bc |
1246 | $data->_select($timeout,0); |
5f05dabc |
1247 | } |
1248 | |
7e1af8bc |
1249 | sub 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 |
1264 | package Net::FTP::A; |
7e1af8bc |
1265 | |
1266 | use vars qw(@ISA $buf); |
5f05dabc |
1267 | use Carp; |
1268 | |
7e1af8bc |
1269 | @ISA = qw(Net::FTP::dataconn); |
5f05dabc |
1270 | |
7e1af8bc |
1271 | sub 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 |
1323 | sub 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 |
1354 | package Net::FTP::I; |
7e1af8bc |
1355 | |
1356 | use vars qw(@ISA $buf); |
5f05dabc |
1357 | use Carp; |
1358 | |
7e1af8bc |
1359 | @ISA = qw(Net::FTP::dataconn); |
5f05dabc |
1360 | |
7e1af8bc |
1361 | sub 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 |
1376 | sub 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 | |
1390 | 1; |
1391 | |