* clcommit.m4sh, libltdl/config/mailnotify.m4sh: Rewrite option parsing loop over M4SH_GETOPTS macro, and adjust all clients of option variables to use generated option names. --- ChangeLog | 5 + clcommit.m4sh | 318 ++++++++++---------------------- libltdl/config/mailnotify.m4sh | 394 ++++++++++++++++++++-------------------- 3 files changed, 306 insertions(+), 411 deletions(-)
diff --git a/ChangeLog b/ChangeLog index c511b59..6c397c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2010-06-05 Gary V. Vaughan <g...@gnu.org> + Update and simplify all m4sh scripts to use latest getopt.m4sh. + * clcommit.m4sh, libltdl/config/mailnotify.m4sh: Rewrite option + parsing loop over M4SH_GETOPTS macro, and adjust all clients of + option variables to use generated option names. + Add missing quote for literal ? in a shell case statement. * libltdl/config/getopt.m4sh (m4go_shortnoargs): Quote initial ? correctly for use in a shell case statement. diff --git a/clcommit.m4sh b/clcommit.m4sh index 8c14be2..ff27f9d 100644 --- a/clcommit.m4sh +++ b/clcommit.m4sh @@ -1,7 +1,7 @@ AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl # @configure_input@ -# clcommit (GNU @PACKAGE@) version 2.0.1 +# clcommit (GNU @PACKAGE@) version 2.1 # Written by Gary V. Vaughan <g...@gnu.org> # and Alexandre Oliva <aol...@redhat.com> @@ -32,16 +32,16 @@ AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl # --debug enable verbose shell tracing # -n --dry-run don't commit anything # --fast same as --force --first -# -F file --file=FILE read commit message from FILE +# -F FILE --file=FILE read commit message from FILE # -1 --first extract first entry from ChangeLog, no git diff # -f --force don't check (unless *followed* by -n), and just # display commit message instead of running $PAGER # --from=ADDRESS override default from ADDRESS in commit email -# -m msg --message=STRING set commit message to STRING +# -m STRING --message=STRING set commit message to STRING # --msg=STRING same as -m # -p --push push the changes back to origin # -r [FILE] --rcfile[=FILE] read default option from FILE [./.clcommitrc] -# -s addr --sendmail=ADDRESS send commit email of the differences to ADDRESS +# -s ADDR --sendmail=ADDR send commit email of the differences to ADDRESS # --signature[=FILE] add FILE to the end of the email [~/.signature] # --signoff add a Signed-off-by attribution at the end # -S TEXT --summary=TEXT specify a TEXT subject line for the commit email @@ -83,19 +83,12 @@ m4_divert_pop m4_include([getopt.m4sh]) M4SH_VERBATIM([[ -# Global variables: -opt_commit=: -opt_first=false -opt_push=false -opt_tags=false -opt_update=: -opt_verbose=false - -git_flags= -mailnotify_flags= -sendmail_to= +# Locations for important files: +log_dir="`func_mktempdir`" +log_file="$log_dir/log" +push_conflicts="$log_dir/git_push.log" -exit_cmd=: +trap '$RM -r "$log_dir"; exit $EXIT_FAILURE' 1 2 15 # try to find out whether read supports -r if echo bt | tr b '\\' | { read -r line; test "X$line" = 'X\t'; } 2>/dev/null @@ -104,196 +97,81 @@ then else read_r=read fi +]]) -# Locations for important files: -signature_file= -log_dir="`func_mktempdir`" -log_file="$log_dir/log" -push_conflicts="$log_dir/git_push.log" - -trap '$RM -r "$log_dir"; exit $EXIT_FAILURE' 1 2 15 - -set -e - -# Parse options once, thoroughly. This comes as soon as possible in -# the script to make things like `clcommit --version' happen quickly. -{ - # sed scripts: - my_sed_single_opt='1s/^\(..\).*$/\1/;q' - my_sed_single_rest='1s/^..\(.*\)$/\1/;q' - my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' - my_sed_long_arg='1s/^--[^=]*=//' - - # this just eases exit handling - while test $# -gt 0; do - opt="$1" - shift - case $opt in - - --author|-a) test $# = 0 && func_missing_arg $opt && break - func_quote_for_eval "$1" - git_flags="$git_flags --author=$func_quote_for_eval_result" - shift - ;; - - --[cC]hange[lL]og|-C) - test $# = 0 && func_missing_arg $opt && break - if test -f "$1"; then :; else - func_error "ChangeLog file \`$1' does not exist" - break - fi - ChangeLog="$1" - shift - ;; - - --debug) func_echo "enabling shell trace mode" - mailnotify_flags="$mailnotify_flags --debug" - set -x - ;; - - --dry-run|-n) opt_commit=false; opt_update=: ;; - - --fast) set dummy --force --first ${1+"$@"}; shift ;; - - --file|-F) test $# = 0 && func_missing_arg $opt && break - if $opt_first || test -f "$log_file"; then - func_error "you can have at most one of -m, -F and -1" - break - fi - if cat < "$1" > "$log_file"; then :; else - break - fi - shift - ;; - - --first|-1) if test -f "$log_File"; then - func_error "you can have at most one of -m, -F and -1" - break - fi - opt_first=: - ;; - - --force|-f) opt_update=false; PAGER=cat ;; - - --from) test $# = 0 && func_missing_arg $opt && break - func_quote_for_eval "$1" - mailnotify_flags="$mailnotify_flags --from=$func_quote_for_eval_result" - shift - ;; - - --message|--msg|-m) - test $# = 0 && func_missing_arg $opt && break - if $opt_first || test -f "$log_file"; then - func_error "you can have at most one of -m, -F and -1" - break - fi - echo "$1" > "$log_file" - shift - ;; - - --push|-p) opt_push=: ;; - - --rcfile|-r) rc_file="./.clcommitrc" - if test $# -gt 0; then - case $1 in - -*) ;; - *) rc_file="$1"; shift ;; - esac - fi - if test -f "$rc_file"; then :; else - func_error "rcfile \`$rc_file' does not exist" - exit_cmd=exit - break - fi - # The funny quoting allows keeping one option per - # line in $rc_file: - eval set dummy `echo \`cat $rc_file\` \${1+"\$@"}` - shift - ;; - - --sendmail|-s) test $# = 0 && func_missing_arg $opt && break - func_quote_for_eval "$1" - sendmail_to="$func_quote_for_eval_result" - shift - ;; - - --signature) test $# = 0 && func_missing_arg $opt && break - signature_file="$HOME/.signature" - case $1 in - -*) ;; - *) signature_file="$1"; shift ;; - esac - if test -f "$signature_file"; then :; else - func_error "\`$signature_file': file not found" - break - fi - ;; - - --signoff) git_flags="$git_flags --signoff" ;; - - --summary|-S) test $# = 0 && func_missing_arg $opt && break - summary="$1" - shift - ;; - - --tags) opt_tags=: ;; - - --verbose|-v) opt_verbose=: ;; - - # Separate optargs to long options: - --*=*) - arg=`echo "$opt" | $SED "$my_sed_long_arg"` - opt=`echo "$opt" | $SED "$my_sed_long_opt"` - set dummy "$opt" "$arg" ${1+"$@"} - shift - ;; - - # Separate optargs to short options: - -a*|-m*|-F*|-C*|-S*|-s*) - arg=`echo "$opt" |$SED "$my_sed_single_rest"` - opt=`echo "$opt" |$SED "$my_sed_single_opt"` - set dummy "$opt" "$arg" ${1+"$@"} - shift - ;; - - # Separate non-argument short options: - -1*|-f*|-p*|-n*|-q*) - rest=`echo "$opt" |$SED "$my_sed_single_rest"` - opt=`echo "$opt" |$SED "$my_sed_single_opt"` - set dummy "$opt" "-$rest" ${1+"$@"} - shift - ;; - - -\?|-h) func_usage ;; - --help) func_help ;; - --version) func_version ;; - --) break ;; - -*) func_fatal_help "unrecognized option \`$opt'" ;; - *) set dummy "$opt" ${1+"$@"}; shift; break ;; - esac - done - - if test -z "$sendmail_to"; then +dnl SHORT LONG DEFAULT INIT +dnl ---------------------------------------------------------------------- +M4SH_GETOPTS( + [1], [--first], [], [], + [a^!], [--author], [], [ + git_flags="${git_flags+$git_flags }--author=$opt_author"], + [...@], [--changelog|--Change[Ll]og], [], [], + [F!], [--file], [], [ + cat "[$]1" > "$log_file" || break], + [f], [--force], [], [ + PAGER=cat], + [m!], [--message|--msg], [], [ + echo "[$]1" > "$log_file"], + [n], [--dry-run|--dryrun], [], [ + mailnotify_flags="${mailnotify_flags+$mailnotify_flags }--dry-run"], + [p], [--push], [], [], + [...@?], [--rcfile], [./.clcommitrc], [ + # The funny quoting allows keeping one option per line in $opt_rcfile: + eval set dummy `echo \`cat $opt_rcfile\` '${1+"[$]@"}'` + shift], + [S!], [--summary], [], [], + [s^!], [--sendmail], [], [], + [v], [--verbose], [], [ + mailnotify_flags="${mailnotify_flags+$mailnotify_flags }--verbose"], + [], [--fast], [], [ + set dummy --force --first ${1+"[$]@"}; shift], + [^!], [--from], [], [ + mailnotify_flags="${mailnotify_flags+$mailnotify_flags }--from=$opt_from"], + [...@?], [--signature], [], [ + test -n "$opt_signature" || opt_signature="$HOME/.signature"], + [], [--signoff], [], [ + git_flags="${git_flags+$git_flags }$opt"], + [], [--tags], [], [], + [ + # pass debug flag along to mailnotify + $opt_debug && + mailnotify_flags="${mailnotify_flags+$mailnotify_flags }--debug" + + # validate $opt_first, $opt_file and $opt_message + if $opt_first; then + test -n "$opt_file$opt_message" && + func_error "you can have at most one of -m, -F and -1" + else + test -n "$opt_file" && test -n "$opt_message" && + func_error "you can have at most one of -m, -F and -1" + fi + # validate $opt_from and $opt_signature + test -n "$opt_sendmail" || { # can't have a from address without a destination address - test -n "$sendmail_from" && + test -n "$opt_from" && func_error "can't use --from without --sendmail." && exit_cmd=exit # can't use a signature file without a destination address - test -n "$signature_file" && + test -n "$opt_signature" && func_error "can't use --signature without --sendmail." && exit_cmd=exit - fi + } - $opt_tags && test x"$opt_push" = xfalse && - func_error "can't use --tags without --push." && exit_cmd=exit + # validate $opt_tags + $opt_push || { + $opt_tags && + func_error "can't use --tags without --push." && exit_cmd=exit + } +]) - # Bail if the options were screwed - $exit_cmd $EXIT_FAILURE -} +M4SH_VERBATIM([[ +# Bail out on command errors! +set -e # func_check_conflicts func_check_conflicts () { + func_verbose "checking for commit conflicts..." if $GIT push --dry-run > "$push_conflicts" 2>&1; then :; else cat "$push_conflicts" >&2 func_fatal_error "some conflicts were found with upstream repository, aborting..." @@ -304,25 +182,25 @@ func_check_conflicts () # func_check_commit_msg func_check_commit_msg () { - if test -z "$ChangeLog"; then + if test -z "$opt_changelog"; then for f in ${1+"$@"}; do case "$f" in ChangeLog* | */ChangeLog*) - if test -z "$ChangeLog"; then - ChangeLog="$f" + if test -z "$opt_changelog"; then + opt_changelog="$f" else - func_fatal_error "multiple ChangeLog files: $ChangeLog and $f" + func_fatal_error "multiple ChangeLog files: $opt_changelog and $f" fi ;; esac done fi - func_verbose "$progname: checking commit message..." + func_verbose "checking commit message..." separate_summary=: # whether to separate summary lines for git if $opt_first; then skipping=: - $SED 's,^,+,' < ${ChangeLog-ChangeLog} | + $SED 's,^,+,' < ${opt_changelog-ChangeLog} | while $read_r line; do case "$line" in "+") if $skipping; then skipping=false; else break; fi;; @@ -345,7 +223,7 @@ func_check_commit_msg () done | $SED 's,^\+ ,,' > "$log_file" || exit $EXIT_FAILURE else - $GIT diff ${ChangeLog-ChangeLog} | + $GIT diff ${opt_changelog-ChangeLog} | while $read_r line; do case $line in "--- "*) :;; @@ -387,13 +265,19 @@ func_commit () test $# -gt 0 && subject="$@" test $# -gt 0 || { set dummy -a; shift; } - func_verbose "$GIT commit$git_flags -F $log_file ${...@}" - $GIT commit$git_flags -F $log_file ${1+"$@"} || exit $EXIT_FAILURE + func_verbose "$GIT commit $git_flags -F $log_file ${...@}" + $opt_dry_run || + $GIT commit $git_flags -F $log_file ${1+"$@"} || exit $EXIT_FAILURE - if $opt_push; then - $GIT push - $opt_tags && $GIT push --tags - fi + $opt_push && { + func_verbose "$GIT push" + $opt_dry_run || $GIT push + + $opt_tags && { + func_verbose "$GIT push --tags" + $opt_dry_run || $GIT push --tags + } + } : } @@ -403,7 +287,7 @@ func_commit () func_mailnotify () { notify_file="${log_dir}/notify" - func_verbose "Mailing commit notification to $sendmail_to" + func_verbose "Mailing commit notification to \"$opt_sendmail\"" { echo Subject: $subject @@ -417,9 +301,9 @@ func_mailnotify () echo "" echo "Log Message:" $SED -e 's,^, ,' "$log_file" - test -f "$signature_file" && { + test -f "$opt_signature" && { echo '-- ' - cat "$signature_file" + cat "$opt_signature" } } > "$notify_file" @@ -434,11 +318,10 @@ func_mailnotify () my_mail_body=`$SED -e '2,$p;d' "$notify_file"` echo "$my_mail_body" > "$notify_file" - func_verbose "mailing commit notification to \"$sendmail_to\"" func_quote_for_eval "$my_mail_subject" func_show_eval "$MAILNOTIFY $mailnotify_flags \ -s $func_quote_for_eval_result -m 'text/plain' -f '$notify_file' \ - -- $sendmail_to" + -- $opt_sendmail" } @@ -458,17 +341,18 @@ func_mailnotify () func_error "*** They should be used to separate distinct commits." fi - $opt_update && $opt_push && func_check_conflicts + # $opt_force says to force the changes through without checking for conflicts + $opt_push && { + $opt_force || func_check_conflicts + } # Do not check for empty $log_file again, even though the user might have # zeroed it out. If s/he did, it was probably intentional. - if $opt_commit; then - func_commit ${1+"$@"} - fi + func_commit ${1+"$@"} - # Send a copy of the log_file if sendmail_to was set: + # Send a copy of the log_file if opt_sendmail was set: subject=`sed -n '1p' "$log_file"` - if test -n "$sendmail_to"; then + if test -n "$opt_sendmail"; then if ! $opt_push; then func_warning "Mail notification NOT sent for commit to local repository." else diff --git a/libltdl/config/mailnotify.m4sh b/libltdl/config/mailnotify.m4sh index a95f201..d8a24e3 100644 --- a/libltdl/config/mailnotify.m4sh +++ b/libltdl/config/mailnotify.m4sh @@ -1,10 +1,10 @@ AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl # @configure_input@ -# mailnotify (GNU @PACKAGE@) version 0.6 +# mailnotify (GNU @PACKAGE@) version 1.0 # Written by Gary V. Vaughan <g...@gnu.org> -# Copyright (C) 2004, 2006 Free Software Foundation, Inc. +# Copyright (C) 2004, 2006, 2010 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -24,19 +24,17 @@ AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# Usage: $progname [OPTION]... [--] to-address... +# Usage: $progname [OPTIONS]... # -# --debug enable verbose shell tracing -# -C ADDR --carbon-copy=ADDR send a carbon-copy to ADDR -# -F ADDR --from=ADDR override default from address with ADDR +# -x --debug enable verbose shell tracing +# --dry-run don't actually post the mime message # -f FILE --filename=FILE content of this part +# -h FILE --headers=FILE read additional headers from FILE # -m TYPE --mime-type=TYPE mime-type of this part -# -n another mime part (-f, -m) to follow # -o FILE --output-file=FILE output to FILE instead of sending -# -s TEXT --subject=TEXT set subject header # -v --verbose run in verbose mode # --version print version information -# -h,-? --help print short or long help message +# -? --help print short or long help message # Assemble a (possibly multi-part) mime message and hand it to the local # sendmail for onward delivery. MUAs tend to mangle patch attachments in @@ -48,12 +46,19 @@ AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl # For example to send a patch as an attachment, assuming the patch itself # is in PATCHFILE: # -# echo 'Applied to HEAD' > body -# $progname -f body -m text/plain -n -f PATCHFILE -m text/x-patch \ -# -s 'FYI: PATCHFILE' patch-l...@foo.org +# echo 'From: m...@example.org' > headers +# echo 'To: patch-l...@foo.org' >> headers +# echo 'Subject: FYI: PATCHFILE' >> headers +# echo 'Cc: some...@example.org' >> headers +# echo 'Applied this patch to HEAD' > body +# $progname -h headers -f body -m text/plain -f PATCHFILE -m text/x-patch +# +# There is no set order or requirement for mail headers in the headers +# file, though you will obviously need someone's address in 'To:', and +# it's not polite to omit the 'Subject:' header... # You will probably find using this script in conjunction with clcommit -# or cvsapply will save you an awful lot of typing. +# saves you a lot of typing. # Report bugs to <g...@gnu.org> @@ -66,134 +71,78 @@ m4_divert_pop m4_include([getopt.m4sh]) M4SH_VERBATIM([[ -# Global variables: -multipart=1 -outputfile="" - sed_mail_address='s,^.*<\(.*\)>.*$,\1,' +]]) -# Parse options once, thoroughly. This comes as soon as possible in -# the script to make things like `mailnotify --version' happen quickly. -{ - # sed scripts: - my_sed_single_opt='1s/^\(..\).*$/\1/;q' - my_sed_single_rest='1s/^..\(.*\)$/\1/;q' - my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' - my_sed_long_arg='1s/^--[^=]*=//' - - while test $# -gt 0; do - opt="$1" - shift - case $opt in - --debug) func_echo "enabling shell trace mode" - set -x - ;; - - -C|--carbon-copy) test $# -eq 0 && func_missing_arg "$opt" && break - func_quote_for_eval "$1" - cc="$func_quote_for_eval_result" - shift - ;; - - -F|--from) test $# -eq 0 && func_missing_arg "$opt" && break - func_quote_for_eval "$1" - from="$func_quote_for_eval_result" - shift - ;; - - -f|--filename) test $# -eq 0 && func_missing_arg "$opt" && break - if test -f "$1"; then :; else - func_error "\`$1' does not exist" - exit_cmd=exit - break - fi - eval datafile$multipart=\"$1\" - shift - ;; - - -m|--mime-type) test $# -eq 0 && func_missing_arg "$opt" && break - case $1 in - text/*) ;; - */*) func_error "only text/* mime-types supported" - ;; - *) func_error "invalid mime-type, \`$1'" - exit_cmd=exit - ;; - esac - eval ctype$multipart=\"$1\" - shift - ;; - - -n) if eval test -z \"\$ctype$multipart\" || - eval test -z \"\$datafile$multipart\"; then - func_fatal_error "One part is incomplete -- each part needs a filename and a mime-type" - fi - multipart=`expr 1 + $multipart` - ;; - - -o|--output-file) test $# -eq 0 && func_missing_arg "$opt" && break - func_quote_for_eval "$1" - outputfile="$func_quote_for_eval_result" - shift - ;; - - -s|--subject) test $# -eq 0 && func_missing_arg "$opt" && break - func_quote_for_eval "$1" - subject="$func_quote_for_eval_result" - shift - ;; - - -v|--verbose) opt_verbose=: ;; - - # Separate optargs to long options: - --carbon-copy=*|--from=*|--filename=*|--mime-type=*|--output-file=*|--subject=*) - arg=`echo "$opt" | $SED "$my_sed_long_arg"` - opt=`echo "$opt" | $SED "$my_sed_long_opt"` - set -- "$opt" "$arg" ${1+"$@"} - ;; - - # Separate optargs to short options: - -C*|-F*|-f*|-m*|-o*|-s*) - arg=`echo "$opt" |$SED "$my_sed_single_rest"` - opt=`echo "$opt" |$SED "$my_sed_single_opt"` - set -- "$opt" "$arg" ${1+"$@"} - ;; - - # Separate non-argument short options: - -n*|-v*) - rest=`echo "$opt" |$SED "$my_sed_single_rest"` - opt=`echo "$opt" |$SED "$my_sed_single_opt"` - set -- "$opt" "-$rest" ${1+"$@"} - ;; - - -\?|-h) func_usage ;; - --help) func_help ;; - --version) func_version ;; - --) break ;; - -*) func_fatal_help "unrecognized option \`$opt'" ;; - *) set -- "$opt" ${1+"$@"}; break ;; - esac - done - - test $# -gt 0 || - func_fatal_help "no destination address" - - if test -z "$outputfile"; then - if test -z "$subject" || - eval test -z \"\$ctype$multipart\" || - eval test -z \"\$datafile$multipart\"; then +dnl SHORT LONG DEFAULT INIT +dnl ---------------------------------------------------------------------- +dnl There are several options supported below for backwards compatibility, +dnl but which are not mentioned in the help. +M4SH_GETOPTS( + [C^!], [--carbon-copy], [], [], + [F^!], [--from], [], [], + [...@+], [--filename], [], [], + [...@!], [--headers], [], [], + [m+!], [--mime-type], [], [ + case [$]1 in + text/*) ;; + */*) func_error "\`[$]1': only text/* mime-types supported" + ;; + *) func_error "invalid mime-type, \`[$]1'" + exit_cmd=exit + ;; + esac], + [n], [], [], [], + [o!], [--output-file], [], [], + [s^!], [--subject], [], [], + [v], [--verbose], [], [], + [], [--dry-run|--dryrun], [], [], + [ + # ensure destination address(es) available + test [$]# -gt 0 || + grep '^\(To\|Cc\|Bcc\): ' "${opt_headers-nosuchfile}" >/dev/null 2>&1 || + func_fatal_help "no destination address" + + # validate headers + test "$opt_headers" && { + test -n "$opt_carbon_copy" && grep "^Cc: *" "$opt_headers" >/dev/null 2>&1 && { + func_error "specify \`Cc:' in either \`$opt_headers' or with \`--carbon-copy'." + exit_cmd=exit + } + test -n "$opt_from" && grep "^From: *" "$opt_headers" >/dev/null 2>&1 && { + func_error "specify \`From:' in either \`$opt_headers' or with \`--from'." + exit_cmd=exit + } + test -n "$opt_subject" && grep "^Subject: *" "$opt_headers" >/dev/null 2>&1 && { + func_error "specify \`Subject:' in either \`$opt_headers' or with \`--subject'." + exit_cmd=exit + } + } + + # validate mime parts + if test "${opt_mime_type_num-0}" -ne "${opt_filename_num-0}"; then + func_fatal_error "One part is incomplete -- each part needs a filename and a mime-type" + fi + if test -z "$opt_output_file"; then + test -f "$opt_headers" || if test -z "$opt_subject" || + eval test -z \"\$opt_mime_type_$opt_mime_type_num\" || + eval test -z \"\$opt_filename_$opt_filename_num\"; then func_fatal_error "if output is not directed to a file -s, -f, and -m are all required" fi else - eval test -n \"\$datafile$multipart\" || + eval test -n \"\$opt_filename_$opt_filename_num\" || func_fatal_error "-f is required." - eval test -n \"\$ctype$multipart\" || + eval test -n \"\$opt_mime_type_$opt_mime_type_num\" || func_fatal_error "with output directed to a file, -m is required" fi - eval test -f \"\$datafile$multipart\" || - eval func_fatal_error \"\$datafile$multipart: file not found\" -} + # validate $opt_dry_run + $opt_dry_run && SENDMAIL="echo $SENDMAIL" +]) + +M4SH_VERBATIM([[ +# Bail out on command errors! +set -e # func_headers outfile destination # Generate common headers to OUTFILE, where DESTINATION is a comma @@ -209,14 +158,26 @@ func_headers () } d' - { + $opt_dry_run || { echo "User-Agent: $PROGRAM/`$SED \"$my_sed_version_no\" < $progpath`" echo "MIME-Version: 1.0" - test -n "$from" && eval echo From: $from - eval echo To: $my_destination - test -n "$cc" && eval echo CC: $cc - test -n "$subject" && eval echo Subject: $subject + + # Deprecated command line options take precedence at the moment + my_elide="Bcc" + test -n "$opt_from" && + my_elide="${my_elide+$my_elide\|}From" && eval echo From: $opt_from + test -n "$my_destination" && + my_elide="${my_elide+$my_elide\|}To" && eval echo To: $my_destination + test -n "$opt_carbon_copy" && + my_elide="${my_elide+$my_elide\|}Cc" && eval echo CC: $opt_carbon_copy + test -n "$opt_subject" && + my_elide="${my_elide+$my_elide\|}Subject" && eval echo Subject: $opt_subject + + # Plus any additional headers + test -n "$opt_headers" && $SED "/^\($my_elide\): */d" "$opt_headers" } > "$my_outfile" + + : } @@ -226,11 +187,11 @@ func_single_content () { my_outfile="$1" - cat >> "$my_outfile" <<EOF -Content-Type: $ctype1; + $opt_dry_run || cat >> "$my_outfile" <<EOF +Content-Type: $opt_mime_type_1; Content-Transfer-Encoding: 7bit -`cat $datafile1` +`cat $opt_filename_1` EOF } @@ -241,7 +202,8 @@ func_multipart_content () { my_outfile="$1" boundary="boundary-${HOST}-$$-`date | tr ' :' -`" - cat <<EOF >> "$my_outfile" + $opt_dry_run || { + cat <<EOF >> "$my_outfile" Content-Type: multipart/mixed; boundary="$boundary" @@ -249,31 +211,34 @@ This is a multimedia message in MIME format. If you are reading this prefix, your mail reader does not understand MIME. You may wish to look into upgrading to a mime-aware mail reader. EOF - i=0 - while test $i -lt $multipart - do - i=`expr 1 + $i` - eval file=\"\$datafile$i\" - name=`echo "$file" | $SED $basename` - { - echo "" - echo "--$boundary" - if test $i -gt 1; then - eval echo \"Content-Type: \$ctype$i\;\" - echo " name=\"$name\"" - else - eval echo \"Content-Type: \$ctype$i\" - fi - echo "Content-Transfer-Encoding: 7bit" - echo "" - cat "$file" - } >> "$my_outfile" - done - { - echo "" - echo "--${boundary}--" - echo "" - } >> "$my_outfile" + i=0 + while test $i -lt $opt_filename_num + do + i=`expr 1 + $i` + eval file=\"\$opt_filename_$i\" + name=`echo "$file" | $SED $basename` + { + echo "" + echo "--$boundary" + if test $i -gt 1; then + eval echo \"Content-Type: \$opt_mime_type_$i\;\" + echo " name=\"$name\"" + else + eval echo \"Content-Type: \$opt_mime_type_$i\" + fi + echo "Content-Transfer-Encoding: 7bit" + echo "" + cat "$file" + } >> "$my_outfile" + done + { + echo "" + echo "--${boundary}--" + echo "" + } >> "$my_outfile" + } + + : } @@ -289,25 +254,29 @@ func_sendmail () my_destination="$2" my_from="$3" + $opt_dry_run && my_infile=/dev/null + from_name=`eval echo "X$my_from" | $Xsed -e 's, *<.*> *$,,'` from_addr=`eval echo "X$my_from" | $Xsed -e "$sed_mail_address"` save_PATH="$PATH" PATH="/usr/lib:/usr/sbin:$PATH" - save_IFS="$IFS" - IFS=':' - for try_sendmail_dir in $PATH; do + $opt_dry_run || { + save_IFS="$IFS" + IFS=':' + for try_sendmail_dir in $PATH; do + IFS="$save_IFS" + PATH="$save_PATH" + if test -x "$try_sendmail_dir/$SENDMAIL"; then + SENDMAIL="$try_sendmail_dir/$SENDMAIL" + break + fi + done IFS="$save_IFS" - PATH="$save_PATH" - if test -x "$try_sendmail_dir/$SENDMAIL"; then - SENDMAIL="$try_sendmail_dir/$SENDMAIL" - break - fi - done - IFS="$save_IFS" - PATH="$save_PATH" - test -x "$SENDMAIL" || func_fatal_error "sendmail executable not found" + PATH="$save_PATH" + test -x "$SENDMAIL" || func_fatal_error "sendmail executable not found" + } func_verbose "Delivering mail, please wait..." if test -n "$from_name"; then @@ -319,13 +288,40 @@ func_sendmail () fi if test $? -eq 0; then func_verbose "...succeeded." - $RM $my_infile + $opt_dry_run || $RM $my_infile else func_fatal_error "Mail delivery failed, draft mail is in $my_infile" fi } +# func_extract_email_from_header re_header headerfile +func_extract_email () +{ + my_re_header="$1" + my_headerfile="$2" + $as_unset func_extract_email_result + + save_IFS="$IFS" + IFS=' +' + for to in : `grep "$my_re_header" "$my_headerfile" 2>/dev/null`; do + IFS="$save_IFS" + test "X$to" = X: && continue + + line=`echo "$to" | $SED "s,$my_re_header,,"` + + IFS=, + for addr in $line; do + IFS="$save_IFS" + func_quote_for_eval "$addr" + to_addr=`echo "$func_quote_for_eval_result" | $SED "$sed_mail_address"` + test -n "$to_addr" || to_addr="$func_quote_for_eval_result" + func_extract_email_result="${func_extract_email_result+$func_extract_email_result }$to_addr" + done + done + IFS="$save_IFS" +} ## ----- ## ## main. ## @@ -333,47 +329,57 @@ func_sendmail () { tmp_dir="`func_mktempdir`" + headers="$tmp_dir/headers" fname="$tmp_dir/mail" + trap '$RM -r "$tmp_dir"; exit $EXIT_FAILURE' 1 2 15 # Generate a comma separated list of destination addresses for the # mail headers: - destination="" + $as_unset destination for to in : ${1+"$@"} do test "X$to" = X: && continue func_quote_for_eval "$to" - - case $destination in - "") destination="$func_quote_for_eval_result" ;; - *) destination="$destination, $func_quote_for_eval_result" ;; - esac + destination="${destination+$destination, }$func_quote_for_eval_result" done - func_headers "$fname" "$destination" - if test $multipart -gt 1; then + + if test $opt_filename_num -gt 1; then func_multipart_content "$fname" else func_single_content "$fname" fi - # Generate a space delimited list of destination addresses for sendmail: - if test -z "$outputfile"; then - destination="" + # Generate a list of destination addresses for sendmail: + if test -z "$opt_output_file"; then + $as_unset destination for to in : ${1+"$@"} do test "X$to" = X: && continue func_quote_for_eval "$to" - to_addr=`echo "$func_quote_for_eval_result" | sed "$sed_mail_address"` + to_addr=`echo "$func_quote_for_eval_result" | $SED "$sed_mail_address"` test -n "$to_addr" || to_addr="$func_quote_for_eval_result" - destination="$destination $to_addr" + destination="${destination+$destination }$to_addr" done - func_sendmail "$fname" "$destination" "$from" + func_extract_email '^To: *' "$opt_headers" + destination="${destination+$destination }$func_extract_email_result" + func_extract_email '^Cc: *' "$opt_headers" + destination="${destination+$destination }$func_extract_email_result" + func_extract_email '^Bcc: *' "$opt_headers" + destination="${destination+$destination }$func_extract_email_result" + + test -n "$opt_from" || { + func_extract_email '^From: *' "$opt_headers" + opt_from="$func_extract_email_result" + } + + func_sendmail "$fname" "$destination" "$opt_from" else - mv $fname $outputfile || exit $EXIT_FAILURE + mv $fname $opt_output_file || exit $EXIT_FAILURE fi $RM -r "$tmp_dir" -- 1.7.1