- my $s = eval { $part->body_str };
-
- # badly-encoded message? tell the world about it!
- return attach_link($upfx, $ct, $p, $fn) if $@;
-
- my @lines = split(/^/m, $s);
- $s = '';
- if (defined($fn) || $depth > 0) {
- $s .= attach_link($upfx, $ct, $p, $fn);
- $s .= "\n";
+ # makes no difference to browsers, and don't screw up filename
+ # link generation in diffs with the extra '%0D'
+ $s =~ s/\r\n/\n/sg;
+
+ # will be escaped to `•' in HTML
+ obfuscate_addrs($ibx, $s, "\x{2022}") if $ibx->{obfuscate};
+
+ # always support diff-highlighting, but we can't linkify hunk
+ # headers for solver unless some coderepo are configured:
+ my $diff;
+ if ($s =~ /^--- [^\n]+\n\+{3} [^\n]+\n@@ /ms) {
+ # diffstat anchors do not link across attachments or messages,
+ # -apfx is just a stable prefix for making diffstat anchors
+ # linkable to the first diff hunk w/o crossing attachments
+ $idx =~ tr!.!/!; # compatibility with previous versions
+ $ctx->{-apfx} = $upfx . $idx;
+
+ # do attr => filename mappings for diffstats in git diffs:
+ $ctx->{-anchors} = {} if $s =~ /^diff --git /sm;
+ $diff = 1;
+ delete $ctx->{-long_path};
+ my $spfx;
+ if ($ibx->{-repo_objs}) {
+ if (index($upfx, '//') >= 0) { # absolute URL (Atom feeds)
+ $spfx = $upfx;
+ $spfx =~ s!/([^/]*)/\z!/!;
+ } else {
+ my $n_slash = $upfx =~ tr!/!/!;
+ if ($n_slash == 0) {
+ $spfx = '../';
+ } elsif ($n_slash == 1) {
+ $spfx = '';
+ } else { # nslash == 2
+ $spfx = '../../';
+ }
+ }
+ }
+ $ctx->{-spfx} = $spfx;
+ };
+
+ # some editors don't put trailing newlines at the end:
+ $s .= "\n" unless $s =~ /\n\z/s;
+
+ # split off quoted and unquoted blocks:
+ my @sections = PublicInbox::MsgIter::split_quotes($s);
+ undef $s; # free memory
+ if (defined($fn) || ($depth > 0 && !$part->{is_submsg}) || $err) {
+ # badly-encoded message with $err? tell the world about it!
+ attach_link($ctx, $ct, $p, $fn, $err);
+ $$rv .= "\n";