[PATCH 1/2] Another way of locating UID of just saved message

Vladimir.Marek at oracle.com Vladimir.Marek at oracle.com
Wed Aug 3 15:59:21 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 |   67 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py
index 3c702f4..9104faa 100644
--- a/offlineimap/folder/IMAP.py
+++ b/offlineimap/folder/IMAP.py
@@ -317,6 +317,70 @@ 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.
+
+        if self.getmessagelist():
+            start = 1+max(self.getmessagelist().keys())
+        else:
+            # Folder was empty - start from 1
+            start = 1
+
+        # The problem is that imapobj quotes all parameters. That must not happen
+        # with range X:*. So we use bytearray for that
+
+        result = imapobj.uid('FETCH', bytearray('%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 +549,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)
-- 
1.7.3.2





More information about the OfflineIMAP-project mailing list