use warnings;
use URI::Escape qw/uri_escape_utf8/;
use Date::Parse qw/str2time/;
-use Encode qw/find_encoding/;
use Encode::MIME::Header;
+use Plack::Util;
use PublicInbox::Hval qw/ascii_html/;
use PublicInbox::Linkify;
use PublicInbox::MID qw/mid_clean id_compress mid2path mid_mime/;
use PublicInbox::MsgIter;
+use PublicInbox::Address;
+use PublicInbox::WwwStream;
require POSIX;
use constant INDENT => ' ';
use constant TCHILD => '` ';
sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD };
-# public functions:
+# public functions: (unstable)
sub msg_html {
my ($ctx, $mime, $footer) = @_;
- $footer = defined($footer) ? "\n$footer" : '';
my $hdr = $mime->header_obj;
- headers_to_html_header($hdr, $ctx) .
- multipart_text_as_html($mime, '') .
- '</pre><hr /><pre>' .
- html_footer($hdr, 1, $ctx, 'R/') .
- $footer .
- '</pre></body></html>';
+ my $tip = _msg_html_prepare($hdr, $ctx);
+ PublicInbox::WwwStream->new($ctx, sub {
+ my ($nr, undef) = @_;
+ if ($nr == 1) {
+ $tip . multipart_text_as_html($mime, '') .
+ '</pre><hr />'
+ } elsif ($nr == 2) {
+ '<pre>' . html_footer($hdr, 1, $ctx) .
+ '</pre>' . msg_reply($ctx, $hdr) . '<hr />'
+ } else {
+ undef
+ }
+ });
}
-# /$INBOX/$MESSAGE_ID/R/
+# /$INBOX/$MESSAGE_ID/#R
sub msg_reply {
- my ($ctx, $hdr, $footer) = @_;
- my $s = $hdr->header('Subject');
- $s = '(no subject)' if (!defined $s) || ($s eq '');
- my $f = $hdr->header('From');
- $f = '' unless defined $f;
- my $mid = $hdr->header_raw('Message-ID');
- $mid = PublicInbox::Hval->new_msgid($mid);
- my $t = ascii_html($s);
+ my ($ctx, $hdr) = @_;
my $se_url =
'https://kernel.org/pub/software/scm/git/docs/git-send-email.html';
my ($arg, $link) = mailto_arg_link($hdr);
push @$arg, '/path/to/YOUR_REPLY';
- "<html><head><title>replying to \"$t\"</title></head><body><pre>" .
- "replying to message:\n\n" .
- "Subject: <b>$t</b>\n" .
- "From: ". ascii_html($f) .
- "\nDate: " . ascii_html($hdr->header('Date')) .
- "\nMessage-ID: <" . $mid->as_html . ">\n\n" .
- "There are multiple ways to reply:\n\n" .
+ "<hr /><pre\nid=R>".
+ "You may reply publically to <a\nhref=#t>this message</a> via\n".
+ "plain-text email using any one of the following methods:\n\n" .
"* Save the following mbox file, import it into your mail client,\n" .
- " and reply-to-all from there: <a\nhref=../raw>mbox</a>\n\n" .
+ " and reply-to-all from there: <a\nhref=raw>mbox</a>\n\n" .
"* Reply to all the recipients using the <b>--to</b>, <b>--cc</b>,\n" .
" and <b>--in-reply-to</b> switches of git-send-email(1):\n\n" .
"\tgit send-email \\\n\t\t" .
- join(" \\ \n\t\t", @$arg ). "\n\n" .
+ join(" \\\n\t\t", @$arg ). "\n\n" .
qq( <a\nhref="$se_url">$se_url</a>\n\n) .
"* If your mail client supports setting the <b>In-Reply-To</b>" .
" header\n via mailto: links, try the " .
qq(<a\nhref="$link">mailto: link</a>\n) .
- "\nFor context, the original <a\nhref=../>message</a> or " .
- qq(<a\nhref="../t/#u">thread</a>) .
- '</pre><hr /><pre>' . $footer . '</pre></body></html>';
+ '</pre>';
}
sub in_reply_to {
$seen->{$id} = "#$id"; # save the anchor for children, later
my $mid = PublicInbox::Hval->new_msgid($mid_raw);
- my $from = $hdr->header('From');
- my @from = Email::Address->parse($from);
- $from = $from[0]->name;
+ my $from = PublicInbox::Address::from_name($hdr->header('From'));
my $root_anchor = $state->{root_anchor} || '';
my $path = $root_anchor ? '../../' : '';
# scan through all parts, looking for displayable text
msg_iter($mime, sub { index_walk($fh, $mhref, $_[0]) });
- $rv = "\n" . html_footer($hdr, 0, $ctx, "$path$href/R/");
+ $rv = "\n" . html_footer($hdr, 0, $ctx, "$path$href/#R");
if (defined $irt) {
unless (defined $parent_anchor) {
('</ul></li>' x ($max - 1)) . '</ul>');
}
}
- Email::Address->purge_cache;
# there could be a race due to a message being deleted in git
# but still being in the Xapian index:
my $desc = $part->header('Content-Description');
$desc = $fn unless defined $desc;
$desc = '' unless defined $desc;
- $desc = ': '.$desc if $desc;
my $sfn;
- if (defined $fn && $fn =~ /\A[\w-]+\.[a-z0-9]+\z/) {
+ if (defined $fn && $fn =~ /\A[[:alnum:]][\w\.-]+[[:alnum:]]\z/) {
$sfn = $fn;
} elsif ($ct eq 'text/plain') {
$sfn = 'a.txt';
} else {
$sfn = 'a.bin';
}
- qq($nl<a\nhref="$upfx$idx-$sfn">[-- Attachment #$idx$desc --]\n) .
- "[-- Type: $ct, Size: $size bytes --]</a>"
+ my @ret = qq($nl<a\nhref="$upfx$idx-$sfn">[-- Attachment #$idx: );
+ my $ts = "Type: $ct, Size: $size bytes";
+ push(@ret, ($desc eq '') ? "$ts --]" : "$desc --]\n[-- $ts --]");
+ join('', @ret, '</a>');
}
sub add_text_body {
$s;
}
-sub headers_to_html_header {
+sub _msg_html_prepare {
my ($hdr, $ctx) = @_;
my $srch = $ctx->{srch} if $ctx;
my $atom = '';
- my $rv = '';
- my $upfx = '';
+ my $rv = "<pre\nid=b>"; # anchor for body start
if ($srch) {
- $atom = qq{<link\nrel=alternate\ntitle="Atom feed"\n} .
- qq!href="${upfx}t.atom"\ntype="application/atom+xml"/>!;
+ $ctx->{-upfx} = '../';
}
-
my @title;
my $mid = $hdr->header_raw('Message-ID');
$mid = PublicInbox::Hval->new_msgid($mid);
$v = PublicInbox::Hval->new($v);
if ($h eq 'From') {
- my @from = Email::Address->parse($v->raw);
- $title[1] = ascii_html($from[0]->name);
+ my $n = PublicInbox::Address::from_name($v->raw);
+ $title[1] = ascii_html($n);
} elsif ($h eq 'Subject') {
$title[0] = $v->as_html;
if ($srch) {
$rv .= "$h: " . $v->as_html . "\n";
}
+ $ctx->{-title_html} = join(' - ', @title);
$rv .= 'Message-ID: <' . $mid->as_html . '> ';
- $rv .= "(<a\nhref=\"${upfx}raw\">raw</a>)\n";
+ $rv .= "(<a\nhref=\"raw\">raw</a>)\n";
$rv .= _parent_headers($hdr, $srch);
$rv .= "\n";
-
- ("<html><head><title>". join(' - ', @title) . "</title>$atom".
- PublicInbox::Hval::STYLE .
- "</head><body><pre\nid=b>" . # anchor for body start
- $rv);
}
sub thread_skel {
foreach my $h (qw(From To Cc)) {
my $v = $hdr->header($h);
defined($v) && ($v ne '') or next;
- my @addrs = Email::Address->parse($v);
- foreach my $recip (@addrs) {
- my $address = $recip->address;
+ my @addrs = PublicInbox::Address::emails($v);
+ foreach my $address (@addrs) {
my $dst = lc($address);
$cc{$dst} ||= $address;
$to ||= $dst;
}
}
- Email::Address->purge_cache;
my @arg;
my $subj = $hdr->header('Subject') || '';
} else {
$irt = '';
}
-
- $irt . qq(<a\nhref="$rhref">reply</a>) . $idx;
+ $rhref ||= '#R';
+ $irt .= qq(<a\nhref="$rhref">reply</a>);
+ $irt .= $idx;
}
sub linkify_ref_nosrch {
sub emit_index_topics {
my ($state) = @_;
- my $off = $state->{ctx}->{cgi}->param('o');
- $off = 0 unless defined $off;
+ my ($off) = (($state->{ctx}->{cgi}->param('o') || '0') =~ /(\d+)/);
$state->{order} = [];
$state->{subjs} = {};
$state->{latest} = {};
my $max = 25;
- my %opts = ( offset => int $off, limit => $max * 4 );
+ my %opts = ( offset => $off, limit => $max * 4 );
while (scalar @{$state->{order}} < $max) {
my $sres = $state->{srch}->query('', \%opts);
my $nr = scalar @{$sres->{msgs}} or last;