summaryrefslogtreecommitdiff
path: root/lib/JWebmail/View
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2023-03-13 21:34:03 +0100
committerJannis M. Hoffmann <jannis@fehcom.de>2023-03-13 21:34:03 +0100
commit8ee2d7149baa58ea225cb40e0f95030ee21f1081 (patch)
tree11d2bd52f36d3d566f9abcb30654b9bd78e56422 /lib/JWebmail/View
parent6441b5ad6657873fcd8f3695515fa6ef3bc4e6f5 (diff)
Split up Helper plugin and added Views instead
Diffstat (limited to 'lib/JWebmail/View')
-rw-r--r--lib/JWebmail/View/RenderMail.pm191
-rw-r--r--lib/JWebmail/View/Webmail.pm88
2 files changed, 279 insertions, 0 deletions
diff --git a/lib/JWebmail/View/RenderMail.pm b/lib/JWebmail/View/RenderMail.pm
new file mode 100644
index 0000000..07f356c
--- /dev/null
+++ b/lib/JWebmail/View/RenderMail.pm
@@ -0,0 +1,191 @@
+package JWebmail::View::RenderMail;
+
+use Mojo::Base -base;
+
+use Mojo::ByteStream;
+use Mojo::Util 'xml_escape';
+
+
+has 'c';
+
+
+sub render_text_plain {
+ my ($_self, $_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 ($self, $_subtype, $_content, $path) = @_;
+
+ my $url = $self->c->url_for('raw', id => $self->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_image {
+ my ($_self, $subtype, $content, $_path) = @_;
+
+ return qq'<img src="data:image/$subtype;base64,$content" />';
+}
+
+sub render_multipart_alternative {
+ my ($self, $_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 = $self->mime_render(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 .= $self->mime_render(to_mime_types($_->{head}), $_->{body}, [@$path, $#$parts-$i]);
+ $R .= "</details>\n";
+ }
+ ++$i;
+ }
+ return $R . "</div>\n";
+}
+
+sub render_multipart {
+ my ($self, $_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 .= $self->mime_render(to_mime_types($_->{head}), $_->{body}, [@$path, $i]);
+ }
+ elsif (lc $_->{head}{content_disposition} eq 'attachment') {
+ $R .= '<p>';
+ $R .= $self->c->link_to($self->c->url_for(raw => id => $self->c->stash('id'))->query(path => join('.', @$path, $i)), (download => $_->{head}{filename}) => sub {
+ 'Attachment ' . xml_escape($_->{head}{filename}) . ' of type ' . to_mime_type($_->{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 ($self, $category, $value) = @_;
+
+ my $R = '';
+
+ if (ref $value eq 'ARRAY' && $value->@*) {
+ $R .= '<dt>' . xml_escape(uc $self->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 ($self, $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 $self->c->l('subject')) . '</dt>';
+ $R .= '<dd>' . xml_escape($msg->{head}{subject}) . "</dd>\n";
+ $R .= $self->_format_header(from => $msg->{head}{from});
+ $R .= $self->_format_header(to => $msg->{head}{to});
+ $R .= $self->_format_header(cc => $msg->{head}{cc});
+ $R .= $self->_format_header(bcc => $msg->{head}{bcc});
+ $R .= '<dt>' . xml_escape(uc $self->c->l('date')) . '</dt>';
+ $R .= '<dd>' . xml_escape($msg->{head}{date}) . "</dd>\n";
+ $R .= '<dt>' . xml_escape(uc $self->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 .= $self->mime_render(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,
+ 'image' => \&render_image,
+);
+
+sub mime_render {
+ my ($self, $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->($self, $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 format_mail {
+ my ($self, $mail) = @_;
+
+ return Mojo::ByteStream->new($self->mime_render('message', 'rfc822', $mail, []));
+}
+
+1
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+JWebmail::View::RenderMail - Does the heavy lifting of converting an E-Mail to HTML
+
+=head1 FUNCTIONS
+
+=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.
+
+=head1 METHODS
+
+=head2 format_mail
+
+Renders a mail to html recursively.
diff --git a/lib/JWebmail/View/Webmail.pm b/lib/JWebmail/View/Webmail.pm
new file mode 100644
index 0000000..464c97e
--- /dev/null
+++ b/lib/JWebmail/View/Webmail.pm
@@ -0,0 +1,88 @@
+package JWebmail::View::Webmail;
+
+use Mojo::Base -base;
+
+use POSIX qw(floor round log);
+
+
+### template formatting functions
+
+sub print_sizes10 {
+ shift;
+ my $var = shift || return '0 Byte';
+
+ my $i = floor(((log($var)/log(10))+1e-5) / 3);
+ my $expo = $i * 3;
+
+ my @PREFIX;
+ $PREFIX[0] = 'Byte';
+ $PREFIX[1] = 'kByte';
+ $PREFIX[2] = 'MByte';
+ $PREFIX[3] = 'GByte';
+ $PREFIX[4] = 'TByte';
+ $PREFIX[5] = 'PByte';
+
+ return sprintf('%.0f %s', $var / (10**$expo), $PREFIX[$i]);
+}
+
+sub print_sizes2 {
+ shift;
+ my $var = shift || return '0 Byte';
+
+ my $i = floor(((log($var)/log(2))+1e-5) / 10);
+ my $expo = $i * 10;
+ my %PREFIX = (
+ 0 => 'Byte',
+ 1 => 'KiByte',
+ 2 => 'MiByte',
+ 3 => 'GiByte',
+ 4 => 'TiByte',
+ 5 => 'PiByte',
+ );
+ my $pref = $PREFIX{$i};
+ return round($var / (2**$expo)) . " $pref";
+}
+
+my sub dgt { "([[:digit:]]{$_[0]})" }
+
+sub parse_iso_date {
+ shift;
+ state $rx = do { my $re = dgt(4).'-'.dgt(2).'-'.dgt(2).'T'.dgt(2).':'.dgt(2).':'.dgt(2); qr/$re/a };
+ my @d = shift =~ /$rx/;
+ if (@d != 6) {
+ # TODO
+ warn "issue when parsing date";
+ }
+ return {
+ year => $d[0],
+ month => $d[1],
+ mday => $d[2],
+ hour => $d[3],
+ min => $d[4],
+ sec => $d[5],
+ };
+}
+
+1
+
+__END__
+
+=head1 VIEW METHODS
+
+=head2 print_sizes10
+
+A helper for templates used to format byte sizes.
+
+ $app->helper(print_sizes10 => sub { shift; JWebmail::Plugin::Helper::print_sizes10(@_) });
+
+ %= print_sizes10 12345 # => 12 kB
+
+=head2 print_sizes2
+
+A helper for templates used to format byte sizes.
+
+ %= print_sizes10 12345 # => 12 KiB
+
+This is not registered by default.
+
+=head2 parse_iso_date