From b053ab454fa60b8abef0a54aee447cf8130959de Mon Sep 17 00:00:00 2001 From: "Peter J. Holzer" Date: Sun, 17 Mar 2019 22:17:02 +0100 Subject: [PATCH] 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. --- mbox2web | 73 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/mbox2web b/mbox2web index 2a29c36..5d11e25 100755 --- a/mbox2web +++ b/mbox2web @@ -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)