]> Sergey Matveev's repositories - public-inbox.git/commitdiff
view: skip ghosts with no direct children
authorEric Wong <e@80x24.org>
Sat, 10 Dec 2016 01:09:49 +0000 (01:09 +0000)
committerEric Wong <e@80x24.org>
Sat, 10 Dec 2016 03:23:46 +0000 (03:23 +0000)
Otherwise, a malicious or broken client could populate the
thread skeleton with invalid References.  We only care about
ghosts which messages correctly refer to, not totally bogus ones
which may be the result of long line or token truncation +
wrapping in MUA headers.

lib/PublicInbox/SearchThread.pm

index 5774a9562b55f27956fd8e8e1baad11389e95e08..ee35f0d020616b86595c42d702cdc48082fe7971 100644 (file)
@@ -33,7 +33,8 @@ sub thread {
        my $self = shift;
        _add_message($self, $_) foreach @{$self->{messages}};
        my $id_table = delete $self->{id_table};
-       $self->{rootset} = [ grep { !delete $_->{parent} } values %$id_table ];
+       $self->{rootset} = [ grep {
+               !delete($_->{parent}) && $_->visible } values %$id_table ];
 }
 
 sub _get_cont_for_id ($$) {
@@ -133,15 +134,23 @@ sub has_descendent {
        0;
 }
 
+# Do not show/keep ghosts iff they have no children.  Sometimes
+# a ghost Message-ID is the result of a long header line
+# being folded/mangled by a MUA, and not a missing message.
+sub visible ($) {
+       my ($self) = @_;
+       $self->{smsg} || scalar values %{$self->{children}};
+}
+
 sub order_children {
        my ($cur, $ordersub) = @_;
 
-       my %seen = ($cur => 1);
+       my %seen = ($cur => 1); # self-referential loop prevention
        my @q = ($cur);
        while (defined($cur = shift @q)) {
                my $c = $cur->{children}; # The hashref here...
 
-               $c = [ grep { !$seen{$_}++ } values %$c ]; # spot/break loops
+               $c = [ grep { !$seen{$_}++ && visible($_) } values %$c ];
                $c = $ordersub->($c) if scalar @$c > 1;
                $cur->{children} = $c; # ...becomes an arrayref
                push @q, @$c;