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:
parent
ac7c5a47ef
commit
b925fd1296
@ -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
|
||||||
|
@ -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:
|
||||||
|
srckey = key.replace(dest.getsep(),src.getsep())
|
||||||
|
if status.getfolder(key.replace(dest.getsep(),status.getsep())).isnewfolder():
|
||||||
dest.makefolder(key)
|
dest.makefolder(key)
|
||||||
|
newfolders.append(srckey)
|
||||||
|
else:
|
||||||
|
UIBase.getglobalui().ignorefolder (key, src, dest)
|
||||||
|
ignoredfolders.append(srckey)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Find deleted folders.
|
# Find deleted folders.
|
||||||
@ -158,6 +170,8 @@ class BaseRepository(CustomConfig.ConfigHelperMixin):
|
|||||||
# if not key in srchash:
|
# if not key in srchash:
|
||||||
# dest.deletefolder(key)
|
# dest.deletefolder(key)
|
||||||
|
|
||||||
|
return (ignoredfolders,newfolders)
|
||||||
|
|
||||||
##### Keepalive
|
##### Keepalive
|
||||||
|
|
||||||
def startkeepalive(self):
|
def startkeepalive(self):
|
||||||
|
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user