Locally created mailboxes not synchronized to IMAP

Vladimir Marek Vladimir.Marek at Oracle.COM
Mon Aug 1 09:44:05 BST 2011


Hi,

I found that if I create local mailbox, it is not replicated on IMAP.
Other direction works fine. I was playing with it yesterday afternoon
and I finally made it working. But it's not completely trivial fix, so
as usual I might have overlooked something. I am attaching the diff I
have, just to have some chance for comments. It's doing several things

 - if there's directory on one side, and it's not on other, I first
   consult local status folder to see if we knew the directory before.
   If it's completely new, let's sync it. If we knew the directory, it
   means it was erased on one side and I just print warning

 - reformatted tabs -> spaces (mixed tabs spaces break my autoindenting
   in vim, and I'm too lazy to make it more robust :) )

 - syncfoldersto now accepts just one copyfolder, not list of them. This
   is something I haven't understood why it is there ...

 - I had to implement 'getfolders' methond in repository/LocalStatus.py,
   so that I can check if we knew given mailbox in the past. It's not
   very robust at the moment and I haven't tried SQL local status.

 - repository/Maildir.py had a strange check 
-            if self.getsep() == '/' and dirname != '.':
+            if dirname != '.':
   that was breaking nested mailboxes for me. By removing it I probably
   broke something else, but it works for me now. I have to investigate.
Strange is that self.getsep() is by default "." so I wonder if the
recursion worked in the past?


I'll appreciate any comments. I'm quite sure you already love me
spamming you with strange diffs, but there's not may other things I
would like to improve, as it is nearly perfect anyway. So I'll stop
bothering you soon :)

Thank you
-- 
	Vlad
-------------- next part --------------
diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py
index a989441..be139da 100644
--- a/offlineimap/accounts.py
+++ b/offlineimap/accounts.py
@@ -232,7 +232,7 @@ class SyncableAccount(Account):
             # replicate the folderstructure from REMOTE to LOCAL
             if not localrepos.getconf('readonly', False):
                 self.ui.syncfolders(remoterepos, localrepos)
-                remoterepos.syncfoldersto(localrepos, [statusrepos])
+                remoterepos.syncfoldersto(localrepos, statusrepos)
 
             # iterate through all folders on the remote repo and sync
             for remotefolder in remoterepos.getfolders():
diff --git a/offlineimap/repository/Base.py b/offlineimap/repository/Base.py
index 34f2f4a..a5dc2e5 100644
--- a/offlineimap/repository/Base.py
+++ b/offlineimap/repository/Base.py
@@ -18,6 +18,7 @@
 
 import os.path
 import traceback
+import pprint
 from offlineimap import CustomConfig
 from offlineimap.ui import getglobalui
 
@@ -42,14 +43,14 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
     # The 'restoreatime' config parameter only applies to local Maildir
     # mailboxes.
     def restore_atime(self):
-	if self.config.get('Repository ' + self.name, 'type').strip() != \
-		'Maildir':
-	    return
+        if self.config.get('Repository ' + self.name, 'type').strip() != \
+            'Maildir':
+            return
 
-	if not self.config.has_option('Repository ' + self.name, 'restoreatime') or not self.config.getboolean('Repository ' + self.name, 'restoreatime'):
-	    return
+        if not self.config.has_option('Repository ' + self.name, 'restoreatime') or not self.config.getboolean('Repository ' + self.name, 'restoreatime'):
+            return
 
-	return self.restore_folder_atimes()
+        return self.restore_folder_atimes()
 
     def connect(self):
         """Establish a connection to the remote, if necessary.  This exists
@@ -114,42 +115,65 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
     def getfolder(self, foldername):
         raise NotImplementedError
     
-    def syncfoldersto(self, dest, copyfolders):
+    def syncfoldersto(self, dest, copyfolder):
         """Syncs the folders in this repository to those in dest.
         It does NOT sync the contents of those folders.
 
-        For every time dest.makefolder() is called, also call makefolder()
-        on each folder in copyfolders."""
+        For every time makefolder() is called, also call makefolder() in
+        copyfolder."""
         src = self
         srcfolders = src.getfolders()
         destfolders = dest.getfolders()
+        copyfoldedrs = copyfolder.getfolders()
+        copyfolders = copyfolder.getfolders()
 
         # Create hashes with the names, but convert the source folders
         # to the dest folder's sep.
 
         srchash = {}
+#        pprint.pprint(srcfolders)
         for folder in srcfolders:
-            srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \
-                                                           folder
+            srchash[folder.getvisiblename().replace(src.getsep(), "/")] = folder
         desthash = {}
+#        pprint.pprint(destfolders)
         for folder in destfolders:
-            desthash[folder.getvisiblename()] = folder
-
+            desthash[folder.getvisiblename().replace(dest.getsep(), "/")] = folder
+        copyhash = {}
+#        pprint.pprint(copyfolders)
+        for folder in copyfolders:
+            copyhash[folder.getvisiblename().replace(copyfolder.getsep(), "/")] = folder
+
+        def syncfoldersto_internal(where, key):
+            self.ui._msg("Creating folder %s" % key)
+            try:
+                where.makefolder(key.replace("/", where.getsep()))
+                copyfolder.makefolder(key.replace("/", copyfolder.getsep()))
+            except (KeyboardInterrupt):
+                raise
+            except:
+                self.ui.warn("ERROR Attempting to create folder " \
+                    + key + ":"  +traceback.format_exc())
+
+#        print "srchash"
+#        print srchash
+#        print "desthash"
+#        print desthash
+#        print "copyhash"
+#        print copyhash
         #
         # Find new folders.
         #
-        
-        for key in srchash.keys():
-            if not key in desthash:
-                try:
-                    dest.makefolder(key)
-                    for copyfolder in copyfolders:
-                        copyfolder.makefolder(key.replace(dest.getsep(), copyfolder.getsep()))
-                except (KeyboardInterrupt):
-                    raise
-                except:
-                    self.ui.warn("ERROR Attempting to create folder " \
-                        + key + ":"  +traceback.format_exc())
+        for key in set(srchash.keys()) - set(desthash.keys()):
+            if key in copyhash:
+                self.ui._msg("Should delete %s" % key)
+            else:
+                syncfoldersto_internal(dest, key)
+
+        for key in set(desthash.keys()) - set(srchash.keys()):
+            if key in copyhash:
+                self.ui._msg("Should delete %s" % key)
+            else:
+                syncfoldersto_internal(self, key)
 
         #
         # Find deleted folders.
diff --git a/offlineimap/repository/LocalStatus.py b/offlineimap/repository/LocalStatus.py
index 022be21..d9cac9e 100644
--- a/offlineimap/repository/LocalStatus.py
+++ b/offlineimap/repository/LocalStatus.py
@@ -83,11 +83,11 @@ class LocalStatusRepository(BaseRepository):
         """Returns a list of ALL folders on this server.
 
         This is currently nowhere used in the code."""
-        if self._folders != None:
-            return self._folders
-
-        for folder in os.listdir(self.directory):
-            self._folders = retval.append(self.getfolder(folder))
+        #  def __init__(self, root, name, repository, accountname, config):
+        if self._folders == None:
+            self._folders = []
+            for folder in os.listdir(self.directory):
+                self._folders.append(self.LocalStatusFolderClass(self.directory, folder, self, self.account, self.config))
         return self._folders
 
     def forgetfolders(self):
diff --git a/offlineimap/repository/Maildir.py b/offlineimap/repository/Maildir.py
index 069748a..c4b527d 100644
--- a/offlineimap/repository/Maildir.py
+++ b/offlineimap/repository/Maildir.py
@@ -132,8 +132,10 @@ class MaildirRepository(BaseRepository):
             toppath = root
         self.debug("  toppath = %s" % toppath)
 
+	#print "!!!!!!!!!!!!!!!!"
+	#print os.listdir(toppath)
         # Iterate over directories in top & top itself.
-        for dirname in os.listdir(toppath) + ['.']:
+        for dirname in os.listdir(toppath):
             self.debug("  *** top of loop")
             self.debug("  dirname = %s" % dirname)
             if dirname in ['cur', 'new', 'tmp']:
@@ -142,6 +144,7 @@ class MaildirRepository(BaseRepository):
                 continue
             fullname = os.path.join(toppath, dirname)
             self.debug("  fullname = %s" % fullname)
+            #print "  fullname = %s" % fullname
             if not os.path.isdir(fullname):
                 self.debug("  skipping this entry (not a directory)")
                 # Not a directory -- not a folder.
@@ -154,6 +157,7 @@ class MaildirRepository(BaseRepository):
                 os.path.isdir(os.path.join(fullname, 'tmp'))):
                 # This directory has maildir stuff -- process
                 self.debug("  This is maildir folder '%s'." % foldername)
+                #print "  This is maildir folder '%s'." % foldername
 
 		if self.config.has_option('Repository %s' % self,
                                           'restoreatime') and \
@@ -166,8 +170,10 @@ class MaildirRepository(BaseRepository):
                                                            self,
                                                            self.accountname,
                                                            self.config))
-            if self.getsep() == '/' and dirname != '.':
+	    #print "getsep=%s dirname=%s" % (self.getsep(), dirname)
+            if dirname != '.':
                 # Recursively check sub-directories for folders too.
+		#print "recursing extension=%s root=%s foldername=%s" % (extension, root, foldername)
                 retval.extend(self._getfolders_scandir(root, foldername))
         self.debug("_GETFOLDERS_SCANDIR RETURNING %s" % \
                    repr([x.getname() for x in retval]))


More information about the OfflineIMAP-project mailing list