From 00fe6eb843daf5465e99fa3bb753bec11644e96a Mon Sep 17 00:00:00 2001 From: Brendan Howell Date: Mon, 8 May 2017 00:01:34 +0200 Subject: [PATCH] refactor email message formatting. redo unread lister. keep track of imapid-shortcode mappings. --- screenless/bureau/mailroom/mailroom.py | 101 +++++++++++------- screenless/bureau/publications/news.html | 17 ++- .../bureau/publications/publications.py | 3 + 3 files changed, 77 insertions(+), 44 deletions(-) diff --git a/screenless/bureau/mailroom/mailroom.py b/screenless/bureau/mailroom/mailroom.py index 37374f7..6fb7b45 100644 --- a/screenless/bureau/mailroom/mailroom.py +++ b/screenless/bureau/mailroom/mailroom.py @@ -77,43 +77,20 @@ class MailRoom(Bureau): try: self.imapserv.select_folder("INBOX") except self.imapserv.AbortError as err: - print("imap connection error: ", err) + self.log.debug("reconnecting after imap connection error: ", err) self.imapserv.logout() self.imapserv = imapclient.IMAPClient(self.host, use_uid=True, ssl=self.imap_ssl) self.imapserv.login(self.login, self.password) self.imapserv.select_folder("INBOX") - def get_imap_id(self, msgid): - """ - take short code and look up the IMAP message id - """ - with self.dbenv.begin(db=self.postdb) as txn: - imap_id = txn.get(msgid.encode()) - return int(imap_id) - - @add_command("fax", "Send a Document Camera Image via Email") - def fax(self, data): - """ - Takes a photograph using the document camera and sends it in an E-mail. + def _make_msg_object(self, imap_id, resp_obj): """ - photo = self.send("PXphoto.") - - @add_command("r", "Print full email") - def read(self, data): + util tidies up message headers deals with encoding """ - Prints out the full detailed version of an email. - """ - shortcode, _ = data.split(".") - imap_id = self.get_imap_id(shortcode) - self._connect_imap() - resp = self.imapserv.fetch([imap_id], - ['INTERNALDATE', 'RFC822']) - - internaldate = resp[imap_id][b'INTERNALDATE'] + internaldate = resp_obj[imap_id][b'INTERNALDATE'] - msg_data = resp[imap_id][b'RFC822'].decode('utf-8') + msg_data = resp_obj[imap_id][b'RFC822'].decode('utf-8') msg_obj = email.message_from_string(msg_data) - print("message fields:", msg_obj.keys()) # format and tidy header data msg = Message() @@ -125,8 +102,7 @@ class MailRoom(Bureau): else: msg.cc = None msg.date = internaldate - msg.shortcode = shortcode - msg.attachments = [] + msg.attachments = [] # TODO: deal with attachments # TODO: should use msg_obj.get_body and deal with HTML msg.content = "" @@ -141,6 +117,54 @@ class MailRoom(Bureau): msg.content = msg.content.replace(">", ">") msg.content = msg.content.replace("\n", "
") + return msg + + def get_imap_id(self, msgid): + """ + take short code and look up the IMAP message id + """ + with self.dbenv.begin(db=self.postdb) as txn: + imap_id = txn.get(msgid.encode()) + return int(imap_id) + + def _imap2shortcode(self, msgid): + """ + returns a short code for a given IMAP id (creating a new mapping if + needed) + """ + with self.dbenv.begin(db=self.postdb_rev) as txn: + shortcode = txn.get(msgid.encode()) + if shortcode is not None: + return shortcode + else: + shortcode = ''.join(random.choice(string.ascii_letters + + string.digits) for _ in range(5)) + txn.put(msgid.encode(), shortcode.encode()) + with self.dbenv.begin(db=self.postdb) as txn: + txn.put(shortcode.encode(), msgid.encode()) + return shortcode + + + @add_command("fax", "Send a Document Camera Image via Email") + def fax(self, data): + """ + Takes a photograph using the document camera and sends it in an E-mail. + """ + photo = self.send("PXphoto.") + + @add_command("r", "Print full email") + def read(self, data): + """ + Prints out the full detailed version of an email. + """ + shortcode, _ = data.split(".") + imap_id = self.get_imap_id(shortcode) + self._connect_imap() + resp = self.imapserv.fetch([imap_id], + ['INTERNALDATE', 'RFC822']) + + msg = self._make_msg_object(imap_id, resp) + # make action barcodes barcode_png = os.path.join("/tmp", "POun." + msg.shortcode + ".png") code128.image("POun." + shortcode).save(barcode_png) @@ -269,16 +293,13 @@ class MailRoom(Bureau): msgs = [] for msgid, data in resp.items(): - msg = {} - env = data[b"ENVELOPE"] - - msg["msgid"] = str(msgid) - sender = env.from_[0] - msg["fromaddr"] = str(sender.mailbox) + "@" + str(sender.host) - msg["fromname"] = str(sender.name) - msg["date"] = str(data[b"INTERNALDATE"]) - msg["size"] = str(data[b"RFC822.SIZE"]) - msg["subject"] = str(env.subject) + msg = self._make_msg_object(msgid, data) + shortcode = self._imap2shortcode(msgid) + + # make action barcodes + msg.d_bc = code128.svg("POd." + shortcode).encode() + msg.sp_bc = code128.svg("POsp." + shortcode).encode() + msg.r_bc = code128.svg("POr." + shortcode).encode() msgs.append(msg) diff --git a/screenless/bureau/publications/news.html b/screenless/bureau/publications/news.html index 6e08968..345f2e6 100644 --- a/screenless/bureau/publications/news.html +++ b/screenless/bureau/publications/news.html @@ -52,6 +52,9 @@ .clearfloats { clear: both; } + .entry { + margin-bottom: 1em; + } .entry .title{ font-weight: bold; font-variant: small-caps; @@ -60,7 +63,13 @@ .entry .source{ font-style: italic; } - .entry .barcode{} + .entry .barcode{ + text-align: left; + } + .entry .barcode svg { + width: 100%; + height: 7mm; + } .entry .summary{ text-align: justify; hyphens: auto; @@ -92,11 +101,11 @@ % for msg in inbox: - ${msg["fromname"]} <${msg["fromaddr"]}> - ${msg["subject"]}${msg["date"]} + ${msg.fromstr} + ${msg.subject}${msg.date} READDELETEMARK AS SPAM - BC-READBC-DELETEBC-MARK AS SPAM + ${msg.r_bc}${msg.d_bc}${msg.sp_bc} % endfor diff --git a/screenless/bureau/publications/publications.py b/screenless/bureau/publications/publications.py index 2d1ebe0..16d8b2d 100644 --- a/screenless/bureau/publications/publications.py +++ b/screenless/bureau/publications/publications.py @@ -9,6 +9,7 @@ import urllib.request, urllib.parse, urllib.error import code128 import feedparser +import html5tidy import lxml.html import PIL from readability import readability @@ -203,6 +204,8 @@ class Publications(Bureau): end = entry.summary.rfind(" ", 0, 499) entry.summary = entry.summary[0:end] + "…" + entry.summary = html5tidy.tidy(entry.summary, fragment=True) + entries.append(entry) return entries