diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/bsmtp2dma	Mon Oct 14 09:47:34 2019 +0200
@@ -0,0 +1,266 @@
+#!/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 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:        @(#)@@PKGORIGIN@@ $HGid$
+
+'
+
+VERSION="@@VERSION@@"
+
+USAGE='
+USAGE: bsmtp2dma [OPTIONS] RECIPIENT ...
+
+Options:
+
+  -8           Does nothing. Just a compatibility option for `bsmtp`.
+
+  -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`.
+
+  -n           Do a dry-run: just print out what would be done
+
+  -s SUBJECT   Set the "Subject:" header
+
+  -r ADDRESS   Set the "Reply-To:" header
+
+  -l NUMBER    Does nothing. Just a compatibility option for `bsmtp`.
+
+  -V           Show the program version and usage and exit.
+
+
+Usage:
+
+  The body of the email message is read from standard input. Message is
+  ended by sending the `EOF` character (`Ctrl-D` on many systems) on the
+  start of a new line, much like many `mail` commands.
+
+'
+
+#
+# Configuration directory
+#
+: ${CONFIGDIR:=@@ETCDIR@@}
+
+test -r "${CONFIGDIR}/bsmtp2dma.conf" && . "${CONFIGDIR}/bsmtp2dma.conf"
+
+
+# Default configuration values
+: ${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"
+
+    if printf "%s" "${_addr}" | 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}" | 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
+        CC
+        FROM
+        REPLYTO
+        SUBJECT
+
+    Returns:
+        0 on success, other values on errors or the error exit code from the
+        underlying mailer
+
+    '
+    local _recipient _rc _oifs _text _pid_mailer
+
+    _recipient="$1"
+    _rc=0
+
+    mkfifo -m 0600 "${MAILFIFO}"
+    _rc=$?
+    if [ ${_rc} -ne 0 ]; then
+        return ${_rc}
+    fi
+
+    exec 3<>"${MAILFIFO}"
+
+    "$MAILER" -f bacula@fmgapp7-bacula9.intern.feldmann-mg.com hostmaster@feldmann-mg.com <&3 &
+    _pid_mailer=$!
+
+    # preserve leading white space when reading
+    _oifs="$IFS"
+    IFS="
+"
+    cat "${MAILCONTENT}" |
+        while read _text; do
+            printf "%s\n" "$_text" >&3
+        done
+    printf ".\n" >&3
+
+    IFS="$_oifs"
+
+    # close the fd to the pipe: coproc should get EOF
+    exec 3>&-
+
+    wait $_pid_mailer
+    _rc=$?
+
+    # we are done with the named pipe
+    rm -f "${MAILFIFO}"
+
+    return ${_rc}
+}
+
+
+while getopts "V8c:f:h:l:nr:s:" _opt; do
+    case ${_opt} in
+        V)
+            echo "bsmtp2dma v${VERSION} (rv:@@HGREVISION@@)"
+            echo "$USAGE"
+            exit 0;
+            ;;
+        8)
+            : # VOID
+            ;;
+        c)
+            CC="$OPTARG"
+            ;;
+        f)
+            FROM="$OPTARG"
+            ;;
+        h)
+            : # VOID
+            ;;
+        l)
+            : # VOID
+            ;;
+        n)
+            DRYRUN="YES"
+            ;;
+        r)
+            REPLYTO="$OPTARG"
+            ;;
+        s)
+            SUBJECT="$OPTARG"
+            ;;
+        \?)
+            exit 2;
+            ;;
+        *)
+            echo "ERROR: inconsistent option handling" >&2
+            exit 2;
+            ;;
+    esac
+done
+
+# return code
+_rc=0
+
+DRYRUN="NO"
+
+MAILTMPDIR="$(mktemp -d)"
+MAILFIFO="${MAILTMPDIR}/mail-stdin"
+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 -r "${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
+_oifs="$IFS"
+IFS="
+"
+while read _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}