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 = {} partial_message_cache = {}
def render_body(msg): def render_body(msg):
content_type = msg.get_content_type() def render_text_plain(msg):
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":
bodytmpl = jenv.get_template("body_text_plain.html") bodytmpl = jenv.get_template("body_text_plain.html")
context = { context = {
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1") "body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
} }
bodyhtml = bodytmpl.render(context) 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 = [] partshtml = []
for part in msg.get_payload(): for part in msg.get_payload():
partshtml.append(render_body(part)) partshtml.append(render_body(part))
@ -107,7 +102,7 @@ def render_body(msg):
"parts": partshtml "parts": partshtml
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "multipart/digest": def render_multipart_digest(msg):
partshtml = [] partshtml = []
for part in msg.get_payload(): for part in msg.get_payload():
partshtml.append(render_message(part)) partshtml.append(render_message(part))
@ -116,7 +111,7 @@ def render_body(msg):
"parts": partshtml "parts": partshtml
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "message/rfc822": def render_message_rfc822(msg):
partshtml = [] partshtml = []
for part in msg.get_payload(): for part in msg.get_payload():
partshtml.append(render_message(part)) partshtml.append(render_message(part))
@ -125,7 +120,7 @@ def render_body(msg):
"parts": partshtml "parts": partshtml
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "text/html": def render_text_html(msg):
htmlpart = HTMLPart() htmlpart = HTMLPart()
htmlpart.feed(msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")) htmlpart.feed(msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1"))
bodytmpl = jenv.get_template("body_text_html.html") bodytmpl = jenv.get_template("body_text_html.html")
@ -133,7 +128,7 @@ def render_body(msg):
"body": jinja2.Markup(htmlpart.as_string()) "body": jinja2.Markup(htmlpart.as_string())
} }
bodyhtml = bodytmpl.render(context) 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") payload = msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
tepart = TextEnrichedPart(payload) tepart = TextEnrichedPart(payload)
bodytmpl = jenv.get_template("body_text_enriched.html") bodytmpl = jenv.get_template("body_text_enriched.html")
@ -141,7 +136,7 @@ def render_body(msg):
"body": jinja2.Markup(tepart.as_string()) "body": jinja2.Markup(tepart.as_string())
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "message/partial": def render_message_partial(msg):
# Default header for get_param is Content-Type # Default header for get_param is Content-Type
whole_msg_id = msg.get_param("id") whole_msg_id = msg.get_param("id")
if not whole_msg_id in partial_message_cache: if not whole_msg_id in partial_message_cache:
@ -167,10 +162,10 @@ def render_body(msg):
encode_message_id(whole_msg_id), encode_message_id(whole_msg_id),
html.escape(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") bodyhtml = save_part(msg, "attachment")
elif content_type == "multipart/signed": def render_multipart_signed(msg):
content, signature = msg.get_payload() content, signature = msg.get_payload()
with tempfile.NamedTemporaryFile(buffering=0) as content_fh: with tempfile.NamedTemporaryFile(buffering=0) as content_fh:
content_fh.write(content.as_bytes()) content_fh.write(content.as_bytes())
@ -194,7 +189,7 @@ def render_body(msg):
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "application/pgp": def render_application_pgp(msg):
with tempfile.NamedTemporaryFile(buffering=0) as content_fh: with tempfile.NamedTemporaryFile(buffering=0) as content_fh:
content_fh.write(msg.get_payload(decode=True)) content_fh.write(msg.get_payload(decode=True))
r = subprocess.run(["gpg", "--decrypt", content_fh.name], r = subprocess.run(["gpg", "--decrypt", content_fh.name],
@ -217,7 +212,7 @@ def render_body(msg):
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "multipart/alternative": def render_multipart_alternative(msg):
partshtml = [] partshtml = []
partstypes = [] partstypes = []
for part in msg.get_payload(): for part in msg.get_payload():
@ -230,24 +225,24 @@ def render_body(msg):
} }
bodyhtml = bodytmpl.render(context) 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") bodytmpl = jenv.get_template("body_application_x-unknown-content-type-scpfile.html")
context = { context = {
"body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1") "body": msg.get_payload(decode=True).decode(msg.get_charset() or "iso-8859-1")
} }
bodyhtml = bodytmpl.render(context) 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 # A PGP signature outside of a multipart/signed - useless
bodytmpl = jenv.get_template("body_application_pgp-signature.html") bodytmpl = jenv.get_template("body_application_pgp-signature.html")
context = { context = {
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "application/x-gzip": def render_application_x_gzip(msg):
bodyhtml = save_part(msg, "attachment") bodyhtml = save_part(msg, "attachment")
elif content_type == "message/news": def render_message_news(msg):
partshtml = [] partshtml = []
for part in msg.get_payload(): for part in msg.get_payload():
partshtml.append(render_message(part)) partshtml.append(render_message(part))
@ -258,11 +253,37 @@ def render_body(msg):
} }
bodyhtml = bodytmpl.render(context) bodyhtml = bodytmpl.render(context)
elif content_type == "image/gif": def render_image_gif(msg):
bodyhtml = save_part(msg, "inline") 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: else:
raise RuntimeError("Content-type " + content_type + " not implemented yet") bodyhtml = renderers[content_type](msg)
return jinja2.Markup(bodyhtml) return jinja2.Markup(bodyhtml)