#/usr/local/bin/perl
## ftpr, last update 91/08/16
## usage: ftpr [-a] [-d] [-t timeout] [-n] hostname topdir yes-regex except-regex
## topdir may be whitespace-separated list of topdirs
## yes-regex defaults to . (meaning everything)
## except-regex defaults to ' ' (meaning no exceptions)
# slight hack here to make ftp talk to the kermit pipe and download direct
# - wjm
require 'chat2.pl';
$| = 1; # not much output, but we like to see it as it happens
$timeout = 60;
$dasha = "";
$nflag = 0;
$host = "localhost";
$topdir = ".";
$yesregex = ".";
$noregex = " ";
$user = "anonymous";
$pass = '
[email protected]';
{
last unless $ARGV[0] =~ /^-/;
$_ = shift;
$trace++, redo if /^-d/; # debug mode
$timeout = $1, redo if /^-t(\d+)/;
$timeout = shift, redo if /^-t/;
$dasha = "-a", redo if /^-a/;
$nflag++, redo if /^-n/;
die "bad flag: $_";
}
$host = shift if @ARGV;
$topdir = shift if @ARGV;
$yesregex = shift if @ARGV;
$noregex = shift if @ARGV;
die "extra args: @ARGV" if @ARGV;
($Control = &chat'open_port($host,21)) || die "open control: $!";
die "expected 2dd for initial banner, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
&ctalk("user $user\n");
$_ = &clisten($timeout);
unless (/^2\d\d/) { # might be logged in already:
die "expected 3dd for password query, got $_"
unless /^3\d\d/;
&ctalk("pass $pass\n");
die "expected 2dd for logged in, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
}
## all set up for a conversation
@list = split(/\s+/,$topdir);
while ($dir = shift list) {
next if $seen{$dir}++;
print "listing $dir\n";
for (&list($dir)) {
(warn "can't parse $_ in $dir"), next
unless ($tag,$file) = /^(.).*\s(\S+)\s*$/;
push(@list, "$dir/$file") if
($tag eq 'd') && ($file !~ /^\.\.?$/);
if ( ($tag eq '-') &&
("$dir/$file" =~ /$yesregex/o) &&
("$dir/$file" !~ /$noregex/o) &&
(! -e "$dir/$file")
) {
print "fetching $dir/$file...\n";
&get("$dir/$file","$dir/$file") unless $nflag;
}
}
}
## shutdown
&ctalk("quit\n");
&clisten(5); # for trace
&chat'close($Control);
exit(0);
sub ctalk {
local($text) = @_;
print "{$text}" if $trace;
&chat'print($Control,$text);
}
sub clisten {
local($secs) = @_;
local($return,$tmp);
while (1) {
$tmp = &chat'expect($Control, $secs, '(.*)\r?\n', '"$1\n"');
print $tmp if $trace;
$return .= $tmp;
return $return if !length($tmp) || $tmp =~ /^\d\d\d /;
}
}
sub dopen {
local($_);
local(@ret) = &chat'open_listen();
&ctalk("port " .
join(",", @ret[0,1,2,3], int($ret[4]/256), $ret[4]%256) .
"\n");
die "expected 2dd for data open, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
$Data = $ret[5];
}
<<'END_NOT_USED';
sub dtalk {
local($text) = @_;
print "{D:$text}" if $trace;
&chat'print($Data,$text);
}
END_NOT_USED
sub dlisten {
local($secs,$forcereturn) = @_;
local($return,$tmp);
while (1) {
$tmp = &chat'expect($Data, $secs,
'(.|\n)+', '$&',
TIMEOUT, '""',
EOF, 'undef');
if (defined $tmp) {
print "[D:$tmp]" if $trace > 1;
$return .= $tmp;
return $return unless (!$forcereturn) && (length $tmp);
# if timeout, return what you have
} else { # eof
return $return;
# maybe undef
}
}
}
sub dclose {
&chat'close($Data);
}
<<'END_NOT_USED';
sub nlst {
local($dir) = @_;
local(@files);
local($_,$tmp);
&dopen();
&ctalk("nlst $dasha $dir/.\n");
die "expected 1dd for nlst, got $_"
unless ($_ = &clisten($timeout)) =~ /^1\d\d/;
$_ = "";
while (1) {
$tmp = &dlisten($timeout);
last unless defined $tmp;
$_ .= $tmp;
}
@files = sort grep(!/^\.\.?$/, split(/\r?\n/))
unless /^ls: /;
die "expected 2dd for nlst complete, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
&dclose();
@files;
}
END_NOT_USED
sub list {
local($dir) = @_;
local(@files);
local($_,$tmp);
&dopen();
&ctalk("list $dasha $dir/.\n");
die "expected 1dd for list, got $_"
unless ($_ = &clisten($timeout)) =~ /^(.*\n)*1/;
$_ = "";
while (1) {
$tmp = &dlisten($timeout);
last unless defined $tmp;
$_ .= $tmp;
}
@files = grep(/^\S[rwx\-]{8}/, split(/\r?\n/));
die "expected 2dd for list complete, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
&dclose();
@files;
}
sub get {
local($from, $to) = @_;
local($todir,*OUT);
($todir = "./$to") =~ s#(.*)/.*#$1#;
#system "mkdir -p $todir" unless -d $todir;
(warn "cannot create $to.TMP: $!"), return
unless open(OUT, "|kermit -i -p e -a $to -s - ");
select((select(OUT))[0]);
&ctalk("type i\n");
die "expected 2dd for type i ok, got $_"
unless ($_ = &clisten($timeout)) =~ /^2\d\d/;
&dopen();
&ctalk("retr $from\n");
unless (($_ = &clisten($timeout)) =~ /^1\d\d/) {
warn "expected 1dd for retr, got $_";
close(OUT);
unlink("$to.TMP");
&dclose();
return;
}
{
$_ = &dlisten($timeout,1);
last unless defined $_;
print OUT;
redo;
}
close(OUT);
unless (($_ = &clisten($timeout)) =~ /^2\d\d/) {
warn "expected 2dd for retr complete, got $_";
close(OUT);
unlink("$to.TMP");
&dclose();
return;
}
&dclose();
}