about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong (Contractor, The Linux Foundation) <e@80x24.org>2018-03-23 20:29:24 +0000
committerEric Wong (Contractor, The Linux Foundation) <e@80x24.org>2018-03-27 02:34:20 +0000
commit007cb8774e7013e2aaca32003bbd1653e3d8582f (patch)
tree24645e152f6c386730dfdc9925b5dd5ca7740752
parent26895bbd94dc93b76274652f9ea35626fd63a5fa (diff)
downloadpublic-inbox-007cb8774e7013e2aaca32003bbd1653e3d8582f.tar.gz
This needs tests and further refinement, but current tests pass.
-rw-r--r--lib/PublicInbox/Mbox.pm12
-rw-r--r--lib/PublicInbox/SearchMsg.pm7
-rw-r--r--lib/PublicInbox/View.pm107
-rw-r--r--lib/PublicInbox/WWW.pm7
-rw-r--r--t/psgi_v2.t12
5 files changed, 118 insertions, 27 deletions
diff --git a/lib/PublicInbox/Mbox.pm b/lib/PublicInbox/Mbox.pm
index 79e09a70..c14037f4 100644
--- a/lib/PublicInbox/Mbox.pm
+++ b/lib/PublicInbox/Mbox.pm
@@ -26,13 +26,6 @@ sub subject_fn ($) {
         $fn eq '' ? 'no-subject' : $fn;
 }
 
-sub smsg_for ($$$) {
-        my ($head, $db, $mid) = @_;
-        my $doc_id = $head->get_docid;
-        my $doc = $db->get_document($doc_id);
-        PublicInbox::SearchMsg->wrap($doc, $mid)->load_expand;
-}
-
 sub mb_stream {
         my ($more) = @_;
         bless $more, 'PublicInbox::Mbox';
@@ -47,7 +40,7 @@ sub getline {
                 return msg_str($ctx, $cur);
         }
         for (; !defined($cur) && $head != $tail; $head++) {
-                my $smsg = smsg_for($head, $db, $ctx->{mid});
+                my $smsg = PublicInbox::SearchMsg->get($head, $db, $ctx->{mid});
                 next if $smsg->type ne 'mail';
                 my $mref = $ctx->{-inbox}->msg_by_smsg($smsg) or next;
                 $cur = Email::Simple->new($mref);
@@ -71,7 +64,8 @@ sub emit_raw {
                 $srch->retry_reopen(sub {
                         ($head, $tail, $db) = $srch->each_smsg_by_mid($mid);
                         for (; !defined($first) && $head != $tail; $head++) {
-                                my $smsg = smsg_for($head, $db, $mid);
+                                my @args = ($head, $db, $mid);
+                                my $smsg = PublicInbox::SearchMsg->get(@args);
                                 next if $smsg->type ne 'mail';
                                 my $mref = $ibx->msg_by_smsg($smsg) or next;
                                 $first = Email::Simple->new($mref);
diff --git a/lib/PublicInbox/SearchMsg.pm b/lib/PublicInbox/SearchMsg.pm
index dd3d58d0..b944868f 100644
--- a/lib/PublicInbox/SearchMsg.pm
+++ b/lib/PublicInbox/SearchMsg.pm
@@ -24,6 +24,13 @@ sub wrap {
         bless { doc => $doc, mime => undef, mid => $mid }, $class;
 }
 
+sub get {
+        my ($class, $head, $db, $mid) = @_;
+        my $doc_id = $head->get_docid;
+        my $doc = $db->get_document($doc_id);
+        load_expand(wrap($class, $doc, $mid))
+}
+
 sub get_val ($$) {
         my ($doc, $col) = @_;
         Search::Xapian::sortable_unserialise($doc->get_value($col));
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 18882afd..34ab3e58 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -9,7 +9,7 @@ use warnings;
 use PublicInbox::MsgTime qw(msg_datestamp);
 use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
 use PublicInbox::Linkify;
-use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape/;
+use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape mids/;
 use PublicInbox::MsgIter;
 use PublicInbox::Address;
 use PublicInbox::WwwStream;
@@ -21,18 +21,23 @@ use constant TCHILD => '` ';
 sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD };
 
 # public functions: (unstable)
+
 sub msg_html {
-        my ($ctx, $mime) = @_;
+        my ($ctx, $mime, $more) = @_;
         my $hdr = $mime->header_obj;
         my $ibx = $ctx->{-inbox};
-        my $obfs_ibx = $ibx->{obfuscate} ? $ibx : undef;
-        my $tip = _msg_html_prepare($hdr, $ctx, $obfs_ibx);
+        my $obfs_ibx = $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 {
                 my ($nr, undef) = @_;
                 if ($nr == 1) {
                         $tip . multipart_text_as_html($mime, '', $obfs_ibx) .
                                 '</pre><hr>'
-                } elsif ($nr == 2) {
+                } elsif ($more && @$more) {
+                        ++$end;
+                        msg_html_more($ctx, $more, $nr);
+                } elsif ($nr == $end) {
                         # fake an EOF if generating the footer fails;
                         # we want to at least show the message if something
                         # here crashes:
@@ -46,6 +51,63 @@ sub msg_html {
         });
 }
 
+sub msg_page {
+        my ($ctx) = @_;
+        my $mid = $ctx->{mid};
+        my $ibx = $ctx->{-inbox};
+        my ($first, $more, $head, $tail, $db);
+        if (my $srch = $ibx->search) {
+                $srch->retry_reopen(sub {
+                        ($head, $tail, $db) = $srch->each_smsg_by_mid($mid);
+                        for (; !defined($first) && $head != $tail; $head++) {
+                                my @args = ($head, $db, $mid);
+                                my $smsg = PublicInbox::SearchMsg->get(@args);
+                                next if $smsg->type ne 'mail';
+                                $first = $ibx->msg_by_smsg($smsg);
+                        }
+                        if ($head != $tail) {
+                                $more = [ $head, $tail, $db ];
+                        }
+                });
+        } else {
+                $first = $ibx->msg_by_mid($mid) or return;
+        }
+        $first ? msg_html($ctx, PublicInbox::MIME->new($first), $more) : undef;
+}
+
+sub msg_html_more {
+        my ($ctx, $more, $nr) = @_;
+        my $str = eval {
+                my $mref;
+                my ($head, $tail, $db) = @$more;
+                for (; !defined($mref) && $head != $tail; $head++) {
+                        my $smsg = PublicInbox::SearchMsg->get($head, $db,
+                                                                $ctx->{mid});
+                        next if $smsg->type ne 'mail';
+                        $mref = $ctx->{-inbox}->msg_by_smsg($smsg);
+                }
+                if ($head == $tail) { # done
+                        @$more = ();
+                } else {
+                        $more->[0] = $head;
+                }
+                if ($mref) {
+                        my $mime = PublicInbox::MIME->new($mref);
+                        _msg_html_prepare($mime->header_obj, $ctx, $more, $nr) .
+                                multipart_text_as_html($mime, '',
+                                                        $ctx->{-obfs_ibx}) .
+                                '</pre><hr>'
+                } else {
+                        '';
+                }
+        };
+        if ($@) {
+                warn "Error lookup up additional messages: $@\n";
+                $str = '<pre>Error looking up additional messages</pre>';
+        }
+        $str;
+}
+
 # /$INBOX/$MESSAGE_ID/#R
 sub msg_reply {
         my ($ctx, $hdr) = @_;
@@ -529,17 +591,26 @@ sub add_text_body {
 }
 
 sub _msg_html_prepare {
-        my ($hdr, $ctx, $obfs_ibx) = @_;
+        my ($hdr, $ctx, $more, $nr) = @_;
         my $srch = $ctx->{srch} if $ctx;
         my $atom = '';
-        my $rv = "<pre\nid=b>"; # anchor for body start
-
+        my $obfs_ibx = $ctx->{-obfs_ibx};
+        my $rv = '';
+        my $mids = mids($hdr);
+        my $multiple = scalar(@$mids) > 1; # zero, one, infinity
+        if ($nr == 0) {
+                if ($more) {
+                        $rv .=
+"<pre>WARNING: multiple messages refer to this Message-ID\n</pre>";
+                }
+                $rv .= "<pre\nid=b>"; # anchor for body start
+        } else {
+                $rv .= '<pre>';
+        }
         if ($srch) {
                 $ctx->{-upfx} = '../';
         }
         my @title;
-        my $mid = mid_clean($hdr->header_raw('Message-ID'));
-        $mid = PublicInbox::Hval->new_msgid($mid);
         foreach my $h (qw(From To Cc Subject Date)) {
                 my $v = $hdr->header($h);
                 defined($v) && ($v ne '') or next;
@@ -564,8 +635,20 @@ sub _msg_html_prepare {
         }
         $title[0] ||= '(no subject)';
         $ctx->{-title_html} = join(' - ', @title);
-        $rv .= 'Message-ID: &lt;' . $mid->as_html . '&gt; ';
-        $rv .= "(<a\nhref=\"raw\">raw</a>)\n";
+        foreach (@$mids) {
+                my $mid = PublicInbox::Hval->new_msgid($_) ;
+                my $mhtml = $mid->as_html;
+                if ($multiple) {
+                        my $href = $mid->{href};
+                        $rv .= "Message-ID: ";
+                        $rv .= "<a\nhref=\"../$href/\">";
+                        $rv .= "&lt;$mhtml&gt;</a> ";
+                        $rv .= "(<a\nhref=\"../$href/raw\">raw</a>)\n";
+                } else {
+                        $rv .= "Message-ID: &lt;$mhtml&gt; ";
+                        $rv .= "(<a\nhref=\"raw\">raw</a>)\n";
+                }
+        }
         $rv .= _parent_headers($hdr, $srch);
         $rv .= "\n";
 }
diff --git a/lib/PublicInbox/WWW.pm b/lib/PublicInbox/WWW.pm
index f86363c6..7bf866f1 100644
--- a/lib/PublicInbox/WWW.pm
+++ b/lib/PublicInbox/WWW.pm
@@ -225,13 +225,8 @@ sub get_mid_txt {
 # /$INBOX/$MESSAGE_ID/                   -> HTML content (short quotes)
 sub get_mid_html {
         my ($ctx) = @_;
-        my $x = mid2blob($ctx) or return r404($ctx);
-
         require PublicInbox::View;
-        require PublicInbox::MIME;
-        my $mime = PublicInbox::MIME->new($x);
-        searcher($ctx);
-        PublicInbox::View::msg_html($ctx, $mime);
+        PublicInbox::View::msg_page($ctx) || r404($ctx);
 }
 
 # /$INBOX/$MESSAGE_ID/t/
diff --git a/t/psgi_v2.t b/t/psgi_v2.t
index 1e45c263..eaa3218c 100644
--- a/t/psgi_v2.t
+++ b/t/psgi_v2.t
@@ -127,6 +127,18 @@ test_psgi(sub { $www->call(@_) }, sub {
                 @from_ = ($raw =~ m/^From /mg);
                 is(scalar(@from_), 3, 'three From_ lines in t.mbox.gz');
         };
+
+        local $SIG{__WARN__} = 'DEFAULT';
+        $res = $cb->(GET('/v2test/a-mid@b/'));
+        $raw = $res->content;
+        like($raw, qr/^hello world$/m, 'got first message');
+        like($raw, qr/^hello world!$/m, 'got second message');
+        like($raw, qr/^hello ghosts$/m, 'got third message');
+        @from_ = ($raw =~ m/>From: /mg);
+        is(scalar(@from_), 3, 'three From: lines');
+        foreach my $mid ('a-mid@b', $new_mid, $third) {
+                like($raw, qr/&lt;\Q$mid\E&gt;/s, "Message-ID $mid shown");
+        }
 });
 
 done_testing();