[PATCH 4/4] Another way of locating UID of just saved message
Vladimir.Marek at oracle.com
Vladimir.Marek at oracle.com
Tue Jul 26 09:59:56 BST 2011
From: Vladimir Marek <vlmarek at volny.cz>
It works by fetching all headers from new messages from IMAP server an searching
for our X-OfflineIMAP marker by using reular expression.
Signed-off-by: Vladimir Marek <vlmarek at volny.cz>
---
offlineimap/folder/IMAP.py | 63 ++++++++++++++++++++++++++++++++++++++++++++
offlineimap/imaplib2.py | 14 ++++++++++
2 files changed, 77 insertions(+), 0 deletions(-)
diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py
index 3c702f4..1e08760 100644
--- a/offlineimap/folder/IMAP.py
+++ b/offlineimap/folder/IMAP.py
@@ -24,6 +24,7 @@ import time
from copy import copy
from Base import BaseFolder
from offlineimap import imaputil, imaplibutil, OfflineImapError
+from offlineimap.imaplib2 import UnquotedString
class IMAPFolder(BaseFolder):
def __init__(self, imapserver, name, visiblename, accountname, repository):
@@ -317,6 +318,65 @@ class IMAPFolder(BaseFolder):
matchinguids.sort()
return long(matchinguids[0])
+ def savemessage_fetchheaders(self, imapobj, headername, headervalue):
+ """ We fetch all new mail headers and search for the right
+ X-OfflineImap line by hand. The response from the server has form:
+ (
+ 'OK',
+ [
+ (
+ '185 (RFC822.HEADER {1789}',
+ '... mail headers ...'
+ ),
+ ' UID 2444)',
+ (
+ '186 (RFC822.HEADER {1789}',
+ '... 2nd mail headers ...'
+ ),
+ ' UID 2445)'
+ ]
+ )
+ We need to locate the UID just after mail headers containing our
+ X-OfflineIMAP line.
+
+ Returns UID when found, 0 when not found.
+ """
+ self.ui.debug('imap', 'savemessage_fetchheaders called for %s: %s' % \
+ (headername, headervalue))
+
+ # run "fetch X:* rfc822.header"
+ # since we stored the mail we are looking for just recently, it would
+ # not be optimal to fetch all messages. So we'll find highest message
+ # UID in our local messagelist and search from there (exactly from
+ # UID+1). That works because UIDs are guaranteed to be unique and
+ # ascending.
+
+ # The problem is that imapobj quotes all parameters. That must not happen
+ # with range X:*. So we use UnquotedString for that
+
+ start = 1+max(self.getmessagelist().keys())
+ result = imapobj.uid('FETCH', UnquotedString('%d:*' % start), 'rfc822.header')
+ assert result[0] == 'OK', 'Error with fetching mail headers: ' + '. '.join(result[1])
+
+ result = result[1]
+
+ found = 0
+ for item in result:
+ if found == 0 and type(item) == type( () ):
+ # Walk just tuples
+ if re.search("(?:^|\\r|\\n)%s:\s*%s(?:\\r|\\n)" % (headername, headervalue), item[1], flags=re.IGNORECASE):
+ found = 1
+ elif found == 1:
+ if type(item) == type (""):
+ uid = re.search("UID\s+(\d+)", item, flags=re.IGNORECASE)
+ if uid:
+ return int(uid.group(1))
+ else:
+ self.ui.warn("Can't parse FETCH response, can't find UID: %s", result.__repr__())
+ else:
+ self.ui.warn("Can't parse FETCH response, we awaited string: %s", result.__repr__())
+
+ return 0
def getmessageinternaldate(self, content, rtime=None):
"""Parses mail and returns an INTERNALDATE string
@@ -485,6 +545,9 @@ class IMAPFolder(BaseFolder):
assert(imapobj.noop()[0] == 'OK')
uid = self.savemessage_searchforheader(imapobj, headername,
headervalue)
+ if uid == 0:
+ self.ui.debug('imap', 'savemessage: second attempt to get new UID failed. Going to try search headers manually')
+ uid = self.savemessage_fetchheaders(imapobj, headername, headervalue)
finally:
self.imapserver.releaseconnection(imapobj)
diff --git a/offlineimap/imaplib2.py b/offlineimap/imaplib2.py
index ec6cd0d..0d6dcf5 100644
--- a/offlineimap/imaplib2.py
+++ b/offlineimap/imaplib2.py
@@ -185,6 +185,20 @@ class Request(object):
+class UnquotedString(object):
+ """ String which will not be quoted when passed to IMAP4 command. It works
+ because IMAP._checkquote skips anything which is not of a 'basestring'
+ type.
+ Fro example:
+ imapobj.uid('FETCH', UnquotedString('*:*'), 'rfc822.header')"""
+ t=""
+
+ def __init__(self, text):
+ self.t=text
+
+ def __repr__(self):
+ return self.t
+
class IMAP4(object):
--
1.7.3.2
More information about the OfflineIMAP-project
mailing list