This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Fix C<print $_> in debugger
[perl5.git] / lib / ftp.pl
CommitLineData
79072805
LW
1#-*-perl-*-
2# This is a wrapper to the chat2.pl routines that make life easier
3# to do ftp type work.
4# Mostly by Lee McLoughlin <lmjm@doc.ic.ac.uk>
5# based on original version by Alan R. Martello <al@ee.pitt.edu>
6# And by A.Macpherson@bnr.co.uk for multi-homed hosts
7#
8# $Header: /a/swan/home/swan/staff/csg/lmjm/src/perl/mirror/RCS/ftp.pl,v 1.17 1993/04/21 10:06:54 lmjm Exp lmjm $
9# $Log: ftp.pl,v $
10# Revision 1.17 1993/04/21 10:06:54 lmjm
11# Send all status reports to STDERR not to STDOUT (to allow use by ftpcat).
12# Allow target file to be '-' meaning STDOUT
13# Added ftp'quote
14#
15# Revision 1.16 1993/01/28 18:59:05 lmjm
16# Allow socket arguemtns to come from main.
17# Minor cleanups - removed old comments.
18#
19# Revision 1.15 1992/11/25 21:09:30 lmjm
20# Added another REST return code.
21#
22# Revision 1.14 1992/08/12 14:33:42 lmjm
23# Fail ftp'write if out of space.
24#
25# Revision 1.13 1992/03/20 21:01:03 lmjm
26# Added in the proxy ftp code from Edwards Reed <err@cinops.xerox.com>
27# Added ftp'delete from Aaron Wohl <aw0g+@andrew.cmu.edu>
28#
29# Revision 1.12 1992/02/06 23:25:56 lmjm
30# Moved code around so can use this as a lib for both mirror and ftpmail.
31# Time out opens. In case Unix doesn't bother to.
32#
33# Revision 1.11 1991/11/27 22:05:57 lmjm
34# Match the response code number at the start of a line allowing
35# for any leading junk.
36#
37# Revision 1.10 1991/10/23 22:42:20 lmjm
38# Added better timeout code.
39# Tried to optimise file transfer
40# Moved open/close code to not leak file handles.
41# Cleaned up the alarm code.
42# Added $fatalerror to show wether the ftp link is really dead.
43#
44# Revision 1.9 1991/10/07 18:30:35 lmjm
45# Made the timeout-read code work.
46# Added restarting file gets.
47# Be more verbose if ever have to call die.
48#
49# Revision 1.8 1991/09/17 22:53:16 lmjm
50# Spot when open_data_socket fails and return a failure rather than dying.
51#
52# Revision 1.7 1991/09/12 22:40:25 lmjm
53# Added Andrew Macpherson's patches for hosts without ip forwarding.
54#
55# Revision 1.6 1991/09/06 19:53:52 lmjm
56# Relaid out the code the way I like it!
57# Changed the debuggin to produce more "appropriate" messages
58# Fixed bugs in the ordering of put and dir listing.
59# Allow for hash printing when getting files (a la ftp).
60# Added the new commands from Al.
61# Don't print passwords in debugging.
62#
63# Revision 1.5 1991/08/29 16:23:49 lmjm
64# Timeout reads from the remote ftp server.
65# No longer call die expect on fatal errors. Just return fail codes.
66# Changed returns so higher up routines can tell whats happening.
67# Get expect/accept in correct order for dir listing.
68# When ftp_show is set then print hashes every 1k transfered (like ftp).
69# Allow for stripping returns out of incoming data.
70# Save last error in a global string.
71#
72# Revision 1.4 1991/08/14 21:04:58 lmjm
73# ftp'get now copes with ungetable files.
74# ftp'expect code changed such that the string_to_print is
75# ignored and the string sent back from the remote system is printed
76# instead.
77# Implemented patches from al. Removed spuiours tracing statements.
78#
79# Revision 1.3 1991/08/09 21:32:18 lmjm
80# Allow for another ok code on cwd's
81# Rejigger the log levels
82# Send \r\n for some odd ftp daemons
83#
84# Revision 1.2 1991/08/09 18:07:37 lmjm
85# Don't print messages unless ftp_show says to.
86#
87# Revision 1.1 1991/08/08 20:31:00 lmjm
88# Initial revision
89#
90
91require 'chat2.pl';
c2960299 92eval "require 'socket.ph'" || eval "require 'sys/socket.ph'" || die "socket.ph missing: $!\n";
79072805
LW
93
94
95package ftp;
96
97if( defined( &main'PF_INET ) ){
98 $pf_inet = &main'PF_INET;
99 $sock_stream = &main'SOCK_STREAM;
100 local($name, $aliases, $proto) = getprotobyname( 'tcp' );
101 $tcp_proto = $proto;
102}
103else {
104 # XXX hardwired $PF_INET, $SOCK_STREAM, 'tcp'
105 # but who the heck would change these anyway? (:-)
106 $pf_inet = 2;
107 $sock_stream = 1;
108 $tcp_proto = 6;
109}
110
111# If the remote ftp daemon doesn't respond within this time presume its dead
112# or something.
113$timeout = 30;
114
115# Timeout a read if I don't get data back within this many seconds
116$timeout_read = 20 * $timeout;
117
118# Timeout an open
119$timeout_open = $timeout;
120
121# This is a "global" it contains the last response from the remote ftp server
122# for use in error messages
123$ftp'response = "";
124# Also ftp'NS is the socket containing the data coming in from the remote ls
125# command.
126
127# The size of block to be read or written when talking to the remote
128# ftp server
129$ftp'ftpbufsize = 4096;
130
131# How often to print a hash out, when debugging
132$ftp'hashevery = 1024;
133# Output a newline after this many hashes to prevent outputing very long lines
134$ftp'hashnl = 70;
135
136# If a proxy connection then who am I really talking to?
137$real_site = "";
138
139# This is just a tracing aid.
140$ftp_show = 0;
141sub ftp'debug
142{
40da2db3 143 $ftp_show = $_[0];
79072805
LW
144# if( $ftp_show ){
145# print STDERR "ftp debugging on\n";
146# }
147}
148
149sub ftp'set_timeout
150{
40da2db3 151 $timeout = $_[0];
79072805
LW
152 $timeout_open = $timeout;
153 $timeout_read = 20 * $timeout;
154 if( $ftp_show ){
155 print STDERR "ftp timeout set to $timeout\n";
156 }
157}
158
159
160sub ftp'open_alarm
161{
162 die "timeout: open";
163}
164
165sub ftp'timed_open
166{
167 local( $site, $ftp_port, $retry_call, $attempts ) = @_;
168 local( $connect_site, $connect_port );
169 local( $res );
170
171 alarm( $timeout_open );
172
173 while( $attempts-- ){
174 if( $ftp_show ){
175 print STDERR "proxy connecting via $proxy_gateway [$proxy_ftp_port]\n" if $proxy;
176 print STDERR "Connecting to $site";
177 if( $ftp_port != 21 ){
178 print STDERR " [port $ftp_port]";
179 }
180 print STDERR "\n";
181 }
182
183 if( $proxy ) {
184 if( ! $proxy_gateway ) {
185 # if not otherwise set
186 $proxy_gateway = "internet-gateway";
187 }
188 if( $debug ) {
189 print STDERR "using proxy services of $proxy_gateway, ";
190 print STDERR "at $proxy_ftp_port\n";
191 }
192 $connect_site = $proxy_gateway;
193 $connect_port = $proxy_ftp_port;
194 $real_site = $site;
195 }
196 else {
197 $connect_site = $site;
198 $connect_port = $ftp_port;
199 }
200 if( ! &chat'open_port( $connect_site, $connect_port ) ){
201 if( $retry_call ){
202 print STDERR "Failed to connect\n" if $ftp_show;
203 next;
204 }
205 else {
206 print STDERR "proxy connection failed " if $proxy;
207 print STDERR "Cannot open ftp to $connect_site\n" if $ftp_show;
208 return 0;
209 }
210 }
211 $res = &ftp'expect( $timeout,
212 120, "service unavailable to $site", 0,
213 220, "ready for login to $site", 1,
214 421, "service unavailable to $site, closing connection", 0);
215 if( ! $res ){
216 &chat'close();
217 next;
218 }
219 return 1;
220 }
221 continue {
222 print STDERR "Pausing between retries\n";
223 sleep( $retry_pause );
224 }
225 return 0;
226}
227
228sub ftp'open
229{
230 local( $site, $ftp_port, $retry_call, $attempts ) = @_;
231
232 $SIG{ 'ALRM' } = "ftp\'open_alarm";
233
234 local( $ret ) = eval "&timed_open( '$site', $ftp_port, $retry_call, $attempts )";
235 alarm( 0 );
236
237 if( $@ =~ /^timeout/ ){
238 return -1;
239 }
240 return $ret;
241}
242
243sub ftp'login
244{
245 local( $remote_user, $remote_password ) = @_;
246
247 if( $proxy ){
2ad7ff01 248 &ftp'send( "USER $remote_user\@$site" );
79072805
LW
249 }
250 else {
251 &ftp'send( "USER $remote_user" );
252 }
253 local( $val ) =
254 &ftp'expect($timeout,
255 230, "$remote_user logged in", 1,
256 331, "send password for $remote_user", 2,
257
258 500, "syntax error", 0,
259 501, "syntax error", 0,
260 530, "not logged in", 0,
261 332, "account for login not supported", 0,
262
263 421, "service unavailable, closing connection", 0);
264 if( $val == 1 ){
265 return 1;
266 }
267 if( $val == 2 ){
268 # A password is needed
269 &ftp'send( "PASS $remote_password" );
270
271 $val = &ftp'expect( $timeout,
272 230, "$remote_user logged in", 1,
273
274 202, "command not implemented", 0,
275 332, "account for login not supported", 0,
276
277 530, "not logged in", 0,
278 500, "syntax error", 0,
279 501, "syntax error", 0,
280 503, "bad sequence of commands", 0,
281
282 421, "service unavailable, closing connection", 0);
283 if( $val == 1){
284 # Logged in
285 return 1;
286 }
287 }
288 # If I got here I failed to login
289 return 0;
290}
291
292sub ftp'close
293{
294 &ftp'quit();
295 &chat'close();
296}
297
298# Change directory
299# return 1 if successful
300# 0 on a failure
301sub ftp'cwd
302{
303 local( $dir ) = @_;
304
305 &ftp'send( "CWD $dir" );
306
307 return &ftp'expect( $timeout,
308 200, "working directory = $dir", 1,
309 250, "working directory = $dir", 1,
310
311 500, "syntax error", 0,
312 501, "syntax error", 0,
313 502, "command not implemented", 0,
314 530, "not logged in", 0,
315 550, "cannot change directory", 0,
316 421, "service unavailable, closing connection", 0 );
317}
318
319# Get a full directory listing:
320# &ftp'dir( remote LIST options )
321# Start a list goin with the given options.
322# Presuming that the remote deamon uses the ls command to generate the
323# data to send back then then you can send it some extra options (eg: -lRa)
324# return 1 if sucessful and 0 on a failure
325sub ftp'dir_open
326{
327 local( $options ) = @_;
328 local( $ret );
329
330 if( ! &ftp'open_data_socket() ){
331 return 0;
332 }
333
334 if( $options ){
335 &ftp'send( "LIST $options" );
336 }
337 else {
338 &ftp'send( "LIST" );
339 }
340
341 $ret = &ftp'expect( $timeout,
342 150, "reading directory", 1,
343
344 125, "data connection already open?", 0,
345
346 450, "file unavailable", 0,
347 500, "syntax error", 0,
348 501, "syntax error", 0,
349 502, "command not implemented", 0,
350 530, "not logged in", 0,
351
352 421, "service unavailable, closing connection", 0 );
353 if( ! $ret ){
354 &ftp'close_data_socket;
355 return 0;
356 }
357
358 #
359 # the data should be coming at us now
360 #
361
362 # now accept
363 accept(NS,S) || die "accept failed $!";
364
365 return 1;
366}
367
368
369# Close down reading the result of a remote ls command
370# return 1 if successful and 0 on failure
371sub ftp'dir_close
372{
373 local( $ret );
374
375 # read the close
376 #
377 $ret = &ftp'expect($timeout,
378 226, "", 1, # transfer complete, closing connection
379 250, "", 1, # action completed
380
381 425, "can't open data connection", 0,
382 426, "connection closed, transfer aborted", 0,
383 451, "action aborted, local error", 0,
384 421, "service unavailable, closing connection", 0);
385
386 # shut down our end of the socket
387 &ftp'close_data_socket;
388
389 if( ! $ret ){
390 return 0;
391 }
392
393 return 1;
394}
395
396# Quit from the remote ftp server
397# return 1 if successful and 0 on failure
398sub ftp'quit
399{
400 $site_command_check = 0;
401 @site_command_list = ();
402
403 &ftp'send("QUIT");
404
405 return &ftp'expect($timeout,
406 221, "Goodbye", 1, # transfer complete, closing connection
407
408 500, "error quitting??", 0);
409}
410
411sub ftp'read_alarm
412{
413 die "timeout: read";
414}
415
416sub ftp'timed_read
417{
418 alarm( $timeout_read );
419 return sysread( NS, $buf, $ftpbufsize );
420}
421
422sub ftp'read
423{
424 $SIG{ 'ALRM' } = "ftp\'read_alarm";
425
426 local( $ret ) = eval '&timed_read()';
427 alarm( 0 );
428
429 if( $@ =~ /^timeout/ ){
430 return -1;
431 }
432 return $ret;
433}
434
435# Get a remote file back into a local file.
436# If no loc_fname passed then uses rem_fname.
437# returns 1 on success and 0 on failure
438sub ftp'get
439{
440 local($rem_fname, $loc_fname, $restart ) = @_;
441
442 if ($loc_fname eq "") {
443 $loc_fname = $rem_fname;
444 }
445
446 if( ! &ftp'open_data_socket() ){
447 print STDERR "Cannot open data socket\n";
448 return 0;
449 }
450
451 if( $loc_fname ne '-' ){
452 # Find the size of the target file
453 local( $restart_at ) = &ftp'filesize( $loc_fname );
454 if( $restart && $restart_at > 0 && &ftp'restart( $restart_at ) ){
455 $restart = 1;
456 # Make sure the file can be updated
457 chmod( 0644, $loc_fname );
458 }
459 else {
460 $restart = 0;
461 unlink( $loc_fname );
462 }
463 }
464
465 &ftp'send( "RETR $rem_fname" );
466
467 local( $ret ) =
468 &ftp'expect($timeout,
469 150, "receiving $rem_fname", 1,
470
471 125, "data connection already open?", 0,
472
473 450, "file unavailable", 2,
474 550, "file unavailable", 2,
475
476 500, "syntax error", 0,
477 501, "syntax error", 0,
478 530, "not logged in", 0,
479
480 421, "service unavailable, closing connection", 0);
481 if( $ret != 1 ){
482 print STDERR "Failure on RETR command\n";
483
484 # shut down our end of the socket
485 &ftp'close_data_socket;
486
487 return 0;
488 }
489
490 #
491 # the data should be coming at us now
492 #
493
494 # now accept
495 accept(NS,S) || die "accept failed: $!";
496
497 #
498 # open the local fname
499 # concatenate on the end if restarting, else just overwrite
500 if( !open(FH, ($restart ? '>>' : '>') . $loc_fname) ){
501 print STDERR "Cannot create local file $loc_fname\n";
502
503 # shut down our end of the socket
504 &ftp'close_data_socket;
505
506 return 0;
507 }
508
509# while (<NS>) {
510# print FH ;
511# }
512
513 local( $start_time ) = time;
514 local( $bytes, $lasthash, $hashes ) = (0, 0, 0);
515 while( ($len = &ftp'read()) > 0 ){
516 $bytes += $len;
517 if( $strip_cr ){
518 $ftp'buf =~ s/\r//g;
519 }
520 if( $ftp_show ){
521 while( $bytes > ($lasthash + $ftp'hashevery) ){
522 print STDERR '#';
523 $lasthash += $ftp'hashevery;
524 $hashes++;
525 if( ($hashes % $ftp'hashnl) == 0 ){
526 print STDERR "\n";
527 }
528 }
529 }
530 if( ! print FH $ftp'buf ){
531 print STDERR "\nfailed to write data";
532 return 0;
533 }
534 }
535 close( FH );
536
537 # shut down our end of the socket
538 &ftp'close_data_socket;
539
540 if( $len < 0 ){
541 print STDERR "\ntimed out reading data!\n";
542
543 return 0;
544 }
545
546 if( $ftp_show ){
547 if( $hashes && ($hashes % $ftp'hashnl) != 0 ){
548 print STDERR "\n";
549 }
550 local( $secs ) = (time - $start_time);
551 if( $secs <= 0 ){
552 $secs = 1; # To avoid a divide by zero;
553 }
554
555 local( $rate ) = int( $bytes / $secs );
556 print STDERR "Got $bytes bytes ($rate bytes/sec)\n";
557 }
558
559 #
560 # read the close
561 #
562
563 $ret = &ftp'expect($timeout,
564 226, "Got file", 1, # transfer complete, closing connection
565 250, "Got file", 1, # action completed
566
567 110, "restart not supported", 0,
568 425, "can't open data connection", 0,
569 426, "connection closed, transfer aborted", 0,
570 451, "action aborted, local error", 0,
571 421, "service unavailable, closing connection", 0);
572
573 return $ret;
574}
575
576sub ftp'delete
577{
578 local( $rem_fname, $val ) = @_;
579
580 &ftp'send("DELE $rem_fname" );
581 $val = &ftp'expect( $timeout,
582 250,"Deleted $rem_fname", 1,
583 550,"Permission denied",0
584 );
585 return $val == 1;
586}
587
588sub ftp'deldir
589{
590 local( $fname ) = @_;
591
592 # not yet implemented
593 # RMD
594}
595
596# UPDATE ME!!!!!!
597# Add in the hash printing and newline conversion
598sub ftp'put
599{
600 local( $loc_fname, $rem_fname ) = @_;
601 local( $strip_cr );
602
603 if ($loc_fname eq "") {
604 $loc_fname = $rem_fname;
605 }
606
607 if( ! &ftp'open_data_socket() ){
608 return 0;
609 }
610
611 &ftp'send("STOR $rem_fname");
612
613 #
614 # the data should be coming at us now
615 #
616
617 local( $ret ) =
618 &ftp'expect($timeout,
619 150, "sending $loc_fname", 1,
620
621 125, "data connection already open?", 0,
622 450, "file unavailable", 0,
623
624 532, "need account for storing files", 0,
625 452, "insufficient storage on system", 0,
626 553, "file name not allowed", 0,
627
628 500, "syntax error", 0,
629 501, "syntax error", 0,
630 530, "not logged in", 0,
631
632 421, "service unavailable, closing connection", 0);
633
634 if( $ret != 1 ){
635 # shut down our end of the socket
636 &ftp'close_data_socket;
637
638 return 0;
639 }
640
641
642 #
643 # the data should be coming at us now
644 #
645
646 # now accept
647 accept(NS,S) || die "accept failed: $!";
648
649 #
650 # open the local fname
651 #
652 if( !open(FH, "<$loc_fname") ){
653 print STDERR "Cannot open local file $loc_fname\n";
654
655 # shut down our end of the socket
656 &ftp'close_data_socket;
657
658 return 0;
659 }
660
661 while (<FH>) {
662 print NS ;
663 }
664 close(FH);
665
666 # shut down our end of the socket to signal EOF
667 &ftp'close_data_socket;
668
669 #
670 # read the close
671 #
672
673 $ret = &ftp'expect($timeout,
674 226, "file put", 1, # transfer complete, closing connection
675 250, "file put", 1, # action completed
676
677 110, "restart not supported", 0,
678 425, "can't open data connection", 0,
679 426, "connection closed, transfer aborted", 0,
680 451, "action aborted, local error", 0,
681 551, "page type unknown", 0,
682 552, "storage allocation exceeded", 0,
683
684 421, "service unavailable, closing connection", 0);
685 if( ! $ret ){
686 print STDERR "error putting $loc_fname\n";
687 }
688 return $ret;
689}
690
691sub ftp'restart
692{
693 local( $restart_point, $ret ) = @_;
694
695 &ftp'send("REST $restart_point");
696
697 #
698 # see what they say
699
700 $ret = &ftp'expect($timeout,
701 350, "restarting at $restart_point", 1,
702
703 500, "syntax error", 0,
704 501, "syntax error", 0,
705 502, "REST not implemented", 2,
706 530, "not logged in", 0,
707 554, "REST not implemented", 2,
708
709 421, "service unavailable, closing connection", 0);
710 return $ret;
711}
712
713# Set the file transfer type
714sub ftp'type
715{
716 local( $type ) = @_;
717
718 &ftp'send("TYPE $type");
719
720 #
721 # see what they say
722
723 $ret = &ftp'expect($timeout,
724 200, "file type set to $type", 1,
725
726 500, "syntax error", 0,
727 501, "syntax error", 0,
728 504, "Invalid form or byte size for type $type", 0,
729
730 421, "service unavailable, closing connection", 0);
731 return $ret;
732}
733
734$site_command_check = 0;
735@site_command_list = ();
736
737# routine to query the remote server for 'SITE' commands supported
738sub ftp'site_commands
739{
740 local( $ret );
741
742 # if we havent sent a 'HELP SITE', send it now
743 if( !$site_command_check ){
744
745 $site_command_check = 1;
746
747 &ftp'send( "HELP SITE" );
748
749 # assume the line in the HELP SITE response with the 'HELP'
750 # command is the one for us
751 $ret = &ftp'expect( $timeout,
752 ".*HELP.*", "", "\$1",
753 214, "", "0",
754 202, "", "0" );
755
756 if( $ret eq "0" ){
757 print STDERR "No response from HELP SITE\n" if( $ftp_show );
758 }
759
760 @site_command_list = split(/\s+/, $ret);
761 }
762
763 return @site_command_list;
764}
765
766# return the pwd, or null if we can't get the pwd
767sub ftp'pwd
768{
769 local( $ret, $cwd );
770
771 &ftp'send( "PWD" );
772
773 #
774 # see what they say
775
776 $ret = &ftp'expect( $timeout,
777 257, "working dir is", 1,
778 500, "syntax error", 0,
779 501, "syntax error", 0,
780 502, "PWD not implemented", 0,
781 550, "file unavailable", 0,
782
783 421, "service unavailable, closing connection", 0 );
784 if( $ret ){
785 if( $ftp'response =~ /^257\s"(.*)"\s.*$/ ){
786 $cwd = $1;
787 }
788 }
789 return $cwd;
790}
791
792# return 1 for success, 0 for failure
793sub ftp'mkdir
794{
795 local( $path ) = @_;
796 local( $ret );
797
798 &ftp'send( "MKD $path" );
799
800 #
801 # see what they say
802
803 $ret = &ftp'expect( $timeout,
804 257, "made directory $path", 1,
805
806 500, "syntax error", 0,
807 501, "syntax error", 0,
808 502, "MKD not implemented", 0,
809 530, "not logged in", 0,
810 550, "file unavailable", 0,
811
812 421, "service unavailable, closing connection", 0 );
813 return $ret;
814}
815
816# return 1 for success, 0 for failure
817sub ftp'chmod
818{
819 local( $path, $mode ) = @_;
820 local( $ret );
821
822 &ftp'send( sprintf( "SITE CHMOD %o $path", $mode ) );
823
824 #
825 # see what they say
826
827 $ret = &ftp'expect( $timeout,
828 200, "chmod $mode $path succeeded", 1,
829
830 500, "syntax error", 0,
831 501, "syntax error", 0,
832 502, "CHMOD not implemented", 0,
833 530, "not logged in", 0,
834 550, "file unavailable", 0,
835
836 421, "service unavailable, closing connection", 0 );
837 return $ret;
838}
839
840# rename a file
841sub ftp'rename
842{
843 local( $old_name, $new_name ) = @_;
844 local( $ret );
845
846 &ftp'send( "RNFR $old_name" );
847
848 #
849 # see what they say
850
851 $ret = &ftp'expect( $timeout,
852 350, "", 1,
853
854 500, "syntax error", 0,
855 501, "syntax error", 0,
856 502, "RNFR not implemented", 0,
857 530, "not logged in", 0,
858 550, "file unavailable", 0,
859 450, "file unavailable", 0,
860
861 421, "service unavailable, closing connection", 0);
862
863
864 # check if the "rename from" occurred ok
865 if( $ret ) {
866 &ftp'send( "RNTO $new_name" );
867
868 #
869 # see what they say
870
871 $ret = &ftp'expect( $timeout,
872 250, "rename $old_name to $new_name", 1,
873
874 500, "syntax error", 0,
875 501, "syntax error", 0,
876 502, "RNTO not implemented", 0,
877 503, "bad sequence of commands", 0,
878 530, "not logged in", 0,
879 532, "need account for storing files", 0,
880 553, "file name not allowed", 0,
881
882 421, "service unavailable, closing connection", 0);
883 }
884
885 return $ret;
886}
887
888
889sub ftp'quote
890{
891 local( $cmd ) = @_;
892
893 &ftp'send( $cmd );
894
895 return &ftp'expect( $timeout,
896 200, "Remote '$cmd' OK", 1,
897 500, "error in remote '$cmd'", 0 );
898}
899
900# ------------------------------------------------------------------------------
901# These are the lower level support routines
902
903sub ftp'expectgot
904{
905 ($ftp'response, $ftp'fatalerror) = @_;
906 if( $ftp_show ){
907 print STDERR "$ftp'response\n";
908 }
909}
910
911#
912# create the list of parameters for chat'expect
913#
914# ftp'expect(time_out, {value, string_to_print, return value});
915# if the string_to_print is "" then nothing is printed
916# the last response is stored in $ftp'response
917#
918# NOTE: lmjm has changed this code such that the string_to_print is
919# ignored and the string sent back from the remote system is printed
920# instead.
921#
922sub ftp'expect {
923 local( $ret );
924 local( $time_out );
925 local( $expect_args );
926
927 $ftp'response = '';
928 $ftp'fatalerror = 0;
929
930 @expect_args = ();
931
932 $time_out = shift(@_);
933
934 while( @_ ){
935 local( $code ) = shift( @_ );
936 local( $pre ) = '^';
937 if( $code =~ /^\d/ ){
938 $pre =~ "[.|\n]*^";
939 }
940 push( @expect_args, "$pre(" . $code . " .*)\\015\\n" );
941 shift( @_ );
942 push( @expect_args,
943 "&ftp'expectgot( \$1, 0 ); " . shift( @_ ) );
944 }
945
946 # Treat all unrecognised lines as continuations
947 push( @expect_args, "^(.*)\\015\\n" );
948 push( @expect_args, "&ftp'expectgot( \$1, 0 ); 100" );
949
950 # add patterns TIMEOUT and EOF
951
952 push( @expect_args, 'TIMEOUT' );
953 push( @expect_args, "&ftp'expectgot( \"timed out\", 1 ); 0" );
954
955 push( @expect_args, 'EOF' );
956 push( @expect_args, "&ftp'expectgot( \"remote server gone away\", 1 ); 0" );
957
958 if( $ftp_show > 9 ){
959 &printargs( $time_out, @expect_args );
960 }
961
962 $ret = &chat'expect( $time_out, @expect_args );
963 if( $ret == 100 ){
964 # we saw a continuation line, wait for the end
965 push( @expect_args, "^.*\n" );
966 push( @expect_args, "100" );
967
968 while( $ret == 100 ){
969 $ret = &chat'expect( $time_out, @expect_args );
970 }
971 }
972
973 return $ret;
974}
975
976#
977# opens NS for io
978#
979sub ftp'open_data_socket
980{
981 local( $ret );
982 local( $hostname );
983 local( $sockaddr, $name, $aliases, $proto, $port );
984 local( $type, $len, $thisaddr, $myaddr, $a, $b, $c, $d );
985 local( $mysockaddr, $family, $hi, $lo );
986
987
988 $sockaddr = 'S n a4 x8';
989 chop( $hostname = `hostname` );
990
991 $port = "ftp";
992
993 ($name, $aliases, $proto) = getprotobyname( 'tcp' );
994 ($name, $aliases, $port) = getservbyname( $port, 'tcp' );
995
996# ($name, $aliases, $type, $len, $thisaddr) =
997# gethostbyname( $hostname );
998 ($a,$b,$c,$d) = unpack( 'C4', $chat'thisaddr );
999
1000# $this = pack( $sockaddr, &main'AF_INET, 0, $thisaddr );
1001 $this = $chat'thisproc;
1002
1003 socket(S, $pf_inet, $sock_stream, $proto ) || die "socket: $!";
1004 bind(S, $this) || die "bind: $!";
1005
1006 # get the port number
1007 $mysockaddr = getsockname(S);
1008 ($family, $port, $myaddr) = unpack( $sockaddr, $mysockaddr );
1009
1010 $hi = ($port >> 8) & 0x00ff;
1011 $lo = $port & 0x00ff;
1012
1013 #
1014 # we MUST do a listen before sending the port otherwise
1015 # the PORT may fail
1016 #
1017 listen( S, 5 ) || die "listen";
1018
1019 &ftp'send( "PORT $a,$b,$c,$d,$hi,$lo" );
1020
1021 return &ftp'expect($timeout,
1022 200, "PORT command successful", 1,
1023 250, "PORT command successful", 1 ,
1024
1025 500, "syntax error", 0,
1026 501, "syntax error", 0,
1027 530, "not logged in", 0,
1028
1029 421, "service unavailable, closing connection", 0);
1030}
1031
1032sub ftp'close_data_socket
1033{
1034 close(NS);
1035}
1036
1037sub ftp'send
1038{
1039 local($send_cmd) = @_;
1040 if( $send_cmd =~ /\n/ ){
1041 print STDERR "ERROR, \\n in send string for $send_cmd\n";
1042 }
1043
1044 if( $ftp_show ){
1045 local( $sc ) = $send_cmd;
1046
1047 if( $send_cmd =~ /^PASS/){
1048 $sc = "PASS <somestring>";
1049 }
1050 print STDERR "---> $sc\n";
1051 }
1052
1053 &chat'print( "$send_cmd\r\n" );
1054}
1055
1056sub ftp'printargs
1057{
1058 while( @_ ){
1059 print STDERR shift( @_ ) . "\n";
1060 }
1061}
1062
1063sub ftp'filesize
1064{
1065 local( $fname ) = @_;
1066
1067 if( ! -f $fname ){
1068 return -1;
1069 }
1070
1071 return (stat( _ ))[ 7 ];
1072
1073}
1074
1075# make this package return true
10761;