Example #1
0
    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()
Example #2
0
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()