From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.0 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 1022E209BA for ; Sat, 10 Dec 2016 03:43:07 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 5/7] view: skip ghosts with no direct children Date: Sat, 10 Dec 2016 03:43:03 +0000 Message-Id: <20161210034305.2654-6-e@80x24.org> In-Reply-To: <20161210034305.2654-1-e@80x24.org> References: <20161210034305.2654-1-e@80x24.org> List-Id: 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 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/PublicInbox/SearchThread.pm b/lib/PublicInbox/SearchThread.pm index 5774a95..ee35f0d 100644 --- a/lib/PublicInbox/SearchThread.pm +++ b/lib/PublicInbox/SearchThread.pm @@ -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; -- EW