From f8baa5a34335fc0fc8ccabfabc601d0af73ab769 Mon Sep 17 00:00:00 2001 From: David Levine Date: Sun, 21 Oct 2012 09:52:46 -0500 Subject: [PATCH] Updated sendfiles(1): 1) Added -from switch. 2) sendfiles will now construct a From address, using the sender's localmbox, if the user does not specify it with -from or the PERSON environment variable. 3) Added support for bzip2, lzma, and zip compression methods. Added a new switch to select the method: -compress . Because support for the old -compress with was broken (it did not use -c with compress/uncompress) and it was undocumented, it has been replaced. Retained old -gzip and -none switches for backward compatibility even though they were undocumented. 4) Allow the recipient argument to be preceded by the optional -to switch iff the subject argument is preceded by the optional -subject switch. Allow the delay value to be specified using the optional -delay switch. 5) Added -version and -help switches. 6) All switches can now be abbreviated. /etc/sendfiles no longer needs to be configured. It's easier to support make distcheck by having it figure out its path at runtime. In viamail, set postproc to post in the same directory as itself, if invoked with a full path. This allows it to support make distcheck. viamail does not read the profile so its postproc is otherwise hard-coded at compile time. Added test-sendfiles. --- .gitignore | 1 - Makefile.am | 12 +-- etc/sendfiles | 178 +++++++++++++++++++++++++++++++++++++ etc/sendfiles.in | 82 ----------------- man/sendfiles.man | 46 +++++++--- test/post/test-sendfiles | 222 ++++++++++++++++++++++++++++++++++++++++++++++ uip/viamail.c | 29 ++++++ 7 files changed, 466 insertions(+), 104 deletions(-) create mode 100755 etc/sendfiles delete mode 100755 etc/sendfiles.in create mode 100755 test/post/test-sendfiles diff --git a/.gitignore b/.gitignore index 4a05816..402f0cc 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,6 @@ a.out.dSYM/ /config/version.c /etc/mhn.defaults /etc/mts.conf -/etc/sendfiles /man/*.[1578] /man/man.sed /man/mh-chart.man diff --git a/Makefile.am b/Makefile.am index 389a6b8..836c37f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -68,7 +68,7 @@ TESTS = test/ali/test-ali test/anno/test-anno \ test/post/test-post-dcc test/post/test-post-fcc \ test/post/test-post-multifrom test/post/test-post-envelope \ test/post/test-post-group test/post/test-mts test/post/test-messageid \ - test/prompter/test-prompter \ + test/post/test-sendfiles test/prompter/test-prompter \ test/rcv/test-rcvdist test/rcv/test-rcvpack test/rcv/test-rcvstore \ test/rcv/test-rcvtty test/refile/test-refile \ test/repl/test-if-str test/repl/test-trailing-newline \ @@ -86,7 +86,7 @@ DISTCHECK_CONFIGURE_FLAGS = DISABLE_SETGID_MAIL=1 ## ## Stuff that should be cleaned via "make clean" ## -CLEANFILES = config/version.c sbr/sigmsg.h etc/mts.conf etc/sendfiles \ +CLEANFILES = config/version.c sbr/sigmsg.h etc/mts.conf \ etc/mhn.defaults man/man.sed man/mh-chart.man $(man_MANS) clean-local: @rm -rf RPM a.out.dSYM uip/a.out.dSYM @@ -211,8 +211,8 @@ man_MANS = man/ali.1 man/anno.1 man/ap.8 man/burst.1 man/comp.1 \ ## Files we need to include in the distribution which aren't found by ## Automake using the automatic rules ## -EXTRA_DIST = config/version.sh sbr/sigmsg.awk etc/mts.conf.in etc/sendfiles.in \ - etc/mhn.defaults.sh $(MHNSEARCHPROG) DATE MACHINES \ +EXTRA_DIST = config/version.sh sbr/sigmsg.awk etc/mts.conf.in \ + etc/mhn.defaults.sh etc/sendfiles $(MHNSEARCHPROG) DATE MACHINES \ docs/ChangeLog_MH-3_to_MH-6.6 \ docs/ChangeLog_MH-6.7.0_to_MH-6.8.4.html \ man/ali.man man/anno.man man/ap.man man/burst.man man/comp.man \ @@ -415,10 +415,6 @@ etc/mhn.defaults: $(srcdir)/etc/mhn.defaults.sh $(MHNSEARCHPROG) @rm -f $@ $(srcdir)/etc/mhn.defaults.sh $(MHNSEARCHPATH) $(MHNSEARCHPROG) > $@ -etc/sendfiles: $(srcdir)/etc/sendfiles.in Makefile - @rm -f $@ - $(SED) -e 's,%libdir%,$(libdir),' < $(srcdir)/etc/sendfiles.in > $@ - ## ## Use configure to set up default LN, but through a make variable so ## that it can be overridden at install time. diff --git a/etc/sendfiles b/etc/sendfiles new file mode 100755 index 0000000..b3f4971 --- /dev/null +++ b/etc/sendfiles @@ -0,0 +1,178 @@ +#!/bin/sh +# +# Sends multiple files and/or directories in a MIME message. +# Requires tar and any specified compression program. +# +# This code is Copyright (c) 2012, by the authors of nmh. See the +# COPYRIGHT file in the root directory of the nmh distribution for +# complete copyright information. + +usage='Usage: sendfiles [switches] -to recipient -subject subject '"\ +"'file1 [file2 ...] + or + sendfiles [switches] recipient subject file1 [file2 ...] + switches are: + -compress [bzip2 | compress | gzip | lzma | none | zip] + -from + -[delay] (expressed in seconds) + -version + -help + Can use PERSON environment variable instead of -from switch.' + + +#### Find location of a program. Bourne shell just puts the name in +#### $0 if it's found from the PATH, so search that if necessary. +finddir() { + case $1 in + */*) dirname "$1" ;; + * ) IFS=: + for d in $PATH; do + [ -f "${d:=.}/$1" -a -x "$d/$1" ] && printf %s "$d" && break + done ;; + esac +} + +die() { + printf '%s\n' "$usage"; exit ${1:-1} +} + +bindir=`finddir $0` +nmhbindir=`cd "$bindir" && pwd` +nmhlibdir=`$nmhbindir/mhparam libdir` + + +#### Process switches. +compress= ## compress method +compressarg=0 ## whether currently handling -compress +delay= ## delay value +delayarg=0 ## whether currently handling -delay +from= ## From: contents +fromarg=0 ## whether currently handling -from +subject= ## Subject: contents +subjectarg=0 ## whether currently handling -subject +to= ## To: address +toarg=0 ## whether currently handling -to +for arg in "$@"; do + case $arg in + -c|-co|-com|-comp|-compr|-compre|-compres|-compress) compressarg=1 ;; + -d|-de|-del|-dela|-delay) delayarg=1 ;; + -[0-9]|-[0-9][0-9]|-[0-9][0-9][0-9]|-[0-9][0-9][0-9][0-9]) + delay=`printf '%s\n' "$arg" | sed -e 's%-%%'` ;; + -f|-fr|-fro|-from) fromarg=1 ;; + #### Support -gzip for backward compatibility. + -gzip) compress=gzip ;; + -h|-he|-hel|-help) die 0 ;; + #### Support -none for backward compatibility. + -none) compress=none ;; + -s|-su|-sub|-subj|-subje|-subjec|-subject) subjectarg=1 ;; + -t|-to) toarg=1 ;; + -v|-ve|-ver|-vers|-versi|-versio|-version) + "$nmhlibdir/viamail" -version | sed 's/viamail/sendfiles/'; exit ;; + -*) die ;; + *) if [ $compressarg -eq 1 ]; then + compress="$arg" + compressarg=0 + elif [ $delayarg -eq 1 ]; then + delay="$arg" + delayarg=0 + elif [ $fromarg -eq 1 ]; then + from="$arg" + fromarg=0 + elif [ $subjectarg -eq 1 ]; then + subject="$arg" + subjectarg=0 + elif [ $toarg -eq 1 ]; then + to="$arg" + toarg=0 + else + #### Argument doesn't apply to a switch, so we're done with switches. + break + fi ;; + esac + shift +done + +#### Check for switch after non-switch argument. +for arg in "$@"; do + case $arg in + -*) die ;; + esac +done + +#### Check for required arguments (to, subject, file(s)). +if [ x"$to" = x ]; then + if [ x"$subject" = x ]; then + if [ $# -ge 3 ]; then + to="$1"; shift + subject="$1"; shift + else + die + fi + else + die + fi +else + [ x"$subject" = x -o $# -lt 1 ] && die +fi + +#### Check for missing mandatory arguments. +checkforargs() { + if [ $compressarg -eq 1 ]; then + printf 'sendfiles: missing argument to -compress\n' >&2; exit 1 + elif [ $delayarg -eq 1 ]; then + printf 'sendfiles: missing argument to -delay\n' >&2; exit 1 + elif [ $fromarg -eq 1 ]; then + printf 'sendfiles: missing argument to -from\n' >&2; exit 1 + elif [ $subjectarg -eq 1 ]; then + printf 'sendfiles: missing argument to -subject\n' >&2; exit 1 + elif [ $toarg -eq 1 ]; then + printf 'sendfiles: missing argument to -to\n' >&2; exit 1 + fi +} + +checkforargs +[ $# -eq 0 ] && die + + +if [ x"$from" = x ]; then + if [ x"$PERSON" = x ]; then + from=`"$nmhlibdir/ap" -format '%(localmbox)' 0` + else + from="$PERSON" + fi +fi + + +#### Determine compression method and descriptive info. +if [ x"$compress" = x ]; then + for compressor in gzip bzip2 lzma zip compress none; do + if [ x"`finddir $compressor`" = x ]; then :; else + compress="$compressor" + break + fi + done +fi + +case $compress in + bzip2) uncompress=bzcat; conversion='; x-conversions=bzip2' ;; + compress) compress='compress -c'; uncompress='uncompress -c'; + conversion='; x-conversions=compress' ;; + gzip) compress='gzip -c'; uncompress='gzip -cd' + conversion='; x-conversions=gzip' ;; + lzma) compress='lzma -c'; uncompress='lzma -cd' + conversion='; x-conversions=lzma' ;; + zip) compress='zip -q'; uncompress='unzip -p' + conversion='; x-conversions=zip' ;; + none) compress=cat uncompress=cat; conversion= ;; + *) printf 'sendfiles: unknown compression method "%s"\n' \ + "$compress" >&2 + die ;; +esac + + +#### Send using viamail. +tar cvf - "$@" | $compress | \ + "$nmhlibdir/viamail" -to "$to" -subject "$subject" \ + -from "$from" -parameters "type=tar$conversion" \ + -comment "extract with $uncompress | tar xvpf -" \ + -delay "$delay" -verbose diff --git a/etc/sendfiles.in b/etc/sendfiles.in deleted file mode 100755 index 85ec6f0..0000000 --- a/etc/sendfiles.in +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/sh -# -# Send multiples files and/or directories as a tar/compressed -# image, in a MIME message. -# - -DELAY=0 -FROM= - -# compression method (none, gzip or compress) -METHOD=none -# compression filter -COMPRESS=cat -# uncompression filter -UNCOMPRESS=cat -# compression description to append to content-type -CONVERSION= - -# default compression method based on installed software -# prefer compress over gzip for backward compatibility -if command -v compress >/dev/null 2>&1 ; then - METHOD=compress -elif command -v gzip >/dev/null 2>&1 ; then - METHOD=gzip -fi - -# handle command-line options to override compression method and delay -while [ $# -gt 3 ]; do - case "$1" in - -gzip) METHOD=gzip - shift - ;; - -compress) METHOD=compress - shift - ;; - -none) METHOD=none - shift - ;; - -*) DELAY="`echo $1 | sed -e 's%-%%'`" - shift - ;; - *) break - ;; - esac -done - -# set variables based on chosen compression method -if [ $METHOD = compress ]; then - COMPRESS=compress - UNCOMPRESS=uncompress - CONVERSION="; x-conversions=compress" -elif [ $METHOD = gzip ]; then - COMPRESS="gzip -c" - UNCOMPRESS="gzip -dc" - CONVERSION="; x-conversions=gzip" -fi - -if [ ! -z "$PERSON" ]; then - FROM="-from $PERSON" -fi - -if [ $# -lt 3 ]; then - echo 'usage: sendfiles: "mailpath" "subject-string" directory-or-file ...' 1>&2 - exit 1; -fi - -mailpath="$1" -echo "mailpath = $mailpath" 1>&2 -shift - -subject="$1" -echo "subject-string = $subject" 1>&2 -shift - -echo "files = $*" 1>&2 - -tar cvf - "$@" | $COMPRESS | \ - %libdir%/viamail -to "$mailpath" -subject "$subject" \ - -parameters "type=tar$CONVERSION" \ - -comment "extract with $UNCOMPRESS | tar xvpf -" \ - -delay "$DELAY" \ - -verbose $FROM diff --git a/man/sendfiles.man b/man/sendfiles.man index af396f1..4b39245 100644 --- a/man/sendfiles.man +++ b/man/sendfiles.man @@ -8,16 +8,22 @@ sendfiles \- send multiple files via a MIME message .HP 5 .na .B sendfiles -.RB [ \-bzip2 " | " \-compress " | " \-gzip " | " \-lzma " | " \-none " | " -zip ] +.RB [ -compress +.IR bzip2 " | " compress " | " gzip " | " lzma " | " none " | " zip ] .br .RB [ \-from .IR sender ] -.RI [ \-delay ] +.RI [ "\-delay n" " | " \-n ] .RB [ \-version ] .RB [ \-help ] .br +.B \-to +.I recipient +.B \-subject +.IR subject " | " .I recipient .I subject +.br .I file/directory1 .RI [ file/directory2 \&...] @@ -29,7 +35,7 @@ is used to send a collection of files and directories via electronic mail. .PP .RS 5 -sendfiles recipient \*(lqsubject\*(rq files\0... +sendfiles -to recipient -subject \*(lqsubject\*(rq files\0... .RE .PP .B sendfiles @@ -43,6 +49,13 @@ will be automatically split up into as many messages as necessary in order to get past most mailers. .PP The +.B \-to +switch specifies the recipient. The +.B \-subject +switch specifies the subject. Alternatively, these two required values +can be provided without their corresponding switch names. +.PP +The .B \-from switch can, and should, be used to specify the sender's mailbox (name and email address). Alternatively, the @@ -56,28 +69,35 @@ mailbox, see in .IR mh-format (5). .PP -The remaining command line switches select the compression program. -One of these can be used to override the run-time determination of -the compression program by +The +.B \-compress +command line switch can be used to override the run-time determination +of the compression program by .BR sendfiles . +.B \-compress +.I none +(alternatively, +.BR \-none ) +disables compression. .PP Sometimes you want .B sendfiles to pause after posting a partial message. This is usually the case when you are running .B sendmail -and expect to generate a lot of partial messages. If the first -argument given to -.B sendfiles -starts with a dash, then it is -interpreted as the number of seconds to pause in between postings, +and expect to generate a lot of partial messages. The +.B \-delay +switch specifies the number of seconds to pause in between postings, e.g., .PP .RS 5 -sendfiles -30 recipient \*(lqsubject\*(rq files\0... +sendfiles -delay 30 -to recipient -subject \*(lqsubject\*(rq files\0... .RE .PP -will pause 30 seconds in between each posting. +will pause 30 seconds in between each posting. An alternate form of +the switch with just the delay time, +.BR \-30 , +for example, is also supported. .PP .SS "Extracting the Received Files" When these messages are received, invoke diff --git a/test/post/test-sendfiles b/test/post/test-sendfiles new file mode 100755 index 0000000..750c760 --- /dev/null +++ b/test/post/test-sendfiles @@ -0,0 +1,222 @@ +#!/bin/sh +###################################################### +# +# Test sendfiles +# +###################################################### + +set -e + +if test -z "$MH_OBJ_DIR"; then + srcdir=`dirname $0`/../.. + MH_OBJ_DIR=`cd $srcdir && pwd`; export MH_OBJ_DIR +fi + +. "$MH_OBJ_DIR/test/common.sh" + +setup_test + +expected=$MH_TEST_DIR/$$.expected +expected_err=$MH_TEST_DIR/$$.expected_err +actual=$MH_TEST_DIR/$$.actual +actual_err=$MH_TEST_DIR/$$.actual_err +localmbox=`$MH_LIB_DIR/ap -format "%(localmbox)" 0` +#### Use this script itself for the test file. +testfiledir="$srcdir/test/post" +testfile=`basename $0` + +(cd "$MH_TEST_DIR" && +mkdir -p tmp && +cat >"$expected_err" < "$mts_fakesendmail" +printf 'sendmail: %s/fakesendmail\n' "$MH_TEST_DIR" >>"$mts_fakesendmail" +MHMTSCONF="$mts_fakesendmail" + +# $1: uncompress command +# $2: argument style: +# new: -to recipient -subject subject +# old: recipient subject +# remaining arguments: sendfiles switches +test_sendfiles () +{ + uncompress="$1"; shift + argstyle="$1"; shift + + if [ "$argstyle" = 'new' ]; then + (cd "$MH_TEST_DIR" && + sendfiles "$@" -to recipient@example.com -subject "sendfiles test" \ + "$testfile" >/dev/null 2>"$actual_err") + elif [ "$argstyle" = 'old' ]; then + (cd "$MH_TEST_DIR" && + sendfiles "$@" recipient@example.com "sendfiles test" \ + "$testfile" >/dev/null 2>"$actual_err") + fi + + check "$expected_err" "$actual_err" 'keep first' + + # fakesendmail drops the message and any cc's into this mbox. + mbox="$MH_TEST_DIR"/Mail/fakesendmail.mbox + inc -silent -file "$mbox" + rm -f "$mbox" "$mbox.map" + + mhlist -verbose last | sed -e 's/ *$//' >"$actual" + (cd $MH_TEST_DIR/tmp && + contents=`mhstore -noauto last 2>&1 | \ + sed -e 's/storing message.*as file //'` && + $uncompress "$contents" | tar xpf - && rm -f "$contents") + + rmm last + check "$testfiledir/$testfile" "$MH_TEST_DIR/tmp/$testfile" \ + 'keep first' + + [ -f "$expected" ] && check "$expected" "$actual" || rm -f "$actual" +} + + +# check -help +cat >"$expected" < + -[delay] (expressed in seconds) + -version + -help + Can use PERSON environment variable instead of -from switch. +EOF + +sendfiles -help >"$actual" 2>&1 +check "$expected" "$actual" + +# check -version +case `sendfiles -v` in + sendfiles\ --*) ;; + * ) printf '%s: sendfiles -v generated unexpected output\n' "$0" >&2 + failed=`expr ${failed:-0} + 1`;; +esac + +# check unknown switch +run_test 'sendfiles -nonexistent' "Usage: sendfiles [switches] -to recipient \ +-subject subject file1 [file2 ...] + or + sendfiles [switches] recipient subject file1 [file2 ...] + switches are: + -compress [bzip2 | compress | gzip | lzma | none | zip] + -from + -[delay] (expressed in seconds) + -version + -help + Can use PERSON environment variable instead of -from switch." + +# check unknown compression method +run_test 'sendfiles -compress unknown to subject file' \ +'sendfiles: unknown compression method "unknown"'" +Usage: sendfiles [switches] -to recipient \ +-subject subject file1 [file2 ...] + or + sendfiles [switches] recipient subject file1 [file2 ...] + switches are: + -compress [bzip2 | compress | gzip | lzma | none | zip] + -from + -[delay] (expressed in seconds) + -version + -help + Can use PERSON environment variable instead of -from switch." + +# Check basic operation, using specified compression method. +# Don't check the mhlist output, by not creating an $expected file, +# because it will vary with compression method and compressed file +# size. +[ "`findprog bzip2`" ] && test_sendfiles 'bzip2 -cd' new -compress bzip2 +[ "`findprog compress`" ] && test_sendfiles uncompress new -compress compress +[ "`findprog gzip`" ] && test_sendfiles 'gzip -cd' new -compress gzip +[ "`findprog gzip`" ] && test_sendfiles 'gzip -cd' new -gzip +[ "`findprog lzma`" ] && test_sendfiles 'lzma -cd' new -compress lzma +[ "`findprog zip`" ] && test_sendfiles 'unzip -p' new -compress zip + +# check with no compression +cat >"$expected" <"$expected" <"$expected" <"$expected" <' + +# check PERSON environment variable +cat >"$expected" <"$expected" <"$expected" <