# 3 - message-ID is compressed if it includes '%' (hack!)
# 4 - change "Re: " normalization, avoid circular Reference ghosts
# 5 - subject_path drops trailing '.'
- SCHEMA_VERSION => 5,
+ # 6 - preserve References: order in document data
+ SCHEMA_VERSION => 6,
QP_FLAGS => FLAG_PHRASE|FLAG_BOOLEAN|FLAG_LOVEHATE|FLAG_WILDCARD,
};
sub xpfx { $all_pfx{$_[0]} }
our %PFX2TERM_RMAP;
+my %meta_pfx = (mid => 1, thread => 1, path => 1, type => 1);
while (my ($k, $v) = each %all_pfx) {
- next if $prob_prefix{$k};
- $PFX2TERM_RMAP{$v} = $k;
+ $PFX2TERM_RMAP{$v} = $k if $meta_pfx{$k};
}
my $mail_query = Search::Xapian::Query->new(xpfx('type') . 'mail');
my $ts = Search::Xapian::sortable_serialise($smsg->ts);
$doc->add_value(PublicInbox::Search::TS, $ts);
- $doc->set_data($smsg->to_doc_data);
-
my $tg = $self->term_generator;
$tg->set_document($doc);
if ($was_ghost) {
$doc_id = $smsg->doc_id;
$self->link_message($smsg, 0);
+ $doc->set_data($smsg->to_doc_data);
$db->replace_document($doc_id, $doc);
} else {
$self->link_message($smsg, 0);
+ $doc->set_data($smsg->to_doc_data);
$doc_id = $db->add_document($doc);
}
};
my @refs = $refs ? ($refs =~ /<([^>]+)>/g) : ();
my $irt = $mime->header_obj->header('In-Reply-To');
if ($irt) {
- if ($irt =~ /<([^>]+)>/) {
- $irt = $1;
- }
+ $irt = mid_compressed(mid_clean($irt));
# maybe some crazies will try to make a circular reference:
if ($irt eq $mid) {
$irt = undef;
} else {
+ # last References should be $irt
+ # we will de-dupe later
push @refs, $irt;
}
}
$uniq{$ref} = 1;
push @refs, $ref;
}
- $irt = undef if (defined $irt && !$uniq{$irt});
}
if (@refs) {
- if (defined $irt) {
- $doc->add_term(xpfx('inreplyto') . $irt);
- }
+ $doc->add_term(xpfx('inreplyto') . $irt) if defined $irt;
+ $smsg->{references_sorted} = '<'.join('><', @refs).'>';
my $ref_pfx = xpfx('references');
my ($class, $doc) = @_;
my $data = $doc->get_data;
$data = $enc_utf8->decode($data);
- my ($mid, $subj, $from, $date) = split(/\n/, $data);
+ my ($mid, $subj, $from, $date, $refs) = split(/\n/, $data);
bless {
doc => $doc,
mid => $mid,
subject => $subj,
date => $date,
from_name => $from,
+ references_sorted => $refs,
}, $class;
}
my ($self) = @_;
my $ts = $self->{ts};
return $ts if $ts;
- $self->{date} = undef;
- $self->date;
- $self->{ts};
+ $self->{ts} = eval {
+ str2time($self->date || $self->mime->header('Date'))
+ } || 0;
}
sub date {
my ($self) = @_;
my $date = $self->{date};
return $date if $date;
- my $ts = eval { str2time($self->mime->header('Date')) } || 0;
- $self->{ts} = $ts;
+ my $ts = eval { str2time($self->mime->header('Date')) };
$self->{date} = POSIX::strftime('%Y-%m-%d %H:%M', gmtime($ts));
}
$self->mid . "\n" .
$self->subject . "\n" .
$self->from_name . "\n".
- $self->date;
+ $self->date . "\n" .
+ $self->references_sorted;
+}
+
+sub references_sorted {
+ my ($self) = @_;
+ my $x = $self->{references_sorted};
+ defined $x ? $x : '';
}
sub ensure_metadata {
if ($val =~ s/$PFX2TERM_RE//o) {
my $field = $PublicInbox::Search::PFX2TERM_RMAP{$1};
- if ($field eq 'references') {
- my $refs = $self->{references} ||= [];
- push @$refs, $val;
- } else {
- $self->{$field} = $val;
- }
+ $self->{$field} = $val;
}
}
}
'X-PI-TS' => $self->ts,
'Message-ID' => "<$self->{mid}>",
);
- if (my $refs = $self->{references}) {
- push @h, References => '<' . join('> <', @$refs) . '>';
- }
- if (my $irt = $self->{inreplyto}) {
- push @h, 'In-Reply-To' => "<$irt>";
- }
- Email::MIME->create(header_str => \@h);
+ my $refs = $self->{references_sorted};
+ my $mime = Email::MIME->create(header_str => \@h);
+ $mime->header_set('References', $refs) if (defined $refs);
+ $mime;
}
sub mid {