Merge branch 'next' of github.com:OfflineIMAP/offlineimap into next
This commit is contained in:
commit
9b911faa58
10
COPYING
10
COPYING
@ -65,7 +65,7 @@ patent must be licensed for everyone's free use or not licensed at all.
|
|||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
The precise terms and conditions for copying, distribution and
|
||||||
modification follow.
|
modification follow.
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ above, provided that you also meet all of these conditions:
|
|||||||
License. (Exception: if the Program itself is interactive but
|
License. (Exception: if the Program itself is interactive but
|
||||||
does not normally print such an announcement, your work based on
|
does not normally print such an announcement, your work based on
|
||||||
the Program is not required to print an announcement.)
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
These requirements apply to the modified work as a whole. If
|
||||||
identifiable sections of that work are not derived from the Program,
|
identifiable sections of that work are not derived from the Program,
|
||||||
and can be reasonably considered independent and separate works in
|
and can be reasonably considered independent and separate works in
|
||||||
@ -178,7 +178,7 @@ access to copy from a designated place, then offering equivalent
|
|||||||
access to copy the source code from the same place counts as
|
access to copy the source code from the same place counts as
|
||||||
distribution of the source code, even though third parties are not
|
distribution of the source code, even though third parties are not
|
||||||
compelled to copy the source along with the object code.
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
except as expressly provided under this License. Any attempt
|
except as expressly provided under this License. Any attempt
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
@ -235,7 +235,7 @@ impose that choice.
|
|||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
This section is intended to make thoroughly clear what is believed to
|
||||||
be a consequence of the rest of this License.
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
original copyright holder who places the Program under this License
|
original copyright holder who places the Program under this License
|
||||||
@ -288,7 +288,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|||||||
POSSIBILITY OF SUCH DAMAGES.
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
14
MAINTAINERS
14
MAINTAINERS
@ -10,10 +10,22 @@ Eygene Ryabinkin
|
|||||||
email: rea at freebsd.org
|
email: rea at freebsd.org
|
||||||
github: konvpalto
|
github: konvpalto
|
||||||
|
|
||||||
|
Sebastian Spaeth
|
||||||
|
email: sebastian at sspaeth.de
|
||||||
|
github: spaetz
|
||||||
|
|
||||||
Nicolas Sebrecht
|
Nicolas Sebrecht
|
||||||
email: nicolas.s-dev at laposte.net
|
email: nicolas.s-dev at laposte.net
|
||||||
github: nicolas33
|
github: nicolas33
|
||||||
|
|
||||||
|
MAILING LIST MAINTAINERS
|
||||||
|
========================
|
||||||
|
|
||||||
|
Eygene Ryabinkin
|
||||||
|
email: rea at freebsd.org
|
||||||
|
|
||||||
Sebastian Spaeth
|
Sebastian Spaeth
|
||||||
email: sebastian at sspaeth.de
|
email: sebastian at sspaeth.de
|
||||||
github: spaetz
|
|
||||||
|
Nicolas Sebrecht
|
||||||
|
email: nicolas.s-dev at laposte.net
|
||||||
|
@ -13,57 +13,6 @@ This document contains assorted guidelines for programmers that want
|
|||||||
to hack OfflineIMAP.
|
to hack OfflineIMAP.
|
||||||
|
|
||||||
|
|
||||||
------------------
|
|
||||||
Exception handling
|
|
||||||
------------------
|
|
||||||
|
|
||||||
OfflineIMAP on many occasions re-raises various exceptions and often
|
|
||||||
changes exception type to `OfflineImapError`. This is not a problem
|
|
||||||
per se, but you must always remember that we need to preserve original
|
|
||||||
tracebacks. This is not hard if you follow these simple rules.
|
|
||||||
|
|
||||||
For re-raising original exceptions, just use::
|
|
||||||
|
|
||||||
raise
|
|
||||||
|
|
||||||
from inside your exception handling code.
|
|
||||||
|
|
||||||
If you need to change exception type, or its argument, or whatever,
|
|
||||||
use this three-argument form::
|
|
||||||
|
|
||||||
raise YourExceptionClass(argum, ents), None, sys.exc_info()[2]
|
|
||||||
|
|
||||||
In this form, you're creating an instance of new exception, so ``raise``
|
|
||||||
will deduce its ``type`` and ``value`` parameters from the first argument,
|
|
||||||
thus the second expression passed to ``raise`` is always ``None``.
|
|
||||||
And the third one is the traceback object obtained from the thread-safe
|
|
||||||
``exc_info()`` function.
|
|
||||||
|
|
||||||
In fact, if you hadn't already imported the whole ``sys`` module, it will
|
|
||||||
be better to import just ``exc_info()``::
|
|
||||||
|
|
||||||
from sys import exc_info
|
|
||||||
|
|
||||||
and raise like this::
|
|
||||||
|
|
||||||
raise YourExceptionClass(argum, ents), None, exc_info()[2]
|
|
||||||
|
|
||||||
since this is the historically-preferred style in the OfflineIMAP code.
|
|
||||||
.. -*- coding: utf-8 -*-
|
|
||||||
.. _OfflineIMAP: https://github.com/OfflineIMAP/offlineimap
|
|
||||||
.. _OLI_git_repo: git://github.com/OfflineIMAP/offlineimap.git
|
|
||||||
|
|
||||||
=================================
|
|
||||||
Coding guidelines for OfflineIMAP
|
|
||||||
=================================
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
.. .. sectnum::
|
|
||||||
|
|
||||||
This document contains assorted guidelines for programmers that want
|
|
||||||
to hack OfflineIMAP.
|
|
||||||
|
|
||||||
|
|
||||||
------------------
|
------------------
|
||||||
Exception handling
|
Exception handling
|
||||||
------------------
|
------------------
|
||||||
|
@ -23,7 +23,8 @@ from offlineimap import __version__,__author__
|
|||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo']
|
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest',
|
||||||
|
'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.viewcode']
|
||||||
autoclass_content = "both"
|
autoclass_content = "both"
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
697
offlineimap.conf
697
offlineimap.conf
File diff suppressed because it is too large
Load Diff
@ -33,15 +33,21 @@ except:
|
|||||||
|
|
||||||
# FIXME: spaghetti code alert!
|
# FIXME: spaghetti code alert!
|
||||||
def getaccountlist(customconfig):
|
def getaccountlist(customconfig):
|
||||||
|
# Account names in a list.
|
||||||
return customconfig.getsectionlist('Account')
|
return customconfig.getsectionlist('Account')
|
||||||
|
|
||||||
# FIXME: spaghetti code alert!
|
# FIXME: spaghetti code alert!
|
||||||
def AccountListGenerator(customconfig):
|
def AccountListGenerator(customconfig):
|
||||||
|
"""Returns a list of instanciated Account class, one per account name."""
|
||||||
|
|
||||||
return [Account(customconfig, accountname)
|
return [Account(customconfig, accountname)
|
||||||
for accountname in getaccountlist(customconfig)]
|
for accountname in getaccountlist(customconfig)]
|
||||||
|
|
||||||
# FIXME: spaghetti code alert!
|
# FIXME: spaghetti code alert!
|
||||||
def AccountHashGenerator(customconfig):
|
def AccountHashGenerator(customconfig):
|
||||||
|
"""Returns a dict of instanciated Account class with the account name as
|
||||||
|
key."""
|
||||||
|
|
||||||
retval = {}
|
retval = {}
|
||||||
for item in AccountListGenerator(customconfig):
|
for item in AccountListGenerator(customconfig):
|
||||||
retval[item.getname()] = item
|
retval[item.getname()] = item
|
||||||
@ -54,9 +60,10 @@ class Account(CustomConfig.ConfigHelperMixin):
|
|||||||
Most of the time you will actually want to use the derived
|
Most of the time you will actually want to use the derived
|
||||||
:class:`accounts.SyncableAccount` which contains all functions used
|
:class:`accounts.SyncableAccount` which contains all functions used
|
||||||
for syncing an account."""
|
for syncing an account."""
|
||||||
#signal gets set when we should stop looping
|
|
||||||
|
# Signal gets set when we should stop looping.
|
||||||
abort_soon_signal = Event()
|
abort_soon_signal = Event()
|
||||||
#signal gets set on CTRL-C/SIGTERM
|
# Signal gets set on CTRL-C/SIGTERM.
|
||||||
abort_NOW_signal = Event()
|
abort_NOW_signal = Event()
|
||||||
|
|
||||||
def __init__(self, config, name):
|
def __init__(self, config, name):
|
||||||
@ -66,6 +73,7 @@ class Account(CustomConfig.ConfigHelperMixin):
|
|||||||
|
|
||||||
:param name: A string denoting the name of the Account
|
:param name: A string denoting the name of the Account
|
||||||
as configured"""
|
as configured"""
|
||||||
|
|
||||||
self.config = config
|
self.config = config
|
||||||
self.name = name
|
self.name = name
|
||||||
self.metadatadir = config.getmetadatadir()
|
self.metadatadir = config.getmetadatadir()
|
||||||
@ -257,8 +265,8 @@ class SyncableAccount(Account):
|
|||||||
raise
|
raise
|
||||||
self.ui.error(e, exc_info()[2])
|
self.ui.error(e, exc_info()[2])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.ui.error(e, exc_info()[2], msg = "While attempting to sync"
|
self.ui.error(e, exc_info()[2], msg="While attempting to sync"
|
||||||
" account '%s'" % self)
|
" account '%s'"% self)
|
||||||
else:
|
else:
|
||||||
# after success sync, reset the looping counter to 3
|
# after success sync, reset the looping counter to 3
|
||||||
if self.refreshperiod:
|
if self.refreshperiod:
|
||||||
@ -483,3 +491,7 @@ def syncfolder(account, remotefolder, quick):
|
|||||||
ui.error(e, msg = "ERROR in syncfolder for %s folder %s: %s" % \
|
ui.error(e, msg = "ERROR in syncfolder for %s folder %s: %s" % \
|
||||||
(account, remotefolder.getvisiblename(),
|
(account, remotefolder.getvisiblename(),
|
||||||
traceback.format_exc()))
|
traceback.format_exc()))
|
||||||
|
finally:
|
||||||
|
for folder in ["statusfolder", "localfolder", "remotefolder"]:
|
||||||
|
if folder in locals():
|
||||||
|
locals()[folder].dropmessagelistcache()
|
||||||
|
@ -247,6 +247,9 @@ class BaseFolder(object):
|
|||||||
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
raise NotImplementedException
|
||||||
|
|
||||||
def getmessagelist(self):
|
def getmessagelist(self):
|
||||||
"""Gets the current message list.
|
"""Gets the current message list.
|
||||||
You must call cachemessagelist() before calling this function!"""
|
You must call cachemessagelist() before calling this function!"""
|
||||||
@ -438,6 +441,11 @@ class BaseFolder(object):
|
|||||||
- headername: name of the header to add
|
- headername: name of the header to add
|
||||||
- headervalue: value of the header to add
|
- headervalue: value of the header to add
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The following documentation will not get displayed correctly after being
|
||||||
|
processed by Sphinx. View the source of this method to read it.
|
||||||
|
|
||||||
This has to deal with strange corner cases where the header is
|
This has to deal with strange corner cases where the header is
|
||||||
missing or empty. Here are illustrations for all the cases,
|
missing or empty. Here are illustrations for all the cases,
|
||||||
showing where the header gets inserted and what the end result
|
showing where the header gets inserted and what the end result
|
||||||
|
@ -40,6 +40,8 @@ CRLF = '\r\n'
|
|||||||
|
|
||||||
class IMAPFolder(BaseFolder):
|
class IMAPFolder(BaseFolder):
|
||||||
def __init__(self, imapserver, name, repository):
|
def __init__(self, imapserver, name, repository):
|
||||||
|
# FIXME: decide if unquoted name is from the responsability of the
|
||||||
|
# caller or not, but not both.
|
||||||
name = imaputil.dequote(name)
|
name = imaputil.dequote(name)
|
||||||
self.sep = imapserver.delim
|
self.sep = imapserver.delim
|
||||||
super(IMAPFolder, self).__init__(name, repository)
|
super(IMAPFolder, self).__init__(name, repository)
|
||||||
@ -248,6 +250,8 @@ class IMAPFolder(BaseFolder):
|
|||||||
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
rtime = imaplibutil.Internaldate2epoch(messagestr)
|
||||||
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
|
self.messagelist[uid] = {'uid': uid, 'flags': flags, 'time': rtime}
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
self.messagelist = None
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def getmessagelist(self):
|
def getmessagelist(self):
|
||||||
|
@ -161,6 +161,8 @@ class LocalStatusFolder(BaseFolder):
|
|||||||
self.readstatus(file)
|
self.readstatus(file)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
self.messagelist = None
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""Save changed data to disk. For this backend it is the same as saveall."""
|
"""Save changed data to disk. For this backend it is the same as saveall."""
|
||||||
|
@ -203,6 +203,9 @@ class LocalStatusSQLiteFolder(BaseFolder):
|
|||||||
self.messagelist[uid]['labels'] = labels
|
self.messagelist[uid]['labels'] = labels
|
||||||
self.messagelist[uid]['mtime'] = row[2]
|
self.messagelist[uid]['mtime'] = row[2]
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
self.messagelist = None
|
||||||
|
|
||||||
# Interface from LocalStatusFolder
|
# Interface from LocalStatusFolder
|
||||||
def save(self):
|
def save(self):
|
||||||
pass
|
pass
|
||||||
|
@ -220,6 +220,9 @@ class MaildirFolder(BaseFolder):
|
|||||||
if self.messagelist is None:
|
if self.messagelist is None:
|
||||||
self.messagelist = self._scanfolder()
|
self.messagelist = self._scanfolder()
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
self.messagelist = None
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def getmessagelist(self):
|
def getmessagelist(self):
|
||||||
return self.messagelist
|
return self.messagelist
|
||||||
|
@ -125,6 +125,9 @@ class MappedIMAPFolder(IMAPFolder):
|
|||||||
finally:
|
finally:
|
||||||
self.maplock.release()
|
self.maplock.release()
|
||||||
|
|
||||||
|
def dropmessagelistcache(self):
|
||||||
|
self._mb.dropmessagelistcache()
|
||||||
|
|
||||||
# Interface from BaseFolder
|
# Interface from BaseFolder
|
||||||
def uidexists(self, ruid):
|
def uidexists(self, ruid):
|
||||||
"""Checks if the (remote) UID exists in this Folder"""
|
"""Checks if the (remote) UID exists in this Folder"""
|
||||||
|
@ -40,6 +40,7 @@ class OfflineImap:
|
|||||||
oi = OfflineImap()
|
oi = OfflineImap()
|
||||||
oi.run()
|
oi.run()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Parse the commandline and invoke everything"""
|
"""Parse the commandline and invoke everything"""
|
||||||
# next line also sets self.config and self.ui
|
# next line also sets self.config and self.ui
|
||||||
@ -321,6 +322,8 @@ class OfflineImap:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Honor CLI --account option, only.
|
||||||
|
# Accounts to sync are put into syncaccounts variable.
|
||||||
activeaccounts = self.config.get("general", "accounts")
|
activeaccounts = self.config.get("general", "accounts")
|
||||||
if options.accounts:
|
if options.accounts:
|
||||||
activeaccounts = options.accounts
|
activeaccounts = options.accounts
|
||||||
|
@ -31,10 +31,10 @@ class LocalEval:
|
|||||||
if path is not None:
|
if path is not None:
|
||||||
# FIXME: limit opening files owned by current user with rights set
|
# FIXME: limit opening files owned by current user with rights set
|
||||||
# to fixed mode 644.
|
# to fixed mode 644.
|
||||||
file = open(path, 'r')
|
foo = open(path, 'r')
|
||||||
module = imp.load_module(
|
module = imp.load_module(
|
||||||
'<none>',
|
'<none>',
|
||||||
file,
|
foo,
|
||||||
path,
|
path,
|
||||||
('', 'r', imp.PY_SOURCE))
|
('', 'r', imp.PY_SOURCE))
|
||||||
for attr in dir(module):
|
for attr in dir(module):
|
||||||
|
@ -39,6 +39,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object):
|
|||||||
self.mapdir = os.path.join(self.uiddir, 'UIDMapping')
|
self.mapdir = os.path.join(self.uiddir, 'UIDMapping')
|
||||||
if not os.path.exists(self.mapdir):
|
if not os.path.exists(self.mapdir):
|
||||||
os.mkdir(self.mapdir, 0o700)
|
os.mkdir(self.mapdir, 0o700)
|
||||||
|
# FIXME: self.uiddir variable name is lying about itself.
|
||||||
self.uiddir = os.path.join(self.uiddir, 'FolderValidity')
|
self.uiddir = os.path.join(self.uiddir, 'FolderValidity')
|
||||||
if not os.path.exists(self.uiddir):
|
if not os.path.exists(self.uiddir):
|
||||||
os.mkdir(self.uiddir, 0o700)
|
os.mkdir(self.uiddir, 0o700)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Maildir repository support
|
# Maildir repository support
|
||||||
# Copyright (C) 2002 John Goerzen
|
# Copyright (C) 2002-2015 John Goerzen & contributors
|
||||||
# <jgoerzen@complete.org>
|
# <jgoerzen@complete.org>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
@ -23,8 +23,8 @@ class GmailMaildirRepository(MaildirRepository):
|
|||||||
def __init__(self, reposname, account):
|
def __init__(self, reposname, account):
|
||||||
"""Initialize a MaildirRepository object. Takes a path name
|
"""Initialize a MaildirRepository object. Takes a path name
|
||||||
to the directory holding all the Maildir directories."""
|
to the directory holding all the Maildir directories."""
|
||||||
super(GmailMaildirRepository, self).__init__(reposname, account)
|
|
||||||
|
|
||||||
|
super(GmailMaildirRepository, self).__init__(reposname, account)
|
||||||
|
|
||||||
def getfoldertype(self):
|
def getfoldertype(self):
|
||||||
return GmailMaildirFolder
|
return GmailMaildirFolder
|
||||||
|
@ -301,6 +301,8 @@ class IMAPRepository(BaseRepository):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def getfolder(self, foldername):
|
def getfolder(self, foldername):
|
||||||
|
"""Return instance of OfflineIMAP representative folder."""
|
||||||
|
|
||||||
return self.getfoldertype()(self.imapserver, foldername, self)
|
return self.getfoldertype()(self.imapserver, foldername, self)
|
||||||
|
|
||||||
def getfoldertype(self):
|
def getfoldertype(self):
|
||||||
@ -314,6 +316,8 @@ class IMAPRepository(BaseRepository):
|
|||||||
self.folders = None
|
self.folders = None
|
||||||
|
|
||||||
def getfolders(self):
|
def getfolders(self):
|
||||||
|
"""Return a list of instances of OfflineIMAP representative folder."""
|
||||||
|
|
||||||
if self.folders != None:
|
if self.folders != None:
|
||||||
return self.folders
|
return self.folders
|
||||||
retval = []
|
retval = []
|
||||||
@ -326,13 +330,13 @@ class IMAPRepository(BaseRepository):
|
|||||||
listresult = listfunction(directory = self.imapserver.reference)[1]
|
listresult = listfunction(directory = self.imapserver.reference)[1]
|
||||||
finally:
|
finally:
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
for string in listresult:
|
for s in listresult:
|
||||||
if string == None or \
|
if s == None or \
|
||||||
(isinstance(string, basestring) and string == ''):
|
(isinstance(s, basestring) and s == ''):
|
||||||
# Bug in imaplib: empty strings in results from
|
# Bug in imaplib: empty strings in results from
|
||||||
# literals. TODO: still relevant?
|
# literals. TODO: still relevant?
|
||||||
continue
|
continue
|
||||||
flags, delim, name = imaputil.imapsplit(string)
|
flags, delim, name = imaputil.imapsplit(s)
|
||||||
flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
|
flaglist = [x.lower() for x in imaputil.flagsplit(flags)]
|
||||||
if '\\noselect' in flaglist:
|
if '\\noselect' in flaglist:
|
||||||
continue
|
continue
|
||||||
@ -353,9 +357,8 @@ class IMAPRepository(BaseRepository):
|
|||||||
self.ui.error(e, exc_info()[2],
|
self.ui.error(e, exc_info()[2],
|
||||||
'Invalid folderinclude:')
|
'Invalid folderinclude:')
|
||||||
continue
|
continue
|
||||||
retval.append(self.getfoldertype()(self.imapserver,
|
retval.append(self.getfoldertype()(
|
||||||
foldername,
|
self.imapserver, foldername, self))
|
||||||
self))
|
|
||||||
finally:
|
finally:
|
||||||
self.imapserver.releaseconnection(imapobj)
|
self.imapserver.releaseconnection(imapobj)
|
||||||
|
|
||||||
|
@ -94,7 +94,8 @@ class LocalStatusRepository(BaseRepository):
|
|||||||
self.forgetfolders()
|
self.forgetfolders()
|
||||||
|
|
||||||
def getfolder(self, foldername):
|
def getfolder(self, foldername):
|
||||||
"""Return the Folder() object for a foldername"""
|
"""Return the Folder() object for a foldername."""
|
||||||
|
|
||||||
if foldername in self._folders:
|
if foldername in self._folders:
|
||||||
return self._folders[foldername]
|
return self._folders[foldername]
|
||||||
|
|
||||||
|
@ -170,8 +170,8 @@ class MaildirRepository(BaseRepository):
|
|||||||
self.debug(" skip this entry (not a directory)")
|
self.debug(" skip this entry (not a directory)")
|
||||||
# Not a directory -- not a folder.
|
# Not a directory -- not a folder.
|
||||||
continue
|
continue
|
||||||
|
# extension can be None.
|
||||||
if extension:
|
if extension:
|
||||||
# extension can be None which fails.
|
|
||||||
foldername = os.path.join(extension, dirname)
|
foldername = os.path.join(extension, dirname)
|
||||||
else:
|
else:
|
||||||
foldername = dirname
|
foldername = dirname
|
||||||
|
Loading…
Reference in New Issue
Block a user