From 5950d5c4e05d47338e97a80dfa0909bf9c870ee5 Mon Sep 17 00:00:00 2001 From: "martin f. krafft" Date: Tue, 4 Mar 2008 19:30:57 +0100 Subject: [PATCH] rewrite processing of postponed messages --- bin/list-postponed-messages | 73 +++++++++++++++++++++++++++++++++ bin/process-delayed-queue | 49 ---------------------- bin/process-tickler | 64 ----------------------------- bin/release-delayed-messages | 11 ++--- bin/resubmit | 59 ++++++++++++++++++++++---- bin/resubmit-postponed-messages | 10 +++++ 6 files changed, 138 insertions(+), 128 deletions(-) create mode 100755 bin/list-postponed-messages delete mode 100755 bin/process-delayed-queue delete mode 100755 bin/process-tickler create mode 100755 bin/resubmit-postponed-messages diff --git a/bin/list-postponed-messages b/bin/list-postponed-messages new file mode 100755 index 0000000..d0ee1af --- /dev/null +++ b/bin/list-postponed-messages @@ -0,0 +1,73 @@ +#!/bin/sh +set -eu + +ME="${0##*/}" + +about() +{ + echo "$ME -- list postponed messages which have expired" + echo "Copyright © martin f. krafft " + echo "Released under the terms of the Artistic Licence 2.0" +} + +usage() +{ + echo "Usage: $ME [options] [ ...]" + echo + echo "Valid options are:" + cat <<-_eof | column -s\& -t + -V|--version & show version information. + -h|--help & show this output. + -a|--all & list all postponed messages, not only expired ones + -s|--stamp & include the time stamp *before* the filename + _eof +} + +SHORTOPTS=Vhas +LONGOPTS=version,help,all,stamp + +maildirs= +listall=0 +timestamp=0 + +for opt in $(getopt -n $ME -o $SHORTOPTS -l $LONGOPTS -u -- "$@"); do + case "$opt" in + -V|--version) about; exit 0;; + -h|--help) about; echo; usage; exit 0;; + -a|--all) listall=1;; + -s|--stamp) timestamp=1;; + --) :;; + *) + if [ -d "$opt/cur" ] && [ -d "$opt/new" ] && [ -d "$opt/tmp" ]; then + maildirs="$maildirs $opt" + else + echo "E: unknown argument: $opt" >&2 + exit 1 + fi + ;; + esac +done + +if [ -z "$maildirs" ]; then + echo "E: no Maildirs specified." >&2 + exit 2 +fi + +NOW=$(date +%s) + +for i in $maildirs; do + d="${i%/}" + echo "$d/new/" + echo "$d/cur/" +done \ + | xargs -I {} find {} -type f \ + | xargs grep '^X-Postponed:' \ + | while read i; do + f="${i%:X-Postponed:*}" + ts="${i#*:X-Postponed: }"; ts="${ts%% *}" + + if [ $listall -eq 1 ] || [ $ts -le $NOW ]; then + [ $timestamp -eq 1 ] && echo -n "$ts " + echo "$f" + fi + done diff --git a/bin/process-delayed-queue b/bin/process-delayed-queue deleted file mode 100755 index 826a346..0000000 --- a/bin/process-delayed-queue +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -set -eu - -MAILDIR=$HOME/.maildir - -SQLITE=/usr/bin/sqlite3 -RESUBMIT=$HOME/.etc/mailfilter/bin/resubmit - -DELAYED_QUEUE_DB=$HOME/.var/procmail/delayed-queue.sqlite - -QUERY='select * from messages where release_ts <= strftime("%s", "now")' - -$SQLITE -list -separator ' ' $DELAYED_QUEUE_DB "$QUERY" \ - | while read msgid basefile ts; do - - file="$MAILDIR/$basefile" - files="$file ${file}:2," - - basename="${file##*/}" - dirname="${file%/*}" - case "${dirname##*/}" in - cur) - files="$files ${file}:2,S ${file}:2,R ${file}:2,RS" - file="${dirname%/cur}/new/$basename" - files="$files $file ${file}:2, ${file}:2,R ${file}:2,RS" - ;; - new) - file="${dirname%/new}/cur/$basename" - files="$files ${file}:2, ${file}:2,S" - ;; - esac - - found=0 - for file in $files; do - if [ -f "$file" ]; then - $RESUBMIT "$file" - echo "I: resubmitted $msgid" - found=1 - break - fi - done - - $SQLITE $DELAYED_QUEUE_DB "delete from messages where msgid = '$msgid'" - - if [ $found -eq 0 ]; then - echo "E: message $msgid not found in $basefile" >&2 - fi - -done diff --git a/bin/process-tickler b/bin/process-tickler deleted file mode 100755 index 28b6c5e..0000000 --- a/bin/process-tickler +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python2.5 -# -*- coding: utf-8 -*- -# -# process-tickler – process message in tickler maildir -# -# Copyright © martin f. krafft -# Released under the terms of the Artistic Licence 2.0 -# - -import mailbox -import os -import sys -import time - -HOME = os.getenv('HOME') -MAILDIR = os.path.join(HOME, '.maildir') -TICKLER_DIR = os.path.join(MAILDIR, '.tickler') -DEST_DIR = os.path.join(MAILDIR, '.resubmit') - -tmd = mailbox.Maildir(TICKLER_DIR) -dmd = mailbox.Maildir(DEST_DIR) -msgids = dict() - -def resubmit(key): - msg = tmd.get_message(key) - print >>sys.stdout, 'I: resubmit message %s' % key - if msg.has_key('X-Tickle-Delivered'): - msg.replace_header('X-Tickle-Delivered', time.strftime('%c')) - else: - msg.add_header('X-Tickle-Delivered', time.strftime('%c')) - dmd.add(msg) - tmd.discard(key) - -for key, msg in tmd.iteritems(): - msgid = msg.get('Message-Id') - if msgid is None: - print >>sys.stderr, 'W: message without ID: ' + key - resubmit(key) - - tickle = msg.get('X-Tickle') - if tickle is None: - print >>sys.stderr, 'W: message without tickle information: ' + msgid - resubmit(key) - - if msgids.get(msgid, None) is None: - msgids[msgid] = list() - msgids[msgid].append((int(tickle.split(' ', 1)[0]), key, msg)) - -for msgid, msgs in msgids.iteritems(): - msgs.sort() - prev_tickle = None - for tickle, key, msg in msgs: - if tickle == prev_tickle: - print >>sys.stderr, 'I: discarding duplicate %s of message %s' % (key, msgid) - tmd.discard(key) - continue - prev_tickle = tickle - - t = time.time() - if t >= tickle: - resubmit(key) - else: - print >>sys.stdout, 'I: message %s still has %d seconds' % (key, - int(tickle - t)) diff --git a/bin/release-delayed-messages b/bin/release-delayed-messages index fd381d3..61abd85 100755 --- a/bin/release-delayed-messages +++ b/bin/release-delayed-messages @@ -1,12 +1,9 @@ #!/bin/sh set -eu -MAILDIR=$HOME/.maildir +DELAYED_QUEUE=$HOME/.maildir/.delayed -SQLITE=/usr/bin/sqlite3 -DELAYED_QUEUE_DB=$HOME/.var/procmail/delayed-queue.sqlite +DIR="${0%/*}" -QUERY="update messages set release_ts = strftime('%s', 'now') where filename like '.delayed/%'" - -$SQLITE $DELAYED_QUEUE_DB "$QUERY" -exec $HOME/.etc/mailfilter/bin/process-delayed-queue +"$DIR"/list-postponed-messages --all "$DELAYED_QUEUE" \ + | exec xargs "$DIR"/resubmit --list diff --git a/bin/resubmit b/bin/resubmit index 17888f9..6bf8819 100755 --- a/bin/resubmit +++ b/bin/resubmit @@ -1,17 +1,60 @@ #!/bin/sh set -eu +ME="${0##*/}" + +about() +{ + echo "$ME -- resubmit messages to the mail filter" + echo "Copyright © martin f. krafft " + echo "Released under the terms of the Artistic Licence 2.0" +} + +usage() +{ + echo "Usage: $ME [options] [ ...]" + echo + echo "Valid options are:" + cat <<-_eof | column -s\& -t + -V|--version & show version information. + -h|--help & show this output. + -l|--list & process the argument list (even if empty), never stdin + _eof +} + +SHORTOPTS=Vhl +LONGOPTS=version,help,list + +list=0 +files= + +for opt in $(getopt -n $ME -o $SHORTOPTS -l $LONGOPTS -u -- "$@"); do + case "$opt" in + -V|--version) about; exit 0;; + -h|--help) about; echo; usage; exit 0;; + -l|--list) list=1;; + --) :;; + *) + if [ -f "$opt" ] && [ -r "$opt" ]; then + files="$files $opt" + else + echo "E: unknown argument: $opt" >&2 + exit 1 + fi + ;; + esac +done + PROCMAIL=$HOME/.etc/mailfilter/procmail/procmailrc -FORMAIL="/usr/bin/formail -I'X-Resubmitted: $(date -R)'" +# execute the date -R only during the eval, not immediately +FILTER='/usr/bin/formail -I"X-Resubmitted: $(date -R)"' -if [ -z "${1:-}" ]; then - eval $FORMAIL | exec $PROCMAIL +if [ -z "${1:-}" ] && [ $list -eq 0 ]; then + eval $FILTER | exec $PROCMAIL else - if [ ! -f "$1" ]; then - echo "E: no such file: $1" >&2 - exit 1 - fi - eval $FORMAIL < "$1" | $PROCMAIL && rm -f "$1" + for f in $files; do + eval $FILTER < "$f" | $PROCMAIL && rm -f "$f" + done fi exit 0 diff --git a/bin/resubmit-postponed-messages b/bin/resubmit-postponed-messages new file mode 100755 index 0000000..1ea3100 --- /dev/null +++ b/bin/resubmit-postponed-messages @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu + +DELAYED_QUEUE=$HOME/.maildir/.delayed +TICKLER_QUEUE=$HOME/.maildir/.store + +DIR="${0%/*}" + +"$DIR"/list-postponed-messages "$TICKLER_QUEUE" "$DELAYED_QUEUE" \ + | exec xargs "$DIR"/resubmit --list -- 2.39.2