X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FView.pm;h=f94daaf2bd65521a97ab591eacb102fc71056ddd;hb=6e6f7999361925e4c944f308df4bc32a1842cd69;hp=cd125e008c08ffe4c6178a60de79531241a4d179;hpb=b0e5062d43a96372801713ef78a78d6a1bc852bc;p=public-inbox.git diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm index cd125e00..f94daaf2 100644 --- a/lib/PublicInbox/View.pm +++ b/lib/PublicInbox/View.pm @@ -6,6 +6,7 @@ package PublicInbox::View; use strict; use warnings; +use bytes (); # only for bytes::length use PublicInbox::MsgTime qw(msg_datestamp); use PublicInbox::Hval qw/ascii_html obfuscate_addrs/; use PublicInbox::Linkify; @@ -14,6 +15,7 @@ use PublicInbox::MsgIter; use PublicInbox::Address; use PublicInbox::WwwStream; use PublicInbox::Reply; +use PublicInbox::ViewDiff qw(flush_diff); require POSIX; use Time::Local qw(timegm); @@ -28,7 +30,7 @@ sub msg_html { my ($ctx, $mime, $more, $smsg) = @_; my $hdr = $mime->header_obj; my $ibx = $ctx->{-inbox}; - my $obfs_ibx = $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; + $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; my $tip = _msg_html_prepare($hdr, $ctx, $more, 0); my $end = 2; PublicInbox::WwwStream->response($ctx, 200, sub { @@ -36,7 +38,7 @@ sub msg_html { if ($nr == 1) { # $more cannot be true w/o $smsg being defined: my $upfx = $more ? '../'.mid_escape($smsg->mid).'/' : ''; - $tip . multipart_text_as_html($mime, $upfx, $obfs_ibx) . + $tip . multipart_text_as_html($mime, $upfx, $ctx) . '
' } elsif ($more && @$more) { ++$end; @@ -81,15 +83,15 @@ sub msg_html_more { my $str = eval { my ($id, $prev, $smsg) = @$more; my $mid = $ctx->{mid}; - $smsg = $ctx->{-inbox}->smsg_mime($smsg); + my $ibx = $ctx->{-inbox}; + $smsg = $ibx->smsg_mime($smsg); my $next = $ctx->{srch}->next_by_mid($mid, \$id, \$prev); @$more = $next ? ($id, $prev, $next) : (); if ($smsg) { my $mime = $smsg->{mime}; my $upfx = '../' . mid_escape($smsg->mid) . '/'; _msg_html_prepare($mime->header_obj, $ctx, $more, $nr) . - multipart_text_as_html($mime, $upfx, - $ctx->{-obfs_ibx}) . + multipart_text_as_html($mime, $upfx, $ctx) . '
' } else { ''; @@ -260,7 +262,8 @@ sub index_entry { $rv .= "\n"; # scan through all parts, looking for displayable text - msg_iter($mime, sub { $rv .= add_text_body($mhref, $obfs_ibx, $_[0]) }); + my $ibx = $ctx->{-inbox}; + msg_iter($mime, sub { $rv .= add_text_body($mhref, $ctx, $_[0]) }); # add the footer $rv .= "\n^ ". @@ -396,7 +399,7 @@ sub thread_index_entry { sub stream_thread ($$) { my ($rootset, $ctx) = @_; - my $inbox = $ctx->{-inbox}; + my $ibx = $ctx->{-inbox}; my @q = map { (0, $_) } @$rootset; my $level; my $smsg; @@ -405,11 +408,11 @@ sub stream_thread ($$) { my $node = shift @q or next; my $cl = $level + 1; unshift @q, map { ($cl, $_) } @{$node->{children}}; - $smsg = $inbox->smsg_mime($node->{smsg}) and last; + $smsg = $ibx->smsg_mime($node->{smsg}) and last; } return missing_thread($ctx) unless $smsg; - $ctx->{-obfs_ibx} = $inbox->{obfuscate} ? $inbox : undef; + $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; $ctx->{-title_html} = ascii_html($smsg->subject); $ctx->{-html_tip} = thread_index_entry($ctx, $level, $smsg); $smsg = undef; @@ -420,7 +423,7 @@ sub stream_thread ($$) { my $node = shift @q or next; my $cl = $level + 1; unshift @q, map { ($cl, $_) } @{$node->{children}}; - if ($smsg = $inbox->smsg_mime($node->{smsg})) { + if ($smsg = $ibx->smsg_mime($node->{smsg})) { return thread_index_entry($ctx, $level, $smsg); } else { return ghost_index_entry($ctx, $level, $node); @@ -459,8 +462,8 @@ sub thread_html { my $rootset = thread_results($ctx, $msgs); # reduce hash lookups in pre_thread->skel_dump - my $inbox = $ctx->{-inbox}; - $ctx->{-obfs_ibx} = $inbox->{obfuscate} ? $inbox : undef; + my $ibx = $ctx->{-inbox}; + $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef; walk_thread($rootset, $ctx, *pre_thread); $skel .= ''; @@ -469,7 +472,7 @@ sub thread_html { # flat display: lazy load the full message from smsg my $smsg; while (my $m = shift @$msgs) { - $smsg = $inbox->smsg_mime($m) and last; + $smsg = $ibx->smsg_mime($m) and last; } return missing_thread($ctx) unless $smsg; $ctx->{-title_html} = ascii_html($smsg->subject); @@ -479,7 +482,7 @@ sub thread_html { return unless $msgs; $smsg = undef; while (my $m = shift @$msgs) { - $smsg = $inbox->smsg_mime($m) and last; + $smsg = $ibx->smsg_mime($m) and last; } return index_entry($smsg, $ctx, scalar @$msgs) if $smsg; $msgs = undef; @@ -488,11 +491,11 @@ sub thread_html { } sub multipart_text_as_html { - my ($mime, $upfx, $obfs_ibx) = @_; + my ($mime, $upfx, $ctx) = @_; my $rv = ""; # scan through all parts, looking for displayable text - msg_iter($mime, sub { $rv .= add_text_body($upfx, $obfs_ibx, $_[0]) }); + msg_iter($mime, sub { $rv .= add_text_body($upfx, $ctx, $_[0]) }); $rv; } @@ -501,12 +504,12 @@ sub flush_quote { # show everything in the full version with anchor from # short version (see above) - my $rv = $l->linkify_1(join('', @$quot)); - @$quot = (); + my $rv = $l->linkify_1($$quot); # we use a here to allow users to specify their own # color for quoted text $rv = $l->linkify_2(ascii_html($rv)); + $$quot = undef; $$s .= qq() . $rv . '' } @@ -545,49 +548,79 @@ sub attach_link ($$$$;$) { } sub add_text_body { - my ($upfx, $obfs_ibx, $p) = @_; + my ($upfx, $ctx, $p) = @_; + my $ibx = $ctx->{-inbox}; + my $obfs_ibx = $ibx->{obfuscate} ? $ibx : undef; # $p - from msg_iter: [ Email::MIME, depth, @idx ] - my ($part, $depth) = @$p; # attachment @idx is unused + my ($part, $depth, @idx) = @$p; my $ct = $part->content_type || 'text/plain'; my $fn = $part->filename; my ($s, $err) = msg_part_text($part, $ct); return attach_link($upfx, $ct, $p, $fn) unless defined $s; - my @lines = split(/^/m, $s); + # makes no difference to browsers, and don't screw up filename + # link generation in diffs with the extra '%0D' + $s =~ s/\r\n/\n/sg; + + # always support diff-highlighting, but we can't linkify hunk + # headers for solver unless some coderepo are configured: + my $diff; + if ($s =~ /^(?:diff|---|\+{3}) /ms) { + # diffstat anchors do not link across attachments or messages: + $idx[0] = $upfx . $idx[0] if $upfx ne ''; + $ctx->{-apfx} = join('/', @idx); + $ctx->{-anchors} = {}; # attr => filename + $ctx->{-diff} = $diff = []; + delete $ctx->{-long_path}; + my $spfx; + if ($ibx->{-repo_objs}) { + if (index($upfx, '//') >= 0) { # absolute URL (Atom feeds) + $spfx = $upfx; + $spfx =~ s!/([^/]*)/\z!/!; + } else { + my $n_slash = $upfx =~ tr!/!/!; + if ($n_slash == 0) { + $spfx = '../'; + } elsif ($n_slash == 1) { + $spfx = ''; + } else { # nslash == 2 + $spfx = '../../'; + } + } + } + $ctx->{-spfx} = $spfx; + }; + + # some editors don't put trailing newlines at the end: + $s .= "\n" unless $s =~ /\n\z/s; + + # split off quoted and unquoted blocks: + my @sections = split(/((?:^>[^\n]*\n)+)/sm, $s); $s = ''; if (defined($fn) || $depth > 0 || $err) { # badly-encoded message with $err? tell the world about it! $s .= attach_link($upfx, $ct, $p, $fn, $err); $s .= "\n"; } - my @quot; my $l = PublicInbox::Linkify->new; - foreach my $cur (@lines) { - if ($cur !~ /^>/) { - # show the previously buffered quote inline - flush_quote(\$s, $l, \@quot) if @quot; - - # regular line, OK + foreach my $cur (@sections) { + if ($cur =~ /\A>/) { + flush_quote(\$s, $l, \$cur); + } elsif ($diff) { + @$diff = split(/^/m, $cur); + $cur = undef; + flush_diff(\$s, $ctx, $l); + } else { + # regular lines, OK $l->linkify_1($cur); $s .= $l->linkify_2(ascii_html($cur)); - } else { - push @quot, $cur; + $cur = undef; } } - if (@quot) { # ugh, top posted - flush_quote(\$s, $l, \@quot); - obfuscate_addrs($obfs_ibx, $s) if $obfs_ibx; - $s; - } else { - obfuscate_addrs($obfs_ibx, $s) if $obfs_ibx; - if ($s =~ /\n\z/s) { # common, last line ends with a newline - $s; - } else { # some editors don't do newlines... - $s .= "\n"; - } - } + obfuscate_addrs($obfs_ibx, $s) if $obfs_ibx; + $s; } sub _msg_html_prepare { @@ -867,11 +900,6 @@ sub missing_thread { PublicInbox::ExtMsg::ext_msg($ctx); } -sub _msg_date { - my ($hdr) = @_; - fmt_ts(msg_datestamp($hdr)); -} - sub fmt_ts { POSIX::strftime('%Y-%m-%d %k:%M', gmtime($_[0])) } sub dedupe_subject { @@ -1075,7 +1103,7 @@ sub dump_topics { my $mbox = qq(mbox.gz); my $atom = qq(Atom); - my $s = "$top\n" . + my $s = "$top\n" . " $ds UTC $n - $mbox / $atom\n"; for (my $i = 0; $i < scalar(@ex); $i += 2) { my $level = $ex[$i];