def __init__(self, root_view, mailbox, uid, gm_msgid, window, color_scheme): self._root_view = root_view self._cache = root_view._cache self._mailbox = mailbox self._uid = uid self._gm_msgid = gm_msgid self._cache.db.create_function("message_view_update_bodystructure", 1, self.on_update_bodystructure) self._cache.db.execute( """ CREATE TEMP TRIGGER message_view_update_bodystructure AFTER UPDATE OF bodystructure ON gmail_messages WHEN NEW.gm_msgid=%d BEGIN SELECT message_view_update_bodystructure(NEW.bodystructure); END""" % self._gm_msgid ) self._cache.db.create_function("message_view_add_body_section", 2, self.on_add_body_section) self._cache.db.execute( """ CREATE TEMP TRIGGER message_view_add_body_section AFTER INSERT ON gmail_message_bodies WHEN NEW.gm_msgid=%d BEGIN SELECT message_view_add_body_section(NEW.section, NEW.body); END""" % self._gm_msgid ) self._widget = ScrollWidget(window, color_scheme) row = self._cache.db.execute( """ SELECT date, timezone, subject, "from", "to", cc, bcc, bodystructure FROM gmail_messages WHERE gm_msgid=? """, (self._gm_msgid,), ).fetchone() self._date = convert_date(row["date"], row["timezone"]) self._from = convert_addrs(row["from"]) self._to = convert_addrs(row["to"]) self._cc = convert_addrs(row["cc"]) self._bcc = convert_addrs(row["bcc"]) self._subject = row["subject"] self._bodystructure = convert_bodystructure(row["bodystructure"]) cur = self._cache.db.execute( """ SELECT section, body FROM gmail_message_bodies WHERE gm_msgid=? """, (self._gm_msgid,), ) self._body_sections = {row["section"]: row["body"] for row in cur} self._root_view.on_open_message(self._mailbox, self._uid, self._bodystructure is None) if self._bodystructure: self._open_body_sections() self._redraw()
class _MessageView: def __init__(self, root_view, mailbox, uid, gm_msgid, window, color_scheme): self._root_view = root_view self._cache = root_view._cache self._mailbox = mailbox self._uid = uid self._gm_msgid = gm_msgid self._cache.db.create_function("message_view_update_bodystructure", 1, self.on_update_bodystructure) self._cache.db.execute( """ CREATE TEMP TRIGGER message_view_update_bodystructure AFTER UPDATE OF bodystructure ON gmail_messages WHEN NEW.gm_msgid=%d BEGIN SELECT message_view_update_bodystructure(NEW.bodystructure); END""" % self._gm_msgid ) self._cache.db.create_function("message_view_add_body_section", 2, self.on_add_body_section) self._cache.db.execute( """ CREATE TEMP TRIGGER message_view_add_body_section AFTER INSERT ON gmail_message_bodies WHEN NEW.gm_msgid=%d BEGIN SELECT message_view_add_body_section(NEW.section, NEW.body); END""" % self._gm_msgid ) self._widget = ScrollWidget(window, color_scheme) row = self._cache.db.execute( """ SELECT date, timezone, subject, "from", "to", cc, bcc, bodystructure FROM gmail_messages WHERE gm_msgid=? """, (self._gm_msgid,), ).fetchone() self._date = convert_date(row["date"], row["timezone"]) self._from = convert_addrs(row["from"]) self._to = convert_addrs(row["to"]) self._cc = convert_addrs(row["cc"]) self._bcc = convert_addrs(row["bcc"]) self._subject = row["subject"] self._bodystructure = convert_bodystructure(row["bodystructure"]) cur = self._cache.db.execute( """ SELECT section, body FROM gmail_message_bodies WHERE gm_msgid=? """, (self._gm_msgid,), ) self._body_sections = {row["section"]: row["body"] for row in cur} self._root_view.on_open_message(self._mailbox, self._uid, self._bodystructure is None) if self._bodystructure: self._open_body_sections() self._redraw() def close(self): self._cache.db.execute("DROP TRIGGER message_view_update_bodystructure") self._cache.db.execute("DROP TRIGGER message_view_add_body_section") self._cache.db.create_function("message_view_update_bodystructure", 0, None) self._cache.db.create_function("message_view_add_body_section", 0, None) def on_update_bodystructure(self, bodystructure): self._bodystructure = convert_bodystructure(bodystructure) self._open_body_sections() self._redraw() def on_add_body_section(self, section, body): self._body_sections[section] = body self._redraw() def _walk_body(self): def _walk_body_helper(body, section): if body.type == "multipart": if body.subtype == "mixed": for i, part in enumerate(body.parts, 1): section.append(str(i)) yield from _walk_body_helper(part, section) section.pop() elif body.subtype == "alternative": # TODO: handle this properly yield body, ".".join(section) section.append("1") yield from _walk_body_helper(body.parts[0], section) section.pop() else: yield body, ".".join(section) else: yield body, ".".join(section) section = [] if self._bodystructure.type != "multipart": section.append("1") yield from _walk_body_helper(self._bodystructure, section) def _open_body_sections(self): sections = [] for body, section in self._walk_body(): if (body.type == "text" or body.type == "message") and section not in self._body_sections: sections.append(section) self._root_view.on_read_body_sections(self._mailbox, self._uid, sections) def _redraw(self): self._widget.reset() self._add_addrs("From", self._from) self._add_addrs("To", self._to) self._add_addrs("Cc", self._cc) self._add_addrs("Bcc", self._bcc) date = self._date.strftime("%a, %b, %Y at %I:%M %p") self._widget.add("Date: %s\n" % date, "header") if self._subject: self._widget.add("Subject: %s\n" % self._subject, "header") self._widget.add("\n", "body") if self._bodystructure: for body, section in self._walk_body(): if body.type == "multipart": if body.subtype == "alternative": alternatives = ", ".join("%s/%s" % (part.type, part.subtype) for part in body.parts) body_div = "[-- Type: %s/%s, Alternatives: [%s] --]\n" % (body.type, body.subtype, alternatives) else: body_div = "[-- Type: %s/%s --]\n" % (body.type, body.subtype) else: size = sizeof_fmt(body.size) body_div = "[-- Type: %s/%s, Encoding: %s, Size: %s --]\n" % ( body.type, body.subtype, body.encoding, size, ) self._widget.add(body_div, "header") if body.type == "text" or body.type == "message": try: content = self._body_sections[section] except KeyError: continue decoded = self._decode_text_body(body, content) self._widget.add(decoded, "body") self._widget.flush() self._widget.refresh() def _add_addrs(self, label, addrs): if addrs: self._widget.add("%s: %s\n" % (label, ", ".join(addrs)), "header") @staticmethod def _decode_text_body(body, content): # TODO: be robust here if body.encoding == "quoted-printable": content = quopri.decodestring(content) elif body.encoding == "base64": content = base64.b64decode(content) elif body.encoding != "7bit" and body.encoding != "8bit": assert False, body.encoding charset = body.params.get("charset", "us-ascii") return content.decode(charset) def handle_input(self, view, c): if c == ord("i"): view.close_message_view() return True elif c == ord("j"): self._widget.scroll(1) self._widget.refresh() return True elif c == ord("k"): self._widget.scroll(-1) self._widget.refresh() return True else: return False def resize(self, nlines, ncols): self._widget.resize(nlines, ncols) self._redraw() def hide(self): return self._widget.setwin(None) def show(self, window): self._widget.setwin(window) self._redraw()