]> code.delx.au - offlineimap/commitdiff
Synchronize newly created folders both ways
authorVincent Beffara <vbeffara@gmail.com>
Sun, 2 Sep 2007 00:43:15 +0000 (01:43 +0100)
committerVincent Beffara <vbeffara@gmail.com>
Sun, 2 Sep 2007 00:43:15 +0000 (01:43 +0100)
This involves several changes at different places:

- syncfoldersto() takes statusfolder as an argument, and returns the
  list of new folders and the list of folders that should be ingnored,
  typically those that were deleted. Warns the user about folders that
  are present only on one side and are not synced.

- syncfoldersto() is called both ways, and on folder creation
  forgetfolders() is used to rebuild the list and take the new creation
  into account. Probably not the most efficient, since it involves
  talking to the IMAP server again, but it will rarely be used anyway.

- Locally created folders are treated separately in the synchronization,
  namely the local messages are uploaded and then the normal sync still
  occurs. If the same folder is created on both sides and contains
  messages on both sides, a two-way sync occurs.

offlineimap/accounts.py
offlineimap/repository/Base.py
offlineimap/ui/UIBase.py

index 9f224d03d943cf10747aec8cba692fa56429883d..a78dc36496f3c47e8760ba5152c33ca72fa40305 100644 (file)
@@ -145,10 +145,19 @@ class AccountSynchronizationMixin:
             localrepos = self.localrepos
             statusrepos = self.statusrepos
             self.ui.syncfolders(remoterepos, localrepos)
-            remoterepos.syncfoldersto(localrepos)
+
+            (remoteignored,remotenew) = remoterepos.syncfoldersto(localrepos,statusrepos)
+            if len(remotenew):
+                localrepos.forgetfolders()
+
+            (localignored,localnew) = localrepos.syncfoldersto(remoterepos,statusrepos)
+            if len(localnew):
+                remoterepos.forgetfolders()
 
             folderthreads = []
             for remotefolder in remoterepos.getfolders():
+                if remotefolder.getvisiblename() in remoteignored:
+                    continue
                 thread = InstanceLimitedThread(\
                     instancename = 'FOLDER_' + self.remoterepos.getname(),
                     target = syncfolder,
@@ -233,6 +242,14 @@ def syncfolder(accountname, remoterepos, remotefolder, localrepos,
 
     #
 
+    if ((statusfolder.isnewfolder()) and
+        (len(localfolder.getmessagelist()) > 0) and
+        (len(remotefolder.getmessagelist()) == 0)):
+            # This is a locally created folder. Copy its contents to the
+            # remote folder, and to the StatusFolder.
+
+            localfolder.syncmessagesto(statusfolder, [remotefolder, statusfolder])
+
     if not statusfolder.isnewfolder():
         # Delete local copies of remote messages.  This way,
         # if a message's flag is modified locally but it has been
index a6c62cd5f70d71477480c2c5930d3e204402c99c..3abd290d233613331aabef2b5b0b910bc15f698c 100644 (file)
@@ -17,6 +17,7 @@
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
 from offlineimap import CustomConfig
+from offlineimap.ui import UIBase
 import os.path
 
 def LoadRepository(name, account, reqtype):
@@ -123,7 +124,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
     def getfolder(self, foldername):
         raise NotImplementedError
     
-    def syncfoldersto(self, dest):
+    def syncfoldersto(self, dest, status):
         """Syncs the folders in this repository to those in dest.
         It does NOT sync the contents of those folders."""
         src = self
@@ -135,6 +136,8 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
 
         srchash = {}
         for folder in srcfolders:
+            if (folder.getvisiblename()[-2:] == src.getsep() + "."):
+                continue
             srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \
                                                            folder
         desthash = {}
@@ -145,9 +148,18 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
         # Find new folders.
         #
         
+        ignoredfolders = []
+        newfolders = []
+
         for key in srchash.keys():
             if not key in desthash:
-                dest.makefolder(key)
+                srckey = key.replace(dest.getsep(),src.getsep())
+                if status.getfolder(key.replace(dest.getsep(),status.getsep())).isnewfolder():
+                    dest.makefolder(key)
+                    newfolders.append(srckey)
+                else:
+                    UIBase.getglobalui().ignorefolder (key, src, dest)
+                    ignoredfolders.append(srckey)
 
         #
         # Find deleted folders.
@@ -157,6 +169,8 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
         #for key in desthash.keys():
         #    if not key in srchash:
         #        dest.deletefolder(key)
+
+        return (ignoredfolders,newfolders)
         
     ##### Keepalive
 
index d0e92e6a07716933f6801144235284ba5b6c7a8c..f4f0b6e684df5c33096295ed1fa6a0e14b4beeff 100644 (file)
@@ -197,7 +197,7 @@ class UIBase:
 
     def syncfolders(s, srcrepos, destrepos):
         if s.verbose >= 0:
-            s._msg("Copying folder structure from %s to %s" % \
+            s._msg("Copying folder structure between %s and %s" % \
                    (s.getnicename(srcrepos), s.getnicename(destrepos)))
 
     ############################## Folder syncing
@@ -218,6 +218,10 @@ class UIBase:
                (folder.getname(), folder.getrepository().getname(),
                 folder.getsaveduidvalidity(), folder.getuidvalidity()))
 
+    def ignorefolder(s, foldername, here, there):
+        s.warn("Folder %s disappeared from %s; skipping it" % \
+               (foldername, there.getname()))
+
     def loadmessagelist(s, repos, folder):
         if s.verbose > 0:
             s._msg("Loading message list for %s[%s]" % (s.getnicename(repos),