From 8e52e5fdea416d6fda0b8d301144af0c043a5a76 Mon Sep 17 00:00:00 2001 From: "Eric Wong (Contractor, The Linux Foundation)" Date: Wed, 21 Mar 2018 01:52:58 +0000 Subject: use both Date: and Received: times We want to rely on Date: to sort messages within individual threads since it keeps messages from git-send-email(1) sorted. However, since developers occasionally have the clock set wrong on their machines, sort overall messages by the newest date in a Received: header so the landing page isn't forever polluted by messages from the future. This also gives us determinism for commit times in most cases, as we'll used the Received: timestamp there, as well. --- lib/PublicInbox/MsgTime.pm | 80 +++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 26 deletions(-) (limited to 'lib/PublicInbox/MsgTime.pm') diff --git a/lib/PublicInbox/MsgTime.pm b/lib/PublicInbox/MsgTime.pm index 87664f4b..4295e873 100644 --- a/lib/PublicInbox/MsgTime.pm +++ b/lib/PublicInbox/MsgTime.pm @@ -4,48 +4,76 @@ package PublicInbox::MsgTime; use strict; use warnings; use base qw(Exporter); -our @EXPORT_OK = qw(msg_timestamp); +our @EXPORT_OK = qw(msg_timestamp msg_datestamp); use Date::Parse qw(str2time); use Time::Zone qw(tz_offset); -sub msg_timestamp ($) { +sub zone_clamp ($) { + my ($zone) = @_; + $zone ||= '+0000'; + # "-1200" is the furthest westermost zone offset, + # but git fast-import is liberal so we use "-1400" + if ($zone >= 1400 || $zone <= -1400) { + warn "bogus TZ offset: $zone, ignoring and assuming +0000\n"; + $zone = '+0000'; + } + $zone; +} + +sub time_response ($) { + my ($ret) = @_; + wantarray ? @$ret : $ret->[0]; +} + +sub msg_received_at ($) { my ($hdr) = @_; # Email::MIME::Header - my ($ts, $zone); - my $mid; my @recvd = $hdr->header_raw('Received'); + my ($ts, $zone); foreach my $r (@recvd) { $zone = undef; $r =~ /\s*(\d+\s+[[:alpha:]]+\s+\d{2,4}\s+ \d+\D\d+(?:\D\d+)\s+([\+\-]\d+))/sx or next; $zone = $2; $ts = eval { str2time($1) } and last; - $mid ||= $hdr->header_raw('Message-ID'); + my $mid = $hdr->header_raw('Message-ID'); warn "no date in $mid Received: $r\n"; } - unless (defined $ts) { - my @date = $hdr->header_raw('Date'); - foreach my $d (@date) { - $zone = undef; - $ts = eval { str2time($d) }; - if ($@) { - $mid ||= $hdr->header_raw('Message-ID'); - warn "bad Date: $d in $mid: $@\n"; - } elsif ($d =~ /\s+([\+\-]\d+)\s*\z/) { - $zone = $1; - } + defined $ts ? [ $ts, zone_clamp($zone) ] : undef; +} + +sub msg_date_only ($) { + my ($hdr) = @_; # Email::MIME::Header + my @date = $hdr->header_raw('Date'); + my ($ts, $zone); + foreach my $d (@date) { + $zone = undef; + $ts = eval { str2time($d) }; + if ($@) { + my $mid = $hdr->header_raw('Message-ID'); + warn "bad Date: $d in $mid: $@\n"; + } elsif ($d =~ /\s+([\+\-]\d+)\s*\z/) { + $zone = $1; } } - $ts = time unless defined $ts; - return $ts unless wantarray; + defined $ts ? [ $ts, zone_clamp($zone) ] : undef; +} - $zone ||= '+0000'; - # "-1200" is the furthest westermost zone offset, - # but git fast-import is liberal so we use "-1400" - if ($zone >= 1400 || $zone <= -1400) { - warn "bogus TZ offset: $zone, ignoring and assuming +0000\n"; - $zone = '+0000'; - } - ($ts, $zone); +# Favors Received header for sorting globally +sub msg_timestamp ($) { + my ($hdr) = @_; # Email::MIME::Header + my $ret; + $ret = msg_received_at($hdr) and return time_response($ret); + $ret = msg_date_only($hdr) and return time_response($ret); + wantarray ? (time, '+0000') : time; +} + +# Favors the Date: header for display and sorting within a thread +sub msg_datestamp ($) { + my ($hdr) = @_; # Email::MIME::Header + my $ret; + $ret = msg_date_only($hdr) and return time_response($ret); + $ret = msg_received_at($hdr) and return time_response($ret); + wantarray ? (time, '+0000') : time; } 1; -- cgit v1.2.3-24-ge0c7