1
0
mirror of https://github.com/OfflineIMAP/offlineimap.git synced 2024-06-30 08:00:55 +02:00

Synchronize newly created folders both ways

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.
This commit is contained in:
Vincent Beffara 2007-09-02 01:43:15 +01:00
parent ac7c5a47ef
commit b925fd1296
3 changed files with 39 additions and 4 deletions

View File

@ -145,10 +145,19 @@ class AccountSynchronizationMixin:
localrepos = self.localrepos localrepos = self.localrepos
statusrepos = self.statusrepos statusrepos = self.statusrepos
self.ui.syncfolders(remoterepos, localrepos) 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 = [] folderthreads = []
for remotefolder in remoterepos.getfolders(): for remotefolder in remoterepos.getfolders():
if remotefolder.getvisiblename() in remoteignored:
continue
thread = InstanceLimitedThread(\ thread = InstanceLimitedThread(\
instancename = 'FOLDER_' + self.remoterepos.getname(), instancename = 'FOLDER_' + self.remoterepos.getname(),
target = syncfolder, 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(): if not statusfolder.isnewfolder():
# Delete local copies of remote messages. This way, # Delete local copies of remote messages. This way,
# if a message's flag is modified locally but it has been # if a message's flag is modified locally but it has been

View File

@ -17,6 +17,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from offlineimap import CustomConfig from offlineimap import CustomConfig
from offlineimap.ui import UIBase
import os.path import os.path
def LoadRepository(name, account, reqtype): def LoadRepository(name, account, reqtype):
@ -123,7 +124,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
def getfolder(self, foldername): def getfolder(self, foldername):
raise NotImplementedError raise NotImplementedError
def syncfoldersto(self, dest): def syncfoldersto(self, dest, status):
"""Syncs the folders in this repository to those in dest. """Syncs the folders in this repository to those in dest.
It does NOT sync the contents of those folders.""" It does NOT sync the contents of those folders."""
src = self src = self
@ -135,6 +136,8 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
srchash = {} srchash = {}
for folder in srcfolders: for folder in srcfolders:
if (folder.getvisiblename()[-2:] == src.getsep() + "."):
continue
srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \ srchash[folder.getvisiblename().replace(src.getsep(), dest.getsep())] = \
folder folder
desthash = {} desthash = {}
@ -145,9 +148,18 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
# Find new folders. # Find new folders.
# #
ignoredfolders = []
newfolders = []
for key in srchash.keys(): for key in srchash.keys():
if not key in desthash: 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. # Find deleted folders.
@ -157,6 +169,8 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
#for key in desthash.keys(): #for key in desthash.keys():
# if not key in srchash: # if not key in srchash:
# dest.deletefolder(key) # dest.deletefolder(key)
return (ignoredfolders,newfolders)
##### Keepalive ##### Keepalive

View File

@ -197,7 +197,7 @@ class UIBase:
def syncfolders(s, srcrepos, destrepos): def syncfolders(s, srcrepos, destrepos):
if s.verbose >= 0: 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))) (s.getnicename(srcrepos), s.getnicename(destrepos)))
############################## Folder syncing ############################## Folder syncing
@ -218,6 +218,10 @@ class UIBase:
(folder.getname(), folder.getrepository().getname(), (folder.getname(), folder.getrepository().getname(),
folder.getsaveduidvalidity(), folder.getuidvalidity())) 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): def loadmessagelist(s, repos, folder):
if s.verbose > 0: if s.verbose > 0:
s._msg("Loading message list for %s[%s]" % (s.getnicename(repos), s._msg("Loading message list for %s[%s]" % (s.getnicename(repos),