home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-05-15 | 56.6 KB | 2,367 lines |
- Newsgroups: comp.sources.misc
- From: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
- Subject: v37i051: ftpmail - Automatic Email to FTP Gateway, v1.13, Part01/02
- Message-ID: <csm-v37i051=ftpmail.142201@sparky.IMD.Sterling.COM>
- X-Md4-Signature: 4ecc925e3f77fe79f85f72c774ea304e
- Date: Tue, 11 May 1993 19:26:09 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: lmjm@doc.ic.ac.uk (Lee M J McLoughlin)
- Posting-number: Volume 37, Issue 51
- Archive-name: ftpmail/part01
- Environment: UNIX, Perl, Sun, Dec, INET
-
- Ftpmail is an email->ftp gateway. You mail requests to a user (eg:
- ftpmail). This causes q.pl to be called which checks the request and
- sticks it in a queue. dq.pl then parses the queue and does the ftp
- transfers that the job specifies mailing back the files that were
- transfers. As various things happen notes are writen in the
- ftpmail log file.
-
- It is all writen in perl and sends responses using either mail or by
- directly calling sendmail. When using sendmail MIME support is
- available.
-
- If a transfer fails for a fatal reason then it is dequed and the user
- is emailed. If it fails for a non-fatal reason (such as timeout on
- connect) then it will be requeued to try later (the next time dq.pl is
- called). Once a transfer (get|dir|ls) has succeeded it is marked as
- DONE and will be skipped. All other commands will still be obeyed. A
- job will only be tried for a fix number of times, then rejected.
-
- For user level details read the help file.
-
- If the file motd is present then its contents are inserted at
- the start of any responses.
-
- ARCHIVES
- --------
-
- This package is available from:
- src.doc.ic.ac.uk:packages/ftpmail/
- grasp1.univ-lyon1.fr:pub/unix/mail/tools/ftpmail/
- ftp.sterling.com:mail/ftpmail
-
- TO INSTALL
- ----------
-
- Create an account called 'ftpmail', the home directory of ftpmail is
- where all the scripts will be installed and subdirectories of it form
- the queues.
-
- Edit config.pl to reflect your local details. (If you
- change the default site also edit help.) The auth file is
- just a series of regexps, so a line of just dot would allow all email
- addresses to use ftpmail.
-
- Once you have edited the above files run inst.pl. inst.pl
- will create the ftpmail directories based on values in
- config.pl and copy in various files. Its a bit of a
- hack.
-
- At src.doc.ic.ac.uk I only allow requests to be submitted via email.
- The ftpmail account is not present on any general machine, just on the
- main mail gateway . On that I use the PP .mailfilter script mechanism
- to cause any mail delivered to that ftpmail to invoke q.pl. But
- anything that causes q.pl to be run on the input request will do.
- Under sendmail create ~ftpmail/.forward containing:
- "|/src.doc.ic.ac.uk/public/ic.doc/ftpmail/q.pl"
- (Or similar.)
-
- The file crontab contains a suggested cron entry that should be run as
- the user ftpmail. This calls dq.pl that dequeues the entries and
- runs them. dq.pl should run forever once started. But as I am a
- paranoid person I call it every half hour just to be safe.
-
- Note that mail sent is sent by ftpmail not ftpmail-request. ftpmail
- does other tricks to prevent mail loops forming. I tried running with
- mail being sent by ftpmail-request and ftpmail-request aliases to me.
- I found that most of the traffic to ftpmail-request is from people who
- submit jobs by replying to ftpmail responses in order to submit new
- jobs.
-
- THANKS
- ------
- Thanks to all those who suggested improvements. Also special thanks
- to Christophe.Wolfhugel@hsc-sec.fr for all his work on mime
- and the new queing system which formed the basis for some of the new code.
-
- WORKERS
- -------
- If you want to help develope ftpmail then there is now a mailing list:
- ftpmail-workers@doc.ic.ac.uk
- To subscribe email to: ftpmail-workers-request@doc.ic.ac.uk
- a message like:
- Subject: add me
-
- subscribe ftpmail-workers Your Full Name Here
-
- COPYRIGHT
- ---------
- Writen by Lee McLoughlin <lmjm@doc.ic.ac.uk>
-
- You can do what you like with this except claim that you wrote it or
- give copies with changes not approved by Lee. Neither Lee nor any other
- organisation can be held liable for any problems caused by the use or
- storage of this package.
- ---
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: README ftp.pl help_english q.pl
- # Wrapped by kent@sparky on Tue May 11 12:58:17 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 2)."'
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(3607 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XFtpmail is an email->ftp gateway. You mail requests to a user (eg:
- Xftpmail). This causes q.pl to be called which checks the request and
- Xsticks it in a queue. dq.pl then parses the queue and does the ftp
- Xtransfers that the job specifies mailing back the files that were
- Xtransfers. As various things happen notes are writen in the
- Xftpmail log file.
- X
- XIt is all writen in perl and sends responses using either mail or by
- Xdirectly calling sendmail. When using sendmail MIME support is
- Xavailable.
- X
- XIf a transfer fails for a fatal reason then it is dequed and the user
- Xis emailed. If it fails for a non-fatal reason (such as timeout on
- Xconnect) then it will be requeued to try later (the next time dq.pl is
- Xcalled). Once a transfer (get|dir|ls) has succeeded it is marked as
- XDONE and will be skipped. All other commands will still be obeyed. A
- Xjob will only be tried for a fix number of times, then rejected.
- X
- XFor user level details read the help file.
- X
- XIf the file motd is present then its contents are inserted at
- Xthe start of any responses.
- X
- XARCHIVES
- X--------
- XThis packages is available from:
- X src.doc.ic.ac.uk:packages/ftpmail/
- X grasp1.univ-lyon1.fr:pub/unix/mail/tools/ftpmail/
- X
- X
- XTO INSTALL
- X----------
- X
- XCreate an account called 'ftpmail', the home directory of ftpmail is
- Xwhere all the scripts will be installed and subdirectories of it form
- Xthe queues.
- X
- XEdit config.pl to reflect your local details. (If you
- Xchange the default site also edit help.) The auth file is
- Xjust a series of regexps, so a line of just dot would allow all email
- Xaddresses to use ftpmail.
- X
- XOnce you have edited the above files run inst.pl. inst.pl
- Xwill create the ftpmail directories based on values in
- Xconfig.pl and copy in various files. Its a bit of a
- Xhack.
- X
- XAt src.doc.ic.ac.uk I only allow requests to be submitted via email.
- XThe ftpmail account is not present on any general machine, just on the
- Xmain mail gateway . On that I use the PP .mailfilter script mechanism
- Xto cause any mail delivered to that ftpmail to invoke q.pl. But
- Xanything that causes q.pl to be run on the input request will do.
- XUnder sendmail create ~ftpmail/.forward containing:
- X"|/src.doc.ic.ac.uk/public/ic.doc/ftpmail/q.pl"
- X(Or similar.)
- X
- XThe file crontab contains a suggested cron entry that should be run as
- Xthe user ftpmail. This calls dq.pl that dequeues the entries and
- Xruns them. dq.pl should run forever once started. But as I am a
- Xparanoid person I call it every half hour just to be safe.
- X
- XNote that mail sent is sent by ftpmail not ftpmail-request. ftpmail
- Xdoes other tricks to prevent mail loops forming. I tried running with
- Xmail being sent by ftpmail-request and ftpmail-request aliases to me.
- XI found that most of the traffic to ftpmail-request is from people who
- Xsubmit jobs by replying to ftpmail responses in order to submit new
- Xjobs.
- X
- XTHANKS
- X------
- XThanks to all those who suggested improvements. Also special thanks
- Xto Christophe.Wolfhugel@hsc-sec.fr for all his work on mime
- Xand the new queing system which formed the basis for some of the new code.
- X
- XWORKERS
- X-------
- XIf you want to help develope ftpmail then there is now a mailing list:
- X ftpmail-workers@doc.ic.ac.uk
- XTo subscribe email to: ftpmail-workers-request@doc.ic.ac.uk
- Xa message like:
- X Subject: add me
- X
- X subscribe ftpmail-workers Your Full Name Here
- X
- XCOPYRIGHT
- X---------
- XWriten by Lee McLoughlin <lmjm@doc.ic.ac.uk>
- X
- XYou can do what you like with this except claim that you wrote it or
- Xgive copies with changes not approved by Lee. Neither Lee nor any other
- Xorganisation can be held liable for any problems caused by the use or
- Xstorage of this package.
- END_OF_FILE
- if test 3607 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'ftp.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ftp.pl'\"
- else
- echo shar: Extracting \"'ftp.pl'\" \(28699 characters\)
- sed "s/^X//" >'ftp.pl' <<'END_OF_FILE'
- X#-*-perl-*-
- X# This is a wrapper to the chat2.pl routines that make life easier
- X# to do ftp type work.
- X# Mostly by Lee McLoughlin <lmjm@doc.ic.ac.uk>
- X# based on original version by Alan R. Martello <al@ee.pitt.edu>
- X# And by A.Macpherson@bnr.co.uk for multi-homed hosts
- X#
- X# Basic usage:
- X# $ftp_port = 21;
- X# $retry_call = 1;
- X# $attempts = 2;
- X# if( &ftp'open( $site, $ftp_port, $retry_call, $attempts ) != 1 ){
- X# die "failed to open ftp connection";
- X# }
- X# if( ! &ftp'login( $user, $pass ) ){
- X# die "failed to login";
- X# }
- X# &ftp'type( $text_mode ? 'A' : 'I' );
- X# if( ! &ftp'get( $remote_filename, $local_filename, 0 ) ){
- X# die "failed to get file;
- X# }
- X# &ftp'quit();
- X#
- X#
- 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 $
- X# $Log: ftp.pl,v $
- X# Revision 1.25 1993/05/07 23:36:07 lmjm
- X# Corrected typo in expect code causing long continuations to fail.
- X# Timeouts are no longer a fatal error.
- X# Improved the balance in the timeouts.
- X#
- X# Revision 1.24 1993/05/06 23:13:29 lmjm
- X# Major cleanup.
- X# Reset ALRM when done.
- X# Try to reset if cannot write local file on get.
- X# Spot unreadable remote files.
- X# Cleaned up *MAJOR* dumb code in open_data_socket.
- X#
- X# Revision 1.23 1993/05/06 21:14:19 lmjm
- X# Use the new mapin.
- X# Correct put code.
- X#
- X# Revision 1.22 1993/04/29 23:31:26 lmjm
- X# Added sample prog as a comment.
- X# Clear out chat string that may be large.
- X# Moved some declarations out of loops and used packageless functin names to
- X# save space.
- X#
- X# Revision 1.21 1993/04/28 20:45:26 lmjm
- X# Made the RETR/STOR commands report the file.
- X#
- X# Revision 1.20 1993/04/27 19:53:49 lmjm
- X# Allow for filename mapping before Xfer. Useful for VMS -> unix.
- X#
- X# Revision 1.19 1993/04/26 19:58:33 lmjm
- X# Added missing trailing ; - for older perl's
- X#
- X# Revision 1.18 1993/04/25 13:15:43 lmjm
- X# Keep track of wether the service is open and avoid writing to dead sockets.
- X# Added SIGPIPE handler if ftp'set_signals called.
- X# Added a version var.
- X#
- X# Revision 1.17 1993/04/21 10:06:54 lmjm
- X# Send all status reports to STDERR not to STDOUT (to allow use by ftpcat).
- X# Allow target file to be '-' meaning STDOUT
- X# Added ftp'quote
- X#
- X# Revision 1.16 1993/01/28 18:59:05 lmjm
- X# Allow socket arguemtns to come from main.
- X# Minor cleanups - removed old comments.
- X#
- X# Revision 1.15 1992/11/25 21:09:30 lmjm
- X# Added another REST return code.
- X#
- X# Revision 1.14 1992/08/12 14:33:42 lmjm
- X# Fail ftp'write if out of space.
- X#
- X# Revision 1.13 1992/03/20 21:01:03 lmjm
- X# Added in the proxy ftp code from Edwards Reed <err@cinops.xerox.com>
- X# Added ftp'delete from Aaron Wohl <aw0g+@andrew.cmu.edu>
- X#
- X# Revision 1.12 1992/02/06 23:25:56 lmjm
- X# Moved code around so can use this as a lib for both mirror and ftpmail.
- X# Time out opens. In case Unix doesn't bother to.
- X#
- X# Revision 1.11 1991/11/27 22:05:57 lmjm
- X# Match the response code number at the start of a line allowing
- X# for any leading junk.
- X#
- X# Revision 1.10 1991/10/23 22:42:20 lmjm
- X# Added better timeout code.
- X# Tried to optimise file transfer
- X# Moved open/close code to not leak file handles.
- X# Cleaned up the alarm code.
- X# Added $fatalerror to show wether the ftp link is really dead.
- X#
- X# Revision 1.9 1991/10/07 18:30:35 lmjm
- X# Made the timeout-read code work.
- X# Added restarting file gets.
- X# Be more verbose if ever have to call die.
- X#
- X# Revision 1.8 1991/09/17 22:53:16 lmjm
- X# Spot when open_data_socket fails and return a failure rather than dying.
- X#
- X# Revision 1.7 1991/09/12 22:40:25 lmjm
- X# Added Andrew Macpherson's patches for hosts without ip forwarding.
- X#
- X# Revision 1.6 1991/09/06 19:53:52 lmjm
- X# Relaid out the code the way I like it!
- X# Changed the debuggin to produce more "appropriate" messages
- X# Fixed bugs in the ordering of put and dir listing.
- X# Allow for hash printing when getting files (a la ftp).
- X# Added the new commands from Al.
- X# Don't print passwords in debugging.
- X#
- X# Revision 1.5 1991/08/29 16:23:49 lmjm
- X# Timeout reads from the remote ftp server.
- X# No longer call die expect on fatal errors. Just return fail codes.
- X# Changed returns so higher up routines can tell whats happening.
- X# Get expect/accept in correct order for dir listing.
- X# When ftp_show is set then print hashes every 1k transfered (like ftp).
- X# Allow for stripping returns out of incoming data.
- X# Save last error in a global string.
- X#
- X# Revision 1.4 1991/08/14 21:04:58 lmjm
- X# ftp'get now copes with ungetable files.
- X# ftp'expect code changed such that the string_to_print is
- X# ignored and the string sent back from the remote system is printed
- X# instead.
- X# Implemented patches from al. Removed spuiours tracing statements.
- X#
- X# Revision 1.3 1991/08/09 21:32:18 lmjm
- X# Allow for another ok code on cwd's
- X# Rejigger the log levels
- X# Send \r\n for some odd ftp daemons
- X#
- X# Revision 1.2 1991/08/09 18:07:37 lmjm
- X# Don't print messages unless ftp_show says to.
- X#
- X# Revision 1.1 1991/08/08 20:31:00 lmjm
- X# Initial revision
- X#
- X
- Xrequire 'chat2.pl';
- Xrequire 'socket.ph';
- X
- X
- Xpackage ftp;
- X
- Xif( defined( &main'PF_INET ) ){
- X $pf_inet = &main'PF_INET;
- X $sock_stream = &main'SOCK_STREAM;
- X local($name, $aliases, $proto) = getprotobyname( 'tcp' );
- X $tcp_proto = $proto;
- X}
- Xelse {
- X # XXX hardwired $PF_INET, $SOCK_STREAM, 'tcp'
- X # but who the heck would change these anyway? (:-)
- X $pf_inet = 2;
- X $sock_stream = 1;
- X $tcp_proto = 6;
- X}
- X
- X# If the remote ftp daemon doesn't respond within this time presume its dead
- X# or something.
- X$timeout = 100;
- X
- X# Timeout a read if I don't get data back within this many seconds
- X$timeout_read = 2 * $timeout;
- X
- X# Timeout an open
- X$timeout_open = $timeout;
- X
- X$ftp'version = '$Revision: 1.25 $';
- X
- X# This is a "global" it contains the last response from the remote ftp server
- X# for use in error messages
- X$ftp'response = "";
- X# Also ftp'NS is the socket containing the data coming in from the remote ls
- X# command.
- X
- X# The size of block to be read or written when talking to the remote
- X# ftp server
- X$ftp'ftpbufsize = 4096;
- X
- X# How often to print a hash out, when debugging
- X$ftp'hashevery = 1024;
- X# Output a newline after this many hashes to prevent outputing very long lines
- X$ftp'hashnl = 70;
- X
- X# Is there a connection open?
- X$ftp'service_open = 0;
- X
- X# If a proxy connection then who am I really talking to?
- X$real_site = "";
- X
- X# Where error/log reports are sent to
- X$ftp'showfd = 'STDERR';
- X
- X# Name of a function to call on a pathname to map it into a remote
- X# pathname.
- X$ftp'mapunixout = '';
- X$ftp'manunixin = '';
- X
- X# This is just a tracing aid.
- X$ftp_show = 0;
- X
- Xsub ftp'debug
- X{
- X $ftp_show = @_[0];
- X# if( $ftp_show ){
- X# print $ftp'showfd "ftp debugging on\n";
- X# }
- X}
- X
- Xsub ftp'set_timeout
- X{
- X local( $to ) = @_;
- X return if $to == $timeout;
- X $timeout = $to;
- X $timeout_open = $timeout;
- X $timeout_read = 2 * $timeout;
- X if( $ftp_show ){
- X print $ftp'showfd "ftp timeout set to $timeout\n";
- X }
- X}
- X
- X
- Xsub ftp'open_alarm
- X{
- X die "timeout: open";
- X}
- X
- Xsub ftp'timed_open
- X{
- X local( $site, $ftp_port, $retry_call, $attempts ) = @_;
- X local( $connect_site, $connect_port );
- X local( $res );
- X
- X alarm( $timeout_open );
- X
- X while( $attempts-- ){
- X if( $ftp_show ){
- X print $ftp'showfd "proxy connecting via $proxy_gateway [$proxy_ftp_port]\n" if $proxy;
- X print $ftp'showfd "Connecting to $site";
- X if( $ftp_port != 21 ){
- X print $ftp'showfd " [port $ftp_port]";
- X }
- X print $ftp'showfd "\n";
- X }
- X
- X if( $proxy ) {
- X if( ! $proxy_gateway ) {
- X # if not otherwise set
- X $proxy_gateway = "internet-gateway";
- X }
- X if( $debug ) {
- X print $ftp'showfd "using proxy services of $proxy_gateway, ";
- X print $ftp'showfd "at $proxy_ftp_port\n";
- X }
- X $connect_site = $proxy_gateway;
- X $connect_port = $proxy_ftp_port;
- X $real_site = $site;
- X }
- X else {
- X $connect_site = $site;
- X $connect_port = $ftp_port;
- X }
- X if( ! &chat'open_port( $connect_site, $connect_port ) ){
- X if( $retry_call ){
- X print $ftp'showfd "Failed to connect\n" if $ftp_show;
- X next;
- X }
- X else {
- X print $ftp'showfd "proxy connection failed " if $proxy;
- X print $ftp'showfd "Cannot open ftp to $connect_site\n" if $ftp_show;
- X return 0;
- X }
- X }
- X $res = &ftp'expect( $timeout,
- X 120, "service unavailable to $site", 0,
- X 220, "ready for login to $site", 1,
- X 421, "service unavailable to $site, closing connection", 0);
- X if( ! $res ){
- X &chat'close();
- X next;
- X }
- X return 1;
- X }
- X continue {
- X print $ftp'showfd "Pausing between retries\n";
- X sleep( $retry_pause );
- X }
- X return 0;
- X}
- X
- Xsub main'ftp__sighandler
- X{
- X local( $sig ) = @_;
- X local( $msg ) = "Caught a SIG$sig flagging connection down";
- X $ftp'service_open = 0;
- X if( $ftp_logger ){
- X eval "&$ftp_logger( \$msg )";
- X }
- X}
- X
- Xsub ftp'set_signals
- X{
- X $ftp_logger = @_;
- X $SIG{ 'PIPE' } = "ftp__sighandler";
- X}
- X
- X# Set the mapunixout and mapunixin functions
- Xsub ftp'set_namemap
- X{
- X ($ftp'mapunixout, $ftp'mapunixin) = @_;
- X if( $debug ) {
- X print $ftp'showfd "mapunixout = $ftp'mapunixout, $mapunixin = $ftp'mapunixin\n";
- X }
- X}
- X
- X
- Xsub ftp'open
- X{
- X local( $site, $ftp_port, $retry_call, $attempts ) = @_;
- X
- X local( $old_sig ) = $SIG{ 'ALRM' };
- X $SIG{ 'ALRM' } = "ftp\'open_alarm";
- X
- X local( $ret ) = eval "&timed_open( '$site', $ftp_port, $retry_call, $attempts )";
- X alarm( 0 );
- X $SIG{ 'ALRM' } = $old_sig;
- X
- X if( $@ =~ /^timeout/ ){
- X return -1;
- X }
- X
- X if( $ret ){
- X $ftp'service_open = 1;
- X }
- X
- X return $ret;
- X}
- X
- Xsub ftp'login
- X{
- X local( $remote_user, $remote_password ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $proxy ){
- X &ftp'send( "USER $remote_user@$site" );
- X }
- X else {
- X &ftp'send( "USER $remote_user" );
- X }
- X $ret = &ftp'expect( $timeout,
- X 230, "$remote_user logged in", 1,
- X 331, "send password for $remote_user", 2,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 530, "not logged in", 0,
- X 332, "account for login not supported", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X if( $ret == 2 ){
- X # A password is needed
- X &ftp'send( "PASS $remote_password" );
- X
- X $ret = &ftp'expect( $timeout,
- X 230, "$remote_user logged in", 1,
- X
- X 202, "command not implemented", 0,
- X 332, "account for login not supported", 0,
- X
- X 530, "not logged in", 0,
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 503, "bad sequence of commands", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X if( $ret == 1 ){
- X # Logged in
- X return 1;
- X }
- X }
- X # If I got here I failed to login
- X return 0;
- X}
- X
- Xsub service_closed
- X{
- X $ftp'service_open = 0;
- X &chat'close();
- X}
- X
- Xsub ftp'close
- X{
- X &ftp'quit();
- X $ftp'service_open = 0;
- X &chat'close();
- X}
- X
- X# Change directory
- X# return 1 if successful
- X# 0 on a failure
- Xsub ftp'cwd
- X{
- X local( $dir ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $dir = eval "&$ftp'mapunixout( \$dir, 'd' )";
- X }
- X
- X &ftp'send( "CWD $dir" );
- X
- X $ret = &ftp'expect( $timeout,
- X 200, "working directory = $dir", 1,
- X 250, "working directory = $dir", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "command not implemented", 0,
- X 530, "not logged in", 0,
- X 550, "cannot change directory", 0,
- X 421, "service unavailable, closing connection", 99 );
- X
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X return $ret;
- X}
- X
- X# Get a full directory listing:
- X# &ftp'dir( remote LIST options )
- X# Start a list going with the given options.
- X# Presuming that the remote deamon uses the ls command to generate the
- X# data to send back then then you can send it some extra options (eg: -lRa)
- X# return 1 if sucessful and 0 on a failure
- Xsub ftp'dir_open
- X{
- X local( $options ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( ! &ftp'open_data_socket() ){
- X return 0;
- X }
- X
- X if( $options ){
- X &ftp'send( "LIST $options" );
- X }
- X else {
- X &ftp'send( "LIST" );
- X }
- X
- X $ret = &ftp'expect( $timeout,
- X 150, "reading directory", 1,
- X
- X 125, "data connection already open?", 0,
- X
- X 450, "file unavailable", 0,
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "command not implemented", 0,
- X 530, "not logged in", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X if( ! $ret ){
- X &ftp'close_data_socket;
- X return 0;
- X }
- X
- X #
- X # the data should be coming at us now
- X #
- X
- X # now accept
- X accept(NS,S) || die "accept failed $!";
- X
- X return 1;
- X}
- X
- X
- X# Close down reading the result of a remote ls command
- X# return 1 if successful and 0 on failure
- Xsub ftp'dir_close
- X{
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X # read the close
- X #
- X $ret = &ftp'expect($timeout,
- X 226, "", 1, # transfer complete, closing connection
- X 250, "", 1, # action completed
- X
- X 425, "can't open data connection", 0,
- X 426, "connection closed, transfer aborted", 0,
- X 451, "action aborted, local error", 0,
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X if( ! $ret ){
- X return 0;
- X }
- X
- X return 1;
- X}
- X
- X# Quit from the remote ftp server
- X# return 1 if successful and 0 on failure
- Xsub ftp'quit
- X{
- X local( $ret );
- X
- X $site_command_check = 0;
- X @site_command_list = ();
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X &ftp'send( "QUIT" );
- X
- X $ret = &ftp'expect( $timeout,
- X 221, "Goodbye", 1, # transfer complete, closing connection
- X 500, "error quitting??", 0,
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- Xsub ftp'read_alarm
- X{
- X die "timeout: read";
- X}
- X
- Xsub ftp'timed_read
- X{
- X alarm( $timeout_read );
- X return sysread( NS, $buf, $ftpbufsize );
- X}
- X
- Xsub ftp'read
- X{
- X $SIG{ 'ALRM' } = "ftp\'read_alarm";
- X
- X if( ! $ftp'service_open ){
- X return -1;
- X }
- X
- X local( $ret ) = eval '&timed_read()';
- X alarm( 0 );
- X
- X if( $@ =~ /^timeout/ ){
- X return -1;
- X }
- X return $ret;
- X}
- X
- X# Get a remote file back into a local file.
- X# If no loc_fname passed then uses rem_fname.
- X# returns 1 on success and 0 on failure
- Xsub ftp'get
- X{
- X local($rem_fname, $loc_fname, $restart ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $loc_fname eq "" ){
- X $loc_fname = $rem_fname;
- X }
- X
- X if( ! &ftp'open_data_socket() ){
- X print $ftp'showfd "Cannot open data socket\n";
- X return 0;
- X }
- X
- X if( $loc_fname ne '-' ){
- X # Find the size of the target file
- X local( $restart_at ) = &ftp'filesize( $loc_fname );
- X if( $restart && $restart_at > 0 && &ftp'restart( $restart_at ) ){
- X $restart = 1;
- X # Make sure the file can be updated
- X chmod( 0644, $loc_fname );
- X }
- X else {
- X $restart = 0;
- X unlink( $loc_fname );
- X }
- X }
- X
- X if( $ftp'mapunixout ){
- X $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
- X }
- X
- X &ftp'send( "RETR $rem_fname" );
- X
- X $ret = &ftp'expect( $timeout,
- X 150, "receiving $rem_fname", 1,
- X
- X 125, "data connection already open?", 0,
- X 450, "file unavailable", 2,
- X 550, "file unavailable", 2,
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 530, "not logged in", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X if( $ret != 1 ){
- X print $ftp'showfd "Failure on 'RETR $rem_fname' command\n";
- X
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X return 0;
- X }
- X
- X #
- X # the data should be coming at us now
- X #
- X
- X # now accept
- X accept( NS, S ) || die "accept failed: $!";
- X
- X #
- X # open the local fname
- X # concatenate on the end if restarting, else just overwrite
- X if( !open( FH, ($restart ? '>>' : '>') . $loc_fname ) ){
- X print $ftp'showfd "Cannot create local file $loc_fname\n";
- X
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X return 0;
- X }
- X
- X local( $start_time ) = time;
- X local( $bytes, $lasthash, $hashes ) = (0, 0, 0);
- X while( ($len = &ftp'read()) > 0 ){
- X $bytes += $len;
- X if( $strip_cr ){
- X $ftp'buf =~ s/\r//g;
- X }
- X if( $ftp_show ){
- X while( $bytes > ($lasthash + $ftp'hashevery) ){
- X print $ftp'showfd '#';
- X $lasthash += $ftp'hashevery;
- X $hashes++;
- X if( ($hashes % $ftp'hashnl) == 0 ){
- X print $ftp'showfd "\n";
- X }
- X }
- X }
- X if( ! print FH $ftp'buf ){
- X print $ftp'showfd "\nfailed to write data";
- X $bytes = -1;
- X last;
- X }
- X }
- X close( FH );
- X
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X if( $len < 0 ){
- X print $ftp'showfd "\ntimed out reading data!\n";
- X
- X return 0;
- X }
- X
- X if( $ftp_show && $bytes > 0 ){
- X if( $hashes && ($hashes % $ftp'hashnl) != 0 ){
- X print $ftp'showfd "\n";
- X }
- X local( $secs ) = (time - $start_time);
- X if( $secs <= 0 ){
- X $secs = 1; # To avoid a divide by zero;
- X }
- X
- X local( $rate ) = int( $bytes / $secs );
- X print $ftp'showfd "Got $bytes bytes ($rate bytes/sec)\n";
- X }
- X
- X #
- X # read the close
- X #
- X
- X $ret = &ftp'expect( $timeout,
- X 226, "Got file", 1, # transfer complete, closing connection
- X 250, "Got file", 1, # action completed
- X
- X 110, "restart not supported", 0,
- X 425, "can't open data connection", 0,
- X 426, "connection closed, transfer aborted", 0,
- X 451, "action aborted, local error", 0,
- X 550, "permission denied", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X if( $ret && $bytes < 0 ){
- X $ret = 0;
- X }
- X
- X return $ret;
- X}
- X
- Xsub ftp'delete
- X{
- X local( $rem_fname ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
- X }
- X
- X &ftp'send( "DELE $rem_fname" );
- X
- X $ret = &ftp'expect( $timeout,
- X 250, "Deleted $rem_fname", 1,
- X 550, "Permission denied", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X return $ret == 1;
- X}
- X
- Xsub ftp'deldir
- X{
- X local( $fname ) = @_;
- X
- X # not yet implemented
- X # RMD
- X}
- X
- X# UPDATE ME!!!!!!
- X# Add in the hash printing and newline conversion
- Xsub ftp'put
- X{
- X local( $loc_fname, $rem_fname ) = @_;
- X local( $strip_cr );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $loc_fname eq "" ){
- X $loc_fname = $rem_fname;
- X }
- X
- X if( ! &ftp'open_data_socket() ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $rem_fname = eval "&$ftp'mapunixout( \$rem_fname, 'f' )";
- X }
- X
- X &ftp'send( "STOR $rem_fname" );
- X
- X #
- X # the data should be coming at us now
- X #
- X
- X local( $ret ) =
- X &ftp'expect( $timeout,
- X 150, "sending $loc_fname", 1,
- X
- X 125, "data connection already open?", 0,
- X 450, "file unavailable", 0,
- X 532, "need account for storing files", 0,
- X 452, "insufficient storage on system", 0,
- X 553, "file name not allowed", 0,
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 530, "not logged in", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X if( $ret != 1 ){
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X return 0;
- X }
- X
- X
- X #
- X # the data should be coming at us now
- X #
- X
- X # now accept
- X accept(NS,S) || die "accept failed: $!";
- X
- X #
- X # open the local fname
- X #
- X if( !open(FH, "<$loc_fname") ){
- X print $ftp'showfd "Cannot open local file $loc_fname\n";
- X
- X # shut down our end of the socket
- X &ftp'close_data_socket;
- X
- X return 0;
- X }
- X
- X while( <FH> ){
- X if( ! $ftp'service_open ){
- X last;
- X }
- X print NS ;
- X }
- X close( FH );
- X
- X # shut down our end of the socket to signal EOF
- X &ftp'close_data_socket;
- X
- X #
- X # read the close
- X #
- X
- X $ret = &ftp'expect( $timeout,
- X 226, "file put", 1, # transfer complete, closing connection
- X 250, "file put", 1, # action completed
- X
- X 110, "restart not supported", 0,
- X 425, "can't open data connection", 0,
- X 426, "connection closed, transfer aborted", 0,
- X 451, "action aborted, local error", 0,
- X 551, "page type unknown", 0,
- X 552, "storage allocation exceeded", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X if( ! $ret ){
- X print $ftp'showfd "Failure on 'STOR $loc_fname' command\n";
- X }
- X return $ret;
- X}
- X
- Xsub ftp'restart
- X{
- X local( $restart_point, $ret ) = @_;
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X &ftp'send( "REST $restart_point" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 350, "restarting at $restart_point", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "REST not implemented", 2,
- X 530, "not logged in", 0,
- X 554, "REST not implemented", 2,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- X# Set the file transfer type
- Xsub ftp'type
- X{
- X local( $type ) = @_;
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X &ftp'send( "TYPE $type" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 200, "file type set to $type", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 504, "Invalid form or byte size for type $type", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- X$site_command_check = 0;
- X@site_command_list = ();
- X
- X# routine to query the remote server for 'SITE' commands supported
- Xsub ftp'site_commands
- X{
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X # if we havent sent a 'HELP SITE', send it now
- X if( !$site_command_check ){
- X
- X $site_command_check = 1;
- X
- X &ftp'send( "HELP SITE" );
- X
- X # assume the line in the HELP SITE response with the 'HELP'
- X # command is the one for us
- X $ret = &ftp'expect( $timeout,
- X ".*HELP.*", "", "\$1",
- X 214, "", "0",
- X 202, "", "0",
- X 421, "service unavailable, closing connection", "99" );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = "0";
- X }
- X
- X if( $ret eq "0" ){
- X print $ftp'showfd "No response from HELP SITE\n" if( $ftp_show );
- X }
- X
- X @site_command_list = split(/\s+/, $ret);
- X }
- X
- X return @site_command_list;
- X}
- X
- X# return the pwd, or null if we can't get the pwd
- Xsub ftp'pwd
- X{
- X local( $ret, $cwd );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X &ftp'send( "PWD" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 257, "working dir is", 1,
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "PWD not implemented", 0,
- X 550, "file unavailable", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X if( $ret ){
- X if( $ftp'response =~ /^257\s"(.*)"\s.*$/ ){
- X $cwd = $1;
- X }
- X }
- X return $cwd;
- X}
- X
- X# return 1 for success, 0 for failure
- Xsub ftp'mkdir
- X{
- X local( $path ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $path = eval "&$ftp'mapunixout( \$path, 'f' )";
- X }
- X
- X &ftp'send( "MKD $path" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 257, "made directory $path", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "MKD not implemented", 0,
- X 530, "not logged in", 0,
- X 550, "file unavailable", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- X# return 1 for success, 0 for failure
- Xsub ftp'chmod
- X{
- X local( $path, $mode ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $path = eval "&$ftp'mapunixout( \$path, 'f' )";
- X }
- X
- X &ftp'send( sprintf( "SITE CHMOD %o $path", $mode ) );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 200, "chmod $mode $path succeeded", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "CHMOD not implemented", 0,
- X 530, "not logged in", 0,
- X 550, "file unavailable", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- X# rename a file
- Xsub ftp'rename
- X{
- X local( $old_name, $new_name ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X if( $ftp'mapunixout ){
- X $old_name = eval "&$ftp'mapunixout( \$old_name, 'f' )";
- X }
- X
- X &ftp'send( "RNFR $old_name" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 350, "", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "RNFR not implemented", 0,
- X 530, "not logged in", 0,
- X 550, "file unavailable", 0,
- X 450, "file unavailable", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X
- X # check if the "rename from" occurred ok
- X if( $ret ){
- X if( $ftp'mapunixout ){
- X $new_name = eval "&$ftp'mapunixout( \$new_name, 'f' )";
- X }
- X
- X &ftp'send( "RNTO $new_name" );
- X
- X #
- X # see what they say
- X
- X $ret = &ftp'expect( $timeout,
- X 250, "rename $old_name to $new_name", 1,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 502, "RNTO not implemented", 0,
- X 503, "bad sequence of commands", 0,
- X 530, "not logged in", 0,
- X 532, "need account for storing files", 0,
- X 553, "file name not allowed", 0,
- X
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X }
- X
- X return $ret;
- X}
- X
- X
- Xsub ftp'quote
- X{
- X local( $cmd ) = @_;
- X local( $ret );
- X
- X if( ! $ftp'service_open ){
- X return 0;
- X }
- X
- X &ftp'send( $cmd );
- X
- X $ret = &ftp'expect( $timeout,
- X 200, "Remote '$cmd' OK", 1,
- X 500, "error in remote '$cmd'", 0,
- X 421, "service unavailable, closing connection", 99 );
- X if( $ret == 99 ){
- X &service_closed();
- X $ret = 0;
- X }
- X return $ret;
- X}
- X
- X# ------------------------------------------------------------------------------
- X# These are the lower level support routines
- X
- Xsub ftp'expectgot
- X{
- X ($ftp'response, $ftp'fatalerror) = @_;
- X if( $ftp_show ){
- X print $ftp'showfd "$ftp'response\n";
- X }
- X # Zap the chat2 buffer
- X undef( $chat'S );
- X}
- X
- X#
- X# create the list of parameters for chat'expect
- X#
- X# ftp'expect(time_out, {value, string_to_print, return value});
- X# if the string_to_print is "" then nothing is printed
- X# the last response is stored in $ftp'response
- X#
- X# NOTE: lmjm has changed this code such that the string_to_print is
- X# ignored and the string sent back from the remote system is printed
- X# instead.
- X#
- Xsub ftp'expect {
- X local( $ret );
- X local( $time_out );
- X local( @expect_args );
- X local( $code, $pre );
- X
- X $ftp'response = '';
- X $ftp'fatalerror = 0;
- X
- X $time_out = shift( @_ );
- X
- X while( @_ ){
- X $code = shift( @_ );
- X $pre = '^';
- X if( $code =~ /^\d+$/ ){
- X $pre = "[.|\n]*^";
- X }
- X push( @expect_args, "$pre(" . $code . " .*)\\015\\n" );
- X shift( @_ );
- X push( @expect_args,
- X "&expectgot( \$1, 0 ); " . shift( @_ ) );
- X }
- X
- X # Treat all unrecognised lines as continuations
- X push( @expect_args, "^(.*)\\015\\n" );
- X push( @expect_args, "&expectgot( \$1, 0 ); 100" );
- X
- X # add patterns TIMEOUT and EOF
- X
- X push( @expect_args, 'TIMEOUT' );
- X push( @expect_args, "&expectgot( 'timed out', 0 ); 0" );
- X
- X push( @expect_args, 'EOF' );
- X push( @expect_args, "&expectgot( 'remote server gone away', 1 ); 99" );
- X
- X if( $ftp_show > 9 ){
- X &printargs( $time_out, @expect_args );
- X }
- X
- X $ret = &chat'expect( $time_out, @expect_args );
- X if( $ret == 100 ){
- X # we saw a continuation line, wait for the end
- X push( @expect_args, "^.*\n" );
- X push( @expect_args, "100" );
- X
- X while( $ret == 100 ){
- X if( $ftp_show > 9 ){
- X &printargs( $time_out, @expect_args );
- X }
- X $ret = &chat'expect( $time_out, @expect_args );
- X }
- X }
- X
- X return $ret;
- X}
- X
- X
- X
- X#
- X# opens NS for io
- X#
- Xsub ftp'open_data_socket
- X{
- X local( $sockaddr, $port );
- X local( $type, $myaddr, $a, $b, $c, $d );
- X local( $mysockaddr, $family, $hi, $lo );
- X
- X $sockaddr = 'S n a4 x8';
- X
- X ($a,$b,$c,$d) = unpack( 'C4', $chat'thisaddr );
- X $this = $chat'thisproc;
- X
- X socket( S, $pf_inet, $sock_stream, $tcp_proto ) || die "socket: $!";
- X bind( S, $this ) || die "bind: $!";
- X
- X # get the port number
- X $mysockaddr = getsockname( S );
- X ($family, $port, $myaddr) = unpack( $sockaddr, $mysockaddr );
- X
- X $hi = ($port >> 8) & 0x00ff;
- X $lo = $port & 0x00ff;
- X
- X #
- X # we MUST do a listen before sending the port otherwise
- X # the PORT may fail
- X #
- X listen( S, 5 ) || die "listen";
- X
- X &ftp'send( "PORT $a,$b,$c,$d,$hi,$lo" );
- X
- X return &ftp'expect($timeout,
- X 200, "PORT command successful", 1,
- X 250, "PORT command successful", 1 ,
- X
- X 500, "syntax error", 0,
- X 501, "syntax error", 0,
- X 530, "not logged in", 0,
- X
- X 421, "service unavailable, closing connection", 0);
- X}
- X
- Xsub ftp'close_data_socket
- X{
- X close(NS);
- X}
- X
- Xsub ftp'send
- X{
- X local($send_cmd) = @_;
- X
- X if( $send_cmd =~ /\n/ ){
- X print $ftp'showfd "ERROR, \\n in send string for $send_cmd\n";
- X }
- X
- X if( $ftp_show ){
- X local( $sc ) = $send_cmd;
- X
- X if( $send_cmd =~ /^PASS/){
- X $sc = "PASS <somestring>";
- X }
- X print $ftp'showfd "---> $sc\n";
- X }
- X
- X &chat'print( "$send_cmd\r\n" );
- X}
- X
- Xsub ftp'printargs
- X{
- X while( @_ ){
- X print $ftp'showfd shift( @_ ) . "\n";
- X }
- X}
- X
- Xsub ftp'filesize
- X{
- X local( $fname ) = @_;
- X
- X if( ! -f $fname ){
- X return -1;
- X }
- X
- X return (stat( _ ))[ 7 ];
- X
- X}
- X
- X# make this package return true
- X1;
- END_OF_FILE
- if test 28699 -ne `wc -c <'ftp.pl'`; then
- echo shar: \"'ftp.pl'\" unpacked with wrong size!
- fi
- # end of 'ftp.pl'
- fi
- if test -f 'help_english' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'help_english'\"
- else
- echo shar: Extracting \"'help_english'\" \(2921 characters\)
- sed "s/^X//" >'help_english' <<'END_OF_FILE'
- Xftpmail@$hostname - ftp's files and sends them back via electronic mail.
- X
- XIf you have problems please email $managers_email
- Xand quote the following line:
- X$Revision
- X
- X
- X>>Valid commands to the ftpmail gateway are:
- X
- Xreply-to email-address Who to send the response to. This is
- X optional and defaults to the users email address
- X
- X>>Followed by one of:
- X
- Xhelp Just send back help
- Xdelete jobid Delete the given job
- Xopen [site [user [pass]]] Site to ftp to. Defaults are
- X $default_site anonymous reply-to-address.
- X
- X>>If there was an open then it can be followed by up to $max_cmds of the
- X>>following commands
- X
- Xcd pathname Change directory.
- Xls [pathname] short listing of pathname. Default pathname
- X is current directory.
- Xdir [pathname] long listing of pathname. Default pathname
- X is current directory.
- Xget pathname Get a file and email it back.
- X
- Xcompress Compress files/dir-listings before emailing back
- Xgzip Gzip files/dir-listings before emailing back
- X
- Xuuencode
- Xbtoa
- X These are mutually exclusive options for
- X converting a binary file before emailing.
- X (Default is uuencode.)
- X
- Xforce uuencode
- Xforce btoa
- X Force all files or directory listings to
- X be encoded before sending back.
- X There is no default.
- X
- Xmime
- X Send the message as a Mime Verson 1.0 message.
- X Text will be sent as text/plain charset=US-ASCII
- X Non-text as application/octet-stream.
- X If the file is splitup then it will be sent
- X as a message/partial.
- X
- Xforce mime
- X As mime but force text files to be sent as
- X application/octet-stream
- X
- Xno [compress|gzip|uuencode|btoa|mime]
- X Turn the option off.
- X
- Xsize num[K|M]
- X Set the max size a file can be before it
- X is split up and emailed back in parts to
- X the given number of Kilo or Mega bytes.
- X This is limited to $max_size.
- X
- Xmode binary
- Xmode ascii
- X Change the mode selected for the get
- X command. Defaults to binary.
- Xquit End of input - ignore any following lines.
- X
- X
- XExample scripts are:
- X
- Xopen
- Xdir
- Xquit
- X Connect to $default_site and send back the contents of the top level
- X directory
- X
- Xreply-to lmjm@doc.ic.ac.uk
- Xopen
- Xcd unix
- Xget buffer.shar
- Xquit
- X Connect to $default_site and send back the file buffer.shar to
- X lmjm@doc.ic.ac.uk
- X
- Xopen src.doc.ic.ac.uk
- Xcd graphics/X11/X.V11R5
- Xget ls-lR.Z
- Xcd ../contrib
- Xcompress
- Xls -ltra
- Xquit
- X Connect to src.doc.ic.ac.uk, send back the file ls-lR.Z in
- X graphics/X11/X.V11R5. As this is a binary file it has to be transfered
- X in binary mode. Because it is binary it will automatically
- X be uuencoded (the default binary encoder). Then change to ../contrib
- X and mail back a compressed directory listing. Although compressing ls
- X output makes it binary, which then has to be encoded, it still ends up
- X smaller than the original.
- X
- Xopen
- Xcd graphics/X11/X.V11R5/fixes
- Xget fix-08
- Xget fix-09
- Xget sunGX.uu
- Xquit
- X Retrieve some recent X fixes
- X
- X
- Xopen
- Xcd gnu
- Xatob
- Xmode binary
- Xget emacs-18.57.tar.Z
- Xquit
- X
- END_OF_FILE
- if test 2921 -ne `wc -c <'help_english'`; then
- echo shar: \"'help_english'\" unpacked with wrong size!
- fi
- # end of 'help_english'
- fi
- if test -f 'q.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'q.pl'\"
- else
- echo shar: Extracting \"'q.pl'\" \(14086 characters\)
- sed "s/^X//" >'q.pl' <<'END_OF_FILE'
- X#!/usr/bin/perl -s
- X# Very simple ftpmail system
- X# Queue a transfer to be done
- X# By Lee McLoughlin <lmjm@doc.ic.ac.uk>
- X# You can do what you like with this except claim that you wrote it or
- X# give copies with changes not approved by Lee. Neither Lee nor any other
- X# organisation can be held liable for any problems caused by the use or
- X# storage of this package.
- X#
- X# $Header: /a/swan/home/swan/staff/csg/lmjm/src/perl/mirror/ftpmail/RCS/q.pl,v 1.13 1993/05/07 19:05:52 lmjm Exp lmjm $
- X# $Log: q.pl,v $
- X# Revision 1.13 1993/05/07 19:05:52 lmjm
- X# Added Chris's fixed not_ok code.
- X#
- X# Revision 1.12 1993/04/28 18:19:20 lmjm
- X# Handle size suffix correctly.
- X#
- X# Revision 1.11 1993/04/25 20:27:55 lmjm
- X# Cut new release
- X#
- X# Revision 1.10 1993/04/25 14:15:11 lmjm
- X# Allow for multiple help files (one per language).
- X#
- X# Revision 1.9 1993/04/23 23:27:07 lmjm
- X# Massive renaming for sys5.
- X# Also shrink qfile names.
- X# Correct handling of <> on input.
- X#
- X# Revision 1.8 1993/04/23 20:03:17 lmjm
- X# Use own version of library routines before others.
- X#
- X# Revision 1.7 1993/04/23 17:23:40 lmjm
- X# Renamed ftpmail-local-config.pl to ftpmail-config.pl
- X# Made pathnames relative to $ftpmail_dir.
- X# Allow for some leeway in the max_cmds thing.
- X# Look out for $ftpmail_response in the headers.
- X# Fail if no reply_to in the headers.
- X# Keep copies of input if they have peculiar errors.
- X# If prematute end of input - check if the user is just after help.
- X# Allow for 'reply to email'
- X# Log change of reply_to in the job.
- X# Added corrections from Wolf + his not-auth code..
- X# Correct problem with 'no option' handling.
- X#
- X# Revision 1.6 1993/04/21 10:58:40 lmjm
- X# Smarter mail header parsing by andy.linton@comp.vuw.ac.nz
- X#
- X# Revision 1.5 1993/04/20 20:15:40 lmjm
- X# Added delete option.
- X#
- X# Revision 1.4 1993/04/13 10:34:38 lmjm
- X# Tailored help variables.
- X# Cleanup where necessary.
- X# Allowed for a help command.
- X# Corrected size option.
- X#
- X# Revision 1.3 1993/03/30 20:32:22 lmjm
- X# Must have an ftpmail account whose home directory everything is in.
- X# New -test option that uses /tmp/ftpmail-test
- X# Added better error handling.
- X#
- X# Revision 1.2 1993/03/23 21:40:14 lmjm
- X# Now use ftpmail home directory.
- X# Cleanup tmp files when there are problem
- X#
- X
- X$ftpmail = 'ftpmail';
- X
- X$Revision = '$Revision: 1.13 $';
- X
- Xif( $test ){
- X $ftpmail_dir = '/tmp/ftpmail-test';
- X}
- Xelse {
- X # The ftpmail_dir is the home directory of ftpmail.
- X $ftpmail_dir = (getpwnam( $ftpmail ))[ 7 ];
- X}
- X
- Xif( ! $ftpmail_dir ){
- X die "No home directory for ftpmail\n";
- X}
- X
- Xif( ! -d $ftpmail_dir ){
- X die "no such directory as $ftpmail_dir\n";
- X}
- X
- Xchdir( $ftpmail_dir ) || die "cannot chdir to $ftpmail_dir\n";
- X
- X# All the auxillary scripts come from ftpmail's home dir.
- Xunshift( @INC, '.' );
- X
- Xrequire 'config.pl';
- Xrequire 'support.pl';
- X
- X# Don't leave files around writable
- Xumask( 077 );
- X
- X$quenum = time();
- X$qfile = "$quedir/T$quenum.$$";
- X# Lop off the first bit to try and keep the namelen
- X# small enough for system 5.
- X$quenum =~ s/^...//;
- X# If you change this keep the format as: \d+\.\d+
- X$realqfile = "$quedir/$quenum.$$";
- X
- X# No route: a pattern that doesn't match routes
- X$nr = '[^@!%]+';
- X
- X# Copy of incoming data - keep all the header and the first lump of cmds
- X$input_copy = "$incopydir/in$$";
- Xopen( INCOPY, ">$input_copy" ) || &fatal( "Cannot create $input_copy" );
- X$cmd_lines = 0;
- X$in_body = 0;
- X$toomany = 0;
- Xwhile( <> ){
- X print INCOPY;
- X if( /^$/ ){
- X $in_body = 1;
- X next;
- X }
- X if( ! $in_body ){
- X next;
- X }
- X # allow for some leeway in the max_cmds thing.
- X if( $cmd_lines++ > ($max_cmds +5) ){
- X $toomany = 1;
- X }
- X}
- Xclose( INCOPY );
- X
- Xopen( INCOPY, $input_copy ) || &fatal( "Cannot reopen $input_copy" );
- X
- X&read_auth();
- X
- X# Parse the email header to see who sent this message
- X# (This clever bit of code by andy.linton@comp.vuw.ac.nz based on a posting
- X# by Larry Wall.)
- X$/ = ""; # paragraph mode
- X$* = 1; # multi-line pattern matching
- X$_ = <INCOPY>; # read one paragraph
- Xchop( $_ ); # Chop newline ending the paragraph
- X
- X# Should I ignore this?
- Xif( /$ftpmail_response/ ){
- X &log( "Input contains '$ftpmail_response', ignoring file" );
- X &cleanexit();
- X}
- X
- Xs/\n[ \t]+/ /g; # join multi-line entries
- Xs/^reply-to/Reply-To/ig; # Fix up case on header keys
- Xs/^from/From/ig;
- Xs/^sender/Sender-to/ig;
- X%head = ('PRESTUFF', split( /^(\S+):\s*/ )); # split on entry names
- X$reply_to = $head{ 'Reply-To' } || $head{ 'From' } || $head{ 'Sender' };
- Xchop( $reply_to ); # strip newline
- X
- X$/ = "\n"; # line mode
- X$* = 0; # single line pattern matching
- X
- Xif( ! $reply_to ){
- X &log( "No reply_to found in message $input_copy" );
- X # Force a copy to be kept
- X $cleanup = 0;
- X &cleanexit();
- X}
- X
- Xif( $dumb_mailer ){
- X &dumb_fix_reply_to( $reply_to );
- X}
- X
- Xif( $dont_reply_to && $reply_to =~ /$dont_reply_to/i ){
- X &log( "reply_to: $reply_to in dont_reply_to pattern: $dont_reply_to, ignoring" );
- X &cleanexit();
- X}
- X
- Xif( eof ){
- X # Maybe this is an attempt to get help?
- X local( $subject ) = $head{ 'Subject' };
- X if( $subject =~ /help(\s+french)?/ ){
- X &mail_back( "help$1" );
- X }
- X # No point in going any further
- X &log( "Premature end of input $input_copy" );
- X # Force a copy to be kept
- X $cleanup = 0;
- X &cleanexit();
- X}
- X
- Xif( $toomany ){
- X &mail_back( "there are too many commands in your job, the limit is $max_cmds" );
- X}
- X
- X# Anything to actually transfer?
- X$work = 0;
- X
- X# Process lines
- Xwhile( <INCOPY> ){
- X if( /^\s*$/ || /^#/ ){
- X next;
- X }
- X if( /^$ftpmail_response/ ){
- X &log( "Input contains '$ftpmail_response', ignoring file" );
- X &cleanexit();
- X }
- X s/^\s*//;
- X if( /^(reply-to|reply)(\s+to)?(\s+(.+))?/i ){
- X local( $full, $addr ) = ($3, $4);
- X if( $full =~ /^\s*$/ ){
- X &mail_back( "reply-to needs an argument of who to send replies to" );
- X }
- X $new_reply_to = $addr;
- X if( ! $new_reply_to ){
- X &log( "tried to reset reply_to to nothing, ignored" );
- X }
- X else {
- X $reply_to = $new_reply_to;
- X &log( "reply_to reset to $reply_to" );
- X }
- X next;
- X }
- X
- X if( /^delete\s*(.*)/ ){
- X $delete = $1;
- X last;
- X }
- X
- X if( /^help(\s+\S+)?/ ){
- X $help = "help$1";
- X last;
- X }
- X
- X if( /^(open|connect)(\s+(\S+))?(\s+(\S+))?(\s+(\S+))?/i ){
- X if( $site ){
- X &mail_back( "Cannot have multiple open's" );
- X }
- X ($site, $user, $pass ) = ($3, $5, $7);
- X if( $site eq ''){
- X $site = $default_site;
- X }
- X if( $ftp_permitted && $site !~ /$ftp_permitted/ ){
- X &mail_back( "Cannot ftp to that site only sites matching $ftp_permitted are allowed" );
- X }
- X push( @comms, "open $site" );
- X if( $user eq '' ){
- X $user = 'anonymous';
- X }
- X if( $pass eq '' ){
- X $pass = $reply_to;
- X }
- X if( ! $restricted ){
- X push( @comms, "user $user" );
- X push( @comms, "pass $pass" );
- X }
- X else {
- X push( @comms, "user anonymous" );
- X $pass = "ftpmail/$pass";
- X $pass =~ s,^ftpmail/-,-ftpmail/,;
- X push( @comms, "pass $pass" );
- X }
- X }
- X elsif( /^(cd|chdir)(\s+(.+))?/i ){
- X if( $2 =~ /^\s*$/ ){
- X &mail_back( "chdir needs an argument of which directory to move to" );
- X }
- X push( @comms, "cd $3" );
- X }
- X elsif( /^ls\s*(.*)/i ){
- X push( @comms, "ls $1" );
- X $work = 1;
- X }
- X elsif( /^dir\s*(.*)/i ){
- X push( @comms, "dir $1" );
- X $work = 1;
- X }
- X elsif( /^get(\s+(.+))?/i ){
- X if( $1 =~ /^\s*$/ ){
- X &mail_back( "get needs an argument of which file to get" );
- X }
- X push( @comms, "get $2" );
- X $work = 1;
- X }
- X elsif( /^binary/i ){
- X push( @comms, "mode binary" );
- X }
- X elsif( /^ascii/i ){
- X push( @comms, "mode ascii" );
- X }
- X elsif( /^mode(\s+(binary|ascii))?\s*/i ){
- X if( $1 =~ /^\s*$/ ){
- X &mail_back( "mode needs an argument of either binary or ascii" );
- X }
- X push( @comms, "mode $2" );
- X }
- X elsif( /^(compress|gzip|uuencode|btoa|mime)(\s+no)?\s*$/i ){
- X local( $what, $yea_nay ) = ($1, $2);
- X local( $no ) = '';
- X if( $yea_nay =~ /no/i ){
- X $no = ' no';
- X }
- X push( @comms, "$what$no" );
- X }
- X elsif( /^(no)\s*(compress|gzip|uuencode|btoa|mime)\s*$/i ){
- X local( $yea_nay, $what ) = ($1, $2);
- X local( $no ) = '';
- X if( $yea_nay =~ /no/i ){
- X $no = ' no';
- X }
- X push( @comms, "$what$no" );
- X }
- X elsif( /^force(\s+(compress|gzip|uuencode|btoa|mime)\s*)?$/i ){
- X local( $full, $what ) = ($1, $2);
- X if( $full =~ /^\s*$/ ){
- X &mail_back( "force needs an argument of one of: compress gzip uuencode btoa mime" );
- X }
- X push( @comms, "force $what" );
- X }
- X elsif( /^size\s+(\d+)\s*(k|b|m)+\s*$/i ){
- X local( $size ) = $1;
- X if( $2 =~ /[mM]/ ){
- X $size *= (1024*1024);
- X }
- X elsif( $2 =~ /[bB]/ ){
- X $size *= 512;
- X }
- X elsif( $2 =~ /[kK]/ ){
- X $size *= 1024;
- X }
- X if( $size < $min_size || $size > $max_size ){
- X $size = $def_max_size;
- X }
- X push( @comms, "size $size" );
- X }
- X elsif( /^(quit|close|--|==)/i ){
- X last;
- X }
- X else {
- X $error = "Unrecognised input: $_";
- X last;
- X }
- X}
- X
- Xif( !$reply_to ){
- X &fatal( "Must have a 'reply-to emailaddress'" );
- X}
- X
- X&fix_reply_to();
- X
- Xif( ! &auth( $reply_to ) ){
- X &mail_back( "reply-to $reply_to not allowed to use this service" );
- X}
- X
- Xif( $delete ){
- X # If any problems call &mail_back( "delete fail <err>\n<long err>" )
- X # and mail_back will generate sensible error messages
- X if( $delete =~ /^\s*(\d+.\d+)\s*$/ ){
- X $delete = $1;
- X }
- X else {
- X &mail_back( "delete fail bad argument\nShould be delete <jobid> not: delete $delete" );
- X }
- X local( $job ) = "$quedir/$delete";
- X # Make sure the reply_to's are the same
- X if( ! open( job, $job ) ){
- X &mail_back( "delete fail no such job\nCannot delete $delete failed because I couldn't find the job in the queue" );
- X }
- X while( <job> ){
- X if( /^reply-to (.+)$/ ){
- X $job_reply_to = $1;
- X last;
- X }
- X }
- X close( job );
- X if( $job_reply_to ne $reply_to ){
- X &mail_back( "delete fail not queuer\nYou cannot delete this job $delete as, according to the reply-to, you are not\nThe person who queued it.\n" );
- X }
- X # Zap a job and tell them its gone
- X unlink( $job );
- X &mail_back( "deleted $delete by user" );
- X}
- Xelsif( $help ){
- X &mail_back( $help );
- X}
- X
- X
- Xif( !$site ){
- X &mail_back( "Must have an 'open [site [user [pass]]]'" );
- X}
- X
- Xif( ! $work ){
- X &mail_back( "Your job contains no get, ls or dir commands so I am ignoring it" );
- X}
- X
- Xif( $error ){
- X &mail_back( $error );
- X}
- X
- X&log( "queueing entry for $reply_to in $realqfile" );
- X$tries = 0;
- X$whenretry = 0;
- X&write_entry();
- Xrename( $qfile, $realqfile );
- X&mail_back( "ack" );
- X
- Xsub mail_back
- X{
- X local( $error ) = @_;
- X local( $show_help ) = 1;
- X local( $help, $ack, $del, $del_fail );
- X
- X chop( $error ) if $error =~ /\n$/;
- X
- X if( $error =~ /^help(\s+\S+)?/ ){
- X &log( "mail_back: $reply_to $error" );
- X $help = $error;
- X $error = 0;
- X }
- X elsif( $error eq 'ack' ){
- X &log( "mail_back: $reply_to $error" );
- X $ack = 1;
- X $error = 0;
- X }
- X elsif( $error =~ /^deleted / ){
- X &log( "mail_back: $reply_to $error" );
- X $del = $error;
- X $error = 0;
- X }
- X elsif( $error =~ /^(delete fail .*)\n/ ){
- X &log( "mail_back: $reply_to $1" );
- X $del_fail = $error;
- X $error = 0;
- X }
- X else {
- X &log( "mail_back: $reply_to failed to queue because: $error" );
- X }
- X
- X if( $mail_cmd =~ /sendmail/ ){
- X open( MAIL, "| $mail_cmd " ) ||
- X &fatal( "Cannot send email" );
- X print MAIL "To: $reply_to\n";
- X print MAIL "Subject: $ftpmail_response\n\n";
- X }
- X else {
- X open( MAIL, "| $mail_cmd -s '$ftpmail_response' '$reply_to' >/dev/null 2>&1" ) ||
- X &fatal( "Cannot send email" );
- X }
- X
- X print MAIL "$ftpmail_response\n";
- X
- X &mail_motd();
- X
- X if( $error ){
- X print MAIL "ftpmail has failed to queue your request with an";
- X print MAIL " error of:\n\t$error\n";
- X &mail_incopy();
- X }
- X elsif( $ack ){
- X local( $qf ) = $realqfile;
- X $qf =~ s,.*/([^/]+),$1,;
- X print MAIL "ftpmail has received the following job from you:\n";
- X &mail_comms();
- X print MAIL "\nftpmail has queued your job as: $qf\n";
- X local( $queuelen ) = &queuelen() - 1;
- X print MAIL "There are $queuelen jobs ahead of this one in the queue.\n\n";
- X print MAIL "To remove send a message to $ftpmail_email containing just:\ndelete $qf\n\n";
- X &mail_incopy();
- X $show_help = 0;
- X }
- X elsif( $del ){
- X print MAIL "ftpmail has $del\n";
- X $show_help = 0;
- X }
- X elsif( $del_fail ){
- X print MAIL "ftpmail $del_fail\n";
- X $show_help = 0;
- X }
- X
- X if( $show_help ){
- X if( $help =~ /^help(\s+(\S+))/ ){
- X $hf = "$helpdir/$2";
- X }
- X else {
- X $hf = "$helpdir/help";
- X }
- X if( open( HELP, $hf ) ){
- X while( <HELP> ){
- X s/\$default_site/$default_site/g;
- X s/\$help_email/$help_email/g;
- X s/\$managers_email/$managers_email/g;
- X s/\$hostname/$hostname/g;
- X s/\$max_cmds/$max_cmds/g;
- X s/\$max_size/$max_size/g;
- X # I use the []'s to prevent RCS from expanding it
- X s/\$[R]evision/$Revision/g;
- X print MAIL;
- X }
- X close( HELP );
- X }
- X else {
- X print MAIL "Cannot find $help";
- X }
- X }
- X
- X close( MAIL );
- X &cleanexit();
- X}
- X
- Xsub mail_incopy
- X{
- X close( INCOPY );
- X if( ! open( INCOPY, $input_copy ) ){
- X print MAIL "internal error, cannot reopen input file!";
- X }
- X else {
- X print MAIL "\nYour original input " . ($toomany ? "began" : "was") . ">>\n";
- X while( <INCOPY> ){
- X print MAIL;
- X }
- X close( INCOPY );
- X print MAIL "<<End of your input\n";
- X }
- X}
- X
- X# Read a file of patterns for authorised users
- Xsub read_auth
- X{
- X if( ! open( auth, $authfile ) ){
- X &log( "Cannot open $authfile" );
- X return;
- X }
- X while( <auth> ){
- X next if /^#/;
- X chop;
- X if( /^not\s+(.+)$/ ){
- X $bad_add = $1;
- X if( /@/ ){
- X $b = $auth_not_ok;
- X $auth_not_ok = $b ? "$b|$bad_add" : $bad_add;
- X }
- X else {
- X $auth_host{ $bad_add } = 0;
- X }
- X }
- X elsif( /@/ ){
- X # user@host pattern
- X $a = $auth_ok;
- X $auth_ok = $a ? "$a|$_" : $_;
- X }
- X else {
- X # hostname
- X $auth_host{ $_ } = 1;
- X }
- X }
- X close auth;
- X}
- X
- Xsub auth
- X{
- X local( $addr ) = @_;
- X
- X $addr =~ s/.*<(.*)>.*/$1/;
- X $addr =~ s/\([^\)]*\)//g;
- X $addr =~ s/\s+//g;
- X
- X if( $addr =~ /^$auth_not_ok$/i ){
- X return 0;
- X }
- X
- X if( $addr =~ /^$auth_ok$/){
- X return 1;
- X }
- X
- X if( $addr =~ /^($nr)@($nr)$/ ){
- X local( $user, $host ) = ($1, $2);
- X return $auth_host{ $host };
- X }
- X
- X return 0;
- X}
- X
- Xsub fix_reply_to
- X{
- X # Make sure that reply_to doesn't contain any shell escapes
- X # Since I use it as '$reply_to' then all I have to worry about is
- X # backprime itself
- X
- X # For now just zap them!
- X $reply_to =~ s/'//g;
- X}
- X
- X# Try to strip away all comments.
- Xsub dumb_fix_reply_to
- X{
- X $reply_to =~ s/.*<//;
- X $reply_to =~ s/>.*//;
- X $reply_to =~ s/\([^\)]+\)//g;
- X}
- X
- Xsub cleanexit
- X{
- X if( $cleanup ){
- X unlink( $input_copy );
- X }
- X exit( 0 );
- X}
- END_OF_FILE
- if test 14086 -ne `wc -c <'q.pl'`; then
- echo shar: \"'q.pl'\" unpacked with wrong size!
- fi
- chmod +x 'q.pl'
- # end of 'q.pl'
- fi
- echo shar: End of archive 1 \(of 2\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked both archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-