X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FView.pm;h=280d0ea5557024a790012d2bf0ab1e2d950f014b;hb=e3124855ded54f9d9703bd7b72a584edb4422fbe;hp=91443f55c177bc12d8578a7a4d95a4eae1814333;hpb=9703d80efd848f582e5b265db1958e0f143d8712;p=public-inbox.git diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm index 91443f55..280d0ea5 100644 --- a/lib/PublicInbox/View.pm +++ b/lib/PublicInbox/View.pm @@ -10,7 +10,8 @@ use bytes (); # only for bytes::length use PublicInbox::MsgTime qw(msg_datestamp); use PublicInbox::Hval qw(ascii_html obfuscate_addrs prurl mid_href); use PublicInbox::Linkify; -use PublicInbox::MID qw/id_compress mids mids_for_index references/; +use PublicInbox::MID qw(id_compress mids mids_for_index references + $MID_EXTRACT); use PublicInbox::MsgIter; use PublicInbox::Address; use PublicInbox::WwwStream; @@ -18,7 +19,7 @@ use PublicInbox::Reply; use PublicInbox::ViewDiff qw(flush_diff); use POSIX qw(strftime); use Time::Local qw(timegm); -use PublicInbox::SearchMsg qw(subject_normalized); +use PublicInbox::Smsg qw(subject_normalized); use constant COLS => 72; use constant INDENT => ' '; use constant TCHILD => '` '; @@ -149,7 +150,7 @@ sub in_reply_to { sub fold_addresses ($) { return $_[0] if length($_[0]) <= COLS; # try to fold on commas after non-word chars before $lim chars, - # Try to get the "," preceeded by ">" or ")", but avoid folding + # Try to get the "," preceded by ">" or ")", but avoid folding # on the comma where somebody uses "Lastname, Firstname". # We also try to keep the last and penultimate addresses in # the list on the same line if possible, hence the extra \z @@ -296,11 +297,9 @@ sub _th_index_lite { my $nr_c = scalar @$children; my $nr_s = 0; my $siblings; - if (my $smsg = $node->{smsg}) { - # delete saves about 200KB on a 1K message thread - if (my $refs = delete $smsg->{references}) { - ($$irt) = ($refs =~ m/<([^>]+)>\z/); - } + # delete saves about 200KB on a 1K message thread + if (my $refs = delete $node->{references}) { + ($$irt) = ($refs =~ m/$MID_EXTRACT\z/o); } my $irt_map = $mapping->{$$irt} if defined $$irt; if (defined $irt_map) { @@ -309,12 +308,12 @@ sub _th_index_lite { $rv .= $pad . $irt_map->[0]; if ($idx > 0) { my $prev = $siblings->[$idx - 1]; - my $pmid = $prev->{id}; + my $pmid = $prev->{mid}; if ($idx > 2) { my $s = ($idx - 1). ' preceding siblings ...'; $rv .= pad_link($pmid, $level, $s); } elsif ($idx == 2) { - my $ppmid = $siblings->[0]->{id}; + my $ppmid = $siblings->[0]->{mid}; $rv .= $pad . $mapping->{$ppmid}->[0]; } $rv .= $pad . $mapping->{$pmid}->[0]; @@ -323,30 +322,30 @@ sub _th_index_lite { my $s_s = nr_to_s($nr_s, 'sibling', 'siblings'); my $s_c = nr_to_s($nr_c, 'reply', 'replies'); $attr =~ s!\n\z!\n!s; - $attr =~ s! !!s; # no point in duplicating subject + $attr =~ s! (?:" )?!!s; # no point in dup subject $attr =~ s!]+>([^<]+)!$1!s; # no point linking to self $rv .= "@ $attr"; if ($nr_c) { - my $cmid = $children->[0]->{id}; + my $cmid = $children->[0]->{mid}; $rv .= $pad . $mapping->{$cmid}->[0]; if ($nr_c > 2) { my $s = ($nr_c - 1). ' more replies'; $rv .= pad_link($cmid, $level + 1, $s); } elsif (my $cn = $children->[1]) { - $rv .= $pad . $mapping->{$cn->{id}}->[0]; + $rv .= $pad . $mapping->{$cn->{mid}}->[0]; } } my $next = $siblings->[$idx+1] if $siblings && $idx >= 0; if ($next) { - my $nmid = $next->{id}; + my $nmid = $next->{mid}; $rv .= $pad . $mapping->{$nmid}->[0]; my $nnext = $nr_s - $idx; if ($nnext > 2) { my $s = ($nnext - 1).' subsequent siblings'; $rv .= pad_link($nmid, $level, $s); } elsif (my $nn = $siblings->[$idx + 2]) { - $rv .= $pad . $mapping->{$nn->{id}}->[0]; + $rv .= $pad . $mapping->{$nn->{mid}}->[0]; } } $rv .= $pad ."$s_s, $s_c; $ctx->{s_nr}\n"; @@ -368,7 +367,7 @@ sub walk_thread ($$$) { sub pre_thread { # walk_thread callback my ($ctx, $level, $node, $idx) = @_; - $ctx->{mapping}->{$node->{id}} = [ '', $node, $idx, $level ]; + $ctx->{mapping}->{$node->{mid}} = [ '', $node, $idx, $level ]; skel_dump($ctx, $level, $node); } @@ -387,8 +386,8 @@ sub stream_thread_i { # PublicInbox::WwwStream::getline callback my $node = shift @$q or next; my $cl = $level + 1; unshift @$q, map { ($cl, $_) } @{$node->{children}}; - if (my $smsg = $ctx->{-inbox}->smsg_mime($node->{smsg})) { - return thread_index_entry($ctx, $level, $smsg); + if ($ctx->{-inbox}->smsg_mime($node)) { + return thread_index_entry($ctx, $level, $node); } else { return ghost_index_entry($ctx, $level, $node); } @@ -406,7 +405,7 @@ sub stream_thread ($$) { my $node = shift @q or next; my $cl = $level + 1; unshift @q, map { ($cl, $_) } @{$node->{children}}; - $smsg = $ibx->smsg_mime($node->{smsg}) and last; + $smsg = $ibx->smsg_mime($node) and last; } return missing_thread($ctx) unless $smsg; @@ -481,17 +480,6 @@ sub multipart_text_as_html { msg_iter($_[0], \&add_text_body, $_[1], 1); } -sub flush_quote { - my ($s, $l, $quot) = @_; - - my $rv = $l->to_html($$quot); - - # we use a here to allow users to specify their own - # color for quoted text - $$quot = undef; - $$s .= qq() . $rv . '' -} - sub attach_link ($$$$;$) { my ($ctx, $ct, $p, $fn, $err) = @_; my ($part, $depth, @idx) = @$p; @@ -503,9 +491,6 @@ sub attach_link ($$$$;$) { # spotting MUA problems: $ct =~ s/;.*// unless $err; $ct = ascii_html($ct); - my $desc = $part->header('Content-Description'); - $desc = $fn unless defined $desc; - $desc = '' unless defined $desc; my $sfn; if (defined $fn && $fn =~ /\A$PublicInbox::Hval::FN\z/o) { $sfn = $fn; @@ -517,10 +502,13 @@ sub attach_link ($$$$;$) { my $rv = $ctx->{obuf}; $$rv .= qq($nl{mhref}$idx-$sfn">); if ($err) { - $$rv .= "[-- Warning: decoded text below may be mangled --]\n"; + $$rv .= <header('Content-Description') // $fn // ''; $desc = ascii_html($desc); $$rv .= ($desc eq '') ? "$ts --]" : "$desc --]\n[-- $ts --]"; $$rv .= "\n"; @@ -542,6 +530,9 @@ sub add_text_body { # callback for msg_iter # link generation in diffs with the extra '%0D' $s =~ s/\r\n/\n/sg; + # will be escaped to `•' in HTML + obfuscate_addrs($ibx, $s, "\x{2022}") if $ibx->{obfuscate}; + # always support diff-highlighting, but we can't linkify hunk # headers for solver unless some coderepo are configured: my $diff; @@ -575,8 +566,8 @@ sub add_text_body { # callback for msg_iter $s .= "\n" unless $s =~ /\n\z/s; # split off quoted and unquoted blocks: - my @sections = split(/((?:^>[^\n]*\n)+)/sm, $s); - $s = ''; + my @sections = PublicInbox::MsgIter::split_quotes($s); + undef $s; # free memory my $rv = $ctx->{obuf}; if (defined($fn) || $depth > 0 || $err) { # badly-encoded message with $err? tell the world about it! @@ -586,17 +577,19 @@ sub add_text_body { # callback for msg_iter my $l = $ctx->{-linkify} //= PublicInbox::Linkify->new; foreach my $cur (@sections) { if ($cur =~ /\A>/) { - flush_quote($rv, $l, \$cur); + # we use a here to allow users to specify + # their own color for quoted text + $$rv .= qq(); + $$rv .= $l->to_html($cur); + $$rv .= ''; } elsif ($diff) { - flush_diff($rv, $ctx, \$cur); + flush_diff($ctx, \$cur); } else { # regular lines, OK $$rv .= $l->to_html($cur); - $cur = undef; } + undef $cur; # free memory } - - obfuscate_addrs($ibx, $$rv) if $ibx->{obfuscate}; } sub _msg_page_prepare_obuf { @@ -830,7 +823,7 @@ sub indent_for { sub find_mid_root { my ($ctx, $level, $node, $idx) = @_; ++$ctx->{root_idx} if $level == 0; - if ($node->{id} eq $ctx->{mid}) { + if ($node->{mid} eq $ctx->{mid}) { $ctx->{found_mid_at} = $ctx->{root_idx}; return 0; } @@ -887,25 +880,25 @@ sub missing_thread { sub dedupe_subject { my ($prev_subj, $subj, $val) = @_; - my $omit = ''; # '"' denotes identical text omitted + my $omit; # '"' denotes identical text omitted my (@prev_pop, @curr_pop); while (@$prev_subj && @$subj && $subj->[-1] eq $prev_subj->[-1]) { push(@prev_pop, pop(@$prev_subj)); push(@curr_pop, pop(@$subj)); - $omit ||= $val; + $omit //= $val; } pop @$subj if @$subj && $subj->[-1] =~ /^re:\s*/i; if (scalar(@curr_pop) == 1) { - $omit = ''; + $omit = undef; push @$prev_subj, @prev_pop; push @$subj, @curr_pop; } - $omit; + $omit // ''; } sub skel_dump { # walk_thread callback - my ($ctx, $level, $node) = @_; - my $smsg = $node->{smsg} or return _skel_ghost($ctx, $level, $node); + my ($ctx, $level, $smsg) = @_; + $smsg->{blob} or return _skel_ghost($ctx, $level, $smsg); my $skel = $ctx->{skel}; my $cur = $ctx->{cur}; @@ -988,7 +981,7 @@ sub skel_dump { # walk_thread callback sub _skel_ghost { my ($ctx, $level, $node) = @_; - my $mid = $node->{id}; + my $mid = $node->{mid}; my $d = ' [not found] '; $d .= ' ' if exists $ctx->{searchview}; $d .= indent_for($level) . th_pfx($level); @@ -1011,18 +1004,23 @@ sub _skel_ghost { sub sort_ds { [ sort { - (eval { $a->topmost->{smsg}->{ds} } || 0) <=> - (eval { $b->topmost->{smsg}->{ds} } || 0) + (eval { $a->topmost->{ds} } || 0) <=> + (eval { $b->topmost->{ds} } || 0) } @{$_[0]} ]; } # accumulate recent topics if search is supported # returns 200 if done, 404 if not sub acc_topic { # walk_thread callback - my ($ctx, $level, $node) = @_; - my $mid = $node->{id}; - my $smsg = $node->{smsg} // $ctx->{-inbox}->smsg_by_mid($mid); - if ($smsg) { + my ($ctx, $level, $smsg) = @_; + my $mid = $smsg->{mid}; + my $has_blob = $smsg->{blob} // do { + if (my $by_mid = $ctx->{-inbox}->smsg_by_mid($mid)) { + %$smsg = (%$smsg, %$by_mid); + 1; + } + }; + if ($has_blob) { my $subj = subject_normalized($smsg->{subject}); $subj = '(no subject)' if $subj eq ''; my $ds = $smsg->{ds}; @@ -1055,7 +1053,7 @@ sub acc_topic { # walk_thread callback sub dump_topics { my ($ctx) = @_; my $order = delete $ctx->{order}; # [ ds, subj1, subj2, subj3, ... ] - if (!@$order) { + unless ($order) { $ctx->{-html_tip} = '
[No topics in range]
'; return 404; } @@ -1213,7 +1211,7 @@ sub thread_adj_level { sub ghost_index_entry { my ($ctx, $level, $node) = @_; my ($beg, $end) = thread_adj_level($ctx, $level); - $beg . '
'. ghost_parent($ctx->{-upfx}, $node->{id})
+	$beg . '
'. ghost_parent($ctx->{-upfx}, $node->{mid})
 		. '
' . $end; }