[comp.sources.misc] v04i001: mailsplit 2.0 release

wyle@lavi.uucp (08/02/88)

Posting-number: Volume 4, Issue 1
Submitted-by: "A. Nonymous" <wyle@lavi.uucp>
Archive-name: mailsplit2

[Apologies for the delays -- you very nearly lost a moderator over the past
week, due to internal politics on ncoast.  Sigh.  ++bsa]

Here is mailsplit 2.0.  It has flags, options, buzzers, whistles, checks,
debug options, a man page, etc.  Enjoy it, and please send me bugs,
comments, suggestions.  Pass it on.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	mailsplit
#	mailsplit.1
#	undoc
# This archive created: Mon Jul 25 11:51:12 1988
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
mailsplit sends files and/or directories via e-mail using tar,
compress, etc.  It sends an awk-script to re-assemble the pieces at the
receiving side.  It is useful for sending directories and large images
around when you don't have ftp, or you have to cross e-mail network
boundaries.

It is a Bourne-shell script.  Read the over-blown man-page.  Send me
ideas for improvements, bug reports.

-Mitch  (wyle@ethz.uucp)
SHAR_EOF
fi
if test -f 'mailsplit'
then
	echo shar: "will not over-write existing file 'mailsplit'"
else
cat << \SHAR_EOF > 'mailsplit'
#! /bin/sh
#
# mailsplit:     A tarmail variant  -M F Wyle 1988-
#
# @(#)mailsplit    2.1    88/07/25

ME=`/usr/bin/basename $0`
SP=/usr/bin/split
LI=700
CM="$0 $*"
VE="2.1  88/07/25"
MA=/usr/ucb/Mail
FC=0
DE=0
DB=5
MF=""
SU="_default_"
TM=false
FL=""
ne="FL=$FL@"
TO=""
UU=uuencode
TD=/tmp
TA=tar
CO=compress
RA=all

umask 0

for AR in $* ; do
  case $AR in
    -C  ) ne="CO=" ;;
    -D  ) ne="TD=" ;;
    -M  ) ne="MF=" ;;
    -T  ) ne="TA=" ;;
    -V  ) DB=9 ;;
    -d  ) ne="DE=" ;;
    -l  ) ne="LI=" ;;
    -m  ) ne="MA=" ;;
    -n  ) TM=true ;;
    -r  ) ne="RA=" ;;
    -s  ) ne="SU=" ;;
    -t  ) TM=true ;;
    -v  ) echo "$ME version $VE by Mitch Wyle" ;  exit 0 ;;
    -x* ) DB=`echo $AR | cut -c3` ; DB=${DB:-0} ;;
    -u  ) ne="UU=" ;;
    -*  ) echo " " ; echo "Bad flag for $ME": $AR
          echo "Usage:    $ME  [<options>] <mailpath> <file(s)>"
          echo "Example:  $ME  werner@utastro.uucp ./german_lessons"
          echo " "
          exit 0  ;;
    *   ) eval $ne"$AR" ; ne="FL=$FL@" ;;
  esac
done
case $# in
  0 | 1 )
    echo " "
    echo "Usage:    $ME  [<options>] <mailpath> <file(s)>"
    echo "Example:  $ME  werner@utastro.uucp german_lessons"
    echo " "
    exit 0  ;;
esac
IFS=@
set $FL
TO=$1
case $SU in
  _default_ ) SU=$2 ;;
esac

case $DB in
  8|9) set -x ;;
esac

T1=$TD/1sp$$
T2=$TD/2sp$$
T3=$TD/3sp$$

case $RA in
  all) ;;
  *  )
   R=""
   RA=`echo $RA | sed 's/,/\@/'`
   for tok in $RA ; do
     if echo $tok | grep -s '\-' ; then
       t=`echo $tok | sed 's/-/@-@/'`
       set $t
       i=$1
       max=${3:-99}
       while test $i -le $max ; do
         R=$R"@"$i
         i=`expr $i+1`
       done
     else
       R=$R"@"$tok
     fi
     RA=$R
   done ;;
esac

case $DB in
  5|6|7|8|9) echo "beginning tar and compress..." ;;
esac
set $FL ; shift
for i in $* ; do
  if test -s $i ; then
    FC=`expr $FC + 1`
  fi
done
if test $FC -gt 0 ; then
  case $DB in
    1|2|3|4) 
      case $TM in
        true )
          echo "would have issued command:"
          echo "$TA cvf - $* 2> /dev/null | $CO >$T1" ;;
        false)  $TA cvf - $* 2> /dev/null | $CO >$T1 ;;
        *    ) echo "Sigh... Programmer error in $ME at line 93." ;;
      esac ;;
    *) 
      case $TM in
       true )
         echo "would have issued command:"
         echo "$TA cvf - $* | $CO >$T1" ;;
       false) $TA cvf - $* | $CO >$T1 ;;
       *    ) echo "Sigh... Programmer error in $ME at line 101." ;;
      esac ;;
  esac
else
case $DB in
  [5-9] ) echo "...whoops!  Nothing to send!  Punting..." 1>&2 ;;
esac
  exit 1
fi
case $DB in
  5|6|7|8|9) echo "...finished tar, compress, starting uuencode..."
esac
case $TM in
  true )
    echo "would have issued command:"
    echo "$UU $T1 $T1 > $T2 " ;;
  false) $UU $T1 $T1 > $T2 ; ;;
  *    ) echo "Sigh... Programmer error in $ME at line 118." ;;
esac
case $DB in
  5|6|7|8|9) echo "...finished uuencode, starting split..."
esac
case $TM in 
  true )
    echo "would have issued command:" 
    echo "$SP -$LI $T2 $T3" ;; 
  false)  $SP -$LI $T2 $T3 ; ;; 
  *    ) echo "Sigh... Programmer error in $ME at line 128." ;;
esac 
case $TM in
  true )
    echo "would have issued commands:"
    echo "$MA -s "$SU - part n of m" $TO" 
    echo "with n ranging from 1 to m; m cannot be determined."
    echo "without running for real."
    exit 0 ;;
esac 

n=1
set $T3*
for f  do
  SE=false
  case $RA in
    all)  SE=true ;;
    *  )
      for p in $RA ; do
        case $p in
          $n ) SE=true ;;
        esac
      done ;;
  esac
  case $SE in
    true)
    {
    echo " "
    case $n in
    1)
      if test ! -s $f ; then
        case $DB in 
          [5-9]) echo "...whoops!  $SP failed!   Punting..." 1>&2 ;;
        esac 
        exit 1 ;
      fi
      echo "[The attached script will glue these mail messages together,"
      echo "uuencode, uncompress, and extract all the files.  Be sure"
      echo "to send the pieces through this script in the proper order!"
      echo " "
      echo "#! /bin/sh"
      echo "echo extracting data..."
      echo "/bin/awk '"
      echo "BEGIN { inhex = 0 ; part = 0 }"
      echo "/^---/ {"
      echo "  if (\$2 == \"start\") part++"
      echo "  if (\$6 != part) exit 1"
      echo "  if (inhex && (NF > 1))"
      echo "    inhex = 0"
      echo "  else {"
      echo "    inhex = 1"
      echo "    getline"
      echo "  }"
      echo "}"
      echo "{ if (inhex) print \$0 }'  > /tmp/xtr\$\$"
      echo ""
      echo " if test \$? = 1 ; then"
      echo "   echo 'Parts sent through out of order!! Punting.'"
      echo "   /bin/rm -f /tmp/xtr\$\$"
      echo "   exit 1"
      echo " fi"
      echo ""
      echo "echo ...finished extraction, starting uudecode..."
      echo "fname=\`head -100 /tmp/xtr\$\$ | grep begin | cut -f3 -d' '\`"
      echo "OurDir=\`pwd\`"
      echo "cd /tmp"
      echo "$UU xtr\$\$"
      echo "/bin/rm -f xtr\$\$"
      echo "/bin/chmod  777 \$fname"
      echo "mv \$fname \$fname.Z"
      echo "echo ...finished uudecode, starting uncompress..."
      echo "uncompress \$fname"
      echo "mv \$fname \$OurDir"
      echo "cd \$OurDir"
      echo "echo ...finished uncompress, starting tar extraction..."
      echo "$TA xvf \$fname"
      echo "/bin/rm -f /tmp/xtr* \$fname"
      echo " " ;;
    esac
    echo " "
    echo "This file was packed by mailsplit version:"
    echo $VE
    echo with command:
    echo "$CM"
    echo "on: `date`"
    echo " "
    echo "--- start of $SU part $n of $#"
    cat $f
    echo "--- end of $SU part $n of $#"
    echo " "
    echo " "
    } | $MA $MF -s "$SU - part $n of $#" $TO
    case $DB in
      [5-9])   echo "...sent part $n of $# to $MA..." ;;
    esac
    case $DB in
      5|6|7|8|9) echo "...sleeping $DE seconds (waiting for mailer) ..." ;;
    esac
    sleep $DE ;;
  esac
  n=`expr $n + 1`
done
/bin/rm -f $T1 $T2 $T3*
SHAR_EOF
fi
if test -f 'mailsplit.1'
then
	echo shar: "will not over-write existing file 'mailsplit.1'"
else
cat << \SHAR_EOF > 'mailsplit.1'
.\" @(#)mailsplit.1    2.1   88/07/25
.nr N 24
.nr D 5
.TH MAILSPLIT 1 Local
.UC 4
.SH NAME
mailsplit \- package, split, transmit file directories by electronic mail
.SH SYNOPSIS
.B mailsplit 
[
.B options
] 
.B mail-path files
.br
  really:
.br
.B mailsplit
[
.B \-Vntv
] [
.B \-C compress program
] [
.B \-D temporary directory
] [
.B \-M Mailer options
] [
.B \-T archive program
] [
.B \-d delay time
] [
.B \-l split lines
] [
.B \-m mail agent
] [
.B \-r parts
] [
.B \-s subject
] [
.B \-xn set debug-level n
] [
.B \-u ascii encode program
]
.I mail-path[,mailpath] 
.I files [files] ...
.SH DESCRIPTION
.\" ---------------------------------------------------------------
.\" This defines appropriate quote strings for nroff and troff
.ds lq \&"
.ds rq \&"
.if t .ds lq ``
.if t .ds rq ''
.\" Just in case these number registers aren't set yet...
.if \nN==0 .nr N 10
.if \nD==0 .nr D 5
.\" ---------------------------------------------------------------
.I Mailsplit
is a program to package, compress, document, transmit, and re-assemble
multiple files and directories to other users via electronic mail.
Mailsplit uses tar(1), compress(1), split(1) and mail(1) to send the files,
and awk(1) to re-assemble them at the receiving side.  Mailsplit attempts to
preserve the integrity, structure, mode, protection, and ownership of the
transmitted directories.
.SH OPTIONS
Command line options can be used to override the default options in the source
code of
.I mailsplit.
Options and flags can be specified in any order on the command line.
The first non-option or flag token on the command line is interpretted
to be the mail path whither the data should be sent.  All other
non-option or flag tokens are considered files or directories to be
sent.  Since the program is a shell-script, users might want to tune
the defaults for their sites.  All suggestions, improvements,
bug-reports, etc. would be greatly appreciated.  Send them to
wyle@ethz.uucp.
.IP -V
sets the 
.I verbose 
option, and is equivilant to -x9 (maximum debugging).  When this option is
set,
.I mailsplit
will echo everything he does while he's doing it.  This option will generate
an awful lot of useless debugging information and is not recommended unless
you are debugging.
.IP -n
puts
.I mailsplit
into "test" mode.  This mode is analogous to make(1) -n where
.I mailsplit
tells you which commands he would have issued without actually doing anything.
This mode is also good for debugging, or when you're curious what mailsplit
might do with a complicated path or directory.
.IP -t
same as -n
.IP -v
displays version number and exits.  This option is useful only for finding out
which version / patch level your mailsplit is.
.IP -C compress program
tells
.I mailsplit
to use the next argument as the program to use instead of compress(1)
for compressing the archive stream.  In some circumstances, using
compress(1) may expand the size of a stream, in which case one would
might want to use cat(1) to send the archive through unchanged.  The author is
dubious of this option.
.IP -D directory
instructs
.I mailsplit
to use
.I directory
instead of /tmp for temporary files created during the archival, compression,
and encoding process.  This option is necessary if there is very little space
in /tmp, one is sending very large directories, or the file tree on this
system is bizare.
.IP -M mailer options
When this option is used,
.I mailsplit
passes the
.I mailer options
argument(s) to the mail program.  Some mailers need options to get the job
done (we won't mention an infamous X.400 mailer).  Other times, one would
prefer to set options for efficiency, tell the mailer not to run
interactively, etc.  To set more than one option, enclose
.I mailer options
in quotes.  Be careful about the shell's eating quotes.  One might have to
experiment a bit to set all the options needed or desired. 
.IP -T archive program
If this option is set,
.I mailsplit
uses
.I archive program
instead of tar(1) to archive all the files and directories.  If the system
does not have tar(1), it is unlikely that
.I mailsplit
will work.  On the other hand, tar(1) expands binary files enormously, so one
might substitute cat(1) instead of tar(1) to reduce the size of the archive.
.IP -d seconds
tells
.I mailsplit
to wait
.I seconds
seconds after each time he invokes the mailer.  Some mailers (a certain
X.400 system with "MTA congestion problems" will remain nameless) have
problems dealing with sudden, large bursts of messages.  One might want
to set the default in the code to some non-zero value if the mailer on
his system has such problems.  If
.I mailsplit
is usually used for small directories, and the default delay is small,
one should use this flag to set the delay higher if a large number of files or
large directory is sent.
.IP -l lines
This option sets the maximum number of lines for a single mail
message.  The default as distributed is set to keep a message smaller
than 60 Kilobytes.  See the discussion below.  One might want to set
the default higher, and use this option to set a smaller number when
sending mail through mailers which don't like large messages.  (A
certain X.400 mailer...)  Remember that if the archive pieces have to pass
.I through
a mailer which wants small messages, the lines size must be set smaller.
.IP -m mailer
If the system on which
.I mailsplit
is running has more than one mailer (user agent) one can use this flag
to choose a mailer other than the default (/usr/ucb/Mail as
distributed).  
.IP -r parts
The -r(esend) option is used to re-send pieces which became lost in the
wide-area mail networks.
.I parts
is a list of pieces to be re-sent to the recipient.
.I Parts
can be a comma-separated list, or numbers between dashes, or just one number
and a dash, or any combination.  The formal BNF of
.I parts
is:
.nf
.br

parts :== <number>
      |   number,parts
      |   number-number
      |   number-

number:== <digit>
      |   <digit><number>

digit :== 0|1|2|3|4|5|6|7|8|9

.br
.fi
Only those pieces in
.I parts
will be sent.  This option is useful for re-transmitting part 3 of 27 instead
of having to re-transmit all 27 pieces.  One must be sure that the other
options are set
.I exactly the same
as the first transmission, including line-length, etc.
.IP -s subject
sets the subject to
.I subject
instead of using the first file argument for the subject of each mail message
generated.
.IP -xn
sets the debugging level to n, where n is a number from 0 to 9.  The higher
the number, the more debug output.  Setting n to 0 causes
.I mailsplit
to work silently.  No output will be sent to standard out, and only failure
messages will be sent to standard error.  Setting n to 9 is equivilant to -V
(verbose), and gives maximum debug output.
.IP u encoding program
This option sets the encoding program to something other than
uuencode(1c).  The encoding program must be able to take 8-bit binary
and produce 7-bit ASCII data.
.SH DISCUSSION
.PP
A few
.I de
.I facto
standards have evolved on wide-area (e-mail) networks to guarantee the safe
transmission of information:
.sp
.IP -
The information must be text-only, i.e. 7-bit ASCII
.IP -
Lines of text may not exceed 80 characters.  A message must therefore
contain an end-of-line character at least after every 80 characters.
.IP -
A single message may not exceed 64 Kilobytes.
.IP -
Lines of text starting with the word "From" will be translated
to ">From."
.IP -
Blank lines at the end of a mail message are deleted.
.IP -
A message containing a period "." on a line by itself will be terminated
abnormally.
.PP
Upon invocation, the program parses all flags and options, then looks
for at least two parameters on the command line:  The e-mail path(s) of
the receiver(s), and the file or directory name(s) to send.  If one or
both of these parameters is missing, a help message is displayed with a
short "usage" description and an example.
.PP
The directories or files are recursively archived and compressed into a
temporary binary file.  The binary file is then sent through uuencode
so that it is encoded into 7-bit ASCII with end-of-lines every 79
characters.  The resulting ASCII file is then split into several
different files, each of which is smaller than 64 Kilobytes.
.PP
The first file is prepended with instructions as well as the program
needed to unpackage the transmitted message or messages.  All messages
are pre- and post-pended with special start and end text, to assist both
the person receiving the message and the unpackaging program.  Finally,
each message is sent via electronic mail to the recipient, and all
temporary files are deleted.
.PP
During these operations, status information is displayed after each
successful step.  If there are no files to send, an error message is
displayed.
.PP
At the receiving end, a first-time user must extract the unpackaging
program from the first e-mail message, and make the program available
for his use.  A user must perform this step only once, as the packaging
format should not change.  Depending on the size of the transmitted files
or directories, the receiver may get one or several mail messages.  The
messages contain subject headers of the form:
.br
.\" .nf
.sp
"--- start of <package> part <n> of <m>"
.sp
.br
where <package> is the first file or directory name, <m> is the total
number of messages into which the package was split, and <n> is in the
range 1 to m.
.PP
The receiver must then send all of the parts through the unpackaging
program in their proper order.  This is accomplished either from within
the mail reading program, or by saving the messages into a file and
invoking the unpackaging program on the saved file.  Because e-mail
systems will often deliver messages out of order, a warning is included
to send the messages through the unpackaging program in the correct
order.  The re-assembley program also detects this error and exits
with an error status if the pieces are sent through out of order.
.SH EXAMPLES
.LP
% mailsplit wyle@ethz.uucp /etc/hosts
.LP
% mailsplit wyle@ethz.uucp sources -r 5,7,17-21
.LP
% mailsplit -l 700 -x9 wyle@ethz.uucp goodies -s "examples"
.LP
% mailsplit -l 700 -x9 -r 19- wyle@ethz.uucp goodies

.SH AUTHOR
Mitchell F. Wyle  (wyle@ethz.uucp)
.SH BUGS
.LP
BSD specific?
.LP
Re-assembler should accept pieces out of order
.LP
Should be packaged with a configurer, makefile, install script
.SH "SEE ALSO"
split(1), tar(1), mail(1), uuencode(1), uudecode(1), compress(1),
awk(1), sh(1)
SHAR_EOF
fi
if test -f 'undoc'
then
	echo shar: "will not over-write existing file 'undoc'"
else
cat << \SHAR_EOF > 'undoc'
Since I tore the comments out of the code, and it is not customary to send
SCCS files around the net, I made this auxiliary file of documentation.

An alphabetical list of variables, their use and meaning:

AR = argument
CM = command line
CO = compress program may be arc, etc.
DB = Debug level (Verbosity level)
DE = Delay between pieces
FC = file count
FL = File list (build up file list from params on command line in
FL = any order (see /usr/bin/spell) for a good example of obfuscated,
FL = clever parsing code 
LI = the number of lines to split pieces into
MA = mail transport agent
ME = the name of the program running
MF = Mail flags to send to transport
R  = range of pieces to be re-sent during parse stage
RA = range of pieces to be re-sent if mailers on the way failed
SE = send flag; if true, send the piece.  If false, don't
SP = the name of the split program
SU = subject of message  (defaults to first file name)
T1 = temporary file containing output of tar and compress.
T2 = temporary file containing uuencoded stuff
T3 = temporary file(s) containing  split pieces
TA = tar program (may be shar, tar, cat, etc ;-)
TD = Temporary directory in which temp files should go can be . or /tmp.
TM =  Test-mode flag (-n option of make)  Don't do anything, just
TM = echo what you would have done if testmode option not on.
TO = recipient(s) of message
UU = the uuencode program (may be replaced with btoa / atob ;-)
VE = version number
f  = file name (piece) during loop which sends pieces
i  = a loop index used during parse of the range of files to be re-sent
max=  The loop-limit used in parse of range of files to be re-sent
max= is assumed to be 99 if no top-of-range is given.
n  = piece number during the loop which sends pieces via mail
ne =  next param on command line (after flag is set, next param gets
ne = eval'd to the var set in ne  (see above)
t  = a specific token containing a range to be expanded (n-m)
tok= Token during parse of range of files to be re-sent


History:
# Coder        Date      Comments
#------------  -------- ---------------------------------------------------
# M F Wyle     02nov87	Shamelessly stolen from tarmail :-)
# WRU          18feb88	changed variable MAILER, added SPLITTER,
#                     	LINES, USER and a warning about uudecode
# M F Wyle     25mar88	Add tar, extract join-script in 1st msg
# WRU          03apr88  fixed some quoting problems in "echo"-strings
#			cosmetic changes: renamed "mailsplit"
#			created THISNAME
#                       fixed some typos, added Email-addresses, example,
#                       section for suggested improvements
# MFW          05apr88  Fix more quoting problems in echo strings (shell
#                       variables); added /bin/rm cleanup to join-script
# MFW          21jun88  based on WRU's suggestions:
#                       1) add file-name to subject
#                       2) verbose explanations
#                       3) add parts-order checking!  Yippeee!
# MFW          08jul88  Fix uudecode setuid bug
# MFW          12jul88  Fix empty or no files bug, added FILECOUNT
# MFW          17jul88  Added umask 0, delay before mail, check after split
# MFW          19jul88  Major re-write for flags, verbose, sccs control
# MFW          25jul88  Added a range-parser, more flags, some documentation
#                       Up'd release to 2.0 for distribution

Verbal description of algorithm:
====== =========== == ==========
When the program starts, it initializes some variables, then parses the
entire command line.  It builds up a list of non-flag options in the F
variable.  The first parameter in F is the e-mail path.  All others are
files or directories.

If no subject is set via the "-s subject"  flag, the subect is assigned
from the first file to send.  The three temporary file names (variables
T1, T2, and T3) are then assigned.

The range of pieces to be re-sent is parsed.

Debugging output is echo'd to standard out as appropriate for the
debugging level.  If the -t or -n option is set, nothing is really
done, except printing out what would have happened.

The tar, compress, split commands are performed, with appropriate
verbosity for the debugging level.  Certain checks are made along the
way to verify that the commands did not fail.  If one fails, the
program exits with an appropriate failure message.

The files created in $T3* are sent via mail one at a time, with
delays.  The first file sent has a join-script pre-pended.  A file
counter $n is used to label the subject lines.

The temporary files are deleted.

SHAR_EOF
fi
exit 0
#	End of shell archive

-- 
-Mitchell F. Wyle            wyle@ethz.uucp
Institut fuer Informatik     wyle%ifi.ethz.ch@relay.cs.net
ETH Zentrum                  
8092 Zuerich, Switzerland    +41 1 256-5237