offlineimap rev 540

"Automatic Subversion Change Mailer" <[email protected]> Mon, 28 Jul 2003 14:02:39 -0500 (CDT)
Newsgroups gmane.mail.imap.offlineimap.subversion
Message-ID <[email protected]>
You are receiving this message because
all commits get sent to this address.

Author: jgoerzen
Date: 2003-07-28 14:02:02 -0500 (Mon, 28 Jul 2003)
New Revision: 540

Modified:
  offlineimap/branches/twisted/TODO
  offlineimap/branches/twisted/offlineimap/folder/Base.py
  offlineimap/branches/twisted/offlineimap/folder/IMAP.py
  offlineimap/branches/twisted/offlineimap/imaputil.py

Log:
Made a bit more progress


Diff:
Added: offlineimap/branches/twisted/TODO
==============================================================================
--- offlineimap/branches/twisted/TODO	2003-07-28 15:49:43 UTC (rev 539)
+++ offlineimap/branches/twisted/TODO	2003-07-28 19:02:02 UTC (rev 540)
@@ -0,0 +1 @@
+Test with multiple folders

Modified: offlineimap/branches/twisted/offlineimap/folder/Base.py
==============================================================================
--- offlineimap/branches/twisted/offlineimap/folder/Base.py	2003-07-28 15:49:43 UTC (rev 539)
+++ offlineimap/branches/twisted/offlineimap/folder/Base.py	2003-07-28 19:02:02 UTC (rev 540)
@@ -139,7 +139,9 @@
         raise NotImplementedException
 
     def getmessage(self, uid):
-        """Returns the content of the specified message."""
+        """Returns the content of the specified message.
+
+        Returns Deferred"""
         raise NotImplementedException
 
     def savemessage(self, uid, content, flags):
@@ -224,31 +226,66 @@
         if register:
             UIBase.getglobalui().registerthread(self.getaccountname())
         UIBase.getglobalui().copyingmessage(uid, self, applyto)
+        d = self.getmessage(uid)
+        d.addCallback(self.syncmessagesto_neguid_msg_worker, uid, dest, applyto,
+                      register)
+
+    def syncmessagesto_neguid_worker(self, message, uid, dest, applyto,
+                                     register):
         successobject = None
         successuid = None
-        message = self.getmessage(uid)
+        #message = self.getmessage(uid) Now passed in
         flags = self.getmessageflags(uid)
-        for tryappend in applyto:
-            successuid = tryappend.savemessage(uid, message, flags)
-            if successuid >= 0:
-                successobject = tryappend
-                break
-        # Did we succeed?
-        if successobject != None:
-            if successuid:       # Only if IMAP actually assigned a UID
-                # Copy the message to the other remote servers.
-                for appendserver in \
-                        [x for x in applyto if x != successobject]:
-                    appendserver.savemessage(successuid, message, flags)
-                    # Copy to its new name on the local server and delete
-                    # the one without a UID.
-                    self.savemessage(successuid, message, flags)
-            self.deletemessage(uid) # It'll be re-downloaded.
-        else:
-            # Did not find any server to take this message.  Ignore.
-            pass
+        return syncmessagesto_neguid_tryappend(0, None,
+                                               trylist, flags, message, uid, dest,
+                                            applyto, register)
+
+    def syncmessagesto_neguid_tryappend(self, successuid, lasttry,
+                                        trylist, flags,
+                                        message, uid, dest, applyto, register):
+        if successuid >= 0:
+            # Last server took this message.  Proceed.
+            return syncmessagesto_neguid_realappend(successuid, lasttry,
+                                             flags, message, uid, dest, applyto, register)
+        if not len(trylist):
+            # Did not find any server to take thie message.  Ignore.
+            return
+
+        # Process the next one.
         
+        tryappend = trylist[0]
+        trylist = trylist[1:]
 
+        d = tryappend.savemessage(uid, message, flags)
+        d.addCallback(self.syncmessagesto_neguid_tryappend,
+                      tryappend, trylist, flags, message, uid, dest,
+                      applyto, register)
+        return d
+
+
+    def syncmessagesto_neguid_realappend(self, successuid, successobject,
+                                         flags, message, uid, dest, applyto,
+                                         register):
+        # Did we succeed?
+        #if successobject != None:   Assumed given above logic
+        #
+        # I'm not so sure about this successuid thing....
+        deferreds = []
+        if successuid:       # Only if IMAP actually assigned a UID
+            # Copy the message to the other remote servers.
+            for appendserver in \
+                    [x for x in applyto if x != successobject]:
+                d = appendserver.savemessage(successuid, message, flags)
+                deferreds.append(d)
+            # Copy to its new name on the local server and delete
+            # the one without a UID.
+            # Why was this indented another level before?
+            d = self.savemessage(successuid, message, flags)
+            deferreds.append(d)
+        d = self.deletemessage(uid) # It'll be re-downloaded.
+        deferreds.append(d)
+        return defer.DeferredList(deferreds)
+
     def syncmessagesto_neguid(self, dest, applyto):
         """Pass 1 of folder synchronization.
 
@@ -279,24 +316,44 @@
         # really needed.
         if register:
             UIBase.getglobalui().registerthread(self.getaccountname())
+        print uid
+        print type(uid)
+        flags = self.getmessageflags(uid)
         UIBase.getglobalui().copyingmessage(uid, self, applyto)
         message = ''
         # If any of the destinations actually stores the message body,
         # load it up.
         for object in applyto:
             if object.storesmessages():
-                message = self.getmessage(uid)
-                break
-        flags = self.getmessageflags(uid)
-        for object in applyto:
-            newuid = object.savemessage(uid, message, flags)
-            if newuid > 0 and newuid != uid:
-                # Change the local uid.
-                self.savemessage(newuid, message, flags)
-                self.deletemessage(uid)
-                uid = newuid
-        
+                d = self.getmessage(uid)
+                d.addCallback(self.copymessageto_worker, uid, applyto, flags)
+                return d
+        return self.copymessageto_worker('', uid, applyto, flags)
 
+    def copymessageto_worker(self, message, uid, applyto, flags):
+        if len(applyto) == 0:
+            return
+
+        object = applyto[0]
+        d = object.savemessage(uid, message, flags)
+        d.addCallback(self.copymessageto_saveuid, message, uid, applyto[1:],
+                      flags)
+        return d
+
+    def copymessageto_saveuid(self, newuid, message, uid, applyto, flags):
+        if newuid > 0 and newuid != uid:
+            # Change the local uid.
+            d = self.savemessage(newuid, message, flags)
+            d.addCallback(lambda x, uid: self.deletemessage(uid),
+                          uid)
+            uid = newuid
+            d.addCallback(lambda x, message, uid, applyto, flags:
+                          self.copymessageto_worker(message, uid, applyto, flags),
+                          message, uid, applyto, flags)
+            return d
+        else:
+            return self.copymessageto_worker(message, uid, applyto, flags)
+
     def syncmessagesto_copy(self, dest, applyto):
         """Pass 2 of folder synchronization.
 

Modified: offlineimap/branches/twisted/offlineimap/folder/IMAP.py
==============================================================================
--- offlineimap/branches/twisted/offlineimap/folder/IMAP.py	2003-07-28 15:49:43 UTC (rev 539)
+++ offlineimap/branches/twisted/offlineimap/folder/IMAP.py	2003-07-28 19:02:02 UTC (rev 540)
@@ -100,13 +100,12 @@
         #    maindefer.callback(None)
         #    return
         # FIXME: not yet as robust as below.
-        print self.getname(), "flags_uids", flags_uids
-        flags, uids = flags_uids
-        flags = flags[1]
+        flagshash, uids = flags_uids
+        flagshash = flagshash[1]
         uids = uids[1]
-        for msg in flags.keys():
-            flags = imaputil.flagsimap2maildir(flags)
-            uid = uids[msg]
+        for msg in flagshash.keys():
+            flags = imaputil.flagsimap2maildir(flagshash[msg]['FLAGS'])
+            uid = long(uids[msg]['UID'])
             self.messagelist[uid] = {'uid': uid, 'flags': flags}
 
         print self.getname(), "Cached at", self.messagelist
@@ -132,12 +131,19 @@
 
     def getmessage(self, uid):
         imapobj = self.imapserver.acquireconnection()
-        try:
-            imapobj.select(self.getfullname(), readonly = 1)
-            return imapobj.uid('fetch', '%d' % uid, '(BODY.PEEK[])')[1][0][1].replace("\r\n", "\n")
-        finally:
-            self.imapserver.releaseconnection(imapobj)
-    
+        d = imapobj.examine(self.getfullname())
+        d.addCallback(lambda x, uid, useuid, hdr: \
+                      imapobj.fetchSpecific(uid, useuid, hdr),
+                      str(uid), 1, 'BODY.PEEK[]')
+        d.addCallback(self.getmessage_process)
+        return d
+
+    def getmessage_process(self, message):
+        print "getmessage_process: message is", message
+        key = message.keys()[0]
+        print "returning", message[key]
+        return message[key].replace("\r\n", "\n")
+                                      
     def getmessageflags(self, uid):
         return self.messagelist[uid]['flags']
 
@@ -195,88 +201,105 @@
         return long(matchinguids[0])
 
     def savemessage(self, uid, content, flags):
-        imapobj = self.imapserver.acquireconnection()
+        d  = self.imapserver.acquireconnection()
+        d.addCallback(self.savemessage_step1, uid, content, flags)
+        return d
+
+    def savemessage_step1(self, imapobj, uid, content, flags):
         ui = UIBase.getglobalui()
-        ui.debug('imap', 'savemessage: called')
+        ui.debug('imap', 'savemessage_step1: called')
+        d = imapobj.select(self.getfullname())
+        d.addCallback(self.savemessage_step2, imapobj, uid, content, flags)
+
+    def savemessage_step2(self, ignore, imapobj, uid, content, flags):
+        # This backend always assigns a new uid, so the uid arg is ignored.
+        # In order to get the new uid, we need to save off the message ID.
+
+        message = rfc822.Message(StringIO(content))
+        datetuple = rfc822.parsedate(message.getheader('Date'))
+        # Will be None if missing or not in a valid format.
+        if datetuple == None:
+            datetuple = time.localtime()
         try:
-            try:
-                imapobj.select(self.getfullname()) # Needed for search
-            except imapobj.readonly:
-                ui.msgtoreadonly(self, uid, content, flags)
-                # Return indicating message taken, but no UID assigned.
-                # Fudge it.
-                return 0
-            
-            # This backend always assigns a new uid, so the uid arg is ignored.
-            # In order to get the new uid, we need to save off the message ID.
+            if datetuple[0] < 1981:
+                raise ValueError
+            # This could raise a value error if it's not a valid format.
+            date = imaputil.Time2Internaldate(datetuple) 
+        except ValueError:
+            # Argh, sometimes it's a valid format but year is 0102
+            # or something.  Argh.  It seems that Time2Internaldate
+            # will rause a ValueError if the year is 0102 but not 1902,
+            # but some IMAP servers nonetheless choke on 1902.
+            date = imaputil.Time2Internaldate(time.localtime())
 
-            message = rfc822.Message(StringIO(content))
-            datetuple = rfc822.parsedate(message.getheader('Date'))
-            # Will be None if missing or not in a valid format.
-            if datetuple == None:
-                datetuple = time.localtime()
-            try:
-                if datetuple[0] < 1981:
-                    raise ValueError
-                # This could raise a value error if it's not a valid format.
-                date = imaplib.Time2Internaldate(datetuple) 
-            except ValueError:
-                # Argh, sometimes it's a valid format but year is 0102
-                # or something.  Argh.  It seems that Time2Internaldate
-                # will rause a ValueError if the year is 0102 but not 1902,
-                # but some IMAP servers nonetheless choke on 1902.
-                date = imaplib.Time2Internaldate(time.localtime())
+        ui.debug('imap', 'savemessage: using date ' + str(date))
+        content = re.sub("(?<!\r)\n", "\r\n", content)
+        ui.debug('imap', 'savemessage: initial content is: ' + repr(content))
 
-            ui.debug('imap', 'savemessage: using date ' + str(date))
-            content = re.sub("(?<!\r)\n", "\r\n", content)
-            ui.debug('imap', 'savemessage: initial content is: ' + repr(content))
+        (headername, headervalue) = self.savemessage_getnewheader(content)
+        ui.debug('imap', 'savemessage: new headers are: %s: %s' % \
+                 (headername, headervalue))
+        content = self.savemessage_addheader(content, headername,
+                                             headervalue)
+        ui.debug('imap', 'savemessage: new content is: ' + repr(content))
+        ui.debug('imap', 'savemessage: new content length is ' + \
+                 str(len(content)))
 
-            (headername, headervalue) = self.savemessage_getnewheader(content)
-            ui.debug('imap', 'savemessage: new headers are: %s: %s' % \
-                     (headername, headervalue))
-            content = self.savemessage_addheader(content, headername,
-                                                 headervalue)
-            ui.debug('imap', 'savemessage: new content is: ' + repr(content))
-            ui.debug('imap', 'savemessage: new content length is ' + \
-                     str(len(content)))
+        d = imapobj.append(self.getfullname(),
+                           StringIO(content),
+                           imaputil.flagsmaildir2imap(flags),
+                           date)
+        # Checkpoint.  Let it write out the messages.
+        d.addCallback(lambda ignore: imapobj.check())
+        d.addCallback(self.savemessage_fetchuid, imapobj, headername, headervalue, flags, 0)
+        return d
 
-            assert(imapobj.append(self.getfullname(),
-                                       imaputil.flagsmaildir2imap(flags),
-                                       date, content)[0] == 'OK')
+    def savemessage_fetchuid(self, ignore, imapobj, headername, headervalue,
+                             flags, previousattempts):
+        ui.debug('imap', 'savemessage: attempt %d to get new UID' \
+                 % previousattempts)
+        d = self.savemessage_searchforheader(imapobj, headername,
+                                             headervalue)
+        if previousattempts == 1:
+            # This is our last try.
+            d.addCallback(self.savemessage_register, flags)
+            return d
 
-            # Checkpoint.  Let it write out the messages, etc.
-            assert(imapobj.check()[0] == 'OK')
+        d.addCallback(self.savemessage_tryregister, imapobj, headername,
+                      headervalue, flags, previousattempts)
+        return d
 
-            # Keep trying until we get the UID.
-            try:
-                ui.debug('imap', 'savemessage: first attempt to get new UID')
-                uid = self.savemessage_searchforheader(imapobj, headername,
-                                                       headervalue)
-            except ValueError:
-                ui.debug('imap', 'savemessage: first attempt to get new UID failed.  Going to run a NOOP and try again.')
-                assert(imapobj.noop()[0] == 'OK')
-                uid = self.savemessage_searchforheader(imapobj, headername,
-                                                       headervalue)
-        finally:
-            self.imapserver.releaseconnection(imapobj)
+    def savemessage_tryregister(self, uid, imapobj, headername, headervalue,
+                                flags, previousattempts):
+        if not uid:
+            d = imapobj.noop()
+            d.addCallback(self.savemessage_fetchuid, imapobj, headername,
+                                             headervalue, flags,
+                                             previousattempts + 1)
+            return d
+        else:
+            return self.savemessage_register(None, uid, flags)
 
+    def savemessage_register(self, ignore, uid, flags):
+        #self.imapserver.releaseconnection(imapobj)
         self.messagelist[uid] = {'uid': uid, 'flags': flags}
         ui.debug('imap', 'savemessage: returning %d' % uid)
         return uid
 
     def savemessageflags(self, uid, flags):
         imapobj = self.imapserver.acquireconnection()
-        try:
-            try:
-                imapobj.select(self.getfullname())
-            except imapobj.readonly:
-                UIBase.getglobalui().flagstoreadonly(self, [uid], flags)
-                return
-            result = imapobj.uid('store', '%d' % uid, 'FLAGS',
-                                 imaputil.flagsmaildir2imap(flags))
-            assert result[0] == 'OK', 'Error with store: ' + r[1]
-        finally:
-            self.imapserver.releaseconnection(imapobj)
+        d = imapobj.select(self.getfullname())
+        d.addCallback(self.savemessageflags_worker, imapobj, uid, flags)
+        d.addCallback(self.savemessageflags_store, uid, flags)
+        return d
+
+    def savemessageflags_worker(self, ignore, imapobj, uid, flags):
+        return imapobj.setFlags(str(uid),
+                                imaputil.flagsmaildir2imap(flags),
+                                uid = 1)
+
+    def savemessageflags_store(self, result, uid, flags):
+        print "savemessageflags_store: result =", result
         result = result[1][0]
         if not result:
             self.messagelist[uid]['flags'] = flags

Modified: offlineimap/branches/twisted/offlineimap/imaputil.py
==============================================================================
--- offlineimap/branches/twisted/offlineimap/imaputil.py	2003-07-28 15:49:43 UTC (rev 539)
+++ offlineimap/branches/twisted/offlineimap/imaputil.py	2003-07-28 19:02:02 UTC (rev 540)
@@ -19,6 +19,7 @@
 import re, string, types
 from offlineimap.ui import UIBase
 from twisted.internet import defer
+from imaplib import Time2Internaldate, Internaldate2tuple
 
 quotere = re.compile('^("(?:[^"]|\\\\")*")')
 
@@ -136,14 +137,14 @@
     debug("imapsplit() returning:", retval)
     return retval
             
-def flagsimap2maildir(flagstring):
+def flagsimap2maildir(imapflaglist):
     flagmap = {'\\seen': 'S',
                '\\answered': 'R',
                '\\flagged': 'F',
                '\\deleted': 'T',
                '\\draft': 'D'}
     retval = []
-    imapflaglist = [x.lower() for x in flagstring[1:-1].split()]
+    imapflaglist = [x.lower() for x in imapflaglist]
     for imapflag in imapflaglist:
         if flagmap.has_key(imapflag):
             retval.append(flagmap[imapflag])
@@ -161,7 +162,7 @@
         if flagmap.has_key(mdflag):
             retval.append(flagmap[mdflag])
     retval.sort()
-    return '(' + ' '.join(retval) + ')'
+    return retval
 
 def listjoin(list):
     start = None