]> Sergey Matveev's repositories - public-inbox.git/blob - lib/PublicInbox/ContentId.pm
d1a009e77f2ed9e9e8b4de30a79f85a706ef37e8
[public-inbox.git] / lib / PublicInbox / ContentId.pm
1 # Copyright (C) 2018 all contributors <meta@public-inbox.org>
2 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
3
4 package PublicInbox::ContentId;
5 use strict;
6 use warnings;
7 use base qw/Exporter/;
8 our @EXPORT_OK = qw/content_id/;
9 use PublicInbox::MID qw(mids references);
10
11 # not sure if less-widely supported hash families are worth bothering with
12 use Digest::SHA;
13
14 # Content-* headers are often no-ops, so maybe we don't need them
15 my @ID_HEADERS = qw(Subject From Date To Cc);
16
17 sub content_id ($;$) {
18         my ($mime, $alg) = @_;
19         $alg ||= 256;
20         my $dig = Digest::SHA->new($alg);
21         my $hdr = $mime->header_obj;
22
23         # References: and In-Reply-To: get used interchangeably
24         # in some "duplicates" in LKML.  We treat them the same
25         # in SearchIdx, so treat them the same for this:
26         my %seen;
27         foreach my $mid (@{mids($hdr)}) {
28                 $dig->add('mid: '.$mid);
29                 $seen{$mid} = 1;
30         }
31         foreach my $mid (@{references($hdr)}) {
32                 next if $seen{$mid};
33                 $dig->add('ref: '.$mid);
34         }
35         foreach my $h (@ID_HEADERS) {
36                 my @v = $hdr->header_raw($h);
37                 $dig->add("$h: $_") foreach @v;
38         }
39         $dig->add($mime->body_raw);
40         'SHA-' . $dig->algorithm . ':' . $dig->hexdigest;
41 }
42
43 1;