[PATCH] Add new 'startdate' as an alternative to maxage

Grant Likely grant.likely at secretlab.ca
Tue Nov 20 00:01:44 GMT 2012


This patch adds support for a 'startdate' option in the config file as
an alternative to 'maxage'. The reason for the new option is that
'maxage' means the oldest synchronized message is continually moving
forward in time, but using startdate will fix it to a particular date.

This patch also reworks the date range calculations in the modified code
to use the datetime module which already has mechanisms for calculating
differences in time. The new code is shorter and easier to read.

Signed-off-by: Grant Likely <grant.likely at secretlab.ca>
---
 docs/doc-src/advanced_config.rst |    9 +++++++--
 docs/doc-src/index.rst           |    2 +-
 offlineimap.conf                 |    6 ++++++
 offlineimap/folder/IMAP.py       |   26 ++++++++++++++------------
 offlineimap/folder/Maildir.py    |   30 ++++++++++++++----------------
 5 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/docs/doc-src/advanced_config.rst b/docs/doc-src/advanced_config.rst
index 56e6f18..60fe129 100644
--- a/docs/doc-src/advanced_config.rst
+++ b/docs/doc-src/advanced_config.rst
@@ -1,14 +1,19 @@
 Message filtering
 =================
 
-There are two ways to selectively filter messages out of a folder, using `maxsize` and `maxage`. Setting each option will basically ignore all messages that are on the server by pretending they don't exist.
+There are several ways to selectively filter messages out of a folder. Setting one of these options will effectively ignore all messages that are on the server that don't fall into the filter range by pretending they don't exist.
 
 :todo: explain them and give tipps on how to use and not use them. Use cases!
 
 maxage
 ------
+Integer value. Will ignore all messages older than 'maxage' days old
 
-:todo: !
+startdate
+---------
+Date in the form "YYYY-MM-DD". Will ignore all messages older than the specified date
+
+Example: startdate = 2012-10-01
 
 maxsize
 -------
diff --git a/docs/doc-src/index.rst b/docs/doc-src/index.rst
index e7d639e..f2a2fbd 100644
--- a/docs/doc-src/index.rst
+++ b/docs/doc-src/index.rst
@@ -21,7 +21,7 @@ More information on specific topics can be found on the following pages:
 **Configuration**
   * :doc:`user manual/Configuration <MANUAL>`
   * :doc:`Folder filtering & name transformation guide <nametrans>`
-  * :doc:`maxage <advanced_config>`
+  * :doc:`maxage, maxsize and startdate <advanced_config>`
   * :doc:`command line options <offlineimap>`
   * :doc:`Frequently Asked Questions <FAQ>`
 
diff --git a/offlineimap.conf b/offlineimap.conf
index fccceab..1b34323 100644
--- a/offlineimap.conf
+++ b/offlineimap.conf
@@ -242,6 +242,12 @@ remoterepository = RemoteExample
 #
 # maxage =
 
+# Similar to maxage, you can specify offlineimap to sync messages
+# starting at a specific date by. Any messages older than the date
+# specified in startdate will be ignored. Start date strings must be in
+# the form "YYYY-MM-DD", so 2012-07-01 would mean July 1, 2012.
+#
+# startdate = 2012-07-01
 
 # Maildir file format uses colon (:) separator between uniq name and info.
 # Unfortunatelly colon is not allowed character in windows file name. If you
diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py
index 75520c2..3f2ebe1 100644
--- a/offlineimap/folder/IMAP.py
+++ b/offlineimap/folder/IMAP.py
@@ -23,7 +23,7 @@ import time
 from sys import exc_info
 from .Base import BaseFolder
 from offlineimap import imaputil, imaplibutil, OfflineImapError
-from offlineimap.imaplib2 import MonthNames
+from datetime import date, datetime, timedelta
 
 
 class IMAPFolder(BaseFolder):
@@ -121,6 +121,8 @@ class IMAPFolder(BaseFolder):
     def cachemessagelist(self):
         maxage = self.config.getdefaultint("Account %s" % self.accountname,
                                            "maxage", -1)
+        startdate = self.config.getdefault("Account %s" % self.accountname,
+                                           "startdate", None)
         maxsize = self.config.getdefaultint("Account %s" % self.accountname,
                                             "maxsize", -1)
         self.messagelist = {}
@@ -134,20 +136,20 @@ class IMAPFolder(BaseFolder):
             # By default examine all UIDs in this folder
             msgsToFetch = '1:*'
 
-            if (maxage != -1) | (maxsize != -1):
+            if (maxage != -1) or startdate or (maxsize != -1):
                 search_cond = "(";
 
-                if(maxage != -1):
-                    #find out what the oldest message is that we should look at
-                    oldest_struct = time.gmtime(time.time() - (60*60*24*maxage))
-                    if oldest_struct[0] < 1900:
-                        raise OfflineImapError("maxage setting led to year %d. "
-                                               "Abort syncing." % oldest_struct[0],
+                oldest_date = None
+                if startdate:
+                    oldest_date = datetime.strptime(startdate, "%Y-%m-%d").date()
+                elif(maxage != -1):
+                    oldest_date = datetime.utcnow().date() - timedelta(days=maxage)
+                if oldest_date:
+                    if oldest_date.year < 1900:
+                        raise OfflineImapError("maxage/startdate setting led to year %d. "
+                                               "Abort syncing." % oldest_struct.year,
                                                OfflineImapError.ERROR.REPO)
-                    search_cond += "SINCE %02d-%s-%d" % (
-                        oldest_struct[2],
-                        MonthNames[oldest_struct[1]],
-                        oldest_struct[0])
+                    search_cond += oldest_date.strftime("SINCE %d-%b-%Y")
 
                 if(maxsize != -1):
                     if(maxage != -1): # There are two conditions, add space
diff --git a/offlineimap/folder/Maildir.py b/offlineimap/folder/Maildir.py
index 24d943c..14bdcf6 100644
--- a/offlineimap/folder/Maildir.py
+++ b/offlineimap/folder/Maildir.py
@@ -21,6 +21,7 @@ import re
 import os
 from .Base import BaseFolder
 from threading import Lock
+from datetime import date, datetime, timedelta
 
 try:
     from hashlib import md5
@@ -78,6 +79,7 @@ class MaildirFolder(BaseFolder):
         self._foldermd5 = md5(self.getvisiblename()).hexdigest()
         # Cache the full folder path, as we use getfullname() very often
         self._fullname = os.path.join(self.getroot(), self.getname())
+        self.oldest_time_utc = None
 
     def getfullname(self):
         """Return the absolute file path to the Maildir folder (sans cur|new)"""
@@ -92,24 +94,11 @@ class MaildirFolder(BaseFolder):
 
     #Checks to see if the given message is within the maximum age according
     #to the maildir name which should begin with a timestamp
-    def _iswithinmaxage(self, messagename, maxage):
-        #In order to have the same behaviour as SINCE in an IMAP search
-        #we must convert this to the oldest time and then strip off hrs/mins
-        #from that day
-        oldest_time_utc = time.time() - (60*60*24*maxage)
-        oldest_time_struct = time.gmtime(oldest_time_utc)
-        oldest_time_today_seconds = ((oldest_time_struct[3] * 3600) \
-            + (oldest_time_struct[4] * 60) \
-            + oldest_time_struct[5])
-        oldest_time_utc -= oldest_time_today_seconds
-
+    def _iswithinmaxage(self, messagename):
         timestampmatch = re_timestampmatch.search(messagename)
         timestampstr = timestampmatch.group()
         timestamplong = long(timestampstr)
-        if(timestamplong < oldest_time_utc):
-            return False
-        else:
-            return True
+        return timestamplong >= self.oldest_time_utc
 
     def _parse_filename(self, filename):
         """Returns a messages file name components
@@ -153,6 +142,15 @@ class MaildirFolder(BaseFolder):
         :returns: dict that can be used as self.messagelist"""
         maxage = self.config.getdefaultint("Account " + self.accountname,
                                            "maxage", None)
+        startdate = self.config.getdefault("Account " + self.accountname,
+                                           "startdate", None)
+        if startdate:
+            oldest_date = datetime.strptime(startdate, "%Y-%m-%d").date()
+            self.oldest_time_utc = time.mktime(oldest_date.timetuple())
+        elif maxage:
+            oldest_date = datetime.utcnow().date() - timedelta(days=maxage)
+            self.oldest_time_utc = time.mktime(oldest_date.timetuple())
+
         maxsize = self.config.getdefaultint("Account " + self.accountname,
                                             "maxsize", None)
         retval = {}
@@ -167,7 +165,7 @@ class MaildirFolder(BaseFolder):
             # We store just dirannex and filename, ie 'cur/123...'
             filepath = os.path.join(dirannex, filename)
             # check maxage/maxsize if this message should be considered
-            if maxage and not self._iswithinmaxage(filename, maxage):
+            if not self._iswithinmaxage(filename):
                 continue
             if maxsize and (os.path.getsize(os.path.join(
                         self.getfullname(), filepath)) > maxsize):
-- 
1.7.10.4





More information about the OfflineIMAP-project mailing list