diff options
Diffstat (limited to 'lib/JWebmail/Plugin')
-rw-r--r-- | lib/JWebmail/Plugin/Helper.pm | 68 | ||||
-rw-r--r-- | lib/JWebmail/Plugin/RenderMail.pm | 182 |
2 files changed, 189 insertions, 61 deletions
diff --git a/lib/JWebmail/Plugin/Helper.pm b/lib/JWebmail/Plugin/Helper.pm index a98f245..b298a17 100644 --- a/lib/JWebmail/Plugin/Helper.pm +++ b/lib/JWebmail/Plugin/Helper.pm @@ -98,45 +98,6 @@ sub parse_iso_date { }; } -sub to_mime_type { - my $c = shift; - my ($mime_head) = @_; - - return "$mime_head->{content_maintype}/$mime_head->{content_subtype}"; -} - - -### mime type html render functions - -my $render_text_plain = sub { - my ($c, $content) = @_; - - $content = xml_escape($content); - $content =~ s/\n/<br>/g; - - return $content; -}; - -my $render_text_html = sub { - my $c_ = shift; - - return '<iframe src="' . $c_->url_for('read', id => $c_->stash('id'))->query(body => 'html') . '" class=html-mail></iframe>'; -}; - -our %MIME_Render_Subs = ( - 'text/plain' => $render_text_plain, - 'text/html' => $render_text_html, -); - -sub mime_render { - my ($c, $enc, $cont) = @_; - - ($enc) = $enc =~ m<^(\w+/\w+);?>; - - my $renderer = $MIME_Render_Subs{$enc} // return; - return $renderer->($c, $cont); -}; - ### session password handling @@ -210,7 +171,7 @@ sub warn_crypt { state $once = 0; - if ( !TRUE_RANDOM && !$once && lc($c->config->{session}{secure}) eq 's3d' ) { + if ( !TRUE_RANDOM && !$once && lc $c->config->{session}{secure} eq 's3d' ) { $c->log->warn("Falling back to pseudo random generation. Please install Crypt::URandom"); $once = 1; } @@ -308,8 +269,6 @@ sub register { if contains 'parse_iso_date'; $app->helper(print_sizes2 => sub { shift; print_sizes2(@_) }) if contains 'print_sizes2'; - $app->helper(to_mime_type => \&to_mime_type) - if contains 'to_mime_type'; $app->helper(mime_render => \&mime_render) if contains 'mime_render'; $app->helper(session_passwd => \&session_passwd) @@ -324,7 +283,6 @@ sub register { elsif (!$conf->{import}) { # default imports $app->helper(print_sizes10 => sub { shift; print_sizes10(@_) }); $app->helper(parse_iso_date => sub { shift; parse_iso_date(@_) }); - $app->helper(to_mime_type => \&to_mime_type); $app->helper(mime_render => \&mime_render); $app->helper(session_passwd => \&session_passwd); $app->helper(paginate => \&paginate); @@ -333,6 +291,9 @@ sub register { $app->validator->add_filter(non_empty_ul => \&filter_empty_upload); } + else { + die 'unkown value for "import"' + } } @@ -350,16 +311,10 @@ Helper - Functions used as helpers in controller and templates and additional va use Mojo::Base 'Mojolicious'; - use JWebmail::Plugin::Helper; - sub startup($self) { - $self->helper(mime_render => \&JWebmail::Plugin::Helper::mime_render); + $app->plugin('Helper'); } - # or - - $app->plugin('Helper'); - =head1 DESCRIPTION L<JWebmail::Helper> provides useful helper functions and validator cheks and filter for @@ -425,15 +380,6 @@ Sets the stash values (all 1 based inclusive): next_page last_page -=head2 mime_render - -A helper for templates used to display the content of a mail for the browser. -The output is valid html and should not be escaped. - - $app->helper(mime_render => \&JWebmail::Plugin::Helper::mime_render); - - %== mime_render 'text/plain' $content - =head2 session_passwd A helper used to set and get the session password. The behavior can be altered by @@ -469,11 +415,11 @@ On log-in it is transfered plainly. =head1 DEPENDENCIES -Mojolicious and optionally Digest::HMAC_MD5, Crypt::URandom. +Mojolicious and recommended Crypt::URandom. =head1 SEE ALSO -L<JWebmail>, L<JWebmail::Controller::All>, L<Mojolicious>, L<Mojolicious::Controller> +L<JWebmail> =head1 NOTICE 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. + |