[PATCH 3/4] IMAP: revamp _msgs_to_fetch()
Janna Martl
janna.martl109 at gmail.com
Wed Mar 25 05:40:04 GMT 2015
On Wed, Mar 25, 2015 at 05:42:29AM +0100, Nicolas Sebrecht wrote:
>Signed-off-by: Nicolas Sebrecht <nicolas.s-dev at laposte.net>
>---
> offlineimap/folder/IMAP.py | 96 +++++++++++++---------------------------------
> 1 file changed, 27 insertions(+), 69 deletions(-)
>
>diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py
>index bf61ebe..834b446 100644
>--- a/offlineimap/folder/IMAP.py
>+++ b/offlineimap/folder/IMAP.py
>@@ -153,94 +153,52 @@ class IMAPFolder(BaseFolder):
> Arguments:
> - imapobj: instance of IMAPlib
> - maxage (optional): only fetch messages up to maxage days ago
>- - min_uid (optional): only fetch messages with uid > min_uid
>+ - min_uid (optional): only fetch messages with UID >= min_uid
>
>- This function should be called with at most one of maxage or
>- min_uid.
>-
>- If using maxage, this finds the min uid of all messages within
>- maxage, and returns all messages with uid > this min. As maxage
>- is only set if this folder is the local folder, this ensures
>- consistency with remote (which only restricts to uid > this min)
>- in edge cases where the date is much earlier than messages with
>- similar UID's (e.g. the UID was reassigned much later).
>+ This function should be called with at MOST one of maxage OR
>+ min_uid set but not BOTH.
>
> Returns: range(s) for messages or None if no messages
> are to be fetched."""
>
> res_type, imapdata = imapobj.select(self.getfullname(), True, True)
> if imapdata == [None] or imapdata[0] == '0':
>- # Empty folder, no need to populate message list
>+ # Empty folder, no need to populate message list.
> return None
>
>- # By default examine all messages in this folder
>- msgsToFetch = '1:*'
>+ conditions = []
>+
>+ if min_uid != None:
>+ conditions.append("UID %d:*"% min_uid)
>+ elif maxage != None:
>+ # 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],
>+ OfflineImapError.ERROR.REPO)
>+ conditions.append("SINCE %02d-%s-%d"%
>+ oldest_struct[2],
>+ MonthNames[oldest_struct[1]],
>+ oldest_struct[0])
>
> maxsize = self.getmaxsize()
>+ if maxsize != None:
>+ conditions.append("SMALLER %d"% maxsize)
>
>- # Build search condition
>- if maxage or min_uid != None or maxsize != None:
>- search_cond = "(";
>-
>- if maxage:
>- #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],
>- OfflineImapError.ERROR.REPO)
>- search_cond += "SINCE %02d-%s-%d"% (
>- oldest_struct[2],
>- MonthNames[oldest_struct[1]],
>- oldest_struct[0])
>- if min_uid != None:
>- if maxage: # There are two conditions, add space
>- search_cond += " "
>- search_cond += "UID %d:*"% min_uid
>-
>- if maxsize != None:
>- if maxage or min_uid != None:
>- # There are at least two conditions, add space
>- search_cond += " "
>- search_cond += "SMALLER %d"% maxsize
>-
>- search_cond += ")"
>-
>+ if len(conditions) > 1:
>+ # Build SEARCH conditions.
>+ search_cond = "(%s)"% ' '.join(conditions)
> res_type, res_data = imapobj.search(None, search_cond)
> if res_type != 'OK':
> raise OfflineImapError("SEARCH in folder [%s]%s failed. "
> "Search string was '%s'. Server responded '[%s] %s'"% (
> self.getrepository(), self, search_cond, res_type, res_data),
> OfflineImapError.ERROR.FOLDER)
>-
>- if maxage:
>- # Found messages within maxage, but want all messages with UID
>- # > the min uid of the within-maxage messages. Ordering by UID
>- # is the same as ordering by MSN, so we get the messages with
>- # MSN > the min MSN of the within-maxage messages.
>- msg_seq_numbers = map(lambda s : int(s), res_data[0].split())
>- if msg_seq_numbers:
>- min_msn = min(msg_seq_numbers)
>- else:
>- return None
>- if maxsize == None:
>- # If no maxsize, can just ask for all messages with MSN > min_msn
>- return "%d:*"% min_msn
>- else:
>- # Restrict the range min_msn:* to those with acceptable size.
>- # Single-quotes prevent imaplib2 from quoting the sequence.
>- search_cond = "'%d:* (SMALLER %d)'"% (min_msn, maxsize)
>- res_type, res_data = imapobj.search(None, search_cond)
>- if res_type != 'OK':
>- raise OfflineImapError("SEARCH in folder [%s]%s failed. "
>- "Search string was '%s'. Server responded '[%s] %s'"%
>- (self.getrepository(), self, search_cond, res_type,
>- res_data), OfflineImapError.ERROR.FOLDER)
I think this is necessary if we're doing an IMAP-IMAP sync, and right
now self is the local folder. Per our most recent discussion, for the
local folder, there are two steps: (1) find messages within maxage;
(2) expand that list to also include all messages with UID > min(uid's
within maxage). We've already done step (1) above; this is step (2),
except it looks a little different -- step (1) gave us a list of
MSN's, not UID's, so you can ask for msn's in the range min_msn:* if
there are no other conditions to enforce but if you also have to
restrict that to < maxsize, I think you need another query.
> # Resulting MSN are separated by space, coalesce into ranges
>- msgsToFetch = imaputil.uid_sequence(res_data[0].split())
>-
>- return msgsToFetch
>+ return imaputil.uid_sequence(res_data[0].split())
>+ # By default examine all messages in this folder.
>+ return '1:*'
>
> # Interface from BaseFolder
> def msglist_item_initializer(self, uid):
>--
>2.3.1
>
More information about the OfflineIMAP-project
mailing list