comparison bin/bsmtp2dma @ 110:af4eeb94144a

Begin bsmtp2dma tool
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 14 Oct 2019 09:47:34 +0200
parents
children fa73423234bf
comparison
equal deleted inserted replaced
109:0bd594fb56f8 110:af4eeb94144a
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
24 -8 Does nothing. Just a compatibility option for `bsmtp`.
25
26 -d n Does nothing. Just a compatibility option for `bsmtp`.
27
28 -f ADDRESS Set the "From:" header.
29
30 -h MAILHOST:PORT Does nothing. Just a compatibility option for `bsmtp`.
31
32 -n Do a dry-run: just print out what would be done
33
34 -s SUBJECT Set the "Subject:" header
35
36 -r ADDRESS Set the "Reply-To:" header
37
38 -l NUMBER Does nothing. Just a compatibility option for `bsmtp`.
39
40 -V Show the program version and usage and exit.
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
59 # Default configuration values
60 : ${MAILER:=/usr/sbin/sendmail}
61
62
63 parse_addr() {
64 : 'Parse an possibly complex email address.
65
66 Addresses can be of the form
67
68 - Name Parts <user@domain.tld>
69 - user@domain.tld
70
71 `Name Parts` may not contain ``<`` or ``>`` characters.
72
73 Args:
74 _addr: the complex email address
75
76 Returns:
77 0 on success, 1 on errors
78
79 Output (Globals):
80 email_name: the name part (or empty)
81 email_addr: the technical address part (or empty)
82
83 '
84 local _addr
85
86 _addr="$1"
87
88 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+<[^<>]+@[^<>]+>$'; then
89 email_name=$(printf '%s' "${_addr}" | sed -E -e 's/[[:space:]]*<.+$//')
90 email_addr=$(printf '%s' "${_addr}" | sed -E -e 's/^[^<>]+<//' | sed -E -e 's/>$//')
91 return 0
92 fi
93 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+@[^<>]+$'; then
94 email_name=""
95 email_addr="${_addr}"
96 return 0
97 fi
98 return 1
99 }
100
101
102 send_mail() {
103 : 'Send the mail via the underlying configured mailer (dma, sendmail et al.).
104
105 Args:
106 _recipient: The recipient name.
107
108 Will be written into the "To:" header also.
109
110 Input (Globals):
111 MAILER
112 MAILCONTENT
113 MAILFIFO
114 CC
115 FROM
116 REPLYTO
117 SUBJECT
118
119 Returns:
120 0 on success, other values on errors or the error exit code from the
121 underlying mailer
122
123 '
124 local _recipient _rc _oifs _text _pid_mailer
125
126 _recipient="$1"
127 _rc=0
128
129 mkfifo -m 0600 "${MAILFIFO}"
130 _rc=$?
131 if [ ${_rc} -ne 0 ]; then
132 return ${_rc}
133 fi
134
135 exec 3<>"${MAILFIFO}"
136
137 "$MAILER" -f bacula@fmgapp7-bacula9.intern.feldmann-mg.com hostmaster@feldmann-mg.com <&3 &
138 _pid_mailer=$!
139
140 # preserve leading white space when reading
141 _oifs="$IFS"
142 IFS="
143 "
144 cat "${MAILCONTENT}" |
145 while read _text; do
146 printf "%s\n" "$_text" >&3
147 done
148 printf ".\n" >&3
149
150 IFS="$_oifs"
151
152 # close the fd to the pipe: coproc should get EOF
153 exec 3>&-
154
155 wait $_pid_mailer
156 _rc=$?
157
158 # we are done with the named pipe
159 rm -f "${MAILFIFO}"
160
161 return ${_rc}
162 }
163
164
165 while getopts "V8c:f:h:l:nr:s:" _opt; do
166 case ${_opt} in
167 V)
168 echo "bsmtp2dma v${VERSION} (rv:@@HGREVISION@@)"
169 echo "$USAGE"
170 exit 0;
171 ;;
172 8)
173 : # VOID
174 ;;
175 c)
176 CC="$OPTARG"
177 ;;
178 f)
179 FROM="$OPTARG"
180 ;;
181 h)
182 : # VOID
183 ;;
184 l)
185 : # VOID
186 ;;
187 n)
188 DRYRUN="YES"
189 ;;
190 r)
191 REPLYTO="$OPTARG"
192 ;;
193 s)
194 SUBJECT="$OPTARG"
195 ;;
196 \?)
197 exit 2;
198 ;;
199 *)
200 echo "ERROR: inconsistent option handling" >&2
201 exit 2;
202 ;;
203 esac
204 done
205
206 # return code
207 _rc=0
208
209 DRYRUN="NO"
210
211 MAILTMPDIR="$(mktemp -d)"
212 MAILFIFO="${MAILTMPDIR}/mail-stdin"
213 MAILCONTENT="${MAILTMPDIR}/mail-text"
214
215 #
216 # Clean up existing temporary stuff on all sorts of exit
217 # (including the "exit" call (signal 0))
218 #
219 trap 'if [ -d "${MAILTMPDIR}" ]; then rm -r "${MAILTMPDIR}"; fi; exit;' 0 1 2 15
220
221 test -d "${MAILTMPDIR}" || { echo "ERROR: no existing private tmp dir" >&2; exit 1; }
222
223 #
224 # Reset the Shell's option handling system to prepare for handling
225 # other arguments and probably command-local options
226 #
227 shift $((OPTIND-1))
228 OPTIND=1
229
230 # early check whether some recipients are given
231 if [ $# -eq 0 ]; then
232 echo "ERROR: no recipient given" >&2
233 exit 2;
234 fi
235
236 #
237 # Collect the mail text from stdin into a temporary file
238 #
239 exec 3>"${MAILCONTENT}"
240 # preserve leading white space when reading
241 _oifs="$IFS"
242 IFS="
243 "
244 while read _text; do
245 if [ "${_text}" = "." ]; then
246 break
247 else
248 printf "%s\n" "${_text}" >&3
249 fi
250 done
251 exec 3>&-
252 IFS="$_oifs"
253
254 #
255 # Now send the content of the collected mail content to all recipients
256 #
257 until [ $# -eq 0 ]; do
258 send_mail "$1"
259 _rcsm=$?
260 if [ \( ${_rcsm} -ne 0 \) -a \( ${_rc} -eq 0 \) ]; then
261 _rc=${_rcsm}
262 fi
263 shift
264 done
265
266 exit ${_rc}