Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
view sbin/bsmtp2dma @ 814:2310764e5c4e
fports: Implement a global "--jail/-j" option: execute the fports commands in a jail.
The jail just needs to have an installed "pkg" command.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Sat, 09 Nov 2024 00:47:05 +0100 |
| parents | 599fddb2370d |
| children | e2f262ec2bf4 |
line wrap: on
line source
#!/bin/sh # -*- indent-tabs-mode: nil; -*- : 'A simple replacement for Bacula `bsmtp` when the underlying mailer does not listen on TCP ports (e.g. `dma`, `ssmtp` et al.). :Author: Franz Glasner :Copyright: (c) 2019-2024 Franz Glasner. All rights reserved. :License: BSD 3-Clause "New" or "Revised" License. See LICENSE for details. If you cannot find LICENSE see <https://opensource.org/licenses/BSD-3-Clause> :ID: @(#)@@SIMPLEVERSIONTAG@@ ' # shellcheck disable=SC2034 # VERSION appears unused VERSION='@@VERSION@@' USAGE=' USAGE: bsmtp2dma [OPTIONS] RECIPIENT ... Options: -V Show the program version and usage and exit. -8 Does nothing. Just a compatibility option for `bsmtp`. -c ADDRESS Set the "CC:" header. -d n Does nothing. Just a compatibility option for `bsmtp`. -f ADDRESS Set the "From:" header. -h MAILHOST:PORT Does nothing. Just a compatibility option for `bsmtp`. -l NUMBER Does nothing. Just a compatibility option for `bsmtp`. -r ADDRESS Set the "Reply-To:" header -s SUBJECT Set the "Subject:" header Files: The shell style configuration file in @@ETCDIR@@/bsmtp2dma.conf is sourced in at script start. ' # # Configuration directory # : ${CONFIGDIR:="@@ETCDIR@@"} [ -r "${CONFIGDIR}/bsmtp2dma.conf" ] && . "${CONFIGDIR}/bsmtp2dma.conf" # # Default configuration values # # `sendmail` is also valid for `dma` because of the mapping within # `/etc/mail/mailer.conf` # : ${MAILER:=/usr/sbin/sendmail} parse_addr() { : 'Parse an possibly complex email address. Addresses can be of the form - Name Parts <user@domain.tld> - user@domain.tld `Name Parts` may not contain ``<`` or ``>`` characters. Args: _addr: the complex email address Returns: 0 on success, 1 on errors Output (Globals): email_name: the name part (or empty) email_addr: the technical address part (or empty) ' local _addr _addr="$1" test -n "${_addr}" || return 1 if printf "%s" "${_addr}" | /usr/bin/grep -q -E -e '^[^<>]+<[^<>]+@[^<>]+>$'; then email_name=$(printf '%s' "${_addr}" | sed -E -e 's/[[:space:]]*<.+$//') email_addr=$(printf '%s' "${_addr}" | sed -E -e 's/^[^<>]+<//' | sed -E -e 's/>$//') return 0 fi if printf "%s" "${_addr}" | /usr/bin/grep -q -E -e '^[^<>]+@[^<>]+$'; then email_name="" email_addr="${_addr}" return 0 fi return 1 } send_mail() { : 'Send the mail via the underlying configured mailer (dma, sendmail et al.). Args: _recipient: The recipient name. Will be written into the "To:" header also. Input (Globals): MAILER MAILCONTENT MAILFIFO_STDIN MAILFIFO_STDOUT CC FROM REPLYTO SUBJECT Returns: 0 on success, other values on errors or the error exit code from the underlying mailer This procedure starts the configured mailer as coproc and sends email headers and contents to the started mailer. ' local _recipient _rc _oifs _text _pid_mailer _recipient_addr local _from_from _from_addr _sender_addr _dummy _recipient="$1" _rc=0 if parse_addr "${_recipient}"; then _recipient_addr="${email_addr}" else echo "ERROR: unknown recipient address format in \`${_recipient}'" >&2 return 1 fi _sender_addr="$(whoami)@$(hostname -f)" if [ -z "${FROM}" ]; then _from_addr="${_sender_addr}" _from_from="${_from_addr}" else if parse_addr "${FROM}"; then _from_from="${FROM}" _from_addr="${email_addr}" else echo "ERROR: unknown sender name in \`${FROM}'" >&2 return 1 fi fi mkfifo -m 0600 "${MAILFIFO_STDIN}" _rc=$? if [ ${_rc} -ne 0 ]; then return ${_rc} fi mkfifo -m 0600 "${MAILFIFO_STDOUT}" _rc=$? if [ ${_rc} -ne 0 ]; then rm -f "${MAILFIFO_STDIN}" return ${_rc} fi # # Start the mailer **before** opening the pipe; otherwise a # deadlock occurs # "$MAILER" -f "${_sender_addr}" "${_recipient_addr}" <"${MAILFIFO_STDIN}" >"${MAILFIFO_STDOUT}" & _pid_mailer=$! exec 3>"${MAILFIFO_STDIN}" exec 4<"${MAILFIFO_STDOUT}" printf "To: %s\n" "${_recipient}" >&3 printf "From: %s\n" "${_from_from}" >&3 if [ "${_sender_addr}" != "${_from_addr}" ]; then printf "Sender: %s\n" "${_sender_addr}" >&3 fi if [ -n "${SUBJECT}" ]; then printf "Subject: %s\n" "${SUBJECT}" >&3 fi if [ -n "${REPLYTO}" ]; then # # XXX TBD proper Reply-To header value checks: # a comma separated list of full mail addresses # printf "Reply-To: %s\n" "${REPLYTO}" >&3 fi if [ -n "${CC}" ]; then # # XXX TBD proper CC header value checks: # a comma separated list of full mail addresses # printf "Cc: %s\n" "${CC}" >&3 fi printf "\n" >&3 # preserve leading white space when reading with `read` _oifs="$IFS" IFS=$'\n' while read -r _text; do printf "%s\n" "$_text" >&3 done <"${MAILCONTENT}" # not all mailer recognize this # printf ".\n" >&3 IFS="$_oifs" # close the fd to the pipe: coproc should get EOF and terminate exec 3>&- # read eventually remaining stuff from the mailer until EOF IFS='' read -r _dummy <&4 exec 4<&- wait $_pid_mailer _rc=$? # we are done with the named pipes rm -f "${MAILFIFO_STDIN}" rm -f "${MAILFIFO_STDOUT}" return ${_rc} } while getopts "V8c:d:f:h:l:nr:s:" _opt; do case ${_opt} in V) printf 'bsmtp2dma %s\n' '@@SIMPLEVERSIONSTR@@' echo "$USAGE" exit 0; ;; 8) : # VOID ;; c) CC="$OPTARG" ;; d) : # VOID ;; f) FROM="$OPTARG" ;; h) : # VOID ;; l) : # VOID ;; r) REPLYTO="$OPTARG" ;; s) SUBJECT="$OPTARG" ;; \?) exit 2; ;; *) echo "ERROR: inconsistent option handling" >&2 exit 2; ;; esac done # return code _rc=0 MAILTMPDIR="$(mktemp -d)" MAILFIFO_STDIN="${MAILTMPDIR}/mail-stdin" MAILFIFO_STDOUT="${MAILTMPDIR}/mail-stdout" MAILCONTENT="${MAILTMPDIR}/mail-text" # # Clean up existing temporary stuff on all sorts of exit # (including the "exit" call (signal 0)) # trap 'if [ -d "${MAILTMPDIR}" ]; then rm -rf "${MAILTMPDIR}"; fi; exit;' 0 1 2 15 test -d "${MAILTMPDIR}" || { echo "ERROR: no existing private tmp dir" >&2; exit 1; } # # Reset the Shell's option handling system to prepare for handling # other arguments and probably command-local options # shift $((OPTIND-1)) OPTIND=1 # early check whether some recipients are given if [ $# -eq 0 ]; then echo "ERROR: no recipient given" >&2 exit 2; fi # # Collect the mail text from stdin into a temporary file # exec 3>"${MAILCONTENT}" # preserve leading white space when reading with `read` _oifs="$IFS" IFS=$'\n' while read -r _text; do if [ "${_text}" = "." ]; then break else printf "%s\n" "${_text}" >&3 fi done exec 3>&- IFS="$_oifs" # # Now send the content of the collected mail content to all recipients # until [ $# -eq 0 ]; do send_mail "$1" _rcsm=$? if [ \( ${_rcsm} -ne 0 \) -a \( ${_rc} -eq 0 \) ]; then _rc=${_rcsm} fi shift done exit ${_rc}
