From 2cf2a68bd1c25d8fe4f3126f40bd57982cc6b2a4 Mon Sep 17 00:00:00 2001 From: "Jannis M. Hoffmann" Date: Sun, 3 Dec 2023 19:22:12 +0100 Subject: initial commit --- src/jwebmail/render_mail.py | 160 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/jwebmail/render_mail.py (limited to 'src/jwebmail/render_mail.py') diff --git a/src/jwebmail/render_mail.py b/src/jwebmail/render_mail.py new file mode 100644 index 0000000..0e5406c --- /dev/null +++ b/src/jwebmail/render_mail.py @@ -0,0 +1,160 @@ +from flask import current_app, request, url_for +from flask_babel import gettext +from markupsafe import Markup, escape + + +def render_text_plain(_subtype, content, _path): + return f'
{escape(content)}
\n' + + +def render_text_html(_subtype, _content, path): + if path: + url = url_for( + "raw", msgid=request.view_args["msgid"], path=".".join(map(str, path)) + ) + else: + url = url_for("raw", msgid=request.view_args["msgid"]) + + return f'\n' + + +def render_image(subtype, content, _path): + return f'\n' + + +def render_multipart_alternative(_subtype, content, path): + parts = content["parts"] + T = "
" + script_url = url_for("static", filename="src/rendermail.js") + return f'
\n{T}\n{C}\n
\n' + + +def render_multipart(_subtype, content, path): + parts = content["parts"] + R = '
\n' + + for i, p in enumerate(parts): + R += "
\n" + if ( + not p["head"]["content_disposition"] + or p["head"]["content_disposition"].lower() == "none" + or p["head"]["content_disposition"].lower() == "inline" + ): + R += mime_render(*to_mime_types(p["head"]), p["body"], path + (i,)) + elif p["head"]["content_disposition"].lower() == "attachment": + link_text = gettext("Attachment {filename} of type {filetype}").format( + filename=p["head"]["filename"], filetype=to_mime_type(p["head"]) + ) + + ref_url = url_for( + "raw", + msgid=request.view_args["msgid"], + path=".".join(map(str, [*path, i])), + ) + + R += "

" + R += f'\n' + R += f"{escape(link_text)}\n" + R += "

\n" + else: + current_app.log.warning( + "unknown Content-Disposition %s", p["head"]["content_disposition"] + ) + R += f"

unknown Content-Disposition {p['head']['content_disposition']}

\n" + + R += "
\n" + + return R + "
\n" + + +def _format_header(category, value): + R = "" + + if isinstance(value, list) and value: + R += f"
{escape(category)}
\n" + for v in value: + value = ( + f'"{v["display_name"]}" <{v["address"]}>' + if v["display_name"] + else v["address"] + ) + R += f"
{escape(value)}
\n" + + return R + + +def render_message(subtype, msg, path): + if subtype != "rfc822": + current_app.log.warning("unknown message mime-subtype %s", subtype) + + R = '
' + + R += '
' + R += f"
{escape(gettext('Subject'))}
" + R += f"
{escape(msg['head']['subject'])}
\n" + R += _format_header(gettext("From"), msg["head"]["from"]) + R += _format_header(gettext("To"), msg["head"]["to"]) + R += _format_header(gettext("CC"), msg["head"]["cc"]) + R += _format_header(gettext("BCC"), msg["head"]["bcc"]) + R += f"
{escape(gettext('Date'))}
" + R += f"
{escape(msg['head']['date'])}
\n" + R += f"
{escape(gettext('Content-Type'))}
" + R += f"
{to_mime_type(msg['head']['mime'])}
\n" + R += "
\n" + + R += mime_render(*to_mime_types(msg["head"]["mime"]), msg["body"], path + (0,)) + + return R + "
\n" + + +MIMERenderSubs = { + ("text", "plain"): render_text_plain, + ("text", "html"): render_text_html, + ("multipart", "alternative"): render_multipart_alternative, + "multipart": render_multipart, + "message": render_message, + "image": render_image, +} + + +def mime_render(maintype, subtype, content, path): + renderer = MIMERenderSubs.get((maintype, subtype)) or MIMERenderSubs.get(maintype) + + if not renderer: + return f'

Unsupported MIME type of {maintype}/{subtype}.

\n' + + return renderer(subtype, content, path) + + +def to_mime_type(mime): + return escape(f"{mime['content_maintype']}/{mime['content_subtype']}".lower()) + + +def to_mime_types(mime): + return escape(mime["content_maintype"]), escape(mime["content_subtype"]) + + +def format_mail(mail): + return Markup(mime_render("message", "rfc822", mail, tuple())) -- cgit v1.2.3