home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume37 / ftpcat / part01 < prev    next >
Encoding:
Text File  |  1993-05-15  |  46.7 KB  |  2,033 lines

  1. Newsgroups: comp.sources.misc
  2. From: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
  3. Subject: v37i061:  ftpcat - Cat an anon-FTP'd file, Part01/01
  4. Message-ID: <1993May16.021954.23993@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8889ae363efc72e174ab6829d17e6bea
  6. Date: Sun, 16 May 1993 02:19:54 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
  10. Posting-number: Volume 37, Issue 61
  11. Archive-name: ftpcat/part01
  12. Environment: UNIX, Perl, INET
  13.  
  14. This is version 1.3 of ftpcat. ftpcat gets a file via anonymous-FTP and 
  15. sends it to standard output.
  16.  
  17. ftpcat is all writen in perl.  It uses two support libraries ftp.pl and
  18. chat2.pl.
  19.  
  20. To install edit the values in the makefile and do a make install.
  21. ------------
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line, then unpack
  24. # it by saving it into a file and typing "sh file".  To overwrite existing
  25. # files, type "sh file -c".  You can also feed this as standard input via
  26. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  27. # will see the following message at the end:
  28. #        "End of shell archive."
  29. # Contents:  README ftpcat.man ftpcat chat2.pl ftp.pl makefile
  30. # Wrapped by lmjm@swan.doc.ic.ac.uk on Wed May 12 22:27:56 1993
  31. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  32. if test -f 'README' -a "${1}" != "-c" ; then 
  33.   echo shar: Will not clobber existing file \"'README'\"
  34. else
  35. echo shar: Extracting \"'README'\" \(220 characters\)
  36. sed "s/^X//" >'README' <<'END_OF_FILE'
  37. Xftpcat - Get a file via anonymous-FTP and send it to standard
  38. Xoutput.
  39. X
  40. Xftpcat is all writen in perl.  It uses two support libraries ftp.pl and
  41. Xchat2.pl.
  42. X
  43. XTo install edit the values in the makefile and do a make install.
  44. END_OF_FILE
  45. if test 220 -ne `wc -c <'README'`; then
  46.     echo shar: \"'README'\" unpacked with wrong size!
  47. fi
  48. # end of 'README'
  49. fi
  50. if test -f 'ftpcat.man' -a "${1}" != "-c" ; then 
  51.   echo shar: Will not clobber existing file \"'ftpcat.man'\"
  52. else
  53. echo shar: Extracting \"'ftpcat.man'\" \(1238 characters\)
  54. sed "s/^X//" >'ftpcat.man' <<'END_OF_FILE'
  55. X.\" $Header: /a/swan/home/swan/staff/csg/lmjm/src/perl/mirror/ftpcat/RCS/ftpcat.man,v 1.3 1993/05/12 21:27:51 lmjm Exp lmjm $
  56. X.\" $Log: ftpcat.man,v $
  57. X.\" Revision 1.3  1993/05/12  21:27:51  lmjm
  58. X.\" Cleaner english!
  59. X.\"
  60. X.\" Revision 1.2  1993/05/12  21:14:11  lmjm
  61. X.\" Document -a flag.
  62. X.\"
  63. X.\" Revision 1.1  1993/04/21  00:02:38  lmjm
  64. X.\" Initial revision
  65. X.\"
  66. X.\"
  67. X.TH FTPCAT 1L "19 March 1993"
  68. X.SH NAME
  69. Xftpcat \- Get a file via anonymous-FTP and send it to standard output.
  70. X.SH SYNOPSIS
  71. X.B ftpcat
  72. X.B [\-v]
  73. X.B [-a] \fIsite\fP:\fIpathname\fP
  74. X.SH DESCRIPTION
  75. X.B Ftpcat
  76. XFetch a file using anonymous-FTP and send it to standard output.  The
  77. Xfile is transfered in binary mode.
  78. XThe
  79. X.SH OPTIONS
  80. X.TP
  81. X.B \-v
  82. Xshow the conversation with the remote ftp daemon on stderr.
  83. X.B \-a
  84. Xtransfer the file in ascii mode (default is binary which is fine
  85. Xfor Unix to Unix).
  86. X.SH EXAMPLES
  87. X.LP
  88. X.RS
  89. X.ft B
  90. X.nf
  91. Xftpcat src.doc.ic.ac.uk:weather/images/uk/uk.gif | xv -
  92. X.fi
  93. X.ft R
  94. X.RE
  95. X.SH SEE ALSO
  96. Xmirror(1), ftp(1)
  97. X.SH BUGS
  98. XOnly supports username anonymous.
  99. X.SH FEATURES
  100. XFtpcat will never, ever be expanded.  ftpcat is comes from mirror which suffers
  101. Xfrom rampant featurism and ftpcat is not going to follow it.
  102. X.SH AUTHOR
  103. XWritten by Lee McLoughlin <lmjm@doc.ic.ac.uk>.
  104. END_OF_FILE
  105. if test 1238 -ne `wc -c <'ftpcat.man'`; then
  106.     echo shar: \"'ftpcat.man'\" unpacked with wrong size!
  107. fi
  108. # end of 'ftpcat.man'
  109. fi
  110. if test -f 'ftpcat' -a "${1}" != "-c" ; then 
  111.   echo shar: Will not clobber existing file \"'ftpcat'\"
  112. else
  113. echo shar: Extracting \"'ftpcat'\" \(1959 characters\)
  114. sed "s/^X//" >'ftpcat' <<'END_OF_FILE'
  115. X#!/usr/local/bin/perl -s
  116. X# Get a file via FTP and send it to standard output.
  117. X# $Header: /a/swan/home/swan/staff/csg/lmjm/src/perl/mirror/ftpcat/RCS/ftpcat,v 1.3 1993/05/12 21:14:10 lmjm Exp lmjm $
  118. X# $Log: ftpcat,v $
  119. X# Revision 1.3  1993/05/12  21:14:10  lmjm
  120. X# Just use -v for debugging.
  121. X# Use -a for text mode transfers.
  122. X#
  123. X# Revision 1.2  1993/05/07  23:28:06  lmjm
  124. X# Assed missing newline.
  125. X#
  126. X# Revision 1.1  1993/04/21  00:02:37  lmjm
  127. X# Initial revision
  128. X#
  129. X
  130. Xpush( @INC, '/usr/local/lib/perl.extra' );
  131. X
  132. Xrequire 'ftp.pl';
  133. Xrequire 'chat2.pl';
  134. X
  135. X# Some systems hold the username in $USER, some in $LOGNAME.
  136. X$me = $ENV{'USER'} || $ENV{'LOGNAME'};
  137. Xchop( $hostname = `hostname` );
  138. Xif( $hn = (gethostbyname( "$hostname" ))[ 0 ] ){
  139. X    $hostname = $hn;
  140. X}
  141. X
  142. X$remote_user = 'anonymous';
  143. X$remote_password = "$me@$hostname";
  144. X
  145. X$retry_call = 1;
  146. X$attempts = 2;
  147. X$ftp_port = 21;
  148. X
  149. Xif( $v ){
  150. X    &ftp'debug( 1 );
  151. X}
  152. X
  153. X$xfer = shift;
  154. Xif( $xfer !~ /^([^:]+):(.*)$/ ){
  155. X    die "Usage: ftpcat [-v] [-a] site:filename\n";
  156. X}
  157. X$site = $1;
  158. X$filename = $2;
  159. X
  160. Xif( &ftp'open( $site, $ftp_port, $retry_call, $attempts ) != 1 ){
  161. X    &msg( "Cannot open connection\n" );
  162. X    &disconnect();
  163. X    exit( -1 );
  164. X}
  165. X
  166. X$connected = $site;
  167. X
  168. Xif( ! &ftp'login( $remote_user, $remote_password ) ){
  169. X    &msg( "Cannot login\n" );
  170. X    &disconnect();
  171. X    exit( -1 );
  172. X}
  173. X
  174. X$rempwd = &ftp'pwd();
  175. X
  176. Xif( ! &ftp'type( $a ? 'A' : 'I' ) ){
  177. X    &msg( "Cannot set type\n" );
  178. X}
  179. X
  180. Xif( ! &ftp'get( $filename, '-', 0 ) ){
  181. X    &msg( "Failed to get $filename\n" );
  182. X    &disconnect();
  183. X    exit( -1 );
  184. X}
  185. X
  186. X&disconnect();
  187. Xexit( 0 );
  188. X
  189. Xsub disconnect
  190. X{
  191. X    if( $connected ){
  192. X        &msg( "disconnecting from $connected\n" ) if $v;
  193. X        if( ! $ftp'fatalerror ){
  194. X            &ftp'quit();
  195. X        }
  196. X    }
  197. X    &chat'close();
  198. X    $connected = '';
  199. X}
  200. X
  201. Xsub msg
  202. X{
  203. X    local( $todo, $msg );
  204. X
  205. X    if( $#_ == 1 ){
  206. X        ($todo, $msg) = @_;
  207. X    }
  208. X    else {
  209. X        $todo = 0;
  210. X        $msg = @_[ 0 ];
  211. X    }
  212. X
  213. X    if( $todo & $log ){
  214. X        push( @log, $msg );
  215. X    }
  216. X# Not sure about this one.  always print the message even if its a log msg.
  217. X#    else {
  218. X        print $msg;
  219. X#    }
  220. X}
  221. END_OF_FILE
  222. if test 1959 -ne `wc -c <'ftpcat'`; then
  223.     echo shar: \"'ftpcat'\" unpacked with wrong size!
  224. fi
  225. chmod +x 'ftpcat'
  226. # end of 'ftpcat'
  227. fi
  228. if test -f 'chat2.pl' -a "${1}" != "-c" ; then 
  229.   echo shar: Will not clobber existing file \"'chat2.pl'\"
  230. else
  231. echo shar: Extracting \"'chat2.pl'\" \(9620 characters\)
  232. sed "s/^X//" >'chat2.pl' <<'END_OF_FILE'
  233. X# chat.pl: chat with a server
  234. X# Based on: V2.01.alpha.7 91/06/16
  235. X# Randal L. Schwartz (was <merlyn@iwarp.intel.com>)
  236. X# multihome additions by A.Macpherson@bnr.co.uk
  237. X# allow for /dev/pts based systems by Joe Doupnik <JRD@CC.USU.EDU>
  238. X
  239. Xpackage chat;
  240. X
  241. Xif( defined( &main'PF_INET ) ){
  242. X    $pf_inet = &main'PF_INET;
  243. X    $sock_stream = &main'SOCK_STREAM;
  244. X    local($name, $aliases, $proto) = getprotobyname( 'tcp' );
  245. X    $tcp_proto = $proto;
  246. X}
  247. Xelse {
  248. X    # XXX hardwired $PF_INET, $SOCK_STREAM, 'tcp'
  249. X    # but who the heck would change these anyway? (:-)
  250. X    $pf_inet = 2;
  251. X    $sock_stream = 1;
  252. X    $tcp_proto = 6;
  253. X}
  254. X
  255. X
  256. X$sockaddr = 'S n a4 x8';
  257. Xchop($thishost = `hostname`);
  258. X
  259. X# *S = symbol for current I/O, gets assigned *chatsymbol....
  260. X$next = "chatsymbol000000"; # next one
  261. X$nextpat = "^chatsymbol"; # patterns that match next++, ++, ++, ++
  262. X
  263. X
  264. X## $handle = &chat'open_port("server.address",$port_number);
  265. X## opens a named or numbered TCP server
  266. X
  267. Xsub open_port { ## public
  268. X    local($server, $port) = @_;
  269. X
  270. X    local($serveraddr,$serverproc);
  271. X
  272. X    # We may be multi-homed, start with 0, fixup once connexion is made
  273. X    $thisaddr = "\0\0\0\0" ;
  274. X    $thisproc = pack($sockaddr, 2, 0, $thisaddr);
  275. X
  276. X    *S = ++$next;
  277. X    if ($server =~ /^(\d+)+\.(\d+)\.(\d+)\.(\d+)$/) {
  278. X        $serveraddr = pack('C4', $1, $2, $3, $4);
  279. X    } else {
  280. X        local(@x) = gethostbyname($server);
  281. X        return undef unless @x;
  282. X        $serveraddr = $x[4];
  283. X    }
  284. X    $serverproc = pack($sockaddr, 2, $port, $serveraddr);
  285. X    unless (socket(S, $pf_inet, $sock_stream, $tcp_proto)) {
  286. X        ($!) = ($!, close(S)); # close S while saving $!
  287. X        return undef;
  288. X    }
  289. X    unless (bind(S, $thisproc)) {
  290. X        ($!) = ($!, close(S)); # close S while saving $!
  291. X        return undef;
  292. X    }
  293. X    unless (connect(S, $serverproc)) {
  294. X        ($!) = ($!, close(S)); # close S while saving $!
  295. X        return undef;
  296. X    }
  297. X# We opened with the local address set to ANY, at this stage we know
  298. X# which interface we are using.  This is critical if our machine is
  299. X# multi-homed, with IP forwarding off, so fix-up.
  300. X    local($fam,$lport);
  301. X    ($fam,$lport,$thisaddr) = unpack($sockaddr, getsockname(S));
  302. X    $thisproc = pack($sockaddr, 2, 0, $thisaddr);
  303. X# end of post-connect fixup
  304. X    select((select(S), $| = 1)[0]);
  305. X    $next; # return symbol for switcharound
  306. X}
  307. X
  308. X## ($host, $port, $handle) = &chat'open_listen([$port_number]);
  309. X## opens a TCP port on the current machine, ready to be listened to
  310. X## if $port_number is absent or zero, pick a default port number
  311. X## process must be uid 0 to listen to a low port number
  312. X
  313. Xsub open_listen { ## public
  314. X
  315. X    *S = ++$next;
  316. X    local($thisport) = shift || 0;
  317. X    local($thisproc_local) = pack($sockaddr, 2, $thisport, $thisaddr);
  318. X    local(*NS) = "__" . time;
  319. X    unless (socket(NS, $pf_inet, $sock_stream, $tcp_proto)) {
  320. X        ($!) = ($!, close(NS));
  321. X        return undef;
  322. X    }
  323. X    unless (bind(NS, $thisproc_local)) {
  324. X        ($!) = ($!, close(NS));
  325. X        return undef;
  326. X    }
  327. X    unless (listen(NS, 1)) {
  328. X        ($!) = ($!, close(NS));
  329. X        return undef;
  330. X    }
  331. X    select((select(NS), $| = 1)[0]);
  332. X    local($family, $port, @myaddr) =
  333. X        unpack("S n C C C C x8", getsockname(NS));
  334. X    $S{"needs_accept"} = *NS; # so expect will open it
  335. X    (@myaddr, $port, $next); # returning this
  336. X}
  337. X
  338. X## $handle = &chat'open_proc("command","arg1","arg2",...);
  339. X## opens a /bin/sh on a pseudo-tty
  340. X
  341. Xsub open_proc { ## public
  342. X    local(@cmd) = @_;
  343. X
  344. X    *S = ++$next;
  345. X    local(*TTY) = "__TTY" . time;
  346. X    local($pty,$tty) = &_getpty(S,TTY);
  347. X    die "Cannot find a new pty" unless defined $pty;
  348. X    $pid = fork;
  349. X    die "Cannot fork: $!" unless defined $pid;
  350. X    unless ($pid) {
  351. X        close STDIN; close STDOUT; close STDERR;
  352. X        setpgrp(0,$$);
  353. X        if (open(DEVTTY, "/dev/tty")) {
  354. X            ioctl(DEVTTY,0x20007471,0);        # XXX s/b &TIOCNOTTY
  355. X            close DEVTTY;
  356. X        }
  357. X        open(STDIN,"<&TTY");
  358. X        open(STDOUT,">&TTY");
  359. X        open(STDERR,">&STDOUT");
  360. X        die "Oops" unless fileno(STDERR) == 2;    # sanity
  361. X        close(S);
  362. X        exec @cmd;
  363. X        die "Cannot exec @cmd: $!";
  364. X    }
  365. X    close(TTY);
  366. X    $next; # return symbol for switcharound
  367. X}
  368. X
  369. X# $S is the read-ahead buffer
  370. X
  371. X## $return = &chat'expect([$handle,] $timeout_time,
  372. X##     $pat1, $body1, $pat2, $body2, ... )
  373. X## $handle is from previous &chat'open_*().
  374. X## $timeout_time is the time (either relative to the current time, or
  375. X## absolute, ala time(2)) at which a timeout event occurs.
  376. X## $pat1, $pat2, and so on are regexs which are matched against the input
  377. X## stream.  If a match is found, the entire matched string is consumed,
  378. X## and the corresponding body eval string is evaled.
  379. X##
  380. X## Each pat is a regular-expression (probably enclosed in single-quotes
  381. X## in the invocation).  ^ and $ will work, respecting the current value of $*.
  382. X## If pat is 'TIMEOUT', the body is executed if the timeout is exceeded.
  383. X## If pat is 'EOF', the body is executed if the process exits before
  384. X## the other patterns are seen.
  385. X##
  386. X## Pats are scanned in the order given, so later pats can contain
  387. X## general defaults that won't be examined unless the earlier pats
  388. X## have failed.
  389. X##
  390. X## The result of eval'ing body is returned as the result of
  391. X## the invocation.  Recursive invocations are not thought
  392. X## through, and may work only accidentally. :-)
  393. X##
  394. X## undef is returned if either a timeout or an eof occurs and no
  395. X## corresponding body has been defined.
  396. X## I/O errors of any sort are treated as eof.
  397. X
  398. X$nextsubname = "expectloop000000"; # used for subroutines
  399. X
  400. Xsub expect { ## public
  401. X    if ($_[0] =~ /$nextpat/) {
  402. X        *S = shift;
  403. X    }
  404. X    local($endtime) = shift;
  405. X
  406. X    local($timeout,$eof) = (1,1);
  407. X    local($caller) = caller;
  408. X    local($rmask, $nfound, $timeleft, $thisbuf);
  409. X    local($cases, $pattern, $action, $subname);
  410. X    $endtime += time if $endtime < 600_000_000;
  411. X
  412. X    if (defined $S{"needs_accept"}) { # is it a listen socket?
  413. X        local(*NS) = $S{"needs_accept"};
  414. X        delete $S{"needs_accept"};
  415. X        $S{"needs_close"} = *NS;
  416. X        unless(accept(S,NS)) {
  417. X            ($!) = ($!, close(S), close(NS));
  418. X            return undef;
  419. X        }
  420. X        select((select(S), $| = 1)[0]);
  421. X    }
  422. X
  423. X    # now see whether we need to create a new sub:
  424. X
  425. X    unless ($subname = $expect_subname{$caller,@_}) {
  426. X        # nope.  make a new one:
  427. X        $expect_subname{$caller,@_} = $subname = $nextsubname++;
  428. X
  429. X        $cases .= <<"EDQ"; # header is funny to make everything elsif's
  430. Xsub $subname {
  431. X    LOOP: {
  432. X        if (0) { ; }
  433. XEDQ
  434. X        while (@_) {
  435. X            ($pattern,$action) = splice(@_,0,2);
  436. X            if ($pattern =~ /^eof$/i) {
  437. X                $cases .= <<"EDQ";
  438. X        elsif (\$eof) {
  439. X             package $caller;
  440. X            $action;
  441. X        }
  442. XEDQ
  443. X                $eof = 0;
  444. X            } elsif ($pattern =~ /^timeout$/i) {
  445. X            $cases .= <<"EDQ";
  446. X        elsif (\$timeout) {
  447. X             package $caller;
  448. X            $action;
  449. X        }
  450. XEDQ
  451. X                $timeout = 0;
  452. X            } else {
  453. X                $pattern =~ s#/#\\/#g;
  454. X            $cases .= <<"EDQ";
  455. X        elsif (\$S =~ /$pattern/) {
  456. X            \$S = \$';
  457. X             package $caller;
  458. X            $action;
  459. X        }
  460. XEDQ
  461. X            }
  462. X        }
  463. X        $cases .= <<"EDQ" if $eof;
  464. X        elsif (\$eof) {
  465. X            undef;
  466. X        }
  467. XEDQ
  468. X        $cases .= <<"EDQ" if $timeout;
  469. X        elsif (\$timeout) {
  470. X            undef;
  471. X        }
  472. XEDQ
  473. X        $cases .= <<'ESQ';
  474. X        else {
  475. X            $rmask = "";
  476. X            vec($rmask,fileno(S),1) = 1;
  477. X            ($nfound, $rmask) =
  478. X                 select($rmask, undef, undef, $endtime - time);
  479. X            if ($nfound) {
  480. X                $nread = sysread(S, $thisbuf, 1024);
  481. X                if ($nread > 0) {
  482. X                    $S .= $thisbuf;
  483. X                } else {
  484. X                    $eof++, redo LOOP; # any error is also eof
  485. X                }
  486. X            } else {
  487. X                $timeout++, redo LOOP; # timeout
  488. X            }
  489. X            redo LOOP;
  490. X        }
  491. X    }
  492. X}
  493. XESQ
  494. X        eval $cases; die "$cases:\n$@" if $@;
  495. X    }
  496. X    $eof = $timeout = 0;
  497. X    do $subname();
  498. X}
  499. X
  500. X## &chat'print([$handle,] @data)
  501. X## $handle is from previous &chat'open().
  502. X## like print $handle @data
  503. X
  504. Xsub print { ## public
  505. X    if ($_[0] =~ /$nextpat/) {
  506. X        *S = shift;
  507. X    }
  508. X    print S @_;
  509. X    if( $chat'debug ){
  510. X        print STDERR "printed:";
  511. X        print STDERR @_;
  512. X    }
  513. X}
  514. X
  515. X## &chat'close([$handle,])
  516. X## $handle is from previous &chat'open().
  517. X## like close $handle
  518. X
  519. Xsub close { ## public
  520. X    if ($_[0] =~ /$nextpat/) {
  521. X         *S = shift;
  522. X    }
  523. X    close(S);
  524. X    if (defined $S{"needs_close"}) { # is it a listen socket?
  525. X        local(*NS) = $S{"needs_close"};
  526. X        delete $S{"needs_close"};
  527. X        close(NS);
  528. X    }
  529. X}
  530. X
  531. X## @ready_handles = &chat'select($timeout, @handles)
  532. X## select()'s the handles with a timeout value of $timeout seconds.
  533. X## Returns an array of handles that are ready for I/O.
  534. X## Both user handles and chat handles are supported (but beware of
  535. X## stdio's buffering for user handles).
  536. X
  537. Xsub select { ## public
  538. X    local($timeout) = shift;
  539. X    local(@handles) = @_;
  540. X    local(%handlename) = ();
  541. X    local(%ready) = ();
  542. X    local($caller) = caller;
  543. X    local($rmask) = "";
  544. X    for (@handles) {
  545. X        if (/$nextpat/o) { # one of ours... see if ready
  546. X            local(*SYM) = $_;
  547. X            if (length($SYM)) {
  548. X                $timeout = 0; # we have a winner
  549. X                $ready{$_}++;
  550. X            }
  551. X            $handlename{fileno($_)} = $_;
  552. X        } else {
  553. X            $handlename{fileno(/'/ ? $_ : "$caller\'$_")} = $_;
  554. X        }
  555. X    }
  556. X    for (sort keys %handlename) {
  557. X        vec($rmask, $_, 1) = 1;
  558. X    }
  559. X    select($rmask, undef, undef, $timeout);
  560. X    for (sort keys %handlename) {
  561. X        $ready{$handlename{$_}}++ if vec($rmask,$_,1);
  562. X    }
  563. X    sort keys %ready;
  564. X}
  565. X
  566. X# ($pty,$tty) = $chat'_getpty(PTY,TTY):
  567. X# internal procedure to get the next available pty.
  568. X# opens pty on handle PTY, and matching tty on handle TTY.
  569. X# returns undef if can't find a pty.
  570. X# Modify "/dev/pty" to "/dev/pts" for Dell Unix v2.2 (aka SVR4.04). Joe Doupnik.
  571. X
  572. Xsub _getpty { ## private
  573. X    local($_PTY,$_TTY) = @_;
  574. X    $_PTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
  575. X    $_TTY =~ s/^([^']+)$/(caller)[$[]."'".$1/e;
  576. X    local($pty, $tty, $kind);
  577. X    if( -e "/dev/pts000" ){        ## mods by Joe Doupnik Dec 1992
  578. X        $kind = "pts";        ## SVR4 Streams
  579. X    } else {
  580. X        $kind = "pty";        ## BSD Clist stuff
  581. X    }
  582. X    for $bank (112..127) {
  583. X        next unless -e sprintf("/dev/$kind%c0", $bank);
  584. X        for $unit (48..57) {
  585. X            $pty = sprintf("/dev/$kind%c%c", $bank, $unit);
  586. X            open($_PTY,"+>$pty") || next;
  587. X            select((select($_PTY), $| = 1)[0]);
  588. X            ($tty = $pty) =~ s/pty/tty/;
  589. X            open($_TTY,"+>$tty") || next;
  590. X            select((select($_TTY), $| = 1)[0]);
  591. X            system "stty nl>$tty";
  592. X            return ($pty,$tty);
  593. X        }
  594. X    }
  595. X    undef;
  596. X}
  597. X
  598. X1;
  599. END_OF_FILE
  600. if test 9620 -ne `wc -c <'chat2.pl'`; then
  601.     echo shar: \"'chat2.pl'\" unpacked with wrong size!
  602. fi
  603. # end of 'chat2.pl'
  604. fi
  605. if test -f 'ftp.pl' -a "${1}" != "-c" ; then 
  606.   echo shar: Will not clobber existing file \"'ftp.pl'\"
  607. else
  608. echo shar: Extracting \"'ftp.pl'\" \(28699 characters\)
  609. sed "s/^X//" >'ftp.pl' <<'END_OF_FILE'
  610. X#-*-perl-*-
  611. X# This is a wrapper to the chat2.pl routines that make life easier
  612. X# to do ftp type work.
  613. X# Mostly by Lee McLoughlin <lmjm@doc.ic.ac.uk>
  614. X# based on original version by Alan R. Martello <al@ee.pitt.edu>
  615. X# And by A.Macpherson@bnr.co.uk for multi-homed hosts
  616. X#
  617. X# Basic usage:
  618. X#  $ftp_port = 21;
  619. X#  $retry_call = 1;
  620. X#  $attempts = 2;
  621. X#  if( &ftp'open( $site, $ftp_port, $retry_call, $attempts ) != 1 ){
  622. X#   die "failed to open ftp connection";
  623. X#  }
  624. X#  if( ! &ftp'login( $user, $pass ) ){
  625. X#   die "failed to login";
  626. X#  }
  627. X#  &ftp'type( $text_mode ? 'A' : 'I' );
  628. X#  if( ! &ftp'get( $remote_filename, $local_filename, 0 ) ){
  629. X#   die "failed to get file;
  630. X#  }
  631. X#  &ftp'quit();
  632. X#
  633. X#
  634. X# $Header: /a/swan/home/swan/staff/csg/lmjm/src/perl/mirror/RCS/ftp.pl,v 1.25 1993/05/07 23:36:07 lmjm Exp lmjm $
  635. X# $Log: ftp.pl,v $
  636. X# Revision 1.25  1993/05/07  23:36:07  lmjm
  637. X# Corrected typo in expect code causing long continuations to fail.
  638. X# Timeouts are no longer a fatal error.
  639. X# Improved the balance in the timeouts.
  640. X#
  641. X# Revision 1.24  1993/05/06  23:13:29  lmjm
  642. X# Major cleanup.
  643. X# Reset ALRM when done.
  644. X# Try to reset if cannot write local file on get.
  645. X# Spot unreadable remote files.
  646. X# Cleaned up *MAJOR* dumb code in open_data_socket.
  647. X#
  648. X# Revision 1.23  1993/05/06  21:14:19  lmjm
  649. X# Use the new mapin.
  650. X# Correct put code.
  651. X#
  652. X# Revision 1.22  1993/04/29  23:31:26  lmjm
  653. X# Added sample prog as a comment.
  654. X# Clear out chat string that may be large.
  655. X# Moved some declarations out of loops and used packageless functin names to
  656. X# save space.
  657. X#
  658. X# Revision 1.21  1993/04/28  20:45:26  lmjm
  659. X# Made the RETR/STOR commands report the file.
  660. X#
  661. X# Revision 1.20  1993/04/27  19:53:49  lmjm
  662. X# Allow for filename mapping before Xfer.  Useful for VMS -> unix.
  663. X#
  664. X# Revision 1.19  1993/04/26  19:58:33  lmjm
  665. X# Added missing trailing ; - for older perl's
  666. X#
  667. X# Revision 1.18  1993/04/25  13:15:43  lmjm
  668. X# Keep track of wether the service is open and avoid writing to dead sockets.
  669. X# Added SIGPIPE handler if ftp'set_signals called.
  670. X# Added a version var.
  671. X#
  672. X# Revision 1.17  1993/04/21  10:06:54  lmjm
  673. X# Send all status reports to STDERR not to STDOUT (to allow use by ftpcat).
  674. X# Allow target file to be '-' meaning STDOUT
  675. X# Added ftp'quote
  676. X#
  677. X# Revision 1.16  1993/01/28  18:59:05  lmjm
  678. X# Allow socket arguemtns to come from main.
  679. X# Minor cleanups - removed old comments.
  680. X#
  681. X# Revision 1.15  1992/11/25  21:09:30  lmjm
  682. X# Added another REST return code.
  683. X#
  684. X# Revision 1.14  1992/08/12  14:33:42  lmjm
  685. X# Fail ftp'write if out of space.
  686. X#
  687. X# Revision 1.13  1992/03/20  21:01:03  lmjm
  688. X# Added in the proxy ftp code from Edwards Reed <err@cinops.xerox.com>
  689. X# Added  ftp'delete from Aaron Wohl <aw0g+@andrew.cmu.edu>
  690. X#
  691. X# Revision 1.12  1992/02/06  23:25:56  lmjm
  692. X# Moved code around so can use this as a lib for both mirror and ftpmail.
  693. X# Time out opens.  In case Unix doesn't bother to.
  694. X#
  695. X# Revision 1.11  1991/11/27  22:05:57  lmjm
  696. X# Match the response code number at the start of a line allowing
  697. X# for any leading junk.
  698. X#
  699. X# Revision 1.10  1991/10/23  22:42:20  lmjm
  700. X# Added better timeout code.
  701. X# Tried to optimise file transfer
  702. X# Moved open/close code to not leak file handles.
  703. X# Cleaned up the alarm code.
  704. X# Added $fatalerror to show wether the ftp link is really dead.
  705. X#
  706. X# Revision 1.9  1991/10/07  18:30:35  lmjm
  707. X# Made the timeout-read code work.
  708. X# Added restarting file gets.
  709. X# Be more verbose if ever have to call die.
  710. X#
  711. X# Revision 1.8  1991/09/17  22:53:16  lmjm
  712. X# Spot when open_data_socket fails and return a failure rather than dying.
  713. X#
  714. X# Revision 1.7  1991/09/12  22:40:25  lmjm
  715. X# Added Andrew Macpherson's patches for hosts without ip forwarding.
  716. X#
  717. X# Revision 1.6  1991/09/06  19:53:52  lmjm
  718. X# Relaid out the code the way I like it!
  719. X# Changed the debuggin to produce more "appropriate" messages
  720. X# Fixed bugs in the ordering of put and dir listing.
  721. X# Allow for hash printing when getting files (a la ftp).
  722. X# Added the new commands from Al.
  723. X# Don't print passwords in debugging.
  724. X#
  725. X# Revision 1.5  1991/08/29  16:23:49  lmjm
  726. X# Timeout reads from the remote ftp server.
  727. X# No longer call die expect on fatal errors.  Just return fail codes.
  728. X# Changed returns so higher up routines can tell whats happening.
  729. X# Get expect/accept in correct order for dir listing.
  730. X# When ftp_show is set then print hashes every 1k transfered (like ftp).
  731. X# Allow for stripping returns out of incoming data.
  732. X# Save last error in a global string.
  733. X#
  734. X# Revision 1.4  1991/08/14  21:04:58  lmjm
  735. X# ftp'get now copes with ungetable files.
  736. X# ftp'expect code changed such that the string_to_print is
  737. X# ignored and the string sent back from the remote system is printed
  738. X# instead.
  739. X# Implemented patches from al.  Removed spuiours tracing statements.
  740. X#
  741. X# Revision 1.3  1991/08/09  21:32:18  lmjm
  742. X# Allow for another ok code on cwd's
  743. X# Rejigger the log levels
  744. X# Send \r\n for some odd ftp daemons
  745. X#
  746. X# Revision 1.2  1991/08/09  18:07:37  lmjm
  747. X# Don't print messages unless ftp_show says to.
  748. X#
  749. X# Revision 1.1  1991/08/08  20:31:00  lmjm
  750. X# Initial revision
  751. X#
  752. X
  753. Xrequire 'chat2.pl';
  754. Xrequire 'socket.ph';
  755. X
  756. X
  757. Xpackage ftp;
  758. X
  759. Xif( defined( &main'PF_INET ) ){
  760. X    $pf_inet = &main'PF_INET;
  761. X    $sock_stream = &main'SOCK_STREAM;
  762. X    local($name, $aliases, $proto) = getprotobyname( 'tcp' );
  763. X    $tcp_proto = $proto;
  764. X}
  765. Xelse {
  766. X    # XXX hardwired $PF_INET, $SOCK_STREAM, 'tcp'
  767. X    # but who the heck would change these anyway? (:-)
  768. X    $pf_inet = 2;
  769. X    $sock_stream = 1;
  770. X    $tcp_proto = 6;
  771. X}
  772. X
  773. X# If the remote ftp daemon doesn't respond within this time presume its dead
  774. X# or something.
  775. X$timeout = 100;
  776. X
  777. X# Timeout a read if I don't get data back within this many seconds
  778. X$timeout_read = 2 * $timeout;
  779. X
  780. X# Timeout an open
  781. X$timeout_open = $timeout;
  782. X
  783. X$ftp'version = '$Revision: 1.25 $';
  784. X
  785. X# This is a "global" it contains the last response from the remote ftp server
  786. X# for use in error messages
  787. X$ftp'response = "";
  788. X# Also ftp'NS is the socket containing the data coming in from the remote ls
  789. X# command.
  790. X
  791. X# The size of block to be read or written when talking to the remote
  792. X# ftp server
  793. X$ftp'ftpbufsize = 4096;
  794. X
  795. X# How often to print a hash out, when debugging
  796. X$ftp'hashevery = 1024;
  797. X# Output a newline after this many hashes to prevent outputing very long lines
  798. X$ftp'hashnl = 70;
  799. X
  800. X# Is there a connection open?
  801. X$ftp'service_open = 0;
  802. X
  803. X# If a proxy connection then who am I really talking to?
  804. X$real_site = "";
  805. X
  806. X# Where error/log reports are sent to
  807. X$ftp'showfd = 'STDERR';
  808. X
  809. X# Name of a function to call on a pathname to map it into a remote
  810. X# pathname.
  811. X$ftp'mapunixout = '';
  812. X$ftp'manunixin = '';
  813. X
  814. X# This is just a tracing aid.
  815. X$ftp_show = 0;
  816. X
  817. Xsub ftp'debug
  818. X{
  819. X    $ftp_show = @_[0];
  820. X#    if( $ftp_show ){
  821. X#        print $ftp'showfd "ftp debugging on\n";
  822. X#    }
  823. X}
  824. X
  825. Xsub ftp'set_timeout
  826. X{
  827. X    local( $to ) = @_;
  828. X    return if $to == $timeout;
  829. X    $timeout = $to;
  830. X    $timeout_open = $timeout;
  831. X    $timeout_read = 2 * $timeout;
  832. X    if( $ftp_show ){
  833. X        print $ftp'showfd "ftp timeout set to $timeout\n";
  834. X    }
  835. X}
  836. X
  837. X
  838. Xsub ftp'open_alarm
  839. X{
  840. X    die "timeout: open";
  841. X}
  842. X
  843. Xsub ftp'timed_open
  844. X{
  845. X    local( $site, $ftp_port, $retry_call, $attempts ) = @_;
  846. X    local( $connect_site, $connect_port );
  847. X    local( $res );
  848. X
  849. X    alarm( $timeout_open );
  850. X
  851. X    while( $attempts-- ){
  852. X        if( $ftp_show ){
  853. X            print $ftp'showfd "proxy connecting via $proxy_gateway [$proxy_ftp_port]\n" if $proxy;
  854. X            print $ftp'showfd "Connecting to $site";
  855. X            if( $ftp_port != 21 ){
  856. X                print $ftp'showfd " [port $ftp_port]";
  857. X            }
  858. X            print $ftp'showfd "\n";
  859. X        }
  860. X        
  861. X        if( $proxy ) {
  862. X            if( ! $proxy_gateway ) {
  863. X                # if not otherwise set
  864. X                $proxy_gateway = "internet-gateway";
  865. X            }
  866. X            if( $debug ) {
  867. X                print $ftp'showfd "using proxy services of $proxy_gateway, ";
  868. X                print $ftp'showfd "at $proxy_ftp_port\n";
  869. X            }
  870. X            $connect_site = $proxy_gateway;
  871. X            $connect_port = $proxy_ftp_port;
  872. X            $real_site = $site;
  873. X        }
  874. X        else {
  875. X            $connect_site = $site;
  876. X            $connect_port = $ftp_port;
  877. X        }
  878. X        if( ! &chat'open_port( $connect_site, $connect_port ) ){
  879. X            if( $retry_call ){
  880. X                print $ftp'showfd "Failed to connect\n" if $ftp_show;
  881. X                next;
  882. X            }
  883. X            else {
  884. X                print $ftp'showfd "proxy connection failed " if $proxy;
  885. X                print $ftp'showfd "Cannot open ftp to $connect_site\n" if $ftp_show;
  886. X                return 0;
  887. X            }
  888. X        }
  889. X        $res = &ftp'expect( $timeout,
  890. X            120, "service unavailable to $site", 0, 
  891. X            220, "ready for login to $site", 1,
  892. X            421, "service unavailable to $site, closing connection", 0);
  893. X        if( ! $res ){
  894. X            &chat'close();
  895. X            next;
  896. X        }
  897. X        return 1;
  898. X    }
  899. X    continue {
  900. X        print $ftp'showfd "Pausing between retries\n";
  901. X        sleep( $retry_pause );
  902. X    }
  903. X    return 0;
  904. X}
  905. X
  906. Xsub main'ftp__sighandler
  907. X{
  908. X    local( $sig ) = @_;
  909. X    local( $msg ) = "Caught a SIG$sig flagging connection down";
  910. X    $ftp'service_open = 0;
  911. X    if( $ftp_logger ){
  912. X        eval "&$ftp_logger( \$msg )";
  913. X    }
  914. X}
  915. X
  916. Xsub ftp'set_signals
  917. X{
  918. X    $ftp_logger = @_;
  919. X    $SIG{ 'PIPE' } = "ftp__sighandler";
  920. X}
  921. X
  922. X# Set the mapunixout and mapunixin functions
  923. Xsub ftp'set_namemap
  924. X{
  925. X    ($ftp'mapunixout, $ftp'mapunixin) = @_;
  926. X    if( $debug ) {
  927. X        print $ftp'showfd "mapunixout = $ftp'mapunixout, $mapunixin = $ftp'mapunixin\n";
  928. X    }
  929. X}
  930. X
  931. X
  932. Xsub ftp'open
  933. X{
  934. X    local( $site, $ftp_port, $retry_call, $attempts ) = @_;
  935. X
  936. X    local( $old_sig ) = $SIG{ 'ALRM' };
  937. X    $SIG{ 'ALRM' } = "ftp\'open_alarm";
  938. X
  939. X    local( $ret ) = eval "&timed_open( '$site', $ftp_port, $retry_call, $attempts )";
  940. X    alarm( 0 );
  941. X    $SIG{ 'ALRM' } = $old_sig;
  942. X
  943. X    if( $@ =~ /^timeout/ ){
  944. X        return -1;
  945. X    }
  946. X
  947. X    if( $ret ){
  948. X        $ftp'service_open = 1;
  949. X    }
  950. X
  951. X    return $ret;
  952. X}
  953. X
  954. Xsub ftp'login
  955. X{
  956. X    local( $remote_user, $remote_password ) = @_;
  957. X        local( $ret );
  958. X
  959. X    if( ! $ftp'service_open ){
  960. X        return 0;
  961. X    }
  962. X
  963. X    if( $proxy ){
  964. X        &ftp'send( "USER $remote_user@$site" );
  965. X    }
  966. X    else {
  967. X        &ftp'send( "USER $remote_user" );
  968. X    }
  969. X    $ret = &ftp'expect( $timeout,
  970. X        230, "$remote_user logged in", 1,
  971. X        331, "send password for $remote_user", 2,
  972. X
  973. X        500, "syntax error", 0,
  974. X        501, "syntax error", 0,
  975. X        530, "not logged in", 0,
  976. X        332, "account for login not supported", 0,
  977. X
  978. X        421, "service unavailable, closing connection", 99 );
  979. X    if( $ret == 99 ){
  980. X        &service_closed();
  981. X        $ret = 0;
  982. X    }
  983. X    if( $ret == 2 ){
  984. X        # A password is needed
  985. X        &ftp'send( "PASS $remote_password" );
  986. X
  987. X        $ret = &ftp'expect( $timeout,
  988. X            230, "$remote_user logged in", 1,
  989. X
  990. X            202, "command not implemented", 0,
  991. X            332, "account for login not supported", 0,
  992. X
  993. X            530, "not logged in", 0,
  994. X            500, "syntax error", 0,
  995. X            501, "syntax error", 0,
  996. X            503, "bad sequence of commands", 0, 
  997. X
  998. X            421, "service unavailable, closing connection", 99 );
  999. X        if( $ret == 99 ){
  1000. X            &service_closed();
  1001. X            $ret = 0;
  1002. X        }
  1003. X        if( $ret == 1 ){
  1004. X            # Logged in
  1005. X            return 1;
  1006. X        }
  1007. X    }
  1008. X    # If I got here I failed to login
  1009. X    return 0;
  1010. X}
  1011. X
  1012. Xsub service_closed
  1013. X{
  1014. X    $ftp'service_open = 0;
  1015. X    &chat'close();
  1016. X}
  1017. X
  1018. Xsub ftp'close
  1019. X{
  1020. X    &ftp'quit();
  1021. X    $ftp'service_open = 0;
  1022. X    &chat'close();
  1023. X}
  1024. X
  1025. X# Change directory
  1026. X# return 1 if successful
  1027. X# 0 on a failure
  1028. Xsub ftp'cwd
  1029. X{
  1030. X    local( $dir ) = @_;
  1031. X    local( $ret );
  1032. X
  1033. X    if( ! $ftp'service_open ){
  1034. X        return 0;
  1035. X    }
  1036. X
  1037. X    if( $ftp'mapunixout ){
  1038. X        $dir = eval "&$ftp'mapunixout( \$dir, 'd' )";
  1039. X    }
  1040. X
  1041. X    &ftp'send( "CWD $dir" );
  1042. X
  1043. X    $ret = &ftp'expect( $timeout,
  1044. X        200, "working directory = $dir", 1,
  1045. X        250, "working directory = $dir", 1,
  1046. X
  1047. X        500, "syntax error", 0,
  1048. X        501, "syntax error", 0,
  1049. X                502, "command not implemented", 0,
  1050. X        530, "not logged in", 0,
  1051. X                550, "cannot change directory", 0,
  1052. X        421, "service unavailable, closing connection", 99 );
  1053. X
  1054. X    if( $ret == 99 ){
  1055. X        &service_closed();
  1056. X        $ret = 0;
  1057. X    }
  1058. X
  1059. X    return $ret;
  1060. X}
  1061. X
  1062. X# Get a full directory listing:
  1063. X# &ftp'dir( remote LIST options )
  1064. X# Start a list going with the given options.
  1065. X# Presuming that the remote deamon uses the ls command to generate the
  1066. X# data to send back then then you can send it some extra options (eg: -lRa)
  1067. X# return 1 if sucessful and 0 on a failure
  1068. Xsub ftp'dir_open
  1069. X{
  1070. X    local( $options ) = @_;
  1071. X    local( $ret );
  1072. X    
  1073. X    if( ! $ftp'service_open ){
  1074. X        return 0;
  1075. X    }
  1076. X
  1077. X    if( ! &ftp'open_data_socket() ){
  1078. X        return 0;
  1079. X    }
  1080. X    
  1081. X    if( $options ){
  1082. X        &ftp'send( "LIST $options" );
  1083. X    }
  1084. X    else {
  1085. X        &ftp'send( "LIST" );
  1086. X    }
  1087. X    
  1088. X    $ret = &ftp'expect( $timeout,
  1089. X        150, "reading directory", 1,
  1090. X    
  1091. X        125, "data connection already open?", 0,
  1092. X    
  1093. X        450, "file unavailable", 0,
  1094. X        500, "syntax error", 0,
  1095. X        501, "syntax error", 0,
  1096. X        502, "command not implemented", 0,
  1097. X        530, "not logged in", 0,
  1098. X    
  1099. X            421, "service unavailable, closing connection", 99 );
  1100. X    
  1101. X    if( $ret == 99 ){
  1102. X        &service_closed();
  1103. X        $ret = 0;
  1104. X    }
  1105. X
  1106. X    if( ! $ret ){
  1107. X        &ftp'close_data_socket;
  1108. X        return 0;
  1109. X    }
  1110. X    
  1111. X    # 
  1112. X    # the data should be coming at us now
  1113. X    #
  1114. X    
  1115. X    # now accept
  1116. X    accept(NS,S) || die "accept failed $!";
  1117. X    
  1118. X    return 1;
  1119. X}
  1120. X
  1121. X
  1122. X# Close down reading the result of a remote ls command
  1123. X# return 1 if successful and 0 on failure
  1124. Xsub ftp'dir_close
  1125. X{
  1126. X    local( $ret );
  1127. X
  1128. X    if( ! $ftp'service_open ){
  1129. X        return 0;
  1130. X    }
  1131. X
  1132. X    # read the close
  1133. X    #
  1134. X    $ret = &ftp'expect($timeout,
  1135. X            226, "", 1,     # transfer complete, closing connection
  1136. X            250, "", 1,     # action completed
  1137. X
  1138. X            425, "can't open data connection", 0,
  1139. X            426, "connection closed, transfer aborted", 0,
  1140. X            451, "action aborted, local error", 0,
  1141. X            421, "service unavailable, closing connection", 99 );
  1142. X    if( $ret == 99 ){
  1143. X        &service_closed();
  1144. X        $ret = 0;
  1145. X    }
  1146. X
  1147. X    # shut down our end of the socket
  1148. X    &ftp'close_data_socket;
  1149. X
  1150. X    if( ! $ret ){
  1151. X        return 0;
  1152. X    }
  1153. X
  1154. X    return 1;
  1155. X}
  1156. X
  1157. X# Quit from the remote ftp server
  1158. X# return 1 if successful and 0 on failure
  1159. Xsub ftp'quit
  1160. X{
  1161. X    local( $ret );
  1162. X
  1163. X    $site_command_check = 0;
  1164. X    @site_command_list = ();
  1165. X
  1166. X    if( ! $ftp'service_open ){
  1167. X        return 0;
  1168. X    }
  1169. X
  1170. X    &ftp'send( "QUIT" );
  1171. X
  1172. X    $ret = &ftp'expect( $timeout, 
  1173. X        221, "Goodbye", 1,     # transfer complete, closing connection
  1174. X        500, "error quitting??", 0,
  1175. X        421, "service unavailable, closing connection", 99 );
  1176. X    if( $ret == 99 ){
  1177. X        &service_closed();
  1178. X        $ret = 0;
  1179. X    }
  1180. X    return $ret;
  1181. X}
  1182. X
  1183. Xsub ftp'read_alarm
  1184. X{
  1185. X    die "timeout: read";
  1186. X}
  1187. X
  1188. Xsub ftp'timed_read
  1189. X{
  1190. X    alarm( $timeout_read );
  1191. X    return sysread( NS, $buf, $ftpbufsize );
  1192. X}
  1193. X
  1194. Xsub ftp'read
  1195. X{
  1196. X    $SIG{ 'ALRM' } = "ftp\'read_alarm";
  1197. X
  1198. X    if( ! $ftp'service_open ){
  1199. X        return -1;
  1200. X    }
  1201. X
  1202. X    local( $ret ) = eval '&timed_read()';
  1203. X    alarm( 0 );
  1204. X
  1205. X    if( $@ =~ /^timeout/ ){
  1206. X        return -1;
  1207. X    }
  1208. X    return $ret;
  1209. X}
  1210. X
  1211. X# Get a remote file back into a local file.
  1212. X# If no loc_fname passed then uses rem_fname.
  1213. X# returns 1 on success and 0 on failure
  1214. Xsub ftp'get
  1215. X{
  1216. X    local($rem_fname, $loc_fname, $restart ) = @_;
  1217. X    local( $ret );
  1218. X    
  1219. X    if( ! $ftp'service_open ){
  1220. X        return 0;
  1221. X    }
  1222. X
  1223. X    if( $loc_fname eq "" ){
  1224. X        $loc_fname = $rem_fname;
  1225. X    }
  1226. X    
  1227. X    if( ! &ftp'open_data_socket() ){
  1228. X        print $ftp'showfd "Cannot open data socket\n";
  1229. X        return 0;
  1230. X    }
  1231. X
  1232. X    if( $loc_fname ne '-' ){
  1233. X        # Find the size of the target file
  1234. X        local( $restart_at ) = &ftp'filesize( $loc_fname );
  1235. X        if( $restart && $restart_at > 0 && &ftp'restart( $restart_at ) ){
  1236. X            $restart = 1;
  1237. X            # Make sure the file can be updated
  1238. X            chmod( 0644, $loc_fname );
  1239. X        }
  1240. X        else {
  1241. X            $restart = 0;
  1242. X            unlink( $loc_fname );
  1243. X        }
  1244. X    }
  1245. X
  1246. X    if( $ftp'mapunixout ){
  1247. X        $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
  1248. X    }
  1249. X
  1250. X    &ftp'send( "RETR $rem_fname" );
  1251. X    
  1252. X    $ret = &ftp'expect( $timeout, 
  1253. X        150, "receiving $rem_fname", 1,
  1254. X
  1255. X        125, "data connection already open?", 0,
  1256. X        450, "file unavailable", 2,
  1257. X        550, "file unavailable", 2,
  1258. X        500, "syntax error", 0,
  1259. X        501, "syntax error", 0,
  1260. X        530, "not logged in", 0,
  1261. X
  1262. X        421, "service unavailable, closing connection", 99 );
  1263. X    if( $ret == 99 ){
  1264. X        &service_closed();
  1265. X        $ret = 0;
  1266. X    }
  1267. X    if( $ret != 1 ){
  1268. X        print $ftp'showfd "Failure on 'RETR $rem_fname' command\n";
  1269. X
  1270. X        # shut down our end of the socket
  1271. X        &ftp'close_data_socket;
  1272. X
  1273. X        return 0;
  1274. X    }
  1275. X
  1276. X    # 
  1277. X    # the data should be coming at us now
  1278. X    #
  1279. X
  1280. X    # now accept
  1281. X    accept( NS, S ) || die "accept failed: $!";
  1282. X
  1283. X    #
  1284. X    #  open the local fname
  1285. X    #  concatenate on the end if restarting, else just overwrite
  1286. X    if( !open( FH, ($restart ? '>>' : '>') . $loc_fname ) ){
  1287. X        print $ftp'showfd "Cannot create local file $loc_fname\n";
  1288. X
  1289. X        # shut down our end of the socket
  1290. X        &ftp'close_data_socket;
  1291. X
  1292. X        return 0;
  1293. X    }
  1294. X
  1295. X    local( $start_time ) = time;
  1296. X    local( $bytes, $lasthash, $hashes ) = (0, 0, 0);
  1297. X    while( ($len = &ftp'read()) > 0 ){
  1298. X        $bytes += $len;
  1299. X        if( $strip_cr ){
  1300. X            $ftp'buf =~ s/\r//g;
  1301. X        }
  1302. X        if( $ftp_show ){
  1303. X            while( $bytes > ($lasthash + $ftp'hashevery) ){
  1304. X                print $ftp'showfd '#';
  1305. X                $lasthash += $ftp'hashevery;
  1306. X                $hashes++;
  1307. X                if( ($hashes % $ftp'hashnl) == 0 ){
  1308. X                    print $ftp'showfd "\n";
  1309. X                }
  1310. X            }
  1311. X        }
  1312. X        if( ! print FH $ftp'buf ){
  1313. X            print $ftp'showfd "\nfailed to write data";
  1314. X            $bytes = -1;
  1315. X            last;
  1316. X        }
  1317. X    }
  1318. X    close( FH );
  1319. X
  1320. X    # shut down our end of the socket
  1321. X    &ftp'close_data_socket;
  1322. X
  1323. X    if( $len < 0 ){
  1324. X        print $ftp'showfd "\ntimed out reading data!\n";
  1325. X
  1326. X        return 0;
  1327. X    }
  1328. X        
  1329. X    if( $ftp_show && $bytes > 0 ){
  1330. X        if( $hashes && ($hashes % $ftp'hashnl) != 0 ){
  1331. X            print $ftp'showfd "\n";
  1332. X        }
  1333. X        local( $secs ) = (time - $start_time);
  1334. X        if( $secs <= 0 ){
  1335. X            $secs = 1; # To avoid a divide by zero;
  1336. X        }
  1337. X
  1338. X        local( $rate ) = int( $bytes / $secs );
  1339. X        print $ftp'showfd "Got $bytes bytes ($rate bytes/sec)\n";
  1340. X    }
  1341. X
  1342. X    #
  1343. X    # read the close
  1344. X    #
  1345. X
  1346. X    $ret = &ftp'expect( $timeout, 
  1347. X        226, "Got file", 1,     # transfer complete, closing connection
  1348. X            250, "Got file", 1,     # action completed
  1349. X    
  1350. X            110, "restart not supported", 0,
  1351. X            425, "can't open data connection", 0,
  1352. X            426, "connection closed, transfer aborted", 0,
  1353. X            451, "action aborted, local error", 0,
  1354. X        550, "permission denied", 0,
  1355. X
  1356. X        421, "service unavailable, closing connection", 99 );
  1357. X    if( $ret == 99 ){
  1358. X        &service_closed();
  1359. X        $ret = 0;
  1360. X    }
  1361. X
  1362. X    if( $ret && $bytes < 0 ){
  1363. X        $ret = 0;
  1364. X    }
  1365. X
  1366. X    return $ret;
  1367. X}
  1368. X
  1369. Xsub ftp'delete
  1370. X{
  1371. X    local( $rem_fname ) = @_;
  1372. X    local( $ret );
  1373. X
  1374. X    if( ! $ftp'service_open ){
  1375. X        return 0;
  1376. X    }
  1377. X
  1378. X    if( $ftp'mapunixout ){
  1379. X        $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
  1380. X    }
  1381. X
  1382. X    &ftp'send( "DELE $rem_fname" );
  1383. X
  1384. X    $ret = &ftp'expect( $timeout, 
  1385. X        250, "Deleted $rem_fname", 1,
  1386. X        550, "Permission denied", 0,
  1387. X
  1388. X        421, "service unavailable, closing connection", 99 );
  1389. X    if( $ret == 99 ){
  1390. X        &service_closed();
  1391. X        $ret = 0;
  1392. X    }
  1393. X
  1394. X    return $ret == 1;
  1395. X}
  1396. X
  1397. Xsub ftp'deldir
  1398. X{
  1399. X    local( $fname ) = @_;
  1400. X
  1401. X    # not yet implemented
  1402. X    # RMD
  1403. X}
  1404. X
  1405. X# UPDATE ME!!!!!!
  1406. X# Add in the hash printing and newline conversion
  1407. Xsub ftp'put
  1408. X{
  1409. X    local( $loc_fname, $rem_fname ) = @_;
  1410. X    local( $strip_cr );
  1411. X    
  1412. X    if( ! $ftp'service_open ){
  1413. X        return 0;
  1414. X    }
  1415. X
  1416. X    if( $loc_fname eq "" ){
  1417. X        $loc_fname = $rem_fname;
  1418. X    }
  1419. X    
  1420. X    if( ! &ftp'open_data_socket() ){
  1421. X        return 0;
  1422. X    }
  1423. X    
  1424. X    if( $ftp'mapunixout ){
  1425. X        $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
  1426. X    }
  1427. X
  1428. X    &ftp'send( "STOR $rem_fname" );
  1429. X    
  1430. X    # 
  1431. X    # the data should be coming at us now
  1432. X    #
  1433. X    
  1434. X    local( $ret ) =
  1435. X    &ftp'expect( $timeout, 
  1436. X        150, "sending $loc_fname", 1,
  1437. X
  1438. X        125, "data connection already open?", 0,
  1439. X        450, "file unavailable", 0,
  1440. X        532, "need account for storing files", 0,
  1441. X        452, "insufficient storage on system", 0,
  1442. X        553, "file name not allowed", 0,
  1443. X        500, "syntax error", 0,
  1444. X        501, "syntax error", 0,
  1445. X        530, "not logged in", 0,
  1446. X
  1447. X        421, "service unavailable, closing connection", 99 );
  1448. X    if( $ret == 99 ){
  1449. X        &service_closed();
  1450. X        $ret = 0;
  1451. X    }
  1452. X
  1453. X    if( $ret != 1 ){
  1454. X        # shut down our end of the socket
  1455. X        &ftp'close_data_socket;
  1456. X
  1457. X        return 0;
  1458. X    }
  1459. X
  1460. X
  1461. X    # 
  1462. X    # the data should be coming at us now
  1463. X    #
  1464. X    
  1465. X    # now accept
  1466. X    accept(NS,S) || die "accept failed: $!";
  1467. X    
  1468. X    #
  1469. X    #  open the local fname
  1470. X    #
  1471. X    if( !open(FH, "<$loc_fname") ){
  1472. X        print $ftp'showfd "Cannot open local file $loc_fname\n";
  1473. X
  1474. X        # shut down our end of the socket
  1475. X        &ftp'close_data_socket;
  1476. X
  1477. X        return 0;
  1478. X    }
  1479. X    
  1480. X    while( <FH> ){
  1481. X        if( ! $ftp'service_open ){
  1482. X            last;
  1483. X        }
  1484. X        print NS ;
  1485. X    }
  1486. X    close( FH );
  1487. X    
  1488. X    # shut down our end of the socket to signal EOF
  1489. X    &ftp'close_data_socket;
  1490. X    
  1491. X    #
  1492. X    # read the close
  1493. X    #
  1494. X    
  1495. X    $ret = &ftp'expect( $timeout, 
  1496. X        226, "file put", 1,     # transfer complete, closing connection
  1497. X        250, "file put", 1,     # action completed
  1498. X    
  1499. X        110, "restart not supported", 0,
  1500. X        425, "can't open data connection", 0,
  1501. X        426, "connection closed, transfer aborted", 0,
  1502. X        451, "action aborted, local error", 0,
  1503. X        551, "page type unknown", 0,
  1504. X        552, "storage allocation exceeded", 0,
  1505. X    
  1506. X        421, "service unavailable, closing connection", 99 );
  1507. X    if( $ret == 99 ){
  1508. X        &service_closed();
  1509. X        $ret = 0;
  1510. X    }
  1511. X    if( ! $ret ){
  1512. X        print $ftp'showfd "Failure on 'STOR $loc_fname' command\n";
  1513. X    }
  1514. X    return $ret;
  1515. X}
  1516. X
  1517. Xsub ftp'restart
  1518. X{
  1519. X    local( $restart_point, $ret ) = @_;
  1520. X
  1521. X    if( ! $ftp'service_open ){
  1522. X        return 0;
  1523. X    }
  1524. X
  1525. X    &ftp'send( "REST $restart_point" );
  1526. X
  1527. X    # 
  1528. X    # see what they say
  1529. X
  1530. X    $ret = &ftp'expect( $timeout, 
  1531. X        350, "restarting at $restart_point", 1,
  1532. X               
  1533. X        500, "syntax error", 0,
  1534. X        501, "syntax error", 0,
  1535. X        502, "REST not implemented", 2,
  1536. X        530, "not logged in", 0,
  1537. X        554, "REST not implemented", 2,
  1538. X               
  1539. X        421, "service unavailable, closing connection", 99 );
  1540. X    if( $ret == 99 ){
  1541. X        &service_closed();
  1542. X        $ret = 0;
  1543. X    }
  1544. X    return $ret;
  1545. X}
  1546. X
  1547. X# Set the file transfer type
  1548. Xsub ftp'type
  1549. X{
  1550. X    local( $type ) = @_;
  1551. X
  1552. X    if( ! $ftp'service_open ){
  1553. X        return 0;
  1554. X    }
  1555. X
  1556. X    &ftp'send( "TYPE $type" );
  1557. X
  1558. X    # 
  1559. X    # see what they say
  1560. X
  1561. X    $ret = &ftp'expect( $timeout, 
  1562. X        200, "file type set to $type", 1,
  1563. X               
  1564. X        500, "syntax error", 0,
  1565. X        501, "syntax error", 0,
  1566. X        504, "Invalid form or byte size for type $type", 0,
  1567. X               
  1568. X        421, "service unavailable, closing connection", 99 );
  1569. X    if( $ret == 99 ){
  1570. X        &service_closed();
  1571. X        $ret = 0;
  1572. X    }
  1573. X    return $ret;
  1574. X}
  1575. X
  1576. X$site_command_check = 0;
  1577. X@site_command_list = ();
  1578. X
  1579. X# routine to query the remote server for 'SITE' commands supported
  1580. Xsub ftp'site_commands
  1581. X{
  1582. X    local( $ret );
  1583. X    
  1584. X    if( ! $ftp'service_open ){
  1585. X        return 0;
  1586. X    }
  1587. X
  1588. X    # if we havent sent a 'HELP SITE', send it now
  1589. X    if( !$site_command_check ){
  1590. X    
  1591. X        $site_command_check = 1;
  1592. X    
  1593. X        &ftp'send( "HELP SITE" );
  1594. X    
  1595. X        # assume the line in the HELP SITE response with the 'HELP'
  1596. X        # command is the one for us
  1597. X        $ret = &ftp'expect( $timeout,
  1598. X            ".*HELP.*", "", "\$1",
  1599. X            214, "", "0",
  1600. X            202, "", "0",
  1601. X            421, "service unavailable, closing connection", "99" );
  1602. X        if( $ret == 99 ){
  1603. X            &service_closed();
  1604. X            $ret = "0";
  1605. X        }
  1606. X    
  1607. X        if( $ret eq "0" ){
  1608. X            print $ftp'showfd "No response from HELP SITE\n" if( $ftp_show );
  1609. X        }
  1610. X    
  1611. X        @site_command_list = split(/\s+/, $ret);
  1612. X    }
  1613. X    
  1614. X    return @site_command_list;
  1615. X}
  1616. X
  1617. X# return the pwd, or null if we can't get the pwd
  1618. Xsub ftp'pwd
  1619. X{
  1620. X    local( $ret, $cwd );
  1621. X
  1622. X    if( ! $ftp'service_open ){
  1623. X        return 0;
  1624. X    }
  1625. X
  1626. X    &ftp'send( "PWD" );
  1627. X
  1628. X    # 
  1629. X    # see what they say
  1630. X
  1631. X    $ret = &ftp'expect( $timeout, 
  1632. X        257, "working dir is", 1,
  1633. X        500, "syntax error", 0,
  1634. X        501, "syntax error", 0,
  1635. X        502, "PWD not implemented", 0,
  1636. X        550, "file unavailable", 0,
  1637. X
  1638. X        421, "service unavailable, closing connection", 99 );
  1639. X    if( $ret == 99 ){
  1640. X        &service_closed();
  1641. X        $ret = 0;
  1642. X    }
  1643. X    if( $ret ){
  1644. X        if( $ftp'response =~ /^257\s"(.*)"\s.*$/ ){
  1645. X            $cwd = $1;
  1646. X        }
  1647. X    }
  1648. X    return $cwd;
  1649. X}
  1650. X
  1651. X# return 1 for success, 0 for failure
  1652. Xsub ftp'mkdir
  1653. X{
  1654. X    local( $path ) = @_;
  1655. X    local( $ret );
  1656. X
  1657. X    if( ! $ftp'service_open ){
  1658. X        return 0;
  1659. X    }
  1660. X
  1661. X    if( $ftp'mapunixout ){
  1662. X        $path = eval "&$ftp'mapunixout( \$path, 'f' )";
  1663. X    }
  1664. X
  1665. X    &ftp'send( "MKD $path" );
  1666. X
  1667. X    # 
  1668. X    # see what they say
  1669. X
  1670. X    $ret = &ftp'expect( $timeout, 
  1671. X        257, "made directory $path", 1,
  1672. X               
  1673. X        500, "syntax error", 0,
  1674. X        501, "syntax error", 0,
  1675. X        502, "MKD not implemented", 0,
  1676. X        530, "not logged in", 0,
  1677. X        550, "file unavailable", 0,
  1678. X
  1679. X        421, "service unavailable, closing connection", 99 );
  1680. X    if( $ret == 99 ){
  1681. X        &service_closed();
  1682. X        $ret = 0;
  1683. X    }
  1684. X    return $ret;
  1685. X}
  1686. X
  1687. X# return 1 for success, 0 for failure
  1688. Xsub ftp'chmod
  1689. X{
  1690. X    local( $path, $mode ) = @_;
  1691. X    local( $ret );
  1692. X
  1693. X    if( ! $ftp'service_open ){
  1694. X        return 0;
  1695. X    }
  1696. X
  1697. X    if( $ftp'mapunixout ){
  1698. X        $path = eval "&$ftp'mapunixout( \$path, 'f' )";
  1699. X    }
  1700. X
  1701. X    &ftp'send( sprintf( "SITE CHMOD %o $path", $mode ) );
  1702. X
  1703. X    # 
  1704. X    # see what they say
  1705. X
  1706. X    $ret = &ftp'expect( $timeout, 
  1707. X        200, "chmod $mode $path succeeded", 1,
  1708. X               
  1709. X        500, "syntax error", 0,
  1710. X        501, "syntax error", 0,
  1711. X        502, "CHMOD not implemented", 0,
  1712. X        530, "not logged in", 0,
  1713. X        550, "file unavailable", 0,
  1714. X
  1715. X        421, "service unavailable, closing connection", 99 );
  1716. X    if( $ret == 99 ){
  1717. X        &service_closed();
  1718. X        $ret = 0;
  1719. X    }
  1720. X    return $ret;
  1721. X}
  1722. X
  1723. X# rename a file
  1724. Xsub ftp'rename
  1725. X{
  1726. X    local( $old_name, $new_name ) = @_;
  1727. X    local( $ret );
  1728. X
  1729. X    if( ! $ftp'service_open ){
  1730. X        return 0;
  1731. X    }
  1732. X
  1733. X    if( $ftp'mapunixout ){
  1734. X        $old_name = eval "&$ftp'mapunixout( \$old_name, 'f' )";
  1735. X    }
  1736. X
  1737. X    &ftp'send( "RNFR $old_name" );
  1738. X
  1739. X    # 
  1740. X    # see what they say
  1741. X
  1742. X    $ret = &ftp'expect( $timeout, 
  1743. X        350, "", 1,
  1744. X               
  1745. X        500, "syntax error", 0,
  1746. X        501, "syntax error", 0,
  1747. X        502, "RNFR not implemented", 0,
  1748. X        530, "not logged in", 0,
  1749. X        550, "file unavailable", 0,
  1750. X        450, "file unavailable", 0,
  1751. X               
  1752. X        421, "service unavailable, closing connection", 99 );
  1753. X    if( $ret == 99 ){
  1754. X        &service_closed();
  1755. X        $ret = 0;
  1756. X    }
  1757. X
  1758. X    # check if the "rename from" occurred ok
  1759. X    if( $ret ){
  1760. X        if( $ftp'mapunixout ){
  1761. X            $new_name = eval "&$ftp'mapunixout( \$new_name, 'f' )";
  1762. X        }
  1763. X
  1764. X        &ftp'send( "RNTO $new_name" );
  1765. X    
  1766. X        # 
  1767. X        # see what they say
  1768. X    
  1769. X        $ret = &ftp'expect( $timeout, 
  1770. X            250, "rename $old_name to $new_name", 1, 
  1771. X
  1772. X            500, "syntax error", 0,
  1773. X            501, "syntax error", 0,
  1774. X            502, "RNTO not implemented", 0,
  1775. X            503, "bad sequence of commands", 0,
  1776. X            530, "not logged in", 0,
  1777. X            532, "need account for storing files", 0,
  1778. X            553, "file name not allowed", 0,
  1779. X                   
  1780. X            421, "service unavailable, closing connection", 99 );
  1781. X        if( $ret == 99 ){
  1782. X            &service_closed();
  1783. X            $ret = 0;
  1784. X        }
  1785. X    }
  1786. X
  1787. X    return $ret;
  1788. X}
  1789. X
  1790. X
  1791. Xsub ftp'quote
  1792. X{
  1793. X    local( $cmd ) = @_;
  1794. X    local( $ret );
  1795. X
  1796. X    if( ! $ftp'service_open ){
  1797. X        return 0;
  1798. X    }
  1799. X
  1800. X    &ftp'send( $cmd );
  1801. X
  1802. X    $ret = &ftp'expect( $timeout, 
  1803. X        200, "Remote '$cmd' OK", 1,
  1804. X        500, "error in remote '$cmd'", 0,
  1805. X        421, "service unavailable, closing connection", 99 );
  1806. X    if( $ret == 99 ){
  1807. X        &service_closed();
  1808. X        $ret = 0;
  1809. X    }
  1810. X    return $ret;
  1811. X}
  1812. X
  1813. X# ------------------------------------------------------------------------------
  1814. X# These are the lower level support routines
  1815. X
  1816. Xsub ftp'expectgot
  1817. X{
  1818. X    ($ftp'response, $ftp'fatalerror) = @_;
  1819. X    if( $ftp_show ){
  1820. X        print $ftp'showfd "$ftp'response\n";
  1821. X    }
  1822. X    # Zap the chat2 buffer
  1823. X    undef( $chat'S );
  1824. X}
  1825. X
  1826. X#
  1827. X#  create the list of parameters for chat'expect
  1828. X#
  1829. X#  ftp'expect(time_out, {value, string_to_print, return value});
  1830. X#     if the string_to_print is "" then nothing is printed
  1831. X#  the last response is stored in $ftp'response
  1832. X#
  1833. X# NOTE: lmjm has changed this code such that the string_to_print is
  1834. X# ignored and the string sent back from the remote system is printed
  1835. X# instead.
  1836. X#
  1837. Xsub ftp'expect {
  1838. X    local( $ret );
  1839. X    local( $time_out );
  1840. X    local( @expect_args );
  1841. X    local( $code, $pre );
  1842. X    
  1843. X    $ftp'response = '';
  1844. X    $ftp'fatalerror = 0;
  1845. X
  1846. X    $time_out = shift( @_ );
  1847. X    
  1848. X    while( @_ ){
  1849. X        $code = shift( @_ );
  1850. X        $pre = '^';
  1851. X        if( $code =~ /^\d+$/ ){
  1852. X            $pre = "[.|\n]*^";
  1853. X        }
  1854. X        push( @expect_args, "$pre(" . $code . " .*)\\015\\n" );
  1855. X        shift( @_ );
  1856. X        push( @expect_args, 
  1857. X            "&expectgot( \$1, 0 ); " . shift( @_ ) );
  1858. X    }
  1859. X    
  1860. X    # Treat all unrecognised lines as continuations
  1861. X    push( @expect_args, "^(.*)\\015\\n" );
  1862. X    push( @expect_args, "&expectgot( \$1, 0 ); 100" );
  1863. X    
  1864. X    # add patterns TIMEOUT and EOF
  1865. X    
  1866. X    push( @expect_args, 'TIMEOUT' );
  1867. X    push( @expect_args, "&expectgot( 'timed out', 0 ); 0" );
  1868. X    
  1869. X    push( @expect_args, 'EOF' );
  1870. X    push( @expect_args, "&expectgot( 'remote server gone away', 1 ); 99" );
  1871. X    
  1872. X    if( $ftp_show > 9 ){
  1873. X        &printargs( $time_out, @expect_args );
  1874. X    }
  1875. X    
  1876. X    $ret = &chat'expect( $time_out, @expect_args );
  1877. X    if( $ret == 100 ){
  1878. X        # we saw a continuation line, wait for the end
  1879. X        push( @expect_args, "^.*\n" );
  1880. X        push( @expect_args, "100" );
  1881. X    
  1882. X        while( $ret == 100 ){
  1883. X            if( $ftp_show > 9 ){
  1884. X                &printargs( $time_out, @expect_args );
  1885. X            }
  1886. X            $ret = &chat'expect( $time_out, @expect_args );
  1887. X        }
  1888. X    }
  1889. X
  1890. X    return $ret;
  1891. X}
  1892. X
  1893. X
  1894. X
  1895. X#
  1896. X#  opens NS for io
  1897. X#
  1898. Xsub ftp'open_data_socket
  1899. X{
  1900. X    local( $sockaddr, $port );
  1901. X    local( $type, $myaddr, $a, $b, $c, $d );
  1902. X    local( $mysockaddr, $family, $hi, $lo );
  1903. X    
  1904. X    $sockaddr = 'S n a4 x8';
  1905. X
  1906. X    ($a,$b,$c,$d) = unpack( 'C4', $chat'thisaddr );
  1907. X    $this = $chat'thisproc;
  1908. X    
  1909. X    socket( S, $pf_inet, $sock_stream, $tcp_proto ) || die "socket: $!";
  1910. X    bind( S, $this ) || die "bind: $!";
  1911. X    
  1912. X    # get the port number
  1913. X    $mysockaddr = getsockname( S );
  1914. X    ($family, $port, $myaddr) = unpack( $sockaddr, $mysockaddr );
  1915. X    
  1916. X    $hi = ($port >> 8) & 0x00ff;
  1917. X    $lo = $port & 0x00ff;
  1918. X    
  1919. X    #
  1920. X    # we MUST do a listen before sending the port otherwise
  1921. X    # the PORT may fail
  1922. X    #
  1923. X    listen( S, 5 ) || die "listen";
  1924. X    
  1925. X    &ftp'send( "PORT $a,$b,$c,$d,$hi,$lo" );
  1926. X    
  1927. X    return &ftp'expect($timeout,
  1928. X        200, "PORT command successful", 1,
  1929. X        250, "PORT command successful", 1 ,
  1930. X
  1931. X        500, "syntax error", 0,
  1932. X        501, "syntax error", 0,
  1933. X        530, "not logged in", 0,
  1934. X
  1935. X        421, "service unavailable, closing connection", 0);
  1936. X}
  1937. X    
  1938. Xsub ftp'close_data_socket
  1939. X{
  1940. X    close(NS);
  1941. X}
  1942. X
  1943. Xsub ftp'send
  1944. X{
  1945. X    local($send_cmd) = @_;
  1946. X
  1947. X    if( $send_cmd =~ /\n/ ){
  1948. X        print $ftp'showfd "ERROR, \\n in send string for $send_cmd\n";
  1949. X    }
  1950. X    
  1951. X    if( $ftp_show ){
  1952. X        local( $sc ) = $send_cmd;
  1953. X
  1954. X        if( $send_cmd =~ /^PASS/){
  1955. X            $sc = "PASS <somestring>";
  1956. X        }
  1957. X        print $ftp'showfd "---> $sc\n";
  1958. X    }
  1959. X    
  1960. X    &chat'print( "$send_cmd\r\n" );
  1961. X}
  1962. X
  1963. Xsub ftp'printargs
  1964. X{
  1965. X    while( @_ ){
  1966. X        print $ftp'showfd shift( @_ ) . "\n";
  1967. X    }
  1968. X}
  1969. X
  1970. Xsub ftp'filesize
  1971. X{
  1972. X    local( $fname ) = @_;
  1973. X
  1974. X    if( ! -f $fname ){
  1975. X        return -1;
  1976. X    }
  1977. X
  1978. X    return (stat( _ ))[ 7 ];
  1979. X    
  1980. X}
  1981. X
  1982. X# make this package return true
  1983. X1;
  1984. END_OF_FILE
  1985. if test 28699 -ne `wc -c <'ftp.pl'`; then
  1986.     echo shar: \"'ftp.pl'\" unpacked with wrong size!
  1987. fi
  1988. # end of 'ftp.pl'
  1989. fi
  1990. if test -f 'makefile' -a "${1}" != "-c" ; then 
  1991.   echo shar: Will not clobber existing file \"'makefile'\"
  1992. else
  1993. echo shar: Extracting \"'makefile'\" \(552 characters\)
  1994. sed "s/^X//" >'makefile' <<'END_OF_FILE'
  1995. X# Where to install ftpcat and its manual pages
  1996. XINSTBIN=/usr/local/bin
  1997. XINSTLIB=/usr/local/lib/perl
  1998. XINSTMAN=/usr/local/man/manl
  1999. X# The manual page section (normally l or 1)
  2000. XS=l
  2001. XALL=README ftpcat.man ftpcat chat2.pl ftp.pl makefile
  2002. X
  2003. Xall:
  2004. X    echo Only make install means anything
  2005. X
  2006. Xinstall:
  2007. X    cp buffer $(INSTBIN)
  2008. X    chmod 755 $(INSTBIN)/buffer
  2009. X    cp ftpcat.man $(INSTMAN)/buffer.$S
  2010. X    chmod 444 $(INSTMAN)/buffer.$S
  2011. X    cp ftp.pl chat2.pl $(INSTLIB)
  2012. X    chmod 444 $(INSTLIB)/ftp.pl $(INSTLIB)/chat2.pl
  2013. X
  2014. Xftpcat.shar: $(ALL)
  2015. X    $(RM) -f buffer.shar
  2016. X    shar $(ALL) > ftpcat.shar
  2017. END_OF_FILE
  2018. if test 552 -ne `wc -c <'makefile'`; then
  2019.     echo shar: \"'makefile'\" unpacked with wrong size!
  2020. fi
  2021. # end of 'makefile'
  2022. fi
  2023. echo shar: End of shell archive.
  2024. exit 0
  2025.  
  2026. -- 
  2027. --
  2028. Lee McLoughlin.                          Phone: +44 71 589 5111 X 5085
  2029. Dept of Computing, Imperial College,     Fax: +44 71 581 8024
  2030. 180 Queens Gate, London, SW7 2BZ, UK.    Email: L.McLoughlin@doc.ic.ac.uk
  2031.  
  2032. exit 0 # Just in case...
  2033.