diff options
author | Jannis M. Hoffmann <jannis@fehcom.de> | 2023-03-10 13:54:57 +0100 |
---|---|---|
committer | Jannis M. Hoffmann <jannis@fehcom.de> | 2023-03-10 13:54:57 +0100 |
commit | fcf5549584b69e62b6c2f0eb919f6799c7904211 (patch) | |
tree | e5f0e480af0f39f1c0f457ea0aca8d33f8fb4d0b /lib/JWebmail/Plugin/RenderMail.pm | |
parent | df59f9dec32d7f8f08706fd3eb5b784deaa0abfc (diff) |
Proper recursive rendering of mails to html
1. Added raw mode to model
2. Added raw route
3. Moved readmail view parts to RenderMail plugin
4. Renamed displayheaders partial templates
Diffstat (limited to 'lib/JWebmail/Plugin/RenderMail.pm')
-rw-r--r-- | lib/JWebmail/Plugin/RenderMail.pm | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/lib/JWebmail/Plugin/RenderMail.pm b/lib/JWebmail/Plugin/RenderMail.pm new file mode 100644 index 0000000..4417fae --- /dev/null +++ b/lib/JWebmail/Plugin/RenderMail.pm @@ -0,0 +1,182 @@ +package JWebmail::Plugin::RenderMail; + +use Mojo::Base 'Mojolicious::Plugin'; + +use Mojo::ByteStream; +use Mojo::Util 'xml_escape'; + + +sub render_text_plain { + my ($_c, $_subtype, $content, $_path) = @_; + + $content = xml_escape($content); + $content =~ s/\n/<br>/g; + + return qq'<div class="jwm-mail-body jwm-mail-body-text-plain">\n $content </div>\n'; +} + +sub render_text_html { + my ($c, $_subtype, $_content, $path) = @_; + + my $url = $c->url_for('raw', id => $c->stash('id')); + $url = $url->query(path => join('.', @$path)) if @$path; + + return qq'<iframe src="$url" class="jwm-mail-body-text-html" ></iframe>\n'; +} + +sub render_multipart_alternative { + my ($c, $_subtype, $content, $path) = @_; + + my $parts = $content->{parts}; + my $R = qq'<div class="jwm-mail-body jwm-mail-body-multipart-alternative"\n>'; + my $i = 0; + my $end; + + for (reverse @$parts) { + if (!$end) { + my $x = mime_render($c, to_mime_types($_->{head}), $_->{body}, [@$path, $#$parts-$i]); + if ($x) { + $R .= $x; + $end = 1; + } + } + else { + $R .= '<details class="jwm-mail-body-multipart-alternative-extra" >'; + $R .= '<summary>'; + $R .= to_mime_type($_->{head}); + $R .= "</summary>\n"; + $R .= mime_render($c, to_mime_types($_->{head}), $_->{body}, [@$path, $#$parts-$i]); + $R .= "</details>\n"; + } + ++$i; + } + return $R . "</div>\n"; +} + +sub render_multipart { + my ($c, $_subtype, $content, $path) = @_; + + my $parts = $content->{parts}; + my $R = qq'<div class="jwm-mail-body jwm-mail-body-multipart"\n>'; + my $i = 0; + + for (@$parts) { + if ( !$_->{head}{content_disposition} + || lc $_->{head}{content_disposition} eq 'none' + || lc $_->{head}{content_disposition} eq 'inline') { + + $R .= mime_render($c, to_mime_types($_->{head}), $_->{body}, [@$path, $i]); + } + elsif (lc $_->{head}{content_disposition} eq 'attachment') { + $R .= '<p>'; + $R .= $c->link_to($c->url_for(raw => id => $c->stash('id'))->query(path => join('.', @$path, $i))->to_abs, (download => $_->{head}{filename}) => sub { + 'Attachment ' . xml_escape($_->{head}{filename}) . ' of type ' . to_mime_type($c, $_->{head}); + }); + $R .= "</p>\n"; + } + else { + warn "unknown Content-Disposition '$_->{head}{content_disposition}'"; + $R .= "<p>unknown Content-Disposition '$_->{head}{content_disposition}'</p>\n"; + } + ++$i; + } + return $R . "</div>\n"; +} + +sub _format_header { + my ($c, $category, $value) = @_; + + my $R = ''; + + if (ref $value eq 'ARRAY' && $value->@*) { + $R .= '<dt>' . xml_escape(uc $c->l($category)) . "</dt>\n"; + for ($value->@*) { + $R .= '<dd>'; + $R .= xml_escape($_->{display_name} ? qq("$_->{display_name}" <$_->{address}>) : "$_->{address}"); + $R .= "<dd>\n"; + } + } + return $R; +} + +sub render_message { + my ($c, $subtype, $msg, $path) = @_; + + warn "unkown mime-subtype $subtype" unless $subtype eq 'rfc822'; + + my $R .= '<div clas="jwm-mail">'; + + $R .= '<dl class="jwm-mail-header">'; + $R .= '<dt>' . xml_escape(uc $c->l('subject')) . '</dt>'; + $R .= '<dd>' . xml_escape($msg->{head}{subject}) . "</dd>\n"; + $R .= _format_header($c, from => $msg->{head}{from}); + $R .= _format_header($c, to => $msg->{head}{to}); + $R .= _format_header($c, cc => $msg->{head}{cc}); + $R .= _format_header($c, bcc => $msg->{head}{bcc}); + $R .= '<dt>' . xml_escape(uc $c->l('date')) . '</dt>'; + $R .= '<dd>' . xml_escape($msg->{head}{date}) . "</dd>\n"; + $R .= '<dt>' . xml_escape(uc $c->l('content-type')) . '</dt>'; + $R .= '<dd>' . to_mime_type($msg->{head}{mime}) . "</dd>\n"; + $R .= "</dl>\n"; + + #my $content = ref $msg->{body} && exists $msg->{body}{parts} ? $msg->{body}{parts} : $msg->{body}; + + $R .= mime_render($c, to_mime_types($msg->{head}{mime}), $msg->{body}, [@$path, 0]); + + return $R . "</div>\n"; +} + +our %MIME_Render_Subs = ( + 'text/plain' => \&render_text_plain, + 'text/html' => \&render_text_html, + 'multipart/alternative' => \&render_multipart_alternative, + 'multipart' => \&render_multipart, + 'message' => \&render_message, +); + +sub mime_render { + my ($c, $maintype, $subtype, $content, $path) = @_; + + my $renderer = $MIME_Render_Subs{"$maintype/$subtype"} || $MIME_Render_Subs{$maintype}; + + unless ($renderer) { + return "<p>Unsupported MIME type of <code>$maintype/$subtype</code>.</p>\n"; + } + + return $renderer->($c, $subtype, $content, $path); +} + + +sub to_mime_type { lc xml_escape("$_[0]->{content_maintype}/$_[0]->{content_subtype}") } +sub to_mime_types { return xml_escape($_[0]->{content_maintype}), xml_escape($_[0]->{content_subtype}) } + + +sub register { + my ($self, $app, $conf) = @_; + $conf //= {}; + + $app->helper('render_mail.format_mail' => sub { Mojo::ByteStream->new(mime_render($_[0], 'message', 'rfc822', $_[1], [])) }); + $app->helper(to_mime_type => sub { shift; to_mime_type(@_) }); +} + +1 + +__END__ + +=encoding utf-8 + +=head1 NAME + +JWebmail::Plugin::RenderMail - Does the heavy lifting of converting an E-Mail to HTML + +=head1 HELPERS + +=head2 render_mail.format_mail + +Renders a mail to html recursively. + +=head2 to_mime_type + +Combines the content_maintype and content_subtype attributes into the regular MIME description. +These attributes are found in a mail head mime section or as head for multipart messages. + |