commit 87aafff0df4fff512e8d376919d42c5a57faac53
Author: Antoine Amarilli <a3nm@a3nm.net>
Date: Sat, 23 Nov 2019 17:13:41 +0100
first commit
Diffstat:
.gitignore | | | 8 | ++++++++ |
README.md | | | 81 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
add.sh | | | 49 | +++++++++++++++++++++++++++++++++++++++++++++++++ |
delete.sh | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
init.sh | | | 15 | +++++++++++++++ |
poll.sh | | | 56 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
show.sh | | | 28 | ++++++++++++++++++++++++++++ |
7 files changed, 279 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,8 @@
+deleted/
+scheduled/
+sent/
+scheduled_reminders/
+sent_reminders/
+remailback.sqlite
+lock.flock
+email
diff --git a/README.md b/README.md
@@ -0,0 +1,81 @@
+This is a set of shell scripts to make it easy to schedule reminders to be sent
+to yourself about a specific email at a specific time.
+
+## Requirements
+
+You should have in your $PATH the commands get_email_header and
+prepare_email_forward from https://a3nm.net/git/mybin.
+
+Reminder emails will be sent with "sendmail -t" -- you should ensure that this
+will actually send emails correctly, e.g., using msmtp-mta.
+
+## Setup
+
+To get started, write in the "email" file the email address that should receive
+the reminders (it will also be used as a from address for the reminders):
+
+ echo "your_email_address@example.com" > email
+
+Then initialize the DB:
+
+ ./init.sh
+
+Schedule the following in your crontab, e.g., daily, to catch any missing
+reminders:
+
+ /path/to/remailback/poll.sh
+
+## Usage
+
+To configure a reminder about a message, do:
+
+ cat ~/Mailstore/cur/messagefile | ./add.sh 2 weeks, check that order arrived
+
+This invocation will schedule a reminder about the message to be sent in 2 weeks
+(give or take 5 minutes). Details about the reminder are stored in the
+remailback folder and in its DB. An at job with atd is scheduled to send the
+message (but it will be sent by the cron job above even if at fails).
+
+When the time is elapsed, remailback will send a reminder about the email: this
+is an email which is In-Reply-To the original message, includes the original
+message as an attachment, has a similar subject to the original message, and
+includes your note (e.g., "check that order arrived" above).
+
+If you want to check which reminders exist about a message, issue:
+
+ cat ~/Mailstore/cur/messagefile | ./show.sh
+
+If you want to delete all reminders about a message, issue:
+
+ cat ~/Mailstore/cur/messagefile | ./delete.sh
+
+## Using within mutt
+
+TODO
+
+## Reference
+
+### Commands
+
+- init.sh: initialize the DB
+- add.sh: add a reminder for a message
+- delete.sh: delete all reminders for a message
+- show.sh: show all reminders for a message
+- poll.sh: poll for due reminders and send them
+
+### Working files and folders
+
+- remailback.sqlite: sqlite3 database
+- lock.flock: lock (to prevent concurrent writes on the DB)
+
+- scheduled/: copy of email with scheduled reminders
+- sent/: copy of email for which a reminder was sent
+- deleted/: copy of email for which a reminder was deleted
+
+At any time, the contents of these three directories should exactly reflect what
+is in the sqlite database.
+
+- scheduled_reminders/: copy of reminders which were scheduled (just before they
+ were sent)
+- sent_reminders/: copy of reminders which were sent
+
diff --git a/add.sh b/add.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# Add a reminder for a message
+# Usage: cat message | ./add.sh 2 weeks, check that order arrived
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+TARGET=$(echo "$@" | cut -d, -f1)
+REASON=$(echo "$@" | cut -d, -f2- | sed 's/^\s*//;s/\s*$//')
+
+CDATE=$(date +%s)
+TDATE=$(date +%s -d "$TARGET")
+
+if [ $? -ne 0 ]
+then
+ echo "Could not parse date $TARGET"
+ exit 1
+fi
+
+TEMPFILE=$(tempfile)
+cat > $TEMPFILE
+
+# get_email_header command from https://a3nm.net/git/mybin
+
+SUBJECT=$(get_email_header subject < "$TEMPFILE")
+MESSAGEID=$(get_email_header message-id < "$TEMPFILE")
+
+UUID=$(uuidgen)
+
+FILENAME=$(echo "${MESSAGEID}_${SUBJECT}_${TDATE}_${REASON}_${UUID}" | tr -dc 'a-zA-Z@._0-9-')
+
+mkdir -p scheduled
+
+# adapted from https://stackoverflow.com/a/169969
+(
+ # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
+ flock -x -w 10 200 || exit 1
+
+ mv "$TEMPFILE" "scheduled/$FILENAME"
+
+ echo "INSERT INTO reminders (sendtime, createtime, messageid, filename, explanation, status) VALUES('$TDATE', '$CDATE', '$MESSAGEID', '$FILENAME', '$REASON', 'scheduled');" | sqlite3 remailback.sqlite
+
+ # from https://unix.stackexchange.com/a/116451/
+ TDATEDATE=$(date -d "@$TDATE" +'%H:%M %D')
+ echo "$DIR/poll.sh" | at "$TDATEDATE"
+
+) 200>lock.flock
+
diff --git a/delete.sh b/delete.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Mark all reminders about a message as deleted.
+# Usage: cat message | ./delet.sh
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+TEMPFILE=$(tempfile)
+cat > $TEMPFILE
+
+# get_email_header command from https://a3nm.net/git/mybin
+
+MESSAGEID=$(get_email_header message-id < "$TEMPFILE")
+
+# adapted from https://stackoverflow.com/a/169969
+(
+ # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
+ flock -x -w 10 200 || exit 1
+
+ echo "Currently scheduled reminders:"
+ ./show.sh < $TEMPFILE
+
+ mkdir -p deleted
+
+ echo "SELECT * FROM reminders WHERE messageid='$MESSAGEID' AND status='scheduled'" |
+ sqlite3 remailback.sqlite | while read l; do
+ ID=$(echo "$l" | cut -d\| -f1)
+ FILE=$(echo "$l" | cut -d\| -f5)
+ mv "scheduled/$FILE" "deleted/$FILE"
+ echo "UPDATE reminders SET status='deleted' WHERE id='$ID'" |
+ sqlite3 remailback.sqlite
+ echo "Deleted reminder $ID"
+ done
+
+ echo "Scheduled reminders are now:"
+ ./show.sh < $TEMPFILE
+) 200>lock.flock
+
+rm -f "$TEMPFILE"
+
+
diff --git a/init.sh b/init.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+if [ -f remailback.sqlite ]
+then
+ echo "Database already exists -- not initializing"
+ exit 1
+fi
+
+echo "CREATE TABLE reminders(id INTEGER PRIMARY KEY AUTOINCREMENT, sendtime INTEGER, createtime INTEGER, messageid TEXT, filename TEXT, explanation TEXT, status TEXT);" | sqlite3 remailback.sqlite
+
+mkdir -p sent sent_reminders scheduled scheduled_reminders deleted
+
diff --git a/poll.sh b/poll.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+# Poll all scheduled reminders and send the ones that are due.
+# This script is scheduled with "at" when a reminder is added.
+# To be safe, it can also be scheduled to run regularly with cron.
+# Usage: ./poll.sh
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+if [ ! -f email ]
+then
+ echo "Missing from email! Aborting!"
+ exit 1
+fi
+
+EMAIL=$(cat email)
+
+CDATE=$(date +%s)
+# adjust to time offsets -- potentially send reminders 5min early
+# this is in case the clock drifts
+CDATEA=$(($CDATE + 300))
+
+# adapted from https://stackoverflow.com/a/169969
+(
+ # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds
+ flock -x -w 10 200 || exit 1
+
+ echo "SELECT * FROM reminders WHERE sendtime < '$CDATEA' AND status='scheduled'" |
+ sqlite3 remailback.sqlite | while read l; do
+
+ ID=$(echo "$l" | cut -d\| -f1)
+ TTIME=$(echo "$l" | cut -d\| -f2)
+ FILENAME=$(echo "$l" | cut -d\| -f5)
+ EXPL=$(echo "$l" | cut -d\| -f6)
+ FILE="scheduled/$FILENAME"
+
+ # get_email_header and prepare_email_forward commands from https://a3nm.net/git/mybin
+ SUBJECT=$(get_email_header subject < $FILE)
+ MESSAGEID=$(get_email_header message-id < $FILE)
+
+ mkdir -p sent sent_reminders scheduled_reminders
+
+ prepare_email_forward "$EMAIL" "$EMAIL" "PING: $SUBJECT: $EXPL" "$MESSAGEID" "$FILE" "$EXPL" \
+ > "scheduled_reminders/$FILENAME"
+ sendmail -t < "scheduled_reminders/$FILENAME"
+
+ mv "scheduled_reminders/$FILENAME" "sent_reminders/$FILENAME"
+ mv "scheduled/$FILENAME" "sent/$FILENAME"
+
+ echo "UPDATE reminders SET status='sent' WHERE id='$ID'" |
+ sqlite3 remailback.sqlite
+ done
+
+) 200>lock.flock
+
diff --git a/show.sh b/show.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Show all reminders about a message.
+# Usage: cat message | ./delet.sh
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+cd "$DIR"
+
+TEMPFILE=$(tempfile)
+cat > $TEMPFILE
+
+# get_email_header command from https://a3nm.net/git/mybin
+
+MESSAGEID=$(get_email_header message-id < "$TEMPFILE")
+
+rm -f "$TEMPFILE"
+
+echo "SELECT * FROM reminders WHERE messageid='$MESSAGEID'" |
+ sqlite3 remailback.sqlite | while read l; do
+ ID=$(echo "$l" | cut -d\| -f1)
+ TTIME=$(echo "$l" | cut -d\| -f2)
+ TDATE=$(date -d "@$TTIME")
+ EXPL=$(echo "$l" | cut -d\| -f6)
+ STATUS=$(echo "$l" | cut -d\| -f7)
+ echo "Reminder $ID on $TDATE (status '$STATUS'): $EXPL"
+done
+
+