learn to not delete messages

This enables the "append" mode feature. Configuration option is sync_deletes in
both local and remote repositories. Marked EXPERIMENTAL and UNTESTED.

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2016-04-09 21:58:12 +02:00
parent 41e275e9a2
commit d5853b5d65
2 changed files with 44 additions and 16 deletions

View File

@ -428,6 +428,7 @@ remoterepository = RemoteExample
# #
#proxy = SOCKS5:IP:9999 #proxy = SOCKS5:IP:9999
[Repository LocalExample] [Repository LocalExample]
# Each repository requires a "type" declaration. The types supported for # Each repository requires a "type" declaration. The types supported for
@ -473,6 +474,14 @@ localfolders = ~/Test
#startdate = 2015-04-01 #startdate = 2015-04-01
# This option stands in the [Repository LocalExample] section.
#
# Remove messages on remote when deleted in local. Default is yes.
# This feature is EXPERIMENTAL and UNTESTED.
#
#sync_deletes = yes
# This option stands in the [Repository LocalExample] section. # This option stands in the [Repository LocalExample] section.
# #
# Some users may not want the atime (last access time) of folders to be # Some users may not want the atime (last access time) of folders to be
@ -1069,6 +1078,14 @@ remoteuser = username
#createfolders = True #createfolders = True
# This option stands in the [Repository RemoteExample] section.
#
# Remove messages in local when deleted on remote. Default is yes.
# This feature is EXPERIMENTAL and UNTESTED.
#
#sync_deletes = yes
# This option stands in the [Repository RemoteExample] section. # This option stands in the [Repository RemoteExample] section.
# #
# 'foldersort' determines how folders are sorted. # 'foldersort' determines how folders are sorted.

View File

@ -54,24 +54,29 @@ class BaseFolder(object):
if self.visiblename == self.getsep(): if self.visiblename == self.getsep():
self.visiblename = '' self.visiblename = ''
repoconfname = "Repository " + repository.name
self.config = repository.getconfig() self.config = repository.getconfig()
utime_from_header_global = self.config.getdefaultboolean( utime_from_header_global = self.config.getdefaultboolean(
"general", "utime_from_header", False) "general", "utime_from_header", False)
repo = "Repository " + repository.name self._utime_from_header = self.config.getdefaultboolean(
self._utime_from_header = self.config.getdefaultboolean(repo, repoconfname, "utime_from_header", utime_from_header_global)
"utime_from_header", utime_from_header_global)
# Do we need to use mail timestamp for filename prefix? # Do we need to use mail timestamp for filename prefix?
filename_use_mail_timestamp_global = self.config.getdefaultboolean( filename_use_mail_timestamp_global = self.config.getdefaultboolean(
"general", "filename_use_mail_timestamp", False) "general", "filename_use_mail_timestamp", False)
repo = "Repository " + repository.name self._filename_use_mail_timestamp = self.config.getdefaultboolean(
self._filename_use_mail_timestamp = self.config.getdefaultboolean(repo, repoconfname,
"filename_use_mail_timestamp", filename_use_mail_timestamp_global) "filename_use_mail_timestamp",
filename_use_mail_timestamp_global)
self._sync_deletes = self.config.getdefaultboolean(
repoconfname, "sync_deletes", True)
# Determine if we're running static or dynamic folder filtering # Determine if we're running static or dynamic folder filtering
# and check filtering status # and check filtering status
self._dynamic_folderfilter = self.config.getdefaultboolean( self._dynamic_folderfilter = self.config.getdefaultboolean(
repo, "dynamic_folderfilter", False) repoconfname, "dynamic_folderfilter", False)
self._sync_this = repository.should_sync_folder(self.ffilter_name) self._sync_this = repository.should_sync_folder(self.ffilter_name)
if self._dynamic_folderfilter: if self._dynamic_folderfilter:
self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]"% self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]"%
@ -81,9 +86,11 @@ class BaseFolder(object):
(self.ffilter_name, repository)) (self.ffilter_name, repository))
# Passes for syncmessagesto # Passes for syncmessagesto
self.syncmessagesto_passes = [('copying messages' , self.__syncmessagesto_copy), self.syncmessagesto_passes = [
('deleting messages' , self.__syncmessagesto_delete), ('copying messages' , self.__syncmessagesto_copy),
('syncing flags' , self.__syncmessagesto_flags)] ('deleting messages' , self.__syncmessagesto_delete),
('syncing flags' , self.__syncmessagesto_flags)
]
def getname(self): def getname(self):
"""Returns name""" """Returns name"""
@ -756,7 +763,7 @@ class BaseFolder(object):
for uid in uidlist: for uid in uidlist:
self.deletemessage(uid) self.deletemessage(uid)
def copymessageto(self, uid, dstfolder, statusfolder, register = 1): def copymessageto(self, uid, dstfolder, statusfolder, register=1):
"""Copies a message from self to dst if needed, updating the status """Copies a message from self to dst if needed, updating the status
Note that this function does not check against dryrun settings, Note that this function does not check against dryrun settings,
@ -873,8 +880,7 @@ class BaseFolder(object):
thread.start() thread.start()
threads.append(thread) threads.append(thread)
else: else:
self.copymessageto(uid, dstfolder, statusfolder, self.copymessageto(uid, dstfolder, statusfolder, register=0)
register = 0)
for thread in threads: for thread in threads:
thread.join() thread.join()
@ -886,15 +892,20 @@ class BaseFolder(object):
def __syncmessagesto_delete(self, dstfolder, statusfolder): def __syncmessagesto_delete(self, dstfolder, statusfolder):
"""Pass 2: Remove locally deleted messages on dst. """Pass 2: Remove locally deleted messages on dst.
Get all UIDS in statusfolder but not self. These are messages Get all UIDs in statusfolder but not self. These are messages
that were deleted in 'self'. Delete those from dstfolder and that were deleted in 'self'. Delete those from dstfolder and
statusfolder. statusfolder.
This function checks and protects us from action in dryrun mode. This function checks and protects us from action in dryrun mode.
""" """
# The list of messages to delete. If sync of deletions is disabled we
# still remove stale entries from statusfolder (neither in local nor
# remote).
deletelist = filter(
lambda uid: uid >= 0 and not self.uidexists(uid)
and (self._sync_deletes or not dstfolder.uidexists(uid)),
statusfolder.getmessageuidlist())
deletelist = filter(lambda uid: uid >= 0 and not
self.uidexists(uid), statusfolder.getmessageuidlist())
if len(deletelist): if len(deletelist):
# Delete in statusfolder first to play safe. In case of abort, we # Delete in statusfolder first to play safe. In case of abort, we
# won't lose message, we will just unneccessarily retransmit some. # won't lose message, we will just unneccessarily retransmit some.