Implement format=flowed and fix charset handling for text/plain

This commit is contained in:
Peter J. Holzer 2019-05-20 00:32:33 +02:00
parent 647e93afd5
commit b1dbb3d40c
3 changed files with 128 additions and 5 deletions

105
mbox2web
View File

@ -130,11 +130,25 @@ partial_message_cache = {}
def render_body(msg, extra=None): def render_body(msg, extra=None):
def render_text_plain(msg, extra=None): def render_text_plain(msg, extra=None):
bodytmpl = jenv.get_template("body_text_plain.html") # msg.get_charset() doesn't work
context = { ct_params = dict(msg.get_params() or [])
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1") charset = ct_params.get("charset", "iso-8859-1")
} format = ct_params.get("format", "fixed")
return bodytmpl.render(context) 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): def render_multipart_mixed(msg, extra=None):
parts = msg.get_payload() parts = msg.get_payload()
if type(parts) == str: if type(parts) == str:
@ -627,6 +641,87 @@ class TextEnrichedPart:
return self.stack[0].as_string() 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 += "<blockquote>\n"
prev_quote_depth += 1
while ln["quote_depth"] < prev_quote_depth:
s += "</blockquote>\n"
prev_quote_depth -= 1
if ln["flowed"]:
s += "<p class='flowed'>" + html.escape(ln["content"]) + "</p>\n"
else:
s += "<p class='fixed'>" + html.escape(ln["content"]) + "</p>\n"
while 0 < prev_quote_depth:
s += "</blockquote>"
prev_quote_depth -= 1
return s
for f in sys.argv[1:]: for f in sys.argv[1:]:
print("F", f, file=sys.stderr) print("F", f, file=sys.stderr)
mb = mailbox.mbox(f) mb = mailbox.mbox(f)

View File

@ -42,3 +42,23 @@ th {
.partinner.html { .partinner.html {
max-width: 40rem; 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;
}

View File

@ -0,0 +1,8 @@
<div class="partouter">
<div class="partheader">
text/plain
</div>
<div class="partinner text_plain_flowed">
{{body}}
</div>
</div>