X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=lib%2FPublicInbox%2FMID.pm;h=c82e84013ec0d68730423ab4b691074c5b690dc5;hb=1cb230c4d47c8ef5d03f0b8de2f8ad93c303d816;hp=bb40cc76232152e38242d0d13fb595fc3b35e89d;hpb=43bd7b193a936c8368ba5808c1d693c639f25933;p=public-inbox.git
diff --git a/lib/PublicInbox/MID.pm b/lib/PublicInbox/MID.pm
index bb40cc76..c82e8401 100644
--- a/lib/PublicInbox/MID.pm
+++ b/lib/PublicInbox/MID.pm
@@ -1,14 +1,19 @@
-# Copyright (C) 2015 all contributors
-# License: AGPLv3 or later (https://www.gnu.org/licenses/agpl-3.0.txt)
+# Copyright (C) 2015-2018 all contributors
+# License: AGPL-3.0+
#
# Various Message-ID-related functions.
package PublicInbox::MID;
use strict;
use warnings;
use base qw/Exporter/;
-our @EXPORT_OK = qw/mid_clean id_compress mid2path mid_mime/;
+our @EXPORT_OK = qw/mid_clean id_compress mid2path mid_mime mid_escape MID_ESC
+ mids references/;
+use URI::Escape qw(uri_escape_utf8);
use Digest::SHA qw/sha1_hex/;
-use constant MID_MAX => 40; # SHA-1 hex length
+use constant {
+ MID_MAX => 40, # SHA-1 hex length # TODO: get rid of this
+ MAX_MID_SIZE => 244, # max term size (Xapian limitation) - length('Q')
+};
sub mid_clean {
my ($mid) = @_;
@@ -45,6 +50,56 @@ sub mid2path {
"$x2/$x38";
}
-sub mid_mime ($) { $_[0]->header_obj->header_raw('Message-ID') }
+# Only for v1 code paths:
+sub mid_mime ($) { mids($_[0]->header_obj)->[0] }
+
+sub mids ($) {
+ my ($hdr) = @_;
+ my @mids;
+ my @v = $hdr->header_raw('Message-Id');
+ foreach my $v (@v) {
+ my @cur = ($v =~ /<([^>]+)>/sg);
+ if (@cur) {
+ push(@mids, @cur);
+ } else {
+ push(@mids, $v);
+ }
+ }
+ uniq_mids(\@mids);
+}
+
+# last References should be IRT, but some mail clients do things
+# out of order, so trust IRT over References iff IRT exists
+sub references ($) {
+ my ($hdr) = @_;
+ my @mids;
+ foreach my $f (qw(References In-Reply-To)) {
+ my @v = $hdr->header_raw($f);
+ foreach my $v (@v) {
+ push(@mids, ($v =~ /<([^>]+)>/sg));
+ }
+ }
+ uniq_mids(\@mids);
+}
+
+sub uniq_mids ($) {
+ my ($mids) = @_;
+ my @ret;
+ my %seen;
+ foreach my $mid (@$mids) {
+ if (length($mid) > MAX_MID_SIZE) {
+ warn "Message-ID: <$mid> too long, truncating\n";
+ $mid = substr($mid, 0, MAX_MID_SIZE);
+ }
+ next if $seen{$mid};
+ push @ret, $mid;
+ $seen{$mid} = 1;
+ }
+ \@ret;
+}
+
+# RFC3986, section 3.3:
+sub MID_ESC () { '^A-Za-z0-9\-\._~!\$\&\';\(\)\*\+,;=:@' }
+sub mid_escape ($) { uri_escape_utf8($_[0], MID_ESC) }
1;