]> git.friedersdorff.com Git - max/remindme.git/commitdiff
Implement basic functionality
authorMaximilian Friedersdorff <max@friedersdorff.com>
Sun, 22 Dec 2019 17:48:23 +0000 (17:48 +0000)
committerMaximilian Friedersdorff <max@friedersdorff.com>
Sun, 22 Dec 2019 17:48:23 +0000 (17:48 +0000)
Do not yet support repeated reminders

remindme.py [new file with mode: 0644]

diff --git a/remindme.py b/remindme.py
new file mode 100644 (file)
index 0000000..3454eab
--- /dev/null
@@ -0,0 +1,140 @@
+import os
+from smtplib import SMTP_SSL
+import email
+import datetime
+
+from imapclient import IMAPClient, SEEN
+from dateutil.parser import parse
+from cron_descriptor import get_description
+
+
+IMAP_USER = os.environ["REMINDME_IMAP_USER"]
+IMAP_PASS = os.environ["REMINDME_IMAP_PASS"]
+IMAP_HOST = os.environ["REMINDME_IMAP_HOST"]
+SMTP_USER = os.environ.get("REMINDME_SMTP_USER", IMAP_USER)
+SMTP_PASS = os.environ.get("REMINDME_IMAP_PASS", IMAP_PASS)
+SMTP_HOST = os.environ.get("REMINDME_IMAP_HOST", IMAP_HOST)
+
+USAGE = ""
+
+
+__iclient = None
+
+
+def iclient():
+    global __iclient
+    if not __iclient:
+        __iclient = IMAPClient(IMAP_HOST, use_uid=True)
+        __iclient.login(IMAP_USER, IMAP_PASS)
+
+    __iclient.select_folder("INBOX")
+    return __iclient
+
+
+def make_reply(orig, subject, body):
+    reply = email.message.Message()
+    reply["Subject"] = subject
+    reply["In-Reply-To"] = orig["Message-ID"]
+    reply["References"] = orig["Message-ID"]
+    reply.set_payload(body)
+    reply["From"] = "remindme@friedersdorff.com"
+    reply["To"] = orig["From"]
+    return reply
+
+
+def ls(msg, reminders):
+    reply_lines = []
+    for uid, reminder in reminders:
+        body = reminder.get_payload().strip()
+        if body.startswith("repeat"):
+            parsed = get_description(body[6:].strip())
+            reply_lines.append(f"({uid}) {reminder['subject']}: {body} ; {parsed}")
+            pass
+        else:
+            reply_lines.append(f"({uid}) {reminder['subject']}: {body}")
+
+    return make_reply(msg, "Your current reminders", "\n".join(reply_lines))
+
+
+def ack_reminder(uid, reminder):
+    body = reminder.get_payload().strip()
+    if body.startswith("repeat"):
+        parsed = get_description(body[6:].strip())
+        reply_body = f"({uid}) {reminder['subject']}: {body} ; {parsed}"
+        pass
+    else:
+        reply_body = f"({uid}) {reminder['subject']}: {body}"
+
+    return make_reply(reminder, f"Received Reminder: {reminder['subject']}", reply_body)
+
+
+def remind(reminder):
+    f_line = reminder.get_payload().strip().splitlines()[0]
+    if f_line.lower().startswith("repeat"):
+        return False, None
+    else:
+        try:
+            parsed_time = parse(f_line, fuzzy=True)
+        except ValueError:
+            return False, None
+
+        if not parsed_time.tzinfo:
+            send_date = email.utils.parsedate_to_datetime(reminder["Date"])
+            sender_tz = send_date.tzinfo or datetime.timezone.utc
+            parsed_time = parsed_time.replace(tzinfo=sender_tz)
+
+        if datetime.datetime.now(datetime.timezone.utc) > parsed_time:
+            return (
+                True,
+                make_reply(
+                    reminder, f"Re: {reminder['subject']} now", reminder.get_payload()
+                ),
+            )
+
+
+def main():
+    msgs = iclient().search(["ALL"])
+    new_rems, old_rems, metas, to_delete, to_send = [], [], [], [], []
+    for uid, data in iclient().fetch(msgs, ["BODY.PEEK[]", "FLAGS"]).items():
+        mail = email.message_from_bytes(data[b"BODY[]"])
+        if mail.is_multipart():
+            to_delete.append(uid)
+
+        payload = mail.get_payload().strip()
+        if payload.lower().startswith("help") or payload.lower().startswith("list"):
+            metas.append(mail)
+            to_delete.append(uid)
+        else:
+            if SEEN in data[b"FLAGS"]:
+                old_rems.append((uid, mail))
+            else:
+                new_rems.append((uid, mail))
+
+    for meta in metas:
+        if meta.get_payload().strip().startswith("help"):
+            to_send.append(make_reply(meta, "Remindme Help", USAGE))
+        elif meta.get_payload().strip().startswith("list"):
+            to_send.append(ls(meta, old_rems + new_rems))
+
+    for uid, reminder in new_rems:
+        to_send.append(ack_reminder(uid, reminder))
+
+    for uid, reminder in old_rems + new_rems:
+        done, reply = remind(reminder)
+        if reply:
+            to_send.append(reply)
+        if done:
+            to_delete.append(uid)
+
+    iclient().delete_messages(to_delete)
+    iclient().expunge()
+    iclient().add_flags([u[0] for u in new_rems], SEEN)
+
+    with SMTP_SSL(SMTP_HOST) as smtp:
+        smtp.login(SMTP_USER, SMTP_PASS)
+        for reply in to_send:
+            smtp.send_message(reply)
+
+
+if __name__ == "__main__":
+    main()