Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
annotate bin/bsmtp2dma @ 120:5366fb3b222c
Style
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Wed, 16 Oct 2019 00:03:08 +0200 |
| parents | 5c92aeaec114 |
| children | 61df67459e30 |
| rev | line source |
|---|---|
| 110 | 1 #!/bin/sh |
| 2 # -*- indent-tabs-mode: nil; -*- | |
| 3 : 'A simple replacement for Bacula `bsmtp` when the underlying mailer does | |
| 4 not listen on TCP ports (e.g. `dma`, `ssmtp` et al.). | |
| 5 | |
| 6 :Author: Franz Glasner | |
| 7 :Copyright: (c) 2019 Franz Glasner. | |
| 8 All rights reserved. | |
| 9 :License: BSD 3-Clause "New" or "Revised" License. | |
| 10 See LICENSE for details. | |
| 11 If you cannot find LICENSE see | |
| 12 <https://opensource.org/licenses/BSD-3-Clause> | |
| 13 :ID: @(#)@@PKGORIGIN@@ $HGid$ | |
| 14 | |
| 15 ' | |
| 16 | |
| 17 VERSION="@@VERSION@@" | |
| 18 | |
| 19 USAGE=' | |
| 20 USAGE: bsmtp2dma [OPTIONS] RECIPIENT ... | |
| 21 | |
| 22 Options: | |
| 23 | |
| 111 | 24 -V Show the program version and usage and exit. |
| 25 | |
| 110 | 26 -8 Does nothing. Just a compatibility option for `bsmtp`. |
| 27 | |
| 111 | 28 -c ADDRESS Set then "CC:" header. |
| 29 | |
| 110 | 30 -d n Does nothing. Just a compatibility option for `bsmtp`. |
| 31 | |
| 32 -f ADDRESS Set the "From:" header. | |
| 33 | |
| 34 -h MAILHOST:PORT Does nothing. Just a compatibility option for `bsmtp`. | |
| 35 | |
| 111 | 36 -l NUMBER Does nothing. Just a compatibility option for `bsmtp`. |
| 110 | 37 |
| 38 -r ADDRESS Set the "Reply-To:" header | |
| 39 | |
| 111 | 40 -s SUBJECT Set the "Subject:" header |
| 110 | 41 |
| 42 | |
| 43 Usage: | |
| 44 | |
| 45 The body of the email message is read from standard input. Message is | |
| 46 ended by sending the `EOF` character (`Ctrl-D` on many systems) on the | |
| 47 start of a new line, much like many `mail` commands. | |
| 48 | |
| 49 ' | |
| 50 | |
| 51 # | |
| 52 # Configuration directory | |
| 53 # | |
| 54 : ${CONFIGDIR:=@@ETCDIR@@} | |
| 55 | |
| 56 test -r "${CONFIGDIR}/bsmtp2dma.conf" && . "${CONFIGDIR}/bsmtp2dma.conf" | |
| 57 | |
| 58 | |
| 111 | 59 # |
| 110 | 60 # Default configuration values |
| 111 | 61 # |
| 62 # `sendmail` is also valid for `dma` because of the mapping within | |
| 63 # `/etc/mail/mailer.conf` | |
| 64 # | |
| 110 | 65 : ${MAILER:=/usr/sbin/sendmail} |
| 66 | |
| 67 | |
| 68 parse_addr() { | |
| 69 : 'Parse an possibly complex email address. | |
| 70 | |
| 71 Addresses can be of the form | |
| 72 | |
| 73 - Name Parts <user@domain.tld> | |
| 74 - user@domain.tld | |
| 75 | |
| 76 `Name Parts` may not contain ``<`` or ``>`` characters. | |
| 77 | |
| 78 Args: | |
| 79 _addr: the complex email address | |
| 80 | |
| 81 Returns: | |
| 82 0 on success, 1 on errors | |
| 83 | |
| 84 Output (Globals): | |
| 85 email_name: the name part (or empty) | |
| 86 email_addr: the technical address part (or empty) | |
| 87 | |
| 88 ' | |
| 89 local _addr | |
| 90 | |
| 91 _addr="$1" | |
| 111 | 92 test -n "${_addr}" || return 1 |
| 110 | 93 |
| 94 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+<[^<>]+@[^<>]+>$'; then | |
| 95 email_name=$(printf '%s' "${_addr}" | sed -E -e 's/[[:space:]]*<.+$//') | |
| 96 email_addr=$(printf '%s' "${_addr}" | sed -E -e 's/^[^<>]+<//' | sed -E -e 's/>$//') | |
| 97 return 0 | |
| 98 fi | |
| 99 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+@[^<>]+$'; then | |
| 100 email_name="" | |
| 101 email_addr="${_addr}" | |
| 102 return 0 | |
| 103 fi | |
| 104 return 1 | |
| 105 } | |
| 106 | |
| 107 | |
| 108 send_mail() { | |
| 109 : 'Send the mail via the underlying configured mailer (dma, sendmail et al.). | |
| 110 | |
| 111 Args: | |
| 112 _recipient: The recipient name. | |
| 113 | |
| 114 Will be written into the "To:" header also. | |
| 115 | |
| 116 Input (Globals): | |
| 117 MAILER | |
| 118 MAILCONTENT | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
119 MAILFIFO_STDIN |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
120 MAILFIFO_STDOUT |
| 110 | 121 CC |
| 122 FROM | |
| 123 REPLYTO | |
| 124 SUBJECT | |
| 125 | |
| 126 Returns: | |
| 127 0 on success, other values on errors or the error exit code from the | |
| 128 underlying mailer | |
| 129 | |
| 111 | 130 This procedure starts the configured mailer as coproc and sends |
| 131 email headers and contents to the started mailer. | |
| 132 | |
| 110 | 133 ' |
| 111 | 134 local _recipient _rc _oifs _text _pid_mailer _recipient_addr |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
135 local _from_from _from_addr _sender_addr _dummy |
| 110 | 136 |
| 137 _recipient="$1" | |
| 138 _rc=0 | |
| 139 | |
| 111 | 140 if parse_addr "${_recipient}"; then |
| 141 _recipient_addr="${email_addr}" | |
| 142 else | |
| 143 echo "ERROR: unknown recipient address format in \`${_recipient}'" >&2 | |
| 144 return 1 | |
| 145 fi | |
| 146 _sender_addr="$(whoami)@$(hostname -f)" | |
| 147 if [ -z "${FROM}" ]; then | |
| 148 _from_addr="${_sender_addr}" | |
| 149 _from_from="${_from_addr}" | |
| 150 else | |
| 151 if parse_addr "${FROM}"; then | |
| 152 _from_from="${FROM}" | |
| 153 _from_addr="${email_addr}" | |
| 154 else | |
| 155 echo "ERROR: unknown sender name in \`${FROM}'" >&2 | |
| 156 return 1 | |
| 157 fi | |
| 158 fi | |
| 159 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
160 mkfifo -m 0600 "${MAILFIFO_STDIN}" |
| 110 | 161 _rc=$? |
| 162 if [ ${_rc} -ne 0 ]; then | |
| 163 return ${_rc} | |
| 164 fi | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
165 mkfifo -m 0600 "${MAILFIFO_STDOUT}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
166 _rc=$? |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
167 if [ ${_rc} -ne 0 ]; then |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
168 rm -f "${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
169 return ${_rc} |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
170 fi |
| 110 | 171 |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
172 "$MAILER" -f "${_sender_addr}" "${_recipient_addr}" <${MAILFIFO_STDIN} >${MAILFIFO_STDOUT} & |
| 110 | 173 _pid_mailer=$! |
| 174 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
175 exec 3>"${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
176 exec 4<"${MAILFIFO_STDOUT}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
177 |
| 111 | 178 printf "To: %s\n" "${_recipient}" >&3 |
| 179 printf "From: %s\n" "${_from_from}" >&3 | |
| 180 if [ "${_sender_addr}" != "${_from_addr}" ]; then | |
| 181 printf "Sender: %s\n" "${_sender_addr}" >&3 | |
| 182 fi | |
| 183 if [ -n "${SUBJECT}" ]; then | |
| 184 printf "Subject: %s\n" "${SUBJECT}" >&3 | |
| 185 fi | |
| 186 if [ -n "${REPLYTO}" ]; then | |
| 114 | 187 # |
| 188 # XXX TBD proper Reply-To header value checks: | |
| 189 # a comma separated list of full mail addresses | |
| 190 # | |
| 111 | 191 printf "Reply-To: %s\n" "${REPLYTO}" >&3 |
| 192 fi | |
| 193 if [ -n "${CC}" ]; then | |
| 114 | 194 # |
| 195 # XXX TBD proper CC header value checks: | |
| 196 # a comma separated list of full mail addresses | |
| 197 # | |
| 111 | 198 printf "Cc: %s\n" "${CC}" >&3 |
| 199 fi | |
| 200 printf "\n" >&3 | |
| 201 | |
| 202 # preserve leading white space when reading with `read` | |
| 110 | 203 _oifs="$IFS" |
| 204 IFS=" | |
| 205 " | |
| 206 cat "${MAILCONTENT}" | | |
| 207 while read _text; do | |
| 208 printf "%s\n" "$_text" >&3 | |
| 209 done | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
210 # not all mailer recognize this |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
211 # printf ".\n" >&3 |
| 110 | 212 IFS="$_oifs" |
| 213 | |
| 214 # close the fd to the pipe: coproc should get EOF | |
| 215 exec 3>&- | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
216 # read eventually remaining stuff from the mailer until EOF |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
217 IFS='' read _dummy <&4 |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
218 exec 4<&- |
| 110 | 219 |
| 220 wait $_pid_mailer | |
| 221 _rc=$? | |
| 222 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
223 # we are done with the named pipes |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
224 rm -f "${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
225 rm -f "${MAILFIFO_STDOUT}" |
| 110 | 226 |
| 227 return ${_rc} | |
| 228 } | |
| 229 | |
| 230 | |
| 111 | 231 while getopts "V8c:d:f:h:l:nr:s:" _opt; do |
| 110 | 232 case ${_opt} in |
| 233 V) | |
| 234 echo "bsmtp2dma v${VERSION} (rv:@@HGREVISION@@)" | |
| 235 echo "$USAGE" | |
| 236 exit 0; | |
| 237 ;; | |
| 238 8) | |
| 239 : # VOID | |
| 240 ;; | |
| 241 c) | |
| 242 CC="$OPTARG" | |
| 243 ;; | |
| 111 | 244 d) |
| 245 : # VOID | |
| 246 ;; | |
| 110 | 247 f) |
| 248 FROM="$OPTARG" | |
| 249 ;; | |
| 250 h) | |
| 251 : # VOID | |
| 252 ;; | |
| 253 l) | |
| 254 : # VOID | |
| 255 ;; | |
| 256 r) | |
| 257 REPLYTO="$OPTARG" | |
| 258 ;; | |
| 259 s) | |
| 260 SUBJECT="$OPTARG" | |
| 261 ;; | |
| 262 \?) | |
| 263 exit 2; | |
| 264 ;; | |
| 265 *) | |
| 266 echo "ERROR: inconsistent option handling" >&2 | |
| 267 exit 2; | |
| 268 ;; | |
| 269 esac | |
| 270 done | |
| 271 | |
| 272 # return code | |
| 273 _rc=0 | |
| 274 | |
| 275 MAILTMPDIR="$(mktemp -d)" | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
276 MAILFIFO_STDIN="${MAILTMPDIR}/mail-stdin" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
277 MAILFIFO_STDOUT="${MAILTMPDIR}/mail-stdout" |
| 110 | 278 MAILCONTENT="${MAILTMPDIR}/mail-text" |
| 279 | |
| 280 # | |
| 281 # Clean up existing temporary stuff on all sorts of exit | |
| 282 # (including the "exit" call (signal 0)) | |
| 283 # | |
| 111 | 284 trap 'if [ -d "${MAILTMPDIR}" ]; then rm -rf "${MAILTMPDIR}"; fi; exit;' 0 1 2 15 |
| 110 | 285 |
| 286 test -d "${MAILTMPDIR}" || { echo "ERROR: no existing private tmp dir" >&2; exit 1; } | |
| 287 | |
| 288 # | |
| 289 # Reset the Shell's option handling system to prepare for handling | |
| 290 # other arguments and probably command-local options | |
| 291 # | |
| 292 shift $((OPTIND-1)) | |
| 293 OPTIND=1 | |
| 294 | |
| 295 # early check whether some recipients are given | |
| 296 if [ $# -eq 0 ]; then | |
| 297 echo "ERROR: no recipient given" >&2 | |
| 298 exit 2; | |
| 299 fi | |
| 300 | |
| 301 # | |
| 302 # Collect the mail text from stdin into a temporary file | |
| 303 # | |
| 304 exec 3>"${MAILCONTENT}" | |
| 111 | 305 # preserve leading white space when reading with `read` |
| 110 | 306 _oifs="$IFS" |
| 307 IFS=" | |
| 308 " | |
| 309 while read _text; do | |
| 310 if [ "${_text}" = "." ]; then | |
| 311 break | |
| 312 else | |
| 313 printf "%s\n" "${_text}" >&3 | |
| 314 fi | |
| 315 done | |
| 316 exec 3>&- | |
| 317 IFS="$_oifs" | |
| 318 | |
| 319 # | |
| 320 # Now send the content of the collected mail content to all recipients | |
| 321 # | |
| 322 until [ $# -eq 0 ]; do | |
| 323 send_mail "$1" | |
| 324 _rcsm=$? | |
| 325 if [ \( ${_rcsm} -ne 0 \) -a \( ${_rc} -eq 0 \) ]; then | |
| 326 _rc=${_rcsm} | |
| 327 fi | |
| 328 shift | |
| 329 done | |
| 330 | |
| 331 exit ${_rc} |
