From 3b30c4aa93737c7ac3fd8be304b9515988657366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Gross?= Date: Wed, 28 Oct 2015 10:56:16 +0100 Subject: [PATCH] add new config option filename_use_mail_timestamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If this value is true, use (if possible) a timestamp based on message Date or Delivery-date headers. The current system time is used otherwise. filename_use_mail_timestamp and utime_from_header are now completely separated option that do not interfere one with other. To handle this feature in a multithread context we use a hash to count the number of mail with the same timestamp. This method is more accurate than using the old lasttime and timeseq variables. Signed-off-by: Sébastien Gross Signed-off-by: Nicolas Sebrecht --- offlineimap/folder/Base.py | 7 ++++++ offlineimap/folder/Maildir.py | 46 ++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/offlineimap/folder/Base.py b/offlineimap/folder/Base.py index d81f3ef..d2a0706 100644 --- a/offlineimap/folder/Base.py +++ b/offlineimap/folder/Base.py @@ -60,6 +60,13 @@ class BaseFolder(object): self._utime_from_header = self.config.getdefaultboolean(repo, "utime_from_header", utime_from_header_global) + # Do we need to use mail timestamp for filename prefix? + filename_use_mail_timestamp_global = self.config.getdefaultboolean( + "general", "filename_use_mail_timestamp", False) + repo = "Repository " + repository.name + self._filename_use_mail_timestamp = self.config.getdefaultboolean(repo, + "filename_use_mail_timestamp", filename_use_mail_timestamp_global) + # Determine if we're running static or dynamic folder filtering # and check filtering status self._dynamic_folderfilter = self.config.getdefaultboolean( diff --git a/offlineimap/folder/Maildir.py b/offlineimap/folder/Maildir.py index 07d1b73..a7dbf26 100644 --- a/offlineimap/folder/Maildir.py +++ b/offlineimap/folder/Maildir.py @@ -38,22 +38,20 @@ re_uidmatch = re.compile(',U=(\d+)') # Find a numeric timestamp in a string (filename prefix) re_timestampmatch = re.compile('(\d+)'); -timeseq = 0 -lasttime = 0 +timehash = {} timelock = Lock() -def _gettimeseq(): - global lasttime, timeseq, timelock +def _gettimeseq(date=None): + global timehash, timelock timelock.acquire() try: - thistime = long(time.time()) - if thistime == lasttime: - timeseq += 1 - return (thistime, timeseq) + if date is None: + date = long(time.time()) + if timehash.has_key(date): + timehash[date] += 1 else: - lasttime = thistime - timeseq = 0 - return (thistime, timeseq) + timehash[date] = 0 + return (date, timehash[date]) finally: timelock.release() @@ -269,14 +267,14 @@ class MaildirFolder(BaseFolder): filepath = os.path.join(self.getfullname(), filename) return os.path.getmtime(filepath) - def new_message_filename(self, uid, flags=set()): + def new_message_filename(self, uid, flags=set(), date=None): """Creates a new unique Maildir filename :param uid: The UID`None`, or a set of maildir flags :param flags: A set of maildir flags :returns: String containing unique message filename""" - timeval, timeseq = _gettimeseq() + timeval, timeseq = _gettimeseq(date) return '%d_%d.%d.%s,U=%d,FMD5=%s%s2,%s'% \ (timeval, timeseq, os.getpid(), socket.gethostname(), uid, self._foldermd5, self.infosep, ''.join(sorted(flags))) @@ -346,7 +344,27 @@ class MaildirFolder(BaseFolder): # Otherwise, save the message in tmp/ and then call savemessageflags() # to give it a permanent home. tmpdir = os.path.join(self.getfullname(), 'tmp') - messagename = self.new_message_filename(uid, flags) + + # use the mail timestamp given by either Date or Delivery-date mail + # headers. + message_timestamp = None + if self._filename_use_mail_timestamp: + try: + message_timestamp = emailutil.get_message_date(content, 'Date') + if message_timestamp is None: + # Give a try with Delivery-date + date = emailutil.get_message_date(content, 'Delivery-date') + except: + # This should never happen + from email.Parser import Parser + from offlineimap.ui import getglobalui + datestr = Parser().parsestr(content, True).get("Date") + ui = getglobalui() + ui.warn("UID %d has invalid date %s: %s\n" + "Not using message timestamp as file prefix" % (uid, datestr, e)) + # No need to check if date 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, content) if self.utime_from_header: