about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-08-30 00:22:43 +0000
committerEric Wong <e@80x24.org>2015-08-30 00:22:43 +0000
commitf24d362fb0959cdfab37a6da0a66a985764a2752 (patch)
tree551344cf561959bd5c070fc795f15b7c8c59e862
parentf401be8bf5612178074d8d037776fee9e27bfd4c (diff)
downloadpublic-inbox-f24d362fb0959cdfab37a6da0a66a985764a2752.tar.gz
If Xapian search is available, we can load most of the
entire thread and show a more meaningful navigation tree
than the References: and In-Reply-To: headers.  Searching
on those headers themselves is unreliable because it is
possible for clients to omit some references.
-rw-r--r--lib/PublicInbox/View.pm193
1 files changed, 110 insertions, 83 deletions
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index bd0a27aa..946df37f 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -31,10 +31,9 @@ sub msg_html {
         } else {
                 $footer = '';
         }
-        my $srch = $ctx->{srch} if $ctx;
-        headers_to_html_header($mime, $full_pfx, $srch) .
+        headers_to_html_header($mime, $full_pfx, $ctx) .
                 multipart_text_as_html($mime, $full_pfx) .
-                '</pre><hr /><pre>' .
+                '</pre><hr />' . PRE_WRAP .
                 html_footer($mime, 1, $full_pfx, $ctx) .
                 $footer .
                 '</pre></body></html>';
@@ -343,8 +342,8 @@ sub add_text_body {
 }
 
 sub headers_to_html_header {
-        my ($mime, $full_pfx, $srch) = @_;
-
+        my ($mime, $full_pfx, $ctx) = @_;
+        my $srch = $ctx->{srch} if $ctx;
         my $rv = "";
         my @title;
         my $header_obj = $mime->header_obj;
@@ -362,7 +361,8 @@ sub headers_to_html_header {
                 } elsif ($h eq 'Subject') {
                         $title[0] = $v->as_html;
                         if ($srch) {
-                                $rv .= "$h: <a\nhref=\"../../t/$mid_href/\">";
+                                $rv .= "$h: <a\nid=\"t\"\n" .
+                                        "href=\"../../t/$mid_href/\">";
                                 $rv .= $v->as_html . "</a>\n";
                                 next;
                         }
@@ -370,10 +370,47 @@ sub headers_to_html_header {
                 $rv .= "$h: " . $v->as_html . "\n";
 
         }
-
         $rv .= 'Message-ID: &lt;' . $mid->as_html . '&gt; ';
         my $raw_ref = $full_pfx ? 'raw' : "../../m/$mid_href/raw";
         $rv .= "(<a\nhref=\"$raw_ref\">raw</a>)\n";
+        if ($srch) {
+                $rv .= "<a\nhref=\"#r\">References: [see below]</a>\n";
+        } else {
+                $rv .= _parent_headers_nosrch($header_obj);
+        }
+        $rv .= "\n";
+
+        ("<html><head><title>".  join(' - ', @title) .
+         '</title></head><body>' . PRE_WRAP . $rv);
+}
+
+sub thread_inline {
+        my ($dst, $ctx, $cur) = @_;
+        my $srch = $ctx->{srch};
+        my $mid = mid_compress(mid_clean($cur->header('Message-ID')));
+        my $res = $srch->get_thread($mid);
+        my $nr = $res->{total};
+        if ($nr <= 1) {
+                $$dst .= "[only message in thread]\n";
+                return;
+        }
+
+        $$dst .= "roughly $nr messages in thread:\n";
+        my $subj = $srch->subject_path($cur->header('Subject'));
+        my $state = {
+                seen => { $subj => 1 },
+                srch => $srch,
+                cur => $mid,
+        };
+        for (thread_results(load_results($res))->rootset) {
+                inline_dump($dst, $state, $_, 0);
+        }
+        $state->{next_msg};
+}
+
+sub _parent_headers_nosrch {
+        my ($header_obj) = @_;
+        my $rv = '';
 
         my $irt = $header_obj->header('In-Reply-To');
         if (defined $irt) {
@@ -401,11 +438,7 @@ sub headers_to_html_header {
                         $rv .= 'References: '. join(' ', @refs) . "\n";
                 }
         }
-
-        $rv .= "\n";
-
-        ("<html><head><title>".  join(' - ', @title) .
-         '</title></head><body>' . PRE_WRAP . $rv);
+        $rv;
 }
 
 sub html_footer {
@@ -440,25 +473,11 @@ sub html_footer {
         my $srch = $ctx->{srch} if $ctx;
         my $idx = $standalone ? " <a\nhref=\"../../\">index</a>" : '';
         if ($idx && $srch) {
-                $mid = mid_compress(mid_clean($mid));
                 my $t_anchor = defined $irt ? T_ANCHOR : '';
                 $irt = $mime->header('In-Reply-To');
                 $idx = " <a\nhref=\"../../t/$mid/$t_anchor\">".
-                       "threadlink</a>$idx";
-                my $res = $srch->get_followups($mid);
-                if (my $c = $res->{total}) {
-                        my $nr = scalar @{$res->{msgs}};
-                        if ($nr < $c) {
-                                $c = "$nr of $c followups";
-                        } else {
-                                $c = $c == 1 ? '1 followup' : "$c followups";
-                        }
-                        $idx .= "\n$c:\n";
-                        $res->{srch} = $srch;
-                        thread_followups(\$idx, $mime, $res);
-                } else {
-                        $idx .= "\n(no followups, yet)\n";
-                }
+                       "threadlink</a>$idx\n\n";
+                my $next = thread_inline(\$idx, $ctx, $mime);
                 if (defined $irt) {
                         $irt = PublicInbox::Hval->new_msgid($irt);
                         $irt = $irt->as_href;
@@ -466,6 +485,11 @@ sub html_footer {
                 } else {
                         $irt = ' ' x length('parent ');
                 }
+                if ($next) {
+                        $irt .= "<a\nhref=\"../$next/\">next</a> ";
+                } else {
+                        $irt .= '     ';
+                }
         } else {
                 $irt = '';
         }
@@ -489,61 +513,6 @@ sub anchor_for {
         'm' . $id;
 }
 
-sub simple_dump {
-        my ($dst, $root, $node, $level) = @_;
-        return unless $node;
-        # $root = [ undef, \%seen, $srch ];
-        if (my $x = $node->message) {
-                my $f = $x->header('X-PI-From');
-                my $d = $x->header('X-PI-Date');
-                if (defined $f && defined $d) {
-                        my $mid = $x->header('Message-ID');
-                        my $pfx = '  ' x $level;
-                        $$dst .= $pfx;
-
-                        # Subject is never undef, this mail was loaded from
-                        # our Xapian which would've resulted in '' if it were
-                        # really missing (and Filter rejects empty subjects)
-                        my $s = $x->header('Subject');
-                        my $h = $root->[2]->subject_path($s);
-                        if ($root->[1]->{$h}) {
-                                $s = undef;
-                        } else {
-                                $root->[1]->{$h} = 1;
-                                $s = PublicInbox::Hval->new($s);
-                                $s = $s->as_html;
-                        }
-                        my $m = PublicInbox::Hval->new_msgid($mid);
-                        $f = PublicInbox::Hval->new($f);
-                        $d = PublicInbox::Hval->new($d);
-                        $m = '../' . $m->as_href . '/';
-                        $f = $f->as_html;
-                        $d = $d->as_html . ' UTC';
-                        if (defined $s) {
-                                $$dst .= "` <a\nhref=\"$m\">$s</a>\n" .
-                                     "$pfx  by $f @ $d\n";
-                        } else {
-                                $$dst .= "` <a\nhref=\"$m\">$f @ $d</a>\n";
-                        }
-                }
-        }
-        simple_dump($dst, $root, $node->child, $level+1);
-        simple_dump($dst, $root, $node->next, $level);
-}
-
-sub thread_followups {
-        my ($dst, $root, $res) = @_;
-        $root->header_set('X-PI-TS', '0');
-        my $msgs = load_results($res);
-        push @$msgs, $root;
-        my $th = thread_results($msgs);
-        my $srch = $res->{srch};
-        my $subj = $srch->subject_path($root->header('Subject'));
-        my %seen = ($subj => 1);
-        $root = [ undef, \%seen, $srch ];
-        simple_dump($dst, $root, $_, 0) for $th->rootset;
-}
-
 sub thread_html_head {
         my ($mime) = @_;
         my $s = PublicInbox::Hval->new_oneline($mime->header('Subject'));
@@ -601,4 +570,62 @@ sub missing_thread {
 EOF
 }
 
+sub _inline_header {
+        my ($dst, $state, $mime, $level) = @_;
+        my $pfx = '  ' x $level;
+
+        my $cur = $state->{cur};
+        my $mid = $mime->header('Message-ID');
+        my $f = $mime->header('X-PI-From');
+        my $d = $mime->header('X-PI-Date');
+        $f = PublicInbox::Hval->new($f);
+        $d = PublicInbox::Hval->new($d);
+        $f = $f->as_html;
+        $d = $d->as_html . ' UTC';
+        my $midc = mid_compress(mid_clean($mid));
+        if ($cur) {
+                if ($cur eq $midc) {
+                        delete $state->{cur};
+                        $$dst .= "$pfx` <b><a\nid=\"r\"\nhref=\"#t\">".
+                                 "[this message]</a></b> by $f @ $d\n";
+
+                        return;
+                }
+        } else {
+                $state->{next_msg} ||= $midc;
+        }
+
+        # Subject is never undef, this mail was loaded from
+        # our Xapian which would've resulted in '' if it were
+        # really missing (and Filter rejects empty subjects)
+        my $s = $mime->header('Subject');
+        my $h = $state->{srch}->subject_path($s);
+        if ($state->{seen}->{$h}) {
+                $s = undef;
+        } else {
+                $state->{seen}->{$h} = 1;
+                $s = PublicInbox::Hval->new($s);
+                $s = $s->as_html;
+        }
+        my $m = PublicInbox::Hval->new_msgid($mid);
+        $m = '../' . $m->as_href . '/';
+        if (defined $s) {
+                $$dst .= "$pfx` <a\nhref=\"$m\">$s</a>\n" .
+                         "$pfx  $f @ $d\n";
+        } else {
+                $$dst .= "$pfx` <a\nhref=\"$m\">$f @ $d</a>\n";
+        }
+}
+
+sub inline_dump {
+        my ($dst, $state, $node, $level) = @_;
+        return unless $node;
+        return if $state->{stopped};
+        if (my $mime = $node->message) {
+                _inline_header($dst, $state, $mime, $level);
+        }
+        inline_dump($dst, $state, $node->child, $level+1);
+        inline_dump($dst, $state, $node->next, $level);
+}
+
 1;