#!/bin/bash set +e verwendung() { >&2 echo 'digest-mailer collects emails into digests before sending them.' >&2 echo '' >&2 echo 'Usage: digest-mailer [OPTIONS]' >&2 echo ' -f:' >&2 echo ' flush all pending emails' >&2 echo ' -f $receiver:' >&2 echo ' flush pending emails to $receiver (hash)' >&2 echo \ '#HELPTEXT# #' exit 1 } extract_receiver_hash() { sed -n ' /^$/q s/^To:\s*// T p ' | \ sha224sum | \ awk '{print $1}' } if [ "x$1" = 'x--help' ]; then verwendung fi if [ "x$1" = 'x--version' ]; then echo '#VERSION#' exit fi if [ "x$1" = 'x-f' ]; then flush=true shift if [ $# -eq 0 ]; then receiver='' else receiver="$1" shift fi else flush=false fi if [ $# -ne 0 ]; then verwendung fi min_delay=3600 max_delay=3600 agressivity=0 mail_cmd='sendmail -t' if [ -r '#ETCDIR#/digest-mailer.conf' ] then . '#ETCDIR#/digest-mailer.conf' fi sender=$( whoami | \ sha224sum | \ awk '{print $1}' ) if ${flush} && \ [ -z "${receiver}" ]; then exec 9> '#LIBDIR#/digest-mailer/digest-mailer.flush.from.'"${sender}"'.lock' if ! flock -n 9; then # silently fail if lock is not available ("flush" is not _that_ important) exit fi find '#LIBDIR#/digest-mailer' -regextype grep -maxdepth 1 -mindepth 1 \ -regex ".*/${sender}\.[0-9a-f]\+\.[0-9]\+\.[0-9a-f]\+\$" | \ while read -r file; do extract_receiver_hash < "${file}" done | \ sort -u | \ xargs -rn1 "$0" -f exit fi time=$( date +%s ) if ! ${flush}; then message=$( cat ) receiver=$( printf '%s\n' "${message}" | \ extract_receiver_hash ) hash=$( printf '%s' "${message}" | \ sha224sum | \ awk '{print $1}' ) exec 9> '#LIBDIR#/digest-mailer/digest-mailer.from.'"${sender}"'.to.'"${receiver}"'.lock' flock 9 # we block if that lock is not available - the sender expects his mails delivered! printf '%s' "${message}" > "#LIBDIR#/digest-mailer/${sender}.${receiver}.${time}.${hash}" else exec 9> '#LIBDIR#/digest-mailer/digest-mailer.from.'"${sender}"'.to.'"${receiver}"'.lock' if ! flock -n 9; then # silently fail if lock is not available ("flush" is not _that_ important) exit fi fi if [ -s "#LIBDIR#/digest-mailer/${sender}.${receiver}.last-sent" ]; then last_sent=$( cat "#LIBDIR#/digest-mailer/${sender}.${receiver}.last-sent" ) else last_sent='0' fi first_unsent=$( find '#LIBDIR#/digest-mailer' -regextype grep -maxdepth 1 -mindepth 1 \ -regex ".*/${sender}\.${receiver}\.[0-9]\+\.[0-9a-f]\+\$" \ -printf '%f\n' | \ cut -d. -f3 | \ sort -nr | \ tail -n1 ) if ${flush} && \ [ -z "${first_unsent}" ]; then # no pending emails at all exit fi to_send=$( find '#LIBDIR#/digest-mailer' -regextype grep -maxdepth 1 -mindepth 1 \ -regex ".*/${sender}\.${receiver}\.[0-9]\+\.[0-9a-f]\+\$" | \ sort ) to_send_count=$( printf '%s\n' "${to_send}" | \ wc -l ) if [ $((last_sent + min_delay)) -gt ${time} ]; then # last email was sent too close exit fi if [ ${to_send_count} -gt 1 ] && \ printf '%s - (%s+%s)*%s - (%s+%s)*(1-%s)\n' \ "${time}" \ "${min_delay}" "${last_sent}" "${agressivity}" \ "${max_delay}" "${first_unsent}" "${agressivity}" | \ bc | \ grep -q '^-' && \ [ $((first_unsent + max_delay)) -ge ${time} ]; then exit fi printf '%s' "${time}" > "#LIBDIR#/digest-mailer/${sender}.${receiver}.last-sent" if [ ${to_send_count} -eq 1 ]; then ${mail_cmd} < "${to_send}" rm "${to_send}" exit fi { sed -n ' /^$/q s/^Subject:.*$/Subject: mail-digest ('"${to_send_count}"')/ p ' "$( printf '%s\n' "${to_send}" | \ head -n1 )" printf '\n' counter=1 printf '%s\n' "${to_send}" | \ while read -r file; do sed -n ' s/^Subject:\s*// T p ' "${file}" done | \ sort | \ uniq -c | \ sort -k1nr,1 -k2,2 | \ sed ' s/^\s*\([0-9]\+\)\s\+/\1: / ' printf '%s\n' "${to_send}" | \ while read -r file; do date=$( printf '%s\n' "${file##*/}" | \ cut -d. -f3 ) date=$( date -d"@${date}" ) printf 'vvvvv %s. (%s) vvvvv\n' \ "${counter}" \ "${date}" cat "${file}" printf '\n^^^^^ %s. (%s) ^^^^^\n' \ "${counter}" \ "${date}" counter=$((counter+1)) rm "${file}" done } | ${mail_cmd}