Refactor render_body to handle each mime-type in a nested function

This replaces the giant elif cascade with a table lookup. It also allows
me to call one function from another.
This commit is contained in:
Peter J. Holzer 2019-03-17 22:17:02 +01:00
parent 035b4e1002
commit b053ab454f
1 changed files with 47 additions and 26 deletions

View File

@ -83,22 +83,17 @@ def save_part(msg, disposition):
partial_message_cache = {}
def render_body(msg):
content_type = msg.get_content_type()
content_disposition = msg.get_content_disposition()
if content_disposition == "attachment":
# XXX - not sure, if we should just store all content-types.
# We probably should clean up html. Alternatively we could just store
# all of them application/octet-stream, which browsers should download
# and not try to display.
bodyhtml = save_part(msg, content_disposition)
elif content_type == "text/plain":
def render_text_plain(msg):
bodytmpl = jenv.get_template("body_text_plain.html")
context = {
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
}
bodyhtml = bodytmpl.render(context)
elif content_type == "multipart/mixed":
def render_multipart_mixed(msg):
parts = msg.get_payload()
if type(parts) == str:
# mislabelled, assume text/plain
raise NotImplementedError()
partshtml = []
for part in msg.get_payload():
partshtml.append(render_body(part))
@ -107,7 +102,7 @@ def render_body(msg):
"parts": partshtml
}
bodyhtml = bodytmpl.render(context)
elif content_type == "multipart/digest":
def render_multipart_digest(msg):
partshtml = []
for part in msg.get_payload():
partshtml.append(render_message(part))
@ -116,7 +111,7 @@ def render_body(msg):
"parts": partshtml
}
bodyhtml = bodytmpl.render(context)
elif content_type == "message/rfc822":
def render_message_rfc822(msg):
partshtml = []
for part in msg.get_payload():
partshtml.append(render_message(part))
@ -125,7 +120,7 @@ def render_body(msg):
"parts": partshtml
}
bodyhtml = bodytmpl.render(context)
elif content_type == "text/html":
def render_text_html(msg):
htmlpart = HTMLPart()
htmlpart.feed(msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1"))
bodytmpl = jenv.get_template("body_text_html.html")
@ -133,7 +128,7 @@ def render_body(msg):
"body": jinja2.Markup(htmlpart.as_string())
}
bodyhtml = bodytmpl.render(context)
elif content_type == "text/enriched":
def render_text_enriched(msg):
payload = msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
tepart = TextEnrichedPart(payload)
bodytmpl = jenv.get_template("body_text_enriched.html")
@ -141,7 +136,7 @@ def render_body(msg):
"body": jinja2.Markup(tepart.as_string())
}
bodyhtml = bodytmpl.render(context)
elif content_type == "message/partial":
def render_message_partial(msg):
# Default header for get_param is Content-Type
whole_msg_id = msg.get_param("id")
if not whole_msg_id in partial_message_cache:
@ -167,10 +162,10 @@ def render_body(msg):
encode_message_id(whole_msg_id),
html.escape(whole_msg_id))
elif content_type == "application/octet-stream":
def render_application_octet_stream(msg):
bodyhtml = save_part(msg, "attachment")
elif content_type == "multipart/signed":
def render_multipart_signed(msg):
content, signature = msg.get_payload()
with tempfile.NamedTemporaryFile(buffering=0) as content_fh:
content_fh.write(content.as_bytes())
@ -194,7 +189,7 @@ def render_body(msg):
}
bodyhtml = bodytmpl.render(context)
elif content_type == "application/pgp":
def render_application_pgp(msg):
with tempfile.NamedTemporaryFile(buffering=0) as content_fh:
content_fh.write(msg.get_payload(decode=True))
r = subprocess.run(["gpg", "--decrypt", content_fh.name],
@ -217,7 +212,7 @@ def render_body(msg):
}
bodyhtml = bodytmpl.render(context)
elif content_type == "multipart/alternative":
def render_multipart_alternative(msg):
partshtml = []
partstypes = []
for part in msg.get_payload():
@ -230,24 +225,24 @@ def render_body(msg):
}
bodyhtml = bodytmpl.render(context)
elif content_type == "application/x-unknown-content-type-scpfile":
def render_application_x_unknown_content_type_scpfile(msg):
bodytmpl = jenv.get_template("body_application_x-unknown-content-type-scpfile.html")
context = {
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
}
bodyhtml = bodytmpl.render(context)
elif content_type == "application/pgp-signature":
def render_application_pgp_signature(msg):
# A PGP signature outside of a multipart/signed - useless
bodytmpl = jenv.get_template("body_application_pgp-signature.html")
context = {
}
bodyhtml = bodytmpl.render(context)
elif content_type == "application/x-gzip":
def render_application_x_gzip(msg):
bodyhtml = save_part(msg, "attachment")
elif content_type == "message/news":
def render_message_news(msg):
partshtml = []
for part in msg.get_payload():
partshtml.append(render_message(part))
@ -258,11 +253,37 @@ def render_body(msg):
}
bodyhtml = bodytmpl.render(context)
elif content_type == "image/gif":
def render_image_gif(msg):
bodyhtml = save_part(msg, "inline")
renderers = {
"text/plain": render_text_plain,
"multipart/mixed": render_multipart_mixed,
"multipart/digest": render_multipart_digest,
"message/rfc822": render_message_rfc822,
"text/html": render_text_html,
"text/enriched": render_text_enriched,
"message/partial": render_message_partial,
"application/octet-stream": render_application_octet_stream,
"multipart/signed": render_multipart_signed,
"application/pgp": render_application_pgp,
"multipart/alternative": render_multipart_alternative,
"application/x-unknown-content-type-scpfile": render_application_x_unknown_content_type_scpfile,
"application/pgp-signature": render_application_pgp_signature,
"application/x-gzip": render_application_x_gzip,
"message/news": render_message_news,
"image/gif": render_image_gif,
}
content_type = msg.get_content_type()
content_disposition = msg.get_content_disposition()
if content_disposition == "attachment":
# XXX - not sure, if we should just store all content-types.
# We probably should clean up html. Alternatively we could just store
# all of them application/octet-stream, which browsers should download
# and not try to display.
bodyhtml = save_part(msg, content_disposition)
else:
raise RuntimeError("Content-type " + content_type + " not implemented yet")
bodyhtml = renderers[content_type](msg)
return jinja2.Markup(bodyhtml)