diff --git a/mbox2web b/mbox2web index 7f03952..cd3e842 100755 --- a/mbox2web +++ b/mbox2web @@ -130,11 +130,25 @@ partial_message_cache = {} def render_body(msg, extra=None): def render_text_plain(msg, extra=None): - bodytmpl = jenv.get_template("body_text_plain.html") - context = { - "body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1") - } - return bodytmpl.render(context) + # msg.get_charset() doesn't work + ct_params = dict(msg.get_params() or []) + charset = ct_params.get("charset", "iso-8859-1") + format = ct_params.get("format", "fixed") + if format == "fixed": + bodytmpl = jenv.get_template("body_text_plain.html") + context = { + "body": msg.get_payload(decode=True).decode(charset) + } + return bodytmpl.render(context) + elif format == "flowed": + bodytmpl = jenv.get_template("body_text_plain_flowed.html") + parthtml = TextFlowedPart(msg).as_string() + context = { + "body": jinja2.Markup(parthtml), + } + return bodytmpl.render(context) + else: + raise NotImplementedError() def render_multipart_mixed(msg, extra=None): parts = msg.get_payload() if type(parts) == str: @@ -627,6 +641,87 @@ class TextEnrichedPart: return self.stack[0].as_string() +class TextFlowedPart: + def __init__(self, msg): + self.quote_depth = 0 + self.current_line = "" + self.flowed = False + self.lines = [] + self.buffer_filled = False + + ct_params = dict(msg.get_params()) + charset = ct_params.get("charset", "iso-8859-1") + format = ct_params.get("format", "fixed") + delsp = ct_params.get("delsp", "no") == "yes" + raw_text = msg.get_payload(decode=True).decode(charset) + raw_lines = raw_text.split("\n") + + for rl in raw_lines: + quote_depth = 0 + while rl[:1] == ">": + quote_depth += 1 + rl = rl[1:] + if rl[:1] == " ": + rl = rl[1:] + if rl == "-- ": + flowed = None + elif rl[-1:] == " ": + flowed = True + if delsp: + rl = rl[:-1] + else: + flowed = False + self.add_buffer(rl, quote_depth, flowed) + self.flush() + + def add_buffer(self, line, quote_depth, flowed): + if flowed is None: + self.flush() + flowed = False + if quote_depth != self.quote_depth: + self.flush() + self.quote_depth = quote_depth + self.current_line += line + self.flowed |= flowed + self.buffer_filled = True + if not flowed: + self.flush() + + def flush(self): + if self.buffer_filled: + self.lines.append({ + "quote_depth": self.quote_depth, + "flowed": self.flowed, + "content": self.current_line + }) + self.current_line = "" + self.flowed = False + self.buffer_filled = False + + def as_string(self): + prev_quote_depth = 0 + s = "" + for ln in self.lines: + while ln["quote_depth"] > prev_quote_depth: + s += "
\n" + prev_quote_depth += 1 + while ln["quote_depth"] < prev_quote_depth: + s += "
\n" + prev_quote_depth -= 1 + if ln["flowed"]: + s += "

" + html.escape(ln["content"]) + "

\n" + else: + s += "

" + html.escape(ln["content"]) + "

\n" + while 0 < prev_quote_depth: + s += "" + prev_quote_depth -= 1 + return s + + + + + + for f in sys.argv[1:]: print("F", f, file=sys.stderr) mb = mailbox.mbox(f) diff --git a/style/debug.css b/style/debug.css index ccec653..acd6423 100644 --- a/style/debug.css +++ b/style/debug.css @@ -42,3 +42,23 @@ th { .partinner.html { max-width: 40rem; } + +p.fixed { + font-family: monospace; + white-space: pre; + margin: 0.2em; +} + +p.flowed { + font-family: monospace; + white-space: pre-wrap; + max-width: 60em; + margin: 0.2em; +} + +.text_plain_flowed blockquote { + border-left: solid 0.2em #004; + padding-left: 0.8em; + margin: 0em; + background: #EEF; +} diff --git a/templates/body_text_plain_flowed.html b/templates/body_text_plain_flowed.html new file mode 100644 index 0000000..f774190 --- /dev/null +++ b/templates/body_text_plain_flowed.html @@ -0,0 +1,8 @@ +
+
+ text/plain +
+
+{{body}} +
+