| AS_INIT[]m4_divert_push([HEADER-COPYRIGHT])dnl |
| # @configure_input@ |
| |
| # mailnotify (GNU @PACKAGE@) version 1.0 |
| # Written by Gary V. Vaughan <gary@gnu.org> |
| |
| # 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. |
| |
| # Mailnotify is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 2 of the License, or |
| # (at your option) any later version. |
| # |
| # Mailnotify is distributed in the hope that it will be useful, but |
| # WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with mailnotify; see the file COPYING. If not, a copy |
| # can be downloaded from http://www.gnu.org/licenses/gpl.html, |
| # or obtained by writing to the Free Software Foundation, Inc., |
| # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| |
| # Usage: $progname [OPTIONS]... |
| # |
| # -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 |
| # -o FILE --output-file=FILE output to FILE instead of sending |
| # -v --verbose run in verbose mode |
| # --version print version information |
| # -? --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 |
| # various ways: not setting the mime-type correctly, line wrapping the |
| # patch itself, escaping certain values, etc. This script is designed to |
| # make it easier to send a patch as a MIME attachment, though it is general |
| # enough that it might be useful otherwise. |
| |
| # For example to send a patch as an attachment, assuming the patch itself |
| # is in PATCHFILE: |
| # |
| # echo 'From: me@example.org' > headers |
| # echo 'To: patch-list@foo.org' >> headers |
| # echo 'Subject: FYI: PATCHFILE' >> headers |
| # echo 'Cc: someone@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 |
| # saves you a lot of typing. |
| |
| # Report bugs to <gary@gnu.org> |
| |
| : ${HOST=`hostname`} |
| : ${SENDMAIL=sendmail} |
| |
| PROGRAM=mailnotify |
| |
| m4_divert_pop |
| m4_include([getopt.m4sh]) |
| |
| M4SH_VERBATIM([[ |
| sed_mail_address='s,^.*<\(.*\)>.*$,\1,' |
| ]]) |
| |
| 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], [], [], |
| [f@+], [--filename], [], [], |
| [h@!], [--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 \"\$opt_filename_$opt_filename_num\" || |
| func_fatal_error "-f is required." |
| eval test -n \"\$opt_mime_type_$opt_mime_type_num\" || |
| func_fatal_error "with output directed to a file, -m is required" |
| fi |
| |
| # 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 |
| # separated list of fully qualified destination addresses. |
| func_headers () |
| { |
| $opt_debug |
| |
| my_outfile="$1" |
| my_destination="$2" |
| my_sed_version_no=' |
| /^# '$PROGRAM' (GNU / { |
| s/^# .*version // |
| p |
| } |
| d' |
| |
| $opt_dry_run || { |
| echo "User-Agent: $PROGRAM/`$SED \"$my_sed_version_no\" < $progpath`" |
| echo "MIME-Version: 1.0" |
| |
| # 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" |
| |
| : |
| } |
| |
| |
| # func_single_content outfile |
| # Send the only message part as a single mime mail part. |
| func_single_content () |
| { |
| $opt_debug |
| |
| my_outfile="$1" |
| |
| $opt_dry_run || cat >> "$my_outfile" <<EOF |
| Content-Type: $opt_mime_type_1; |
| Content-Transfer-Encoding: 7bit |
| |
| `cat $opt_filename_1` |
| EOF |
| } |
| |
| |
| # func_multipart_content outfile |
| # Send the various message parts to OUTFILE as a multipart mime mail. |
| func_multipart_content () |
| { |
| $opt_debug |
| |
| my_outfile="$1" |
| boundary="boundary-${HOST}-$$-`date | tr ' :' -`" |
| $opt_dry_run || { |
| cat <<EOF >> "$my_outfile" |
| Content-Type: multipart/mixed; |
| boundary="$boundary" |
| |
| 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 $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" |
| } |
| |
| : |
| } |
| |
| |
| # func_sendmail infile destination [from] |
| # Send the message in INFILE to the space delimited list of destination |
| # addresses in DESTINATION. If FROM is given, it is the address the |
| # mail purports to be from. |
| # BEWARE: Many MTAs will refuse mail where FROM does not match the actual |
| # sending domain. |
| func_sendmail () |
| { |
| $opt_debug |
| |
| my_infile="$1" |
| 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" |
| |
| $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" |
| test -x "$SENDMAIL" || func_fatal_error "sendmail executable not found" |
| } |
| |
| func_verbose "Delivering mail, please wait..." |
| if test -n "$from_name"; then |
| $SENDMAIL -F "$from_name" -f "$from_addr" $my_destination < "$my_infile" |
| elif test -n "$from_addr"; then |
| $SENDMAIL -f "$from_addr" $my_destination < "$my_infile" |
| else |
| $SENDMAIL $my_destination < "$my_infile" |
| fi |
| if test $? -eq 0; then |
| func_verbose "...succeeded." |
| $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 () |
| { |
| $opt_debug |
| |
| 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. ## |
| ## ----- ## |
| |
| { |
| 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: |
| $as_unset destination |
| for to in : ${1+"$@"} |
| do |
| test "X$to" = X: && continue |
| |
| func_quote_for_eval "$to" |
| destination="${destination+$destination, }$func_quote_for_eval_result" |
| done |
| func_headers "$fname" "$destination" |
| |
| if test $opt_filename_num -gt 1; then |
| func_multipart_content "$fname" |
| else |
| func_single_content "$fname" |
| fi |
| |
| # 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"` |
| test -n "$to_addr" || to_addr="$func_quote_for_eval_result" |
| destination="${destination+$destination }$to_addr" |
| done |
| 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 $opt_output_file || exit $EXIT_FAILURE |
| fi |
| |
| $RM -r "$tmp_dir" |
| } |
| |
| exit $EXIT_SUCCESS |
| |
| # Local Variables: |
| # mode:shell-script |
| # sh-indentation:2 |
| # End: |
| ]]) |
| |