1 # Copyright (C) 2014, Eric Wong <normalperson@yhbt.net> and all contributors
2 # License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
3 package PublicInbox::View;
6 use CGI qw/escapeHTML escape/;
7 use Encode qw/decode encode/;
8 use Encode::MIME::Header;
10 # only one public function:
12 my ($class, $mime, $full_pfx) = @_;
14 headers_to_html_header($mime) .
15 multipart_text_as_html($mime, $full_pfx) .
19 # only private functions below.
21 sub multipart_text_as_html {
22 my ($mime, $full_pfx) = @_;
26 # scan through all parts, looking for displayable text
27 $mime->walk_parts(sub {
29 return if $part->subparts; # walk_parts already recurses
31 my $part_type = $part->content_type;
32 if ($part_type =~ m!\btext/[a-z0-9\+\._-]+\b!i) {
33 my $fn = $part->filename;
36 defined($fn) or $fn = "part #" . ($part_nr + 1);
37 $rv .= add_filename_line($fn);
40 if (defined $full_pfx) {
41 $rv .= add_text_body_short($part, $part_nr,
44 $rv .= add_text_body_full($part, $part_nr);
46 $rv .= "\n" unless $rv =~ /\n\z/s;
48 $rv .= "-- part #" . ($part_nr + 1) . " ";
49 $rv .= escapeHTML($part_type);
57 sub add_filename_line {
63 $pad x= ($len/2) if ($len > 0);
64 "$pad " . escapeHTML($fn) . " $pad\n";
67 sub add_text_body_short {
68 my ($part, $part_nr, $full_pfx) = @_;
70 my $s = escapeHTML($part->body);
71 $s =~ s!^((?:(?:>[^\n]+)\n)+)!
73 my @lines = split(/\n/, $cur);
75 # show a short snippet of quoted text
76 $cur = join(' ', @lines);
79 my @sum = split(/\s+/, $cur);
82 $cur .= shift(@sum) . ' ';
83 } while (@sum && length($cur) < 68);
85 "> <<a href=${full_pfx}#q${part_nr}_" . $n++ .
94 sub add_text_body_full {
95 my ($part, $part_nr) = @_;
97 my $s = escapeHTML($part->body);
98 $s =~ s!^((?:(?:>[^\n]+)\n)+)!
100 my @lines = split(/\n/, $cur);
102 "<a name=q${part_nr}_" . $n++ . ">$cur</a>";
110 sub trim_message_id {
113 my $html = escapeHTML($mid);
114 my $href = escapeHTML(escape($mid));
119 sub headers_to_html_header {
124 foreach my $h (qw(From To Cc Subject Date)) {
125 my $v = $simple->header($h);
127 $v = decode("MIME-Header", $v);
128 $v = encode("utf8", $v);
133 if ($h eq "From" || $h eq "Subject") {
138 my $mid = $simple->header('Message-ID');
140 my ($html, $href) = trim_message_id($mid);
141 $rv .= "Message-ID: <a href=$href.html>$html</a> ";
142 $rv .= "(<a href=$href.txt>raw message</a>)\n";
145 my $irp = $simple->header('In-Reply-To');
147 my ($html, $href) = trim_message_id($irp);
148 $rv .= "In-Reply-To: <a href=$href.html>$html</a>\n";
152 return ("<html><head><title>".
153 join(' - ', @title) .
154 '</title></head><body><pre style="white-space:pre-wrap">' .