/usr/bin/mh/mhmail is in nmh 1.6-2.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | #! /bin/sh
#
# mhmail -- simple mail 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.
#
# Emulation of compiled mhmail(1), with these differences:
# * Adds -send/-nosend, -headerfield, and -attach options.
# * Adds optional -to switch for recipient addresses.
# * Supports all post(8) (by default, without -profile) or send(1)
# (with -profile) options.
# * Optionally (with -profile) obeys the users profile, including
# AliasFile and send entries.
# * Instead of silently not sending an empty message, notifies user
# "mhmail: empty message not sent, use -body '' to force."
# * The compiled mhmail dropped a trailing newline from the -body argument.
# * Drops support for undocumented -queue option.
usage='Usage: mhmail [-t(o)] addrs ... [switches]
switches are:
-at(tach) file [-at(tach) file] ...
-b(ody) text
-c(c) addrs ...
-f(rom) addr
-hea(derfield) name:value [-hea(derfield) name:value] ...
-su(bject) text
-r(esent)
-pr(ofile)
-se(nd)
-nose(nd)
-v(ersion)
-hel(p)
and all post(8)/send(1) switches
mhmail with no arguments is equivalent to inc'
#### 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
}
#### Convenience function to allow concise code below.
die() {
[ $# -gt 0 ] && printf '%s\n' "$1" >&2
exit 1
}
bindir=`finddir $0`
nmhbindir=`cd "$bindir" && pwd`
nmhlibdir=`$nmhbindir/mhparam libdir`
case `printf 'OK\n' | tail -n 1 2>&1` in
OK) tail='tail -n ' ;;
*) tail='tail -' ;;
esac
#### Checks for missing mandatory arguments.
checkforargs() {
if [ $attacharg -eq 1 ]; then
die 'mhmail: missing argument to -attach'
elif [ $bodyarg -eq 1 ]; then
die 'mhmail: missing argument to -body'
elif [ $ccarg -eq 1 -a "$cclist"x = x ]; then
die 'mhmail: missing argument to -cc'
elif [ $fromarg -eq 1 ]; then
die 'mhmail: missing argument to -from'
elif [ $headerfieldarg -eq 1 ]; then
die 'mhmail: missing argument to -headerfield'
elif [ $subjectarg -eq 1 ]; then
die 'mhmail: missing argument to -subject'
elif [ $toarg -eq 1 ]; then
die 'mhmail: missing argument to -to'
fi
}
if [ $# -eq 0 ]; then
#### Emulate mhmail for reading mail.
exec "$nmhbindir"/inc
fi
#### Go through all the switches so we can build the draft.
tolist= ## To: addresses
toarg=0 ## whether currently handling -to
attacharg=0 ## whether currently handling -attach
attachind=Attach ## attachment indicator
body= ## contents of the message body
bodyarg=0 ## whether currently handling -body
cclist= ## Cc: addresses
ccarg=0 ## whether currently handling -cc
from= ## From: contents
fromarg=0 ## whether currently handling -from
headerfieldlist= ## header fields to be added to draft
headerfieldarg=0 ## whether currently handling -headerfield
mhmailswitch=0 ## whether currently handling any mhmail switch
subject= ## Subject: contents
subjectarg=0 ## whether currently handling -subject
resent=0 ## whether resending
postsendargs= ## switches to pass on to post or send
post_send_switch_arg=0 ## whether currently handling a post/send switch
use_send=0 ## use post (default) or send (-profile)
sendsw=1 ## to send (default) or not to send
for arg in "$@"; do
case $arg in
#### Post and send won't accept -f -or -s because they'd be
#### ambiguous, so no conflicts with them. And they don't have
#### -b, -c, -r, -t. For the new switches that compiled mhmail
#### didn't have: let -p indicate mhmail -profile, not send
#### -port. -send masks the send(1) -send switch. -attach
#### masks the send(1) -attach switch.
-at|-att|-atta|-attac|-attach)
mhmailswitch=1
attacharg=1
use_send=1
;;
-b|-bo|-bod|-body) mhmailswitch=1; bodyarg=1 ;;
-c|-cc) mhmailswitch=1; ccarg=1 ;;
-f|-fr|-fro|-from) mhmailswitch=1; fromarg=1 ;;
-hea|-head|-heade|-header|-headerf|-headerfi|-headerfie|-headerfiel|\
-headerfield) mhmailswitch=1; headerfieldarg=1 ;;
-hel|-help) printf '%s\n' "$usage"; exit ;;
-nose|-nosen|-nosend) mhmailswitch=1; sendsw=0 ;;
-p|-pr|-pro|-prof|-profi|-profil|-profile) mhmailswitch=1; use_send=1 ;;
-resend) die 'mhmail: did you mean -resent instead of -resend?' ;;
-r|-re|-res|-rese|-resen|-resent) mhmailswitch=1; resent=1 ;;
-se|-sen|-send) mhmailswitch=1; sendsw=1 ;;
-su|-sub|-subj|-subje|-subjec|-subject) mhmailswitch=1; subjectarg=1 ;;
-t|-to) toarg=1; ccarg=0 ;;
-v|-ve|-ver|-vers|-versi|-versio|-version)
#### Cheat instead of using autoconf and make to fill in the version.
"$nmhbindir"/mhpath -v | sed 's/mhpath/mhmail/'; exit ;;
-*) if [ $mhmailswitch -eq 1 ]; then
checkforargs
mhmailswitch=0
fi
post_send_switch_arg=1
postsendargs="${postsendargs:+$postsendargs }$arg" ;;
*) mhmailswitch=0
if [ $bodyarg -eq 1 ]; then
body="$arg
"
bodyarg=0
#### Allow -body "" by using just a newline for the body.
[ "$body"x = x ] && body='
'
elif [ $fromarg -eq 1 ]; then
from="$arg"
fromarg=0
elif [ $subjectarg -eq 1 ]; then
subject="$arg"
subjectarg=0
elif [ $attacharg -eq 1 ]; then
headerfieldlist="${headerfieldlist:+$headerfieldlist}$attachind: $arg
"
attacharg=0
elif [ $headerfieldarg -eq 1 ]; then
#### It's not strictly necessary to have one space after
#### the : that separates the header field name from the
#### body, but do it to avoid surprising someone.
#### Solaris sed wants the trailing newline in its input.
add=`printf '%s\n' "$arg" | sed -e 's/:/: /' -e 's/: /: /'`
headerfieldlist="${headerfieldlist:+$headerfieldlist}$add
"
headerfieldarg=0
elif [ $post_send_switch_arg -eq 1 ]; then
postsendargs="${postsendargs:+$postsendargs }$arg"
elif [ $ccarg -eq 1 ]; then
#### ccarg can only be reset to 0 by -to.
cclist="${cclist:+$cclist, }$arg"
else
#### An address.
tolist="${tolist:+$tolist, }$arg"
toarg=0
fi ;;
esac
done
#### Check for at least one address and -from.
if [ "$tolist"x = x ]; then
die 'Usage: mhmail [-t(o)] addrs ... [switches]'
fi
if [ "$from"x = x ]; then
from=`${nmhlibdir}/ap -format '%(localmbox)' 0`
fi
#### Check for missing mandatory arguments.
checkforargs
#### Build header.
[ $resent -eq 0 ] && prefix= || prefix='Resent-'
header="${prefix}To: $tolist
"
[ "$cclist"x = x ] || header="$header${prefix}Cc: $cclist
"
[ "$subject"x = x ] || header="$header${prefix}Subject: $subject
"
[ "$from"x = x ] || header="$header${prefix}From: $from
"
if [ "$headerfieldlist" ]; then
header="$header$headerfieldlist"
fi
#### Set up a file to supply as a draft to post/send. And set a trap
#### to remove it. send moves the file to a backup and can create a
#### .orig file, so it will remove them, too.
umask 077
tmpdir="${MHTMPDIR:-${TMPDIR:-`$nmhbindir/mhpath +`}}"
tmpfilename=`cd "$tmpdir" && "${nmhlibdir}/mkstemp" -p mhmail`
[ $? -ne 0 ] && die "mhmail: failed to create temporary file in $tmpdir"
tmpfile="$tmpdir/$tmpfilename"
backup_char=`"$nmhbindir"/mhparam sbackup`
tmpfilebackup="$tmpdir/${backup_char}${tmpfilename}*"
tmpfileresent=
message_file=
if [ $resent -eq 0 ]; then
#### Add blank line after header if not resending.
header="$header
"
message_file="$tmpfile"
else
if [ $use_send -eq 0 ]; then
postsendargs="${postsendargs:+$postsendargs }-dist"
message_file="$tmpfile"
else
#### When resending with send, tmpfile will just contain the
#### Resent- header fields. "$tmpfileresent" will contain
#### the message that is being resent.
tmpfileresent=`"${nmhlibdir}/mkstemp" -d "$tmpdir" -p mhmail-resent`
[ $? -ne 0 ] && die "mhmail: failed to create temporary file in $tmpdir"
mhdist=1; export mhdist
mhaltmsg=$tmpfileresent; export mhaltmsg
message_file="$tmpfileresent"
printf '' >"$message_file" || exit 2
fi
fi
trap "rm -f '$tmpfile' $tmpfilebackup ${tmpfileresent:+'$tmpfileresent'}" 0
if [ "$body"x = x ]; then
#### First put message header in the file.
printf %s "$header" >"$tmpfile" || exit 2
tmpfile_size_before=`wc -c "$message_file"`
#### Now grab the body from stdin. cat >> handles blank lines
#### better than body=`cat`.
cat >>"$message_file" || exit 2
tmpfile_size_after=`wc -c "$message_file"`
#### Don't allow an empty body (from stdin). Use string
#### comparison so we don't have to strip the filename, etc.
if [ "$tmpfile_size_before" = "$tmpfile_size_after" ]; then
die 'mhmail: empty message not sent, use -body '"''"' to force.'
fi
#### Add trailing newline to body if it doesn't have one.
if [ `${tail}1 "$message_file" | wc -l` -ne 1 ]; then
printf '\n' >>"$message_file" || exit 2
fi
else
#### Add trailing newline to body if it doesn't have one.
[ `printf %s "$body" | ${tail}1 | wc -l` -ne 1 ] && body="$body
"
if [ "$tmpfileresent" ]; then
#### Put just the new message header in the file.
printf %s "$header" >"$tmpfile" || exit 2
#### and the body in the file to resend.
printf %s "$body" >"$tmpfileresent" || exit 2
else
#### Put message header and body in the file.
printf %s "$header$body" >"$tmpfile" || exit 2
fi
fi
if [ $sendsw -eq 0 ]; then
cat "$tmpfile"
else
if [ $use_send -eq 0 ]; then
post_or_send=`$nmhbindir/mhparam postproc`
else
post_or_send="$nmhbindir/send"
fi
if "$post_or_send" "$tmpfile" $postsendargs; then
exit
else
status=$?
mv -f "$tmpfile" dead.letter
printf 'Letter saved in dead.letter\n' >&2
exit $status
fi
fi
|