Merge branch 'next'
Conflicts: Changelog.rst
This commit is contained in:
commit
b569ef551f
@ -11,7 +11,23 @@ ChangeLog
|
||||
on releases. And because I'm lazy, it will also be used as a draft for the
|
||||
releases announces.
|
||||
|
||||
=======
|
||||
OfflineIMAP v6.4.4 (2012-01-06)
|
||||
===============================
|
||||
|
||||
This is a bugfix release, fixing regressions occurring in or since 6.4.0.
|
||||
|
||||
* Fix the missing folder error that occured when a new remote folder was
|
||||
detected (IMAP<->Maildir)
|
||||
|
||||
* Possibly fixed bug that prevented us from ever re-reading Maildir
|
||||
folders, so flag changes and deletions were not detected when running
|
||||
in a refresh loop. This is a regression that was introduced in about
|
||||
6.4.0.
|
||||
|
||||
* Never mangle maildir file names when using nonstandard Maildir flags
|
||||
(such as 'a'), note that they will still be deleted as they are not
|
||||
supported in the sync to an IMAP server.
|
||||
|
||||
OfflineIMAP v6.4.3 (2012-01-04)
|
||||
===============================
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
__all__ = ['OfflineImap']
|
||||
|
||||
__productname__ = 'OfflineIMAP'
|
||||
__version__ = "6.4.3"
|
||||
__version__ = "6.4.4"
|
||||
__copyright__ = "Copyright 2002-2012 John Goerzen & contributors"
|
||||
__author__ = "John Goerzen"
|
||||
__author_email__= "john@complete.org"
|
||||
|
@ -289,10 +289,10 @@ class SyncableAccount(Account):
|
||||
localrepos.getfolders()
|
||||
statusrepos.getfolders()
|
||||
|
||||
remoterepos.sync_folder_structure(localrepos, statusrepos)
|
||||
# replicate the folderstructure between REMOTE to LOCAL
|
||||
if not localrepos.getconfboolean('readonly', False):
|
||||
self.ui.syncfolders(remoterepos, localrepos)
|
||||
remoterepos.syncfoldersto(localrepos, statusrepos)
|
||||
|
||||
# iterate through all folders on the remote repo and sync
|
||||
for remotefolder in remoterepos.getfolders():
|
||||
|
@ -64,13 +64,13 @@ class MaildirFolder(BaseFolder):
|
||||
self.root = root
|
||||
self.sep = sep
|
||||
self.messagelist = None
|
||||
|
||||
# check if we should use a different infosep to support Win file systems
|
||||
self.wincompatible = self.config.getdefaultboolean(
|
||||
"Account "+self.accountname, "maildir-windows-compatible", False)
|
||||
|
||||
self.infosep = '!' if self.wincompatible else ':'
|
||||
"""infosep is the separator between maildir name and flag appendix"""
|
||||
self.flagmatchre = re.compile(self.infosep + '.*2,([A-Z]+)')
|
||||
self.flagmatchre = re.compile('(%s2,)(\w*)' % self.infosep)
|
||||
#self.ui is set in BaseFolder.init()
|
||||
# Cache the full folder path, as we use getfullname() very often
|
||||
self._fullname = os.path.join(self.getroot(), self.getname())
|
||||
@ -162,7 +162,7 @@ class MaildirFolder(BaseFolder):
|
||||
#identify flags in the path name
|
||||
flagmatch = self.flagmatchre.search(messagename)
|
||||
if flagmatch:
|
||||
flags = set(flagmatch.group(1))
|
||||
flags = set(flagmatch.group(2))
|
||||
else:
|
||||
flags = set()
|
||||
# 'filename' is 'dirannex/filename', e.g. cur/123,U=1,FMD5=1:2,S
|
||||
@ -185,7 +185,7 @@ class MaildirFolder(BaseFolder):
|
||||
def cachemessagelist(self):
|
||||
if self.messagelist is None:
|
||||
self.messagelist = self._scanfolder()
|
||||
|
||||
|
||||
def getmessagelist(self):
|
||||
return self.messagelist
|
||||
|
||||
@ -259,7 +259,7 @@ class MaildirFolder(BaseFolder):
|
||||
self.savemessageflags(uid, flags)
|
||||
self.ui.debug('maildir', 'savemessage: returning uid %d' % uid)
|
||||
return uid
|
||||
|
||||
|
||||
def getmessageflags(self, uid):
|
||||
return self.messagelist[uid]['flags']
|
||||
|
||||
@ -274,15 +274,14 @@ class MaildirFolder(BaseFolder):
|
||||
else:
|
||||
dir_prefix = 'new'
|
||||
|
||||
infostr = self.infosep
|
||||
infomatch = re.search('(' + self.infosep + '.*)$', newname)
|
||||
if infomatch: # If the info string is present..
|
||||
infostr = infomatch.group(1)
|
||||
newname = newname.split(self.infosep)[0] # Strip off the info string.
|
||||
infostr = re.sub('2,[A-Z]*', '', infostr)
|
||||
infostr += '2,' + ''.join(sorted(flags))
|
||||
# Strip off existing infostring (preserving small letter flags, that
|
||||
# dovecot uses)
|
||||
infomatch = self.flagmatchre.search(newname)
|
||||
if infomatch:
|
||||
newname = newname[:-len(infomatch.group())] #strip off
|
||||
infostr = '%s2,%s' % (self.infosep, ''.join(sorted(flags)))
|
||||
newname += infostr
|
||||
|
||||
|
||||
newfilename = os.path.join(dir_prefix, newname)
|
||||
if (newfilename != oldfilename):
|
||||
try:
|
||||
@ -292,7 +291,7 @@ class MaildirFolder(BaseFolder):
|
||||
raise OfflineImapError("Can't rename file '%s' to '%s': %s" % (
|
||||
oldfilename, newfilename, e[1]),
|
||||
OfflineImapError.ERROR.FOLDER)
|
||||
|
||||
|
||||
self.messagelist[uid]['flags'] = flags
|
||||
self.messagelist[uid]['filename'] = newfilename
|
||||
|
||||
|
@ -132,8 +132,8 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
|
||||
|
||||
def getfolder(self, foldername):
|
||||
raise NotImplementedError
|
||||
|
||||
def syncfoldersto(self, dst_repo, status_repo):
|
||||
|
||||
def sync_folder_structure(self, dst_repo, status_repo):
|
||||
"""Syncs the folders in this repository to those in dest.
|
||||
|
||||
It does NOT sync the contents of those folders. nametrans rules
|
||||
@ -158,6 +158,9 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
|
||||
|
||||
# Find new folders on src_repo.
|
||||
for src_name, src_folder in src_hash.iteritems():
|
||||
# Don't create on dst_repo, if it is readonly
|
||||
if dst_repo.getconfboolean('readonly', False):
|
||||
break
|
||||
if src_folder.sync_this and not src_name in dst_hash:
|
||||
try:
|
||||
dst_repo.makefolder(src_name)
|
||||
@ -171,6 +174,10 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
|
||||
status_repo.getsep()))
|
||||
# Find new folders on dst_repo.
|
||||
for dst_name, dst_folder in dst_hash.iteritems():
|
||||
if self.getconfboolean('readonly', False):
|
||||
# Don't create missing folder on readonly repo.
|
||||
break
|
||||
|
||||
if dst_folder.sync_this and not dst_name in src_hash:
|
||||
# nametrans sanity check!
|
||||
# Does nametrans back&forth lead to identical names?
|
||||
@ -202,7 +209,6 @@ class BaseRepository(object, CustomConfig.ConfigHelperMixin):
|
||||
src_repo, newdst_name),
|
||||
OfflineImapError.ERROR.REPO)
|
||||
# end sanity check, actually create the folder
|
||||
|
||||
try:
|
||||
src_repo.makefolder(newsrc_name)
|
||||
src_haschanged = True # Need to refresh list
|
||||
|
@ -190,4 +190,8 @@ class MaildirRepository(BaseRepository):
|
||||
if self.folders == None:
|
||||
self.folders = self._getfolders_scandir(self.root)
|
||||
return self.folders
|
||||
|
||||
|
||||
def forgetfolders(self):
|
||||
"""Forgets the cached list of folders, if any. Useful to run
|
||||
after a sync run."""
|
||||
self.folders = None
|
||||
|
@ -285,7 +285,7 @@ class UIBase(object):
|
||||
"""Output that we finished syncing an account (in which time)"""
|
||||
sec = time.time() - self.acct_startimes[account]
|
||||
del self.acct_startimes[account]
|
||||
self._msg("*** Finished account '%s' in %d:%02d" %
|
||||
self.logger.info("*** Finished account '%s' in %d:%02d" %
|
||||
(account, sec // 60, sec % 60))
|
||||
|
||||
def syncfolders(self, src_repo, dst_repo):
|
||||
|
Loading…
Reference in New Issue
Block a user