From 266c88f7a1b041ba169e0c0cab767bf412c23672 Mon Sep 17 00:00:00 2001 From: "Edward Z. Yang" Date: Fri, 31 Aug 2012 16:51:33 -0400 Subject: [PATCH] Add no-delete-local to avoid remote->local delete synchronization. Signed-off-by: Edward Z. Yang --- offlineimap.conf | 12 ++++++++++++ offlineimap/accounts.py | 4 ++-- offlineimap/folder/Base.py | 29 ++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/offlineimap.conf b/offlineimap.conf index fccceaba2..51a196a15 100644 --- a/offlineimap.conf +++ b/offlineimap.conf @@ -252,6 +252,18 @@ remoterepository = RemoteExample #maildir-windows-compatible = no +# In many cases, your remote repository is intended to contain a subset +# of the messages your local repository, because the remote repository +# has less disk space, etc. However, if you just remove messages from +# the remote repository, OfflineIMAP will synchronize the changes back +# and delete your local copies. If you set this to 'yes', OfflineIMAP +# will never delete local files even if they disappear on the remote +# side. Local to remote deletes are still synchronized. See also +# maxage. +# +# no-delete-local = no + + [Repository LocalExample] # Each repository requires a "type" declaration. The types supported for diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py index 8b39c7e20..4b4bd4468 100644 --- a/offlineimap/accounts.py +++ b/offlineimap/accounts.py @@ -435,7 +435,7 @@ def syncfolder(account, remotefolder, quick): # Synchronize remote changes. if not localrepos.getconfboolean('readonly', False): ui.syncingmessages(remoterepos, remotefolder, localrepos, localfolder) - remotefolder.syncmessagesto(localfolder, statusfolder) + remotefolder.syncmessagesto(localfolder, statusfolder, False) else: ui.debug('imap', "Not syncing to read-only repository '%s'" \ % localrepos.getname()) @@ -443,7 +443,7 @@ def syncfolder(account, remotefolder, quick): # Synchronize local changes if not remoterepos.getconfboolean('readonly', False): ui.syncingmessages(localrepos, localfolder, remoterepos, remotefolder) - localfolder.syncmessagesto(remotefolder, statusfolder) + localfolder.syncmessagesto(remotefolder, statusfolder, True) else: ui.debug('', "Not syncing to read-only repository '%s'" \ % remoterepos.getname()) diff --git a/offlineimap/folder/Base.py b/offlineimap/folder/Base.py index 6f6f3645c..d5c542574 100644 --- a/offlineimap/folder/Base.py +++ b/offlineimap/folder/Base.py @@ -294,7 +294,7 @@ def deletemessages(self, uidlist): for uid in uidlist: self.deletemessage(uid) - def copymessageto(self, uid, dstfolder, statusfolder, register = 1): + def copymessageto(self, uid, dstfolder, statusfolder, always_sync_deletes, register = 1): """Copies a message from self to dst if needed, updating the status Note that this function does not check against dryrun settings, @@ -366,7 +366,7 @@ def copymessageto(self, uid, dstfolder, statusfolder, register = 1): exc_info()[2])) raise #raise on unknown errors, so we can fix those - def syncmessagesto_copy(self, dstfolder, statusfolder): + def syncmessagesto_copy(self, dstfolder, statusfolder, always_sync_deletes): """Pass1: Copy locally existing messages not on the other side This will copy messages to dstfolder that exist locally but are @@ -401,16 +401,16 @@ def syncmessagesto_copy(self, dstfolder, statusfolder): self.getcopyinstancelimit(), target = self.copymessageto, name = "Copy message from %s:%s" % (self.repository, self), - args = (uid, dstfolder, statusfolder)) + args = (uid, dstfolder, statusfolder, always_sync_deletes)) thread.start() threads.append(thread) else: - self.copymessageto(uid, dstfolder, statusfolder, + self.copymessageto(uid, dstfolder, statusfolder, always_sync_deletes, register = 0) for thread in threads: thread.join() - def syncmessagesto_delete(self, dstfolder, statusfolder): + def syncmessagesto_delete(self, dstfolder, statusfolder, always_sync_deletes): """Pass 2: Remove locally deleted messages on dst Get all UIDS in statusfolder but not self. These are messages @@ -419,8 +419,19 @@ def syncmessagesto_delete(self, dstfolder, statusfolder): This function checks and protects us from action in ryrun mode. """ + # This is functionally equivalent to having an empty deletelist + # in the case of not always_sync_deletes and no-delete-local turned on; the + # only difference is that in this regime we eagerly clear out + # "stale" entries from statusfolder, i.e. ones that are not + # present in the local or destination folder, whereas if we were + # to skip this the entries hang around until a not always_sync_deletes + # run. + sync_deletes = always_sync_deletes or not self.config.getdefaultboolean("Account " + self.accountname, "no-delete-local", False) + print sync_deletes + import sys + sys.exit() deletelist = filter(lambda uid: uid>=0 \ - and not self.uidexists(uid), + and not self.uidexists(uid) and (sync_deletes or not dstfolder.uidexists(uid)), statusfolder.getmessageuidlist()) if len(deletelist): self.ui.deletingmessages(deletelist, [dstfolder]) @@ -431,7 +442,7 @@ def syncmessagesto_delete(self, dstfolder, statusfolder): for folder in [statusfolder, dstfolder]: folder.deletemessages(deletelist) - def syncmessagesto_flags(self, dstfolder, statusfolder): + def syncmessagesto_flags(self, dstfolder, statusfolder, always_sync_deletes): """Pass 3: Flag synchronization Compare flag mismatches in self with those in statusfolder. If @@ -485,7 +496,7 @@ def syncmessagesto_flags(self, dstfolder, statusfolder): dstfolder.deletemessagesflags(uids, set(flag)) statusfolder.deletemessagesflags(uids, set(flag)) - def syncmessagesto(self, dstfolder, statusfolder): + def syncmessagesto(self, dstfolder, statusfolder, always_sync_deletes): """Syncs messages in this folder to the destination dstfolder. This is the high level entry for syncing messages in one direction. @@ -523,7 +534,7 @@ def syncmessagesto(self, dstfolder, statusfolder): if offlineimap.accounts.Account.abort_NOW_signal.is_set(): break try: - action(dstfolder, statusfolder) + action(dstfolder, statusfolder, always_sync_deletes) except (KeyboardInterrupt): raise except OfflineImapError as e: