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