Package: offlineimap3
Version: 0.0~git20210225.1e7ef9e+dfsg-4
Severity: normal
Tags: patch upstream

Dear Maintainer,

When syncing a mail directory that contained an email with a clearly
bogus Date header, OfflineIMAP would fail because, while handling the
exception raised due to the duff header, it would attempt to parse the
header again.

This is reported upstream at
https://github.com/OfflineIMAP/offlineimap3/issues/134

I've written a patch, which I've attached, and also offered upstream at
https://github.com/OfflineIMAP/offlineimap3/pull/135

-- System Information:
Debian Release: 11.4
  APT prefers stable-updates
  APT policy: (990, 'stable-updates'), (990, 'stable-security'), (990, 
'stable'), (850, 'testing'), (500, 'unstable')
Architecture: arm64 (aarch64)
Foreign Architectures: armhf

Kernel: Linux 5.15.56-v8+ (SMP w/4 CPU threads; PREEMPT)
Kernel taint flags: TAINT_CRAP
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)

Versions of packages offlineimap3 depends on:
ii  python3           3.9.2-3
ii  python3-distro    1.5.0-1
ii  python3-imaplib2  2.57-5.2

offlineimap3 recommends no packages.

offlineimap3 suggests no packages.

-- no debconf information
>From 416df5d7c2327a9d50946cf29d6548812dde6018 Mon Sep 17 00:00:00 2001
From: Adam Dinwoodie <a...@dinwoodie.org>
Date: Thu, 25 Aug 2022 16:12:13 +0100
Subject: [PATCH] Skip parsing date after failing to parse the date

When file_use_mail_timestamp or utime_from_header are enabled,
OfflineIMAP tries to parse the Date header in the email.  If the header
is present but invalid -- it doesn't contain a valid date -- this will
cause email.message to raise an exception.  This is all fine.  However
when handling that exception, OfflineIMAP can't try to extract the date
again: it's clearly invalid, and raising the same exception a second
time while handling the first exception just causes the entire sync to
fail.

To avoid that happening, don't try to provide the invalid date string in
the error message.  Instead, just give the user the UID of the email
that triggered the exception, and the exception text.

Ideally we'd instead fix the code to actually extract the header value
and provide it in the error message, but Python's email.message module
doesn't provide an easy way to get the raw text of the Date header from
an EmailMessage object; it's possible using private variables like
EmailMessage._headers, or by parsing the email using a custom
email.policy.EmailPolicy object that disables the module's attempts to
coerce the header value to a DateTime.  However, a user should be able
to get the problematic Date header from the message directly anyway, so
it's not worth adding all that complexity for something that should be
rare and provides little value.

Fixes #134

Signed-off-by: Adam Dinwoodie <a...@dinwoodie.org>
---
 offlineimap/folder/Maildir.py | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/offlineimap/folder/Maildir.py b/offlineimap/folder/Maildir.py
index f319b66..4237cee 100644
--- a/offlineimap/folder/Maildir.py
+++ b/offlineimap/folder/Maildir.py
@@ -396,32 +396,30 @@ class MaildirFolder(BaseFolder):
                     message_timestamp = self.get_message_date(
                         msg, 'Delivery-date')
             except Exception as e:
-                # This should never happen.
+                # Extracting the date has failed for some reason, such as it
+                # being in an invalid format.
                 from offlineimap.ui import getglobalui
-                datestr = self.get_message_date(msg)
                 ui = getglobalui()
-                ui.warn("UID %d has invalid date %s: %s\n"
-                        "Not using message timestamp as file prefix" %
-                        (uid, datestr, e))
+                ui.warn("UID %d has invalid date: %s\n"
+                        "Not using message timestamp as file prefix" % (uid, 
e))
                 # No need to check if message_timestamp is None here since it
                 # would be overridden by _gettimeseq.
         messagename = self.new_message_filename(uid, flags, 
date=message_timestamp)
         tmpname = self.save_to_tmp_file(messagename, msg)
 
         if self._utime_from_header is True:
             try:
                 date = self.get_message_date(msg, 'Date')
                 if date is not None:
                     os.utime(os.path.join(self.getfullname(), tmpname),
                              (date, date))
-            # In case date is wrongly so far into the future as to be > max
-            # int32.
             except Exception as e:
+                # Extracting the date has failed for some reason, such as it
+                # being in an invalid format.
                 from offlineimap.ui import getglobalui
-                datestr = self.get_message_date(msg)
                 ui = getglobalui()
-                ui.warn("UID %d has invalid date %s: %s\n"
-                        "Not changing file modification time" % (uid, datestr, 
e))
+                ui.warn("UID %d has invalid date: %s\n"
+                        "Not changing file modification time" % (uid, e))
 
         self.messagelist[uid] = self.msglist_item_initializer(uid)
         self.messagelist[uid]['flags'] = flags
-- 
2.34.1

Reply via email to