my $midx = $state->[3]++;
my ($prev, $next) = ($midx - 1, $midx + 1);
my $part_nr = 0;
- my $enc_msg = enc_for($mime->header("Content-Type"));
+ my $enc = enc_for($mime->header("Content-Type"));
my $subj = $mime->header('Subject');
my $header_obj = $mime->header_obj;
- my $mid_raw = $header_obj->header_raw('Message-ID');
+ my $mid_raw = $header_obj->header('Message-ID');
my $id = anchor_for($mid_raw);
$seen->{$id} = "#$id"; # save the anchor for later
my $more = 'permalink';
my $path = $root_anchor ? '../' : '';
my $href = $mid->as_href;
- my $irt = $header_obj->header_raw('In-Reply-To');
+ my $irt = $header_obj->header('In-Reply-To');
my ($anchor_idx, $anchor, $t_anchor);
if (defined $irt) {
$anchor_idx = anchor_for($irt);
if ($level) {
$rv .= '<td><pre>' . (' ' x $level) . '</pre></td>';
}
- $rv .= '<td>' . PRE_WRAP;
+ $rv .= "<td\nid=s$midx>" . PRE_WRAP;
$rv .= "<b\nid=\"$id\">$subj</b>\n";
$rv .= "- by $from @ $ts UTC - ";
- $rv .= "<a\nid=\"s$midx\"\nhref=\"#s$next\">next</a>";
+ $rv .= "<a\nhref=\"#s$next\">next</a>";
if ($prev >= 0) {
$rv .= "/<a\nhref=\"#s$prev\">prev</a>";
}
}
# scan through all parts, looking for displayable text
$mime->walk_parts(sub {
- $rv .= index_walk($_[0], $enc_msg, $part_nr, $fhref, $more_ref);
- $part_nr++;
+ $rv .= index_walk($_[0], $enc, \$part_nr, $fhref, $more_ref);
});
$mime->body_set('');
my $msgs = load_results($res);
my $nr = scalar @$msgs;
return $rv if $nr == 0;
- require PublicInbox::Thread;
- my $th = PublicInbox::Thread->new(@$msgs);
- $th->thread;
- $th->order(*PublicInbox::Thread::sort_ts);
+ my $th = thread_results($msgs);
my $state = [ $srch, { root_anchor => anchor_for($mid) }, undef, 0 ];
{
require PublicInbox::GitCatFile;
$rv .= "<hr />" . PRE_WRAP . $next . $foot . "</pre>";
}
-sub subject_path_html {
- my (undef, $ctx, $foot, $srch) = @_;
- my $path = $ctx->{subject_path};
- my $res = $srch->get_subject_path($path);
- my $rv = '';
- my $msgs = load_results($res);
- my $nr = scalar @$msgs;
- return $rv if $nr == 0;
- require PublicInbox::Thread;
- my $th = PublicInbox::Thread->new(@$msgs);
- $th->thread;
- $th->order(*PublicInbox::Thread::sort_ts);
- my $state = [ $srch, { root_anchor => 'dummy' }, undef, 0 ];
- {
- require PublicInbox::GitCatFile;
- my $git = PublicInbox::GitCatFile->new($ctx->{git_dir});
- thread_entry(\$rv, $git, $state, $_, 0) for $th->rootset;
- }
- my $final_anchor = $state->[3];
- my $next = "<a\nid=\"s$final_anchor\">end of thread</a>\n";
-
- $rv .= "<hr />" . PRE_WRAP . $next . $foot . "</pre>";
-}
-
# only private functions below.
sub index_walk {
- my ($part, $enc_msg, $part_nr, $fhref, $more) = @_;
- my $rv = '';
- return $rv if $part->subparts; # walk_parts already recurses
- my $ct = $part->content_type;
-
- # account for filter bugs...
- if (defined $ct && $ct =~ m!\btext/[xh]+tml\b!i) {
- $part->body_set('');
- return '';
- }
-
- my $enc = enc_for($ct, $enc_msg);
-
- if ($part_nr > 0) {
- my $fn = $part->filename;
- defined($fn) or $fn = "part #" . ($part_nr + 1);
- $rv .= add_filename_line($enc->decode($fn));
- }
-
+ my ($part, $enc, $part_nr, $fhref, $more) = @_;
my $s = add_text_body($enc, $part, $part_nr, $fhref);
if ($more) {
if (length $s) {
# kill per-line trailing whitespace
$s =~ s/[ \t]+$//sgm;
-
- $rv .= $s;
- $s = undef;
- $rv .= "\n";
+ $s .= "\n" unless $s =~ /\n\z/s;
}
- $rv;
+ $s;
}
sub enc_for {
my ($mime, $full_pfx, $srch) = @_;
my $rv = "";
my $part_nr = 0;
- my $enc_msg = enc_for($mime->header("Content-Type"));
+ my $enc = enc_for($mime->header("Content-Type"));
# scan through all parts, looking for displayable text
$mime->walk_parts(sub {
my ($part) = @_;
- return if $part->subparts; # walk_parts already recurses
- my $ct = $part->content_type;
-
- # account for filter bugs...
- return if defined $ct && $ct =~ m!\btext/[xh]+tml\b!i;
-
- my $enc = enc_for($ct, $enc_msg);
-
- if ($part_nr > 0) {
- my $fn = $part->filename;
- defined($fn) or $fn = "part #" . ($part_nr + 1);
- $rv .= add_filename_line($enc->decode($fn));
- }
-
- $rv .= add_text_body($enc, $part, $part_nr, $full_pfx);
- $rv .= "\n" unless $rv =~ /\n\z/s;
- ++$part_nr;
+ $rv .= add_text_body($enc, $part, \$part_nr, $full_pfx);
});
$mime->body_set('');
$rv;
}
sub add_filename_line {
- my ($fn) = @_;
+ my ($enc, $fn) = @_;
my $len = 72;
my $pad = "-";
-
+ $fn = $enc->decode($fn);
$len -= length($fn);
$pad x= ($len/2) if ($len > 0);
"$pad " . ascii_html($fn) . " $pad\n";
}
sub add_text_body {
- my ($enc, $part, $part_nr, $full_pfx) = @_;
+ my ($enc_msg, $part, $part_nr, $full_pfx) = @_;
+ return '' if $part->subparts;
+
+ my $ct = $part->content_type;
+ # account for filter bugs...
+ if (defined $ct && $ct =~ m!\btext/[xh]+tml\b!i) {
+ $part->body_set('');
+ return '';
+ }
+ my $enc = enc_for($ct, $enc_msg);
my $n = 0;
my $nr = 0;
my $s = $part->body;
$s = ascii_html($s);
my @lines = split(/\n/, $s);
$s = '';
+
+ if ($$part_nr > 0) {
+ my $fn = $part->filename;
+ defined($fn) or $fn = "part #" . ($$part_nr + 1);
+ $s .= add_filename_line($enc, $fn);
+ }
+
my @quot;
while (defined(my $cur = shift @lines)) {
if ($cur !~ /^>/) {
# show the previously buffered quote inline
if (scalar @quot) {
- $s .= flush_quote(\@quot, \$n, $part_nr,
+ $s .= flush_quote(\@quot, \$n, $$part_nr,
$full_pfx, 0);
}
push @quot, $cur;
}
}
- $s .= flush_quote(\@quot, \$n, $part_nr, $full_pfx, 1) if scalar @quot;
+ $s .= flush_quote(\@quot, \$n, $$part_nr, $full_pfx, 1) if scalar @quot;
+ $s .= "\n" unless $s =~ /\n\z/s;
+ ++$$part_nr;
$s;
}
my $rv = "";
my @title;
my $header_obj = $mime->header_obj;
- my $mid = $header_obj->header_raw('Message-ID');
+ my $mid = $header_obj->header('Message-ID');
$mid = PublicInbox::Hval->new_msgid($mid);
my $mid_href = $mid->as_href;
foreach my $h (qw(From To Cc Subject Date)) {
$mid_href = "../m/$mid_href" unless $full_pfx;
$rv .= "(<a\nhref=\"$mid_href.txt\">raw</a>)\n";
- my $irt = $header_obj->header_raw('In-Reply-To');
+ my $irt = $header_obj->header('In-Reply-To');
if (defined $irt) {
my $v = PublicInbox::Hval->new_msgid($irt);
my $html = $v->as_html;
$rv .= "<a\nhref=\"$href.html\">$html</a>>\n";
}
- my $refs = $header_obj->header_raw('References');
+ my $refs = $header_obj->header('References');
if ($refs) {
# avoid redundant URLs wasting bandwidth
my %seen;
my $subj = $mime->header('Subject') || '';
$subj = "Re: $subj" unless $subj =~ /\bRe:/;
- my $mid = $mime->header_obj->header_raw('Message-ID');
+ my $mid = $mime->header_obj->header('Message-ID');
my $irt = uri_escape_utf8($mid);
delete $cc{$to};
$to = uri_escape_utf8($to);
my $idx = $standalone ? " <a\nhref=\"../\">index</a>" : '';
if ($idx && $srch) {
- $irt = $mime->header_obj->header_raw('In-Reply-To') || '';
+ $irt = $mime->header_obj->header('In-Reply-To') || '';
$mid = mid_compressed(mid_clean($mid));
my $t_anchor = length $irt ? T_ANCHOR : '';
$idx = " <a\nhref=\"../t/$mid.html$t_anchor\">".
"threadlink</a>$idx";
my $res = $srch->get_followups($mid);
- if (my $c = $res->{count}) {
+ if (my $c = $res->{total}) {
$c = $c == 1 ? '1 followup' : "$c followups";
$idx .= "\n$c:\n";
$res->{srch} = $srch;
sub simple_dump {
my ($dst, $root, $node, $level) = @_;
+ return unless $node;
# $root = [ Root Message-ID, \%seen, $srch ];
if (my $x = $node->message) {
my $mid = $x->header('Message-ID');
}
}
}
- simple_dump($dst, $root, $node->child, $level + 1) if $node->child;
- simple_dump($dst, $root, $node->next, $level) if $node->next;
+ simple_dump($dst, $root, $node->child, $level+1);
+ simple_dump($dst, $root, $node->next, $level);
}
sub thread_followups {
my ($dst, $root, $res) = @_;
- my $msgs = load_results($res);
- require PublicInbox::Thread;
$root->header_set('X-PI-TS', '0');
- my $th = PublicInbox::Thread->new($root, @$msgs);
- $th->thread;
- $th->order(*PublicInbox::Thread::sort_ts);
+ 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);
sub thread_entry {
my ($dst, $git, $state, $node, $level) = @_;
+ return unless $node;
# $state = [ $search_res, $seen, undef, 0 (msg_nr) ];
# $seen is overloaded with 3 types of fields:
# 1) "root_anchor" => anchor_for(Message-ID),
$$dst .= index_entry(undef, $mime, $level, $state);
}
}
- my $cur;
- $cur = $node->child and
- thread_entry($dst, $git, $state, $cur, $level + 1);
- $cur = $node->next and
- thread_entry($dst, $git, $state, $cur, $level);
+ thread_entry($dst, $git, $state, $node->child, $level + 1);
+ thread_entry($dst, $git, $state, $node->next, $level);
}
sub load_results {
defined($ts) ? $ts : 0;
}
+sub thread_results {
+ my ($msgs) = @_;
+ require PublicInbox::Thread;
+ my $th = PublicInbox::Thread->new(@$msgs);
+ $th->thread;
+ $th->order(*PublicInbox::Thread::sort_ts);
+ $th
+}
+
1;