##! /bin/sh
#From cs.utexas.edu!asuvax!gatech!news.byu.edu!eff!iWarp.intel.com|news Fri May  1 14:52:11 CDT 1992
#Article: 10383 of comp.lang.perl
#Path: cse.uta.edu!cs.utexas.edu!asuvax!gatech!news.byu.edu!eff!iWarp.intel.com|news
#From: [email protected] (Randal L. Schwartz)
#Newsgroups: comp.lang.perl
#Subject: Re: Perl FTP Interface (Need Example) (Do I Use expect.pl?)
#Message-ID: <[email protected]>
#Date: 1 May 92 15:27:10 GMT
#References: <[email protected]> <[email protected]>
#Sender: [email protected]
#Reply-To: [email protected] (Randal L. Schwartz)
#Organization: Stonehenge; netaccess via Intel, Beaverton, Oregon, USA
#Lines: 277
#In-Reply-To: [email protected] (Gene Spafford)
#Nntp-Posting-Host: v.iwarp.intel.com
#
#In article <[email protected]>, spaf@cs (Gene Spafford) writes:
#| Well, I guess now is as good a time as any.
#|
#| I have put together a "ftp library package" that allows one to
#| construct fun little ftp programs.  It works well for me -- I've built
#| a mirroring program and a couple of command-line ftp commands.
#|
#| None of this is documented (I got really busy just when I finished
#| testing this).  I'll include the code for the library here, and
#| the code for my two example commands.  One command lets you "ls" a
#| remote directory using ftp, and the other lets you get arbitrary
#| files, in either binary or ascii mode.  I'm half done with one that
#| will let you fetch a remote tree, ala "rcp -r"
#
#Well, hey, since I have a little script that does kinda the same thing
#(the one you're "half done" with), I'll post it.  Amazingly enough,
#it *also* uses chat2.pl :-).
#
#It presumes a BSD-like remote host, and fails miserably on any unusual
#forms of ftpd.  Try it first to see, though.
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#               "End of shell archive."
# Contents:  ftpr
# Wrapped by merlyn@iwarpv on Fri May  1 08:22:59 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'ftpr' -a "${1}" != "-c" ; then
 echo shar: Will not clobber existing file \"'ftpr'\"
else
echo shar: Extracting \"'ftpr'\" \(5037 characters\)
sed "s/^X//" >'ftpr' <<'END_OF_FILE'
X#!/usr/bin/perl
X
X## ftpr, last update 91/08/16
X## usage: ftpr [-a] [-d] [-t timeout] [-n] hostname topdir yes-regex except-regex
X## topdir may be whitespace-separated list of topdirs
X## yes-regex defaults to . (meaning everything)
X## except-regex defaults to ' ' (meaning no exceptions)
X
Xpush(@INC, '/local/merlyn/lib/perl');
X
Xrequire 'chat2.pl';
X
X$| = 1; # not much output, but we like to see it as it happens
X$timeout = 60;
X$dasha = "";
X$nflag = 0;
X$host = "localhost";
X$topdir = ".";
X$yesregex = ".";
X$noregex = " ";
X$user = "anonymous";
X$pass = '[email protected]';
X
X{
X       last unless $ARGV[0] =~ /^-/;
X       $_ = shift;
X       $trace++, redo if /^-d/; # debug mode
X       $timeout = $1, redo if /^-t(\d+)/;
X       $timeout = shift, redo if /^-t/;
X       $dasha = "-a", redo if /^-a/;
X       $nflag++, redo if /^-n/;
X       die "bad flag: $_";
X}
X
X$host = shift if @ARGV;
X$topdir = shift if @ARGV;
X$yesregex = shift if @ARGV;
X$noregex = shift if @ARGV;
X
Xdie "extra args: @ARGV" if @ARGV;
X
X($Control = &chat'open_port($host,21)) || die "open control: $!";
Xdie "expected 2dd for initial banner, got $_"
X       unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X&ctalk("user $user\n");
X$_ = &clisten($timeout);
Xunless (/^2\d\d/) { # might be logged in already:
X       die "expected 3dd for password query, got $_"
X               unless /^3\d\d/;
X       &ctalk("pass $pass\n");
X       die "expected 2dd for logged in, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X}
X## all set up for a conversation
X
X@list = split(/\s+/,$topdir);
Xwhile ($dir = shift list) {
X       next if $seen{$dir}++;
X       print "listing $dir\n";
X       for (&list($dir)) {
X               (warn "can't parse $_ in $dir"), next
X                       unless ($tag,$file) = /^(.).*\s(\S+)\s*$/;
X               push(@list, "$dir/$file") if
X                       ($tag eq 'd') && ($file !~ /^\.\.?$/);
X               if (    ($tag eq '-') &&
X                       ("$dir/$file" =~ /$yesregex/o) &&
X                       ("$dir/$file" !~ /$noregex/o) &&
X                       (! -e "$dir/$file")
X               ) {
X                       print "fetching $dir/$file...\n";
X                       &get("$dir/$file","$dir/$file") unless $nflag;
X               }
X       }
X}
X
X## shutdown
X&ctalk("quit\n");
X&clisten(5); # for trace
X&chat'close($Control);
Xexit(0);
X
Xsub ctalk {
X       local($text) = @_;
X       print "{$text}" if $trace;
X       &chat'print($Control,$text);
X}
X
Xsub clisten {
X       local($secs) = @_;
X       local($return,$tmp);
X       while (1) {
X               $tmp = &chat'expect($Control, $secs, '(.*)\r?\n', '"$1\n"');
X               print $tmp if $trace;
X               $return .= $tmp;
X               return $return if !length($tmp) || $tmp =~ /^\d\d\d /;
X       }
X}
X
Xsub dopen {
X       local($_);
X
X       local(@ret) = &chat'open_listen();
X       &ctalk("port " .
X               join(",", @ret[0,1,2,3], int($ret[4]/256), $ret[4]%256) .
X               "\n");
X       die "expected 2dd for data open, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X       $Data = $ret[5];
X}
X
X<<'END_NOT_USED';
Xsub dtalk {
X       local($text) = @_;
X       print "{D:$text}" if $trace;
X       &chat'print($Data,$text);
X}
XEND_NOT_USED
X
Xsub dlisten {
X       local($secs,$forcereturn) = @_;
X       local($return,$tmp);
X       while (1) {
X               $tmp = &chat'expect($Data, $secs,
X                       '(.|\n)+', '$&',
X                       TIMEOUT, '""',
X                       EOF, 'undef');
X               if (defined $tmp) {
X                       print "[D:$tmp]" if $trace > 1;
X                       $return .= $tmp;
X                       return $return unless (!$forcereturn) && (length $tmp);
X                               # if timeout, return what you have
X               } else { # eof
X                       return $return;
X                               # maybe undef
X               }
X       }
X}
X
Xsub dclose {
X       &chat'close($Data);
X}
X
X<<'END_NOT_USED';
Xsub nlst {
X       local($dir) = @_;
X       local(@files);
X       local($_,$tmp);
X
X       &dopen();
X       &ctalk("nlst $dasha $dir/.\n");
X       die "expected 1dd for nlst, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^1\d\d/;
X       $_ = "";
X       while (1) {
X               $tmp = &dlisten($timeout);
X               last unless defined $tmp;
X               $_ .= $tmp;
X       }
X       @files = sort grep(!/^\.\.?$/, split(/\r?\n/))
X               unless /^ls: /;
X       die "expected 2dd for nlst complete, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X       &dclose();
X       @files;
X}
XEND_NOT_USED
X
Xsub list {
X       local($dir) = @_;
X       local(@files);
X       local($_,$tmp);
X
X       &dopen();
X       &ctalk("list $dasha $dir/.\n");
X       die "expected 1dd for list, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^(.*\n)*1/;
X       $_ = "";
X       while (1) {
X               $tmp = &dlisten($timeout);
X               last unless defined $tmp;
X               $_ .= $tmp;
X       }
X       @files = grep(/^\S[rwx\-]{8}/, split(/\r?\n/));
X       die "expected 2dd for list complete, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X       &dclose();
X       @files;
X}
X
Xsub get {
X       local($from, $to) = @_;
X       local($todir,*OUT);
X
X       ($todir = "./$to") =~ s#(.*)/.*#$1#;
X       system "mkdir -p $todir" unless -d $todir;
X       (warn "cannot create $to.TMP: $!"), return
X               unless open(OUT, ">$to.TMP");
X       select((select(OUT),$|=1)[0]);
X       &ctalk("type i\n");
X       die "expected 2dd for type i ok, got $_"
X               unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
X       &dopen();
X       &ctalk("retr $from\n");
X       unless (($_ = &clisten($timeout)) =~ /^1\d\d/) {
X               warn "expected 1dd for retr, got $_";
X               close(OUT);
X               unlink("$to.TMP");
X               &dclose();
X               return;
X       }
X       {
X               $_ = &dlisten($timeout,1);
X               last unless defined $_;
X               print OUT;
X               redo;
X       }
X       close(OUT);
X       unless (($_ = &clisten($timeout)) =~ /^2\d\d/) {
X               warn "expected 2dd for retr complete, got $_";
X               close(OUT);
X               unlink("$to.TMP");
X               &dclose();
X               return;
X       }
X       &dclose();
X       rename("$to.TMP","$to") || warn "cannot rename $to.TMP to $to: $!";
X}
END_OF_FILE
if test 5037 -ne `wc -c <'ftpr'`; then
   echo shar: \"'ftpr'\" unpacked with wrong size!
fi
chmod +x 'ftpr'
# end of 'ftpr'
fi
echo shar: End of shell archive.
exit 0
--
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| [email protected] ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Intel: putting the 'backward' in 'backward compatible'..."====/