Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
annotate sbin/bsmtp2dma @ 723:a97ec3f07bdb
farray.sh: REFACTOR: More flexible metadata retrieval.
Using an array or alist variable name or token value (with prefix) is now
supported in every function.
This is possible because the value prefixes contain questin marks (?) which
are not allowed in shell variable names.
This again is a major precondition for recursive data structures
(arrays/alists in arrays/alists).
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 05 Oct 2024 21:55:55 +0200 |
| parents | 599fddb2370d |
| children | e2f262ec2bf4 |
| 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 | |
|
438
9c3b1966ba91
Extend copyright to 2024
Franz Glasner <fzglas.hg@dom66.de>
parents:
386
diff
changeset
|
7 :Copyright: (c) 2019-2024 Franz Glasner. |
| 110 | 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> | |
|
386
84d2735fe7f6
Simplified version tagging a lot: it is also faster now.
Franz Glasner <fzglas.hg@dom66.de>
parents:
317
diff
changeset
|
13 :ID: @(#)@@SIMPLEVERSIONTAG@@ |
| 110 | 14 |
| 15 ' | |
| 16 | |
|
643
4f2257ea7d0a
shellcheck: disable SC2034: VERSION appears unused...
Franz Glasner <fzglas.hg@dom66.de>
parents:
550
diff
changeset
|
17 # shellcheck disable=SC2034 # VERSION appears unused |
|
550
847ae246f3cc
Make the port really DATADIR and EXAMPLESDIR safe because the user may redefine DATADIR and EXAMPLESDIR.
Franz Glasner <fzglas.hg@dom66.de>
parents:
537
diff
changeset
|
18 VERSION='@@VERSION@@' |
| 110 | 19 |
| 20 USAGE=' | |
| 21 USAGE: bsmtp2dma [OPTIONS] RECIPIENT ... | |
| 22 | |
| 23 Options: | |
| 24 | |
| 111 | 25 -V Show the program version and usage and exit. |
| 26 | |
| 110 | 27 -8 Does nothing. Just a compatibility option for `bsmtp`. |
| 28 | |
|
316
dc3ac7fc06ea
Typo: "Fix then " -> "Fix the "
Franz Glasner <fzglas.hg@dom66.de>
parents:
145
diff
changeset
|
29 -c ADDRESS Set the "CC:" header. |
| 111 | 30 |
| 110 | 31 -d n Does nothing. Just a compatibility option for `bsmtp`. |
| 32 | |
| 33 -f ADDRESS Set the "From:" header. | |
| 34 | |
| 35 -h MAILHOST:PORT Does nothing. Just a compatibility option for `bsmtp`. | |
| 36 | |
| 111 | 37 -l NUMBER Does nothing. Just a compatibility option for `bsmtp`. |
| 110 | 38 |
| 39 -r ADDRESS Set the "Reply-To:" header | |
| 40 | |
| 111 | 41 -s SUBJECT Set the "Subject:" header |
| 110 | 42 |
| 43 | |
|
123
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
44 Files: |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
45 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
46 The shell style configuration file in |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
47 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
48 @@ETCDIR@@/bsmtp2dma.conf is |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
49 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
50 sourced in at script start. |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
51 |
| 110 | 52 ' |
| 53 | |
| 54 # | |
| 55 # Configuration directory | |
| 56 # | |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
57 : ${CONFIGDIR:="@@ETCDIR@@"} |
| 110 | 58 |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
59 [ -r "${CONFIGDIR}/bsmtp2dma.conf" ] && . "${CONFIGDIR}/bsmtp2dma.conf" |
| 110 | 60 |
| 61 | |
| 111 | 62 # |
| 110 | 63 # Default configuration values |
| 111 | 64 # |
| 65 # `sendmail` is also valid for `dma` because of the mapping within | |
| 66 # `/etc/mail/mailer.conf` | |
| 67 # | |
| 110 | 68 : ${MAILER:=/usr/sbin/sendmail} |
| 69 | |
| 70 | |
| 71 parse_addr() { | |
| 72 : 'Parse an possibly complex email address. | |
| 73 | |
| 74 Addresses can be of the form | |
| 75 | |
| 76 - Name Parts <user@domain.tld> | |
| 77 - user@domain.tld | |
| 78 | |
| 79 `Name Parts` may not contain ``<`` or ``>`` characters. | |
| 80 | |
| 81 Args: | |
| 82 _addr: the complex email address | |
| 83 | |
| 84 Returns: | |
| 85 0 on success, 1 on errors | |
| 86 | |
| 87 Output (Globals): | |
| 88 email_name: the name part (or empty) | |
| 89 email_addr: the technical address part (or empty) | |
| 90 | |
| 91 ' | |
| 92 local _addr | |
| 93 | |
| 94 _addr="$1" | |
| 111 | 95 test -n "${_addr}" || return 1 |
| 110 | 96 |
|
537
62cd970aea9c
Replace the use of "deprecated" egrep calls with "grep -E"
Franz Glasner <fzglas.hg@dom66.de>
parents:
438
diff
changeset
|
97 if printf "%s" "${_addr}" | /usr/bin/grep -q -E -e '^[^<>]+<[^<>]+@[^<>]+>$'; then |
| 110 | 98 email_name=$(printf '%s' "${_addr}" | sed -E -e 's/[[:space:]]*<.+$//') |
| 99 email_addr=$(printf '%s' "${_addr}" | sed -E -e 's/^[^<>]+<//' | sed -E -e 's/>$//') | |
| 100 return 0 | |
| 101 fi | |
|
537
62cd970aea9c
Replace the use of "deprecated" egrep calls with "grep -E"
Franz Glasner <fzglas.hg@dom66.de>
parents:
438
diff
changeset
|
102 if printf "%s" "${_addr}" | /usr/bin/grep -q -E -e '^[^<>]+@[^<>]+$'; then |
| 110 | 103 email_name="" |
| 104 email_addr="${_addr}" | |
| 105 return 0 | |
| 106 fi | |
| 107 return 1 | |
| 108 } | |
| 109 | |
| 110 | |
| 111 send_mail() { | |
| 112 : 'Send the mail via the underlying configured mailer (dma, sendmail et al.). | |
| 113 | |
| 114 Args: | |
| 115 _recipient: The recipient name. | |
| 116 | |
| 117 Will be written into the "To:" header also. | |
| 118 | |
| 119 Input (Globals): | |
| 120 MAILER | |
| 121 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
|
122 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
|
123 MAILFIFO_STDOUT |
| 110 | 124 CC |
| 125 FROM | |
| 126 REPLYTO | |
| 127 SUBJECT | |
| 128 | |
| 129 Returns: | |
| 130 0 on success, other values on errors or the error exit code from the | |
| 131 underlying mailer | |
| 132 | |
| 111 | 133 This procedure starts the configured mailer as coproc and sends |
| 134 email headers and contents to the started mailer. | |
| 135 | |
| 110 | 136 ' |
| 111 | 137 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
|
138 local _from_from _from_addr _sender_addr _dummy |
| 110 | 139 |
| 140 _recipient="$1" | |
| 141 _rc=0 | |
| 142 | |
| 111 | 143 if parse_addr "${_recipient}"; then |
| 144 _recipient_addr="${email_addr}" | |
| 145 else | |
| 146 echo "ERROR: unknown recipient address format in \`${_recipient}'" >&2 | |
| 147 return 1 | |
| 148 fi | |
| 149 _sender_addr="$(whoami)@$(hostname -f)" | |
| 150 if [ -z "${FROM}" ]; then | |
| 151 _from_addr="${_sender_addr}" | |
| 152 _from_from="${_from_addr}" | |
| 153 else | |
| 154 if parse_addr "${FROM}"; then | |
| 155 _from_from="${FROM}" | |
| 156 _from_addr="${email_addr}" | |
| 157 else | |
| 158 echo "ERROR: unknown sender name in \`${FROM}'" >&2 | |
| 159 return 1 | |
| 160 fi | |
| 161 fi | |
| 162 | |
|
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
|
163 mkfifo -m 0600 "${MAILFIFO_STDIN}" |
| 110 | 164 _rc=$? |
| 165 if [ ${_rc} -ne 0 ]; then | |
| 166 return ${_rc} | |
| 167 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
|
168 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
|
169 _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 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
|
171 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
|
172 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
|
173 fi |
| 110 | 174 |
| 121 | 175 # |
| 176 # Start the mailer **before** opening the pipe; otherwise a | |
| 177 # deadlock occurs | |
| 178 # | |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
179 "$MAILER" -f "${_sender_addr}" "${_recipient_addr}" <"${MAILFIFO_STDIN}" >"${MAILFIFO_STDOUT}" & |
| 110 | 180 _pid_mailer=$! |
| 181 | |
|
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
|
182 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
|
183 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
|
184 |
| 111 | 185 printf "To: %s\n" "${_recipient}" >&3 |
| 186 printf "From: %s\n" "${_from_from}" >&3 | |
| 187 if [ "${_sender_addr}" != "${_from_addr}" ]; then | |
| 188 printf "Sender: %s\n" "${_sender_addr}" >&3 | |
| 189 fi | |
| 190 if [ -n "${SUBJECT}" ]; then | |
| 191 printf "Subject: %s\n" "${SUBJECT}" >&3 | |
| 192 fi | |
| 193 if [ -n "${REPLYTO}" ]; then | |
| 114 | 194 # |
| 195 # XXX TBD proper Reply-To header value checks: | |
| 196 # a comma separated list of full mail addresses | |
| 197 # | |
| 111 | 198 printf "Reply-To: %s\n" "${REPLYTO}" >&3 |
| 199 fi | |
| 200 if [ -n "${CC}" ]; then | |
| 114 | 201 # |
| 202 # XXX TBD proper CC header value checks: | |
| 203 # a comma separated list of full mail addresses | |
| 204 # | |
| 111 | 205 printf "Cc: %s\n" "${CC}" >&3 |
| 206 fi | |
| 207 printf "\n" >&3 | |
| 208 | |
| 209 # preserve leading white space when reading with `read` | |
| 110 | 210 _oifs="$IFS" |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
211 IFS=$'\n' |
|
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
212 while read -r _text; do |
|
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
213 printf "%s\n" "$_text" >&3 |
|
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
214 done <"${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
|
215 # 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
|
216 # printf ".\n" >&3 |
| 110 | 217 IFS="$_oifs" |
| 218 | |
| 121 | 219 # close the fd to the pipe: coproc should get EOF and terminate |
| 110 | 220 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
|
221 # read eventually remaining stuff from the mailer until EOF |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
222 IFS='' read -r _dummy <&4 |
|
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 exec 4<&- |
| 110 | 224 |
| 225 wait $_pid_mailer | |
| 226 _rc=$? | |
| 227 | |
|
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
|
228 # 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
|
229 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
|
230 rm -f "${MAILFIFO_STDOUT}" |
| 110 | 231 |
| 232 return ${_rc} | |
| 233 } | |
| 234 | |
| 235 | |
| 111 | 236 while getopts "V8c:d:f:h:l:nr:s:" _opt; do |
| 110 | 237 case ${_opt} in |
| 238 V) | |
|
386
84d2735fe7f6
Simplified version tagging a lot: it is also faster now.
Franz Glasner <fzglas.hg@dom66.de>
parents:
317
diff
changeset
|
239 printf 'bsmtp2dma %s\n' '@@SIMPLEVERSIONSTR@@' |
| 110 | 240 echo "$USAGE" |
| 241 exit 0; | |
| 242 ;; | |
| 243 8) | |
| 244 : # VOID | |
| 245 ;; | |
| 246 c) | |
| 247 CC="$OPTARG" | |
| 248 ;; | |
| 111 | 249 d) |
| 250 : # VOID | |
| 251 ;; | |
| 110 | 252 f) |
| 253 FROM="$OPTARG" | |
| 254 ;; | |
| 255 h) | |
| 256 : # VOID | |
| 257 ;; | |
| 258 l) | |
| 259 : # VOID | |
| 260 ;; | |
| 261 r) | |
| 262 REPLYTO="$OPTARG" | |
| 263 ;; | |
| 264 s) | |
| 265 SUBJECT="$OPTARG" | |
| 266 ;; | |
| 267 \?) | |
| 268 exit 2; | |
| 269 ;; | |
| 270 *) | |
| 271 echo "ERROR: inconsistent option handling" >&2 | |
| 272 exit 2; | |
| 273 ;; | |
| 274 esac | |
| 275 done | |
| 276 | |
| 277 # return code | |
| 278 _rc=0 | |
| 279 | |
| 280 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
|
281 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
|
282 MAILFIFO_STDOUT="${MAILTMPDIR}/mail-stdout" |
| 110 | 283 MAILCONTENT="${MAILTMPDIR}/mail-text" |
| 284 | |
| 285 # | |
| 286 # Clean up existing temporary stuff on all sorts of exit | |
| 287 # (including the "exit" call (signal 0)) | |
| 288 # | |
| 111 | 289 trap 'if [ -d "${MAILTMPDIR}" ]; then rm -rf "${MAILTMPDIR}"; fi; exit;' 0 1 2 15 |
| 110 | 290 |
| 291 test -d "${MAILTMPDIR}" || { echo "ERROR: no existing private tmp dir" >&2; exit 1; } | |
| 292 | |
| 293 # | |
| 294 # Reset the Shell's option handling system to prepare for handling | |
| 295 # other arguments and probably command-local options | |
| 296 # | |
| 297 shift $((OPTIND-1)) | |
| 298 OPTIND=1 | |
| 299 | |
| 300 # early check whether some recipients are given | |
| 301 if [ $# -eq 0 ]; then | |
| 302 echo "ERROR: no recipient given" >&2 | |
| 303 exit 2; | |
| 304 fi | |
| 305 | |
| 306 # | |
| 307 # Collect the mail text from stdin into a temporary file | |
| 308 # | |
| 309 exec 3>"${MAILCONTENT}" | |
| 111 | 310 # preserve leading white space when reading with `read` |
| 110 | 311 _oifs="$IFS" |
|
704
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
312 IFS=$'\n' |
|
599fddb2370d
bsmtp2dma: Some modernizations: use "read -r" and enhance some quoting
Franz Glasner <fzglas.hg@dom66.de>
parents:
643
diff
changeset
|
313 while read -r _text; do |
| 110 | 314 if [ "${_text}" = "." ]; then |
| 315 break | |
| 316 else | |
| 317 printf "%s\n" "${_text}" >&3 | |
| 318 fi | |
| 319 done | |
| 320 exec 3>&- | |
| 321 IFS="$_oifs" | |
| 322 | |
| 323 # | |
| 324 # Now send the content of the collected mail content to all recipients | |
| 325 # | |
| 326 until [ $# -eq 0 ]; do | |
| 327 send_mail "$1" | |
| 328 _rcsm=$? | |
| 329 if [ \( ${_rcsm} -ne 0 \) -a \( ${_rc} -eq 0 \) ]; then | |
| 330 _rc=${_rcsm} | |
| 331 fi | |
| 332 shift | |
| 333 done | |
| 334 | |
| 335 exit ${_rc} |
