Merge branch 'next' of github.com:OfflineIMAP/offlineimap into next
This commit is contained in:
commit
fd79baade5
@ -5,13 +5,67 @@ ChangeLog
|
|||||||
:website: http://offlineimap.org
|
:website: http://offlineimap.org
|
||||||
|
|
||||||
|
|
||||||
|
OfflineIMAP v6.5.7-rc3 (2015- - )
|
||||||
|
===================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
OfflineIMAP v6.5.7-rc2 (2015-01-18)
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
This release candidate should be minor for most users.
|
||||||
|
|
||||||
|
The best points are about SSL not falling back on other authentication methods
|
||||||
|
when failing, better RAM footprint and reduced I/O access.
|
||||||
|
|
||||||
|
Documentation had our attention, too.
|
||||||
|
|
||||||
|
There's some code cleanups and code refactoring, as usual.
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
* Do not keep reloading pyhtonfile, make it stateful.
|
||||||
|
* HACKING: how to create tags.
|
||||||
|
* MANUAL: add minor sample on how to retrieve a password with a helper python file.
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
-----
|
||||||
|
|
||||||
|
* Make OS-default CA certificate file to be requested explicitely.
|
||||||
|
* SSL: do not fallback on other authentication mode if it fails.
|
||||||
|
* Fix regression introduced while style patching.
|
||||||
|
* API documentation: properly auto-document main class, fixes.
|
||||||
|
* ui: Machine: remove offending param for a _printData() call.
|
||||||
|
* Drop caches after having processed folders.
|
||||||
|
|
||||||
|
Changes
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Fix unexpected garbage code.
|
||||||
|
* Properly re-raise exception to save original tracebacks.
|
||||||
|
* Refactoring: avoid redefining various Python keywords.
|
||||||
|
* Code: improvements of comments and more style consistency.
|
||||||
|
* Configuration file: better design and other small improvements.
|
||||||
|
* nametrans documentation: fix minor error.
|
||||||
|
* Unused import removal.
|
||||||
|
* Add a note about the incorrect rendering of the docstring with Sphinx.
|
||||||
|
* Errors handling: log the messages with level ERROR.
|
||||||
|
* MAINTAINERS: add mailing list maintainers.
|
||||||
|
* Fixed copyright statement.
|
||||||
|
* COPYING: fix unexpected characters.
|
||||||
|
|
||||||
|
|
||||||
OfflineIMAP v6.5.7-rc1 (2015-01-07)
|
OfflineIMAP v6.5.7-rc1 (2015-01-07)
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
I think it's time for a new release candidate. Our release cycle are long
|
I think it's time for a new release candidate. Our release cycles are long
|
||||||
enough and users are asked to use the current TIP of the next branch to test
|
enough and users are asked to use the current TIP of the next branch to test
|
||||||
our recent patches.
|
our recent patches.
|
||||||
|
|
||||||
@ -114,7 +168,7 @@ OfflineIMAP v6.5.6 (2014-05-14)
|
|||||||
to Tomasz Żok)
|
to Tomasz Żok)
|
||||||
|
|
||||||
|
|
||||||
OfflineIMAP v6.5.6-RC1 (2014-05-14)
|
OfflineIMAP v6.5.6-rc1 (2014-05-14)
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
* Add knob to invoke folderfilter dynamically on each sync (GitHub#73)
|
* Add knob to invoke folderfilter dynamically on each sync (GitHub#73)
|
||||||
|
@ -2,7 +2,7 @@ __all__ = ['OfflineImap']
|
|||||||
|
|
||||||
__productname__ = 'OfflineIMAP'
|
__productname__ = 'OfflineIMAP'
|
||||||
__version__ = "6.5.7"
|
__version__ = "6.5.7"
|
||||||
__revision__ = "-rc1"
|
__revision__ = "-rc2"
|
||||||
__bigversion__ = __version__ + __revision__
|
__bigversion__ = __version__ + __revision__
|
||||||
__copyright__ = "Copyright 2002-2015 John Goerzen & contributors"
|
__copyright__ = "Copyright 2002-2015 John Goerzen & contributors"
|
||||||
__author__ = "John Goerzen"
|
__author__ = "John Goerzen"
|
||||||
|
@ -45,10 +45,6 @@ class LocalStatusFolder(BaseFolder):
|
|||||||
def isnewfolder(self):
|
def isnewfolder(self):
|
||||||
return not os.path.exists(self.filename)
|
return not os.path.exists(self.filename)
|
||||||
|
|
||||||
# Interface from BaseFolder
|
|
||||||
def getname(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def getfullname(self):
|
def getfullname(self):
|
||||||
return self.filename
|
return self.filename
|
||||||
@ -117,33 +113,33 @@ class LocalStatusFolder(BaseFolder):
|
|||||||
self.messagelist = {}
|
self.messagelist = {}
|
||||||
return
|
return
|
||||||
|
|
||||||
# loop as many times as version, and update format
|
# Loop as many times as version, and update format.
|
||||||
for i in range(1, self.cur_version+1):
|
for i in range(1, self.cur_version + 1):
|
||||||
file = open(self.filename, "rt")
|
|
||||||
self.messagelist = {}
|
self.messagelist = {}
|
||||||
line = file.readline().strip()
|
cache = open(self.filename, "rt")
|
||||||
|
line = cache.readline().strip()
|
||||||
|
|
||||||
# convert from format v1
|
# Format is up to date. break.
|
||||||
if line == (self.magicline % 1):
|
if line == (self.magicline % self.cur_version):
|
||||||
self.ui._msg('Upgrading LocalStatus cache from version 1 to version 2 for %s:%s' %\
|
break
|
||||||
(self.repository, self))
|
|
||||||
self.readstatus_v1(file)
|
# Convert from format v1.
|
||||||
file.close()
|
elif line == (self.magicline % 1):
|
||||||
|
self.ui._msg('Upgrading LocalStatus cache from version 1'
|
||||||
|
'to version 2 for %s:%s'% (self.repository, self))
|
||||||
|
self.readstatus_v1(cache)
|
||||||
|
cache.close()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
# NOTE: Add other format transitions here in the future.
|
# NOTE: Add other format transitions here in the future.
|
||||||
# elif line == (self.magicline % 2):
|
# elif line == (self.magicline % 2):
|
||||||
# self.ui._msg('Upgrading LocalStatus cache from version 2 to version 3 for %s:%s' %\
|
# self.ui._msg(u'Upgrading LocalStatus cache from version 2'
|
||||||
# (self.repository, self))
|
# 'to version 3 for %s:%s'% (self.repository, self))
|
||||||
# self.readstatus_v2(file)
|
# self.readstatus_v2(cache)
|
||||||
# file.close()
|
# cache.close()
|
||||||
# file.save()
|
# cache.save()
|
||||||
|
|
||||||
# format is up to date. break
|
# Something is wrong.
|
||||||
elif line == (self.magicline % self.cur_version):
|
|
||||||
break
|
|
||||||
|
|
||||||
# something is wrong
|
|
||||||
else:
|
else:
|
||||||
errstr = "Unrecognized cache magicline in '%s'" % self.filename
|
errstr = "Unrecognized cache magicline in '%s'" % self.filename
|
||||||
self.ui.warn(errstr)
|
self.ui.warn(errstr)
|
||||||
@ -152,14 +148,14 @@ class LocalStatusFolder(BaseFolder):
|
|||||||
if not line:
|
if not line:
|
||||||
# The status file is empty - should not have happened,
|
# The status file is empty - should not have happened,
|
||||||
# but somehow did.
|
# but somehow did.
|
||||||
errstr = "Cache file '%s' is empty. Closing..." % self.filename
|
errstr = "Cache file '%s' is empty."% self.filename
|
||||||
self.ui.warn(errstr)
|
self.ui.warn(errstr)
|
||||||
file.close()
|
cache.close()
|
||||||
return
|
return
|
||||||
|
|
||||||
assert(line == (self.magicline % self.cur_version))
|
assert(line == (self.magicline % self.cur_version))
|
||||||
self.readstatus(file)
|
self.readstatus(cache)
|
||||||
file.close()
|
cache.close()
|
||||||
|
|
||||||
def dropmessagelistcache(self):
|
def dropmessagelistcache(self):
|
||||||
self.messagelist = None
|
self.messagelist = None
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
from sys import exc_info
|
from sys import exc_info
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from .Base import BaseFolder
|
|
||||||
try:
|
try:
|
||||||
import sqlite3 as sqlite
|
import sqlite3 as sqlite
|
||||||
except:
|
except:
|
||||||
pass #fail only if needed later on, not on import
|
pass #fail only if needed later on, not on import
|
||||||
|
|
||||||
|
from .Base import BaseFolder
|
||||||
|
|
||||||
|
|
||||||
class LocalStatusSQLiteFolder(BaseFolder):
|
class LocalStatusSQLiteFolder(BaseFolder):
|
||||||
"""LocalStatus backend implemented with an SQLite database
|
"""LocalStatus backend implemented with an SQLite database
|
||||||
@ -56,7 +56,8 @@ class LocalStatusSQLiteFolder(BaseFolder):
|
|||||||
if not os.path.exists(dirname):
|
if not os.path.exists(dirname):
|
||||||
os.makedirs(dirname)
|
os.makedirs(dirname)
|
||||||
if not os.path.isdir(dirname):
|
if not os.path.isdir(dirname):
|
||||||
raise UserWarning("SQLite database path '%s' is not a directory." % dirname)
|
raise UserWarning("SQLite database path '%s' is not a directory."%
|
||||||
|
dirname)
|
||||||
|
|
||||||
# dblock protects against concurrent writes in same connection
|
# dblock protects against concurrent writes in same connection
|
||||||
self._dblock = Lock()
|
self._dblock = Lock()
|
||||||
@ -67,14 +68,15 @@ class LocalStatusSQLiteFolder(BaseFolder):
|
|||||||
except NameError:
|
except NameError:
|
||||||
# sqlite import had failed
|
# sqlite import had failed
|
||||||
raise UserWarning('SQLite backend chosen, but no sqlite python '
|
raise UserWarning('SQLite backend chosen, but no sqlite python '
|
||||||
'bindings available. Please install.'), None, exc_info()[2]
|
'bindings available. Please install.'), None, exc_info()[2]
|
||||||
|
|
||||||
#Make sure sqlite is in multithreading SERIALIZE mode
|
#Make sure sqlite is in multithreading SERIALIZE mode
|
||||||
assert sqlite.threadsafety == 1, 'Your sqlite is not multithreading safe.'
|
assert sqlite.threadsafety == 1, 'Your sqlite is not multithreading safe.'
|
||||||
|
|
||||||
#Test if db version is current enough and if db is readable.
|
#Test if db version is current enough and if db is readable.
|
||||||
try:
|
try:
|
||||||
cursor = self.connection.execute("SELECT value from metadata WHERE key='db_version'")
|
cursor = self.connection.execute(
|
||||||
|
"SELECT value from metadata WHERE key='db_version'")
|
||||||
except sqlite.DatabaseError:
|
except sqlite.DatabaseError:
|
||||||
#db file missing or corrupt, recreate it.
|
#db file missing or corrupt, recreate it.
|
||||||
self.__create_db()
|
self.__create_db()
|
||||||
@ -88,9 +90,6 @@ class LocalStatusSQLiteFolder(BaseFolder):
|
|||||||
def storesmessages(self):
|
def storesmessages(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getname(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def getfullname(self):
|
def getfullname(self):
|
||||||
return self.filename
|
return self.filename
|
||||||
|
|
||||||
|
@ -44,13 +44,13 @@ class Repository(object):
|
|||||||
name = account.getconf('remoterepository')
|
name = account.getconf('remoterepository')
|
||||||
# We don't support Maildirs on the remote side.
|
# We don't support Maildirs on the remote side.
|
||||||
typemap = {'IMAP': IMAPRepository,
|
typemap = {'IMAP': IMAPRepository,
|
||||||
'Gmail': GmailRepository}
|
'Gmail': GmailRepository}
|
||||||
|
|
||||||
elif reqtype == 'local':
|
elif reqtype == 'local':
|
||||||
name = account.getconf('localrepository')
|
name = account.getconf('localrepository')
|
||||||
typemap = {'IMAP': MappedIMAPRepository,
|
typemap = {'IMAP': MappedIMAPRepository,
|
||||||
'Maildir': MaildirRepository,
|
'Maildir': MaildirRepository,
|
||||||
'GmailMaildir': GmailMaildirRepository}
|
'GmailMaildir': GmailMaildirRepository}
|
||||||
|
|
||||||
elif reqtype == 'status':
|
elif reqtype == 'status':
|
||||||
# create and return a LocalStatusRepository
|
# create and return a LocalStatusRepository
|
||||||
@ -69,7 +69,7 @@ class Repository(object):
|
|||||||
errstr = ("Could not find section '%s' in configuration. Required "
|
errstr = ("Could not find section '%s' in configuration. Required "
|
||||||
"for account '%s'." % ('Repository %s' % name, account))
|
"for account '%s'." % ('Repository %s' % name, account))
|
||||||
raise OfflineImapError(errstr, OfflineImapError.ERROR.REPO), \
|
raise OfflineImapError(errstr, OfflineImapError.ERROR.REPO), \
|
||||||
None, exc_info()[2]
|
None, exc_info()[2]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
repo = typemap[repostype]
|
repo = typemap[repostype]
|
||||||
@ -77,7 +77,7 @@ class Repository(object):
|
|||||||
errstr = "'%s' repository not supported for '%s' repositories." \
|
errstr = "'%s' repository not supported for '%s' repositories." \
|
||||||
% (repostype, reqtype)
|
% (repostype, reqtype)
|
||||||
raise OfflineImapError(errstr, OfflineImapError.ERROR.REPO), \
|
raise OfflineImapError(errstr, OfflineImapError.ERROR.REPO), \
|
||||||
None, exc_info()[2]
|
None, exc_info()[2]
|
||||||
|
|
||||||
return repo(name, account)
|
return repo(name, account)
|
||||||
|
|
||||||
|
@ -539,7 +539,7 @@ class UIBase(object):
|
|||||||
abortsleep = False
|
abortsleep = False
|
||||||
while sleepsecs > 0 and not abortsleep:
|
while sleepsecs > 0 and not abortsleep:
|
||||||
if account.get_abort_event():
|
if account.get_abort_event():
|
||||||
abortsleep = True
|
abortsleep = True
|
||||||
else:
|
else:
|
||||||
abortsleep = self.sleeping(10, sleepsecs)
|
abortsleep = self.sleeping(10, sleepsecs)
|
||||||
sleepsecs -= 10
|
sleepsecs -= 10
|
||||||
|
Loading…
Reference in New Issue
Block a user