more style consistency

Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Nicolas Sebrecht 2015-01-08 17:13:33 +01:00
parent 594a286888
commit 0f40ca4799
14 changed files with 261 additions and 237 deletions

View File

@ -385,6 +385,7 @@ def syncfolder(account, remotefolder, quick):
"""Synchronizes given remote folder for the specified account.
Filtered folders on the remote side will not invoke this function."""
remoterepos = account.remoterepos
localrepos = account.localrepos
statusrepos = account.statusrepos

View File

@ -19,13 +19,12 @@ import email
from email.Parser import Parser as MailParser
def get_message_date(content, header='Date'):
"""
Parses mail and returns resulting timestamp.
"""Parses mail and returns resulting timestamp.
:param header: the header to extract date from;
:returns: timestamp or `None` in the case of failure.
"""
message = MailParser().parsestr(content, True)
dateheader = message.get(header)
# parsedate_tz returns a 10-tuple that can be passed to mktime_tz

View File

@ -15,14 +15,15 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os.path
import re
from sys import exc_info
from offlineimap import threadutil, emailutil
from offlineimap import globals
from offlineimap.ui import getglobalui
from offlineimap.error import OfflineImapError
import offlineimap.accounts
import os.path
import re
from sys import exc_info
class BaseFolder(object):
@ -31,6 +32,7 @@ class BaseFolder(object):
:para name: Path & name of folder minus root or reference
:para repository: Repository() in which the folder is.
"""
self.ui = getglobalui()
# Save original name for folderfilter operations
self.ffilter_name = name
@ -56,15 +58,15 @@ class BaseFolder(object):
# Determine if we're running static or dynamic folder filtering
# and check filtering status
self._dynamic_folderfilter = \
self.config.getdefaultboolean(repo, "dynamic_folderfilter", False)
self._dynamic_folderfilter = self.config.getdefaultboolean(
repo, "dynamic_folderfilter", False)
self._sync_this = repository.should_sync_folder(self.ffilter_name)
if self._dynamic_folderfilter:
self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]" \
% (self.ffilter_name, repository))
self.ui.debug('', "Running dynamic folder filtering on '%s'[%s]"%
(self.ffilter_name, repository))
elif not self._sync_this:
self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter" \
% (self.ffilter_name, repository))
self.ui.debug('', "Filtering out '%s'[%s] due to folderfilter"%
(self.ffilter_name, repository))
# Passes for syncmessagesto
self.syncmessagesto_passes = [('copying messages' , self.__syncmessagesto_copy),
@ -115,17 +117,20 @@ class BaseFolder(object):
:param statusfolder: keeps track of the last known folder state.
"""
return True
def getcopyinstancelimit(self):
"""For threading folders, returns the instancelimitname for
InstanceLimitedThreads."""
raise NotImplementedError
def storesmessages(self):
"""Should be true for any backend that actually saves message bodies.
(Almost all of them). False for the LocalStatus backend. Saves
us from having to slurp up messages just for localstatus purposes."""
return 1
def getvisiblename(self):
@ -143,14 +148,17 @@ class BaseFolder(object):
def getrepository(self):
"""Returns the repository object that this folder is within."""
return self.repository
def getroot(self):
"""Returns the root of the folder, in a folder-specific fashion."""
return self.root
def getsep(self):
"""Returns the separator for this folder type."""
return self.sep
def getfullname(self):
@ -160,7 +168,8 @@ class BaseFolder(object):
return self.getname()
def getfolderbasename(self):
"""Return base file name of file to store Status/UID info in"""
"""Return base file name of file to store Status/UID info in."""
if not self.name:
basename = '.'
else: #avoid directory hierarchies and file names such as '/'
@ -188,6 +197,7 @@ class BaseFolder(object):
def _getuidfilename(self):
"""provides UIDVALIDITY cache filename for class internal purposes"""
return os.path.join(self.repository.getuiddir(),
self.getfolderbasename())
@ -196,6 +206,7 @@ class BaseFolder(object):
:returns: UIDVALIDITY as (long) number or None, if None had been
saved yet."""
if hasattr(self, '_base_saved_uidvalidity'):
return self._base_saved_uidvalidity
uidfilename = self._getuidfilename()
@ -212,6 +223,7 @@ class BaseFolder(object):
This function is not threadsafe, so don't attempt to call it
from concurrent threads."""
newval = self.get_uidvalidity()
uidfilename = self._getuidfilename()
@ -225,45 +237,50 @@ class BaseFolder(object):
This function needs to be implemented by each Backend
:returns: UIDVALIDITY as a (long) number"""
raise NotImplementedError
def cachemessagelist(self):
"""Reads the message list from disk or network and stores it in
memory for later use. This list will not be re-read from disk or
memory unless this function is called again."""
raise NotImplementedError
def getmessagelist(self):
"""Gets the current message list.
You must call cachemessagelist() before calling this function!"""
raise NotImplementedError
def msglist_item_initializer(self, uid):
"""
Returns value for empty messagelist element with given UID.
"""Returns value for empty messagelist element with given UID.
This function must initialize all fields of messagelist item
and must be called every time when one creates new messagelist
entry to ensure that all fields that must be present are present.
entry to ensure that all fields that must be present are present."""
"""
raise NotImplementedError
def uidexists(self, uid):
"""Returns True if uid exists"""
return uid in self.getmessagelist()
def getmessageuidlist(self):
"""Gets a list of UIDs.
You may have to call cachemessagelist() before calling this function!"""
return self.getmessagelist().keys()
def getmessagecount(self):
"""Gets the number of messages."""
return len(self.getmessagelist())
def getmessage(self, uid):
"""Returns the content of the specified message."""
raise NotImplementedError
def savemessage(self, uid, content, flags, rtime):
@ -286,20 +303,23 @@ class BaseFolder(object):
Note that savemessage() does not check against dryrun settings,
so you need to ensure that savemessage is never called in a
dryrun mode.
"""
dryrun mode."""
raise NotImplementedError
def getmessagetime(self, uid):
"""Return the received time for the specified message."""
raise NotImplementedError
def getmessagemtime(self, uid):
"""Returns the message modification time of the specified message."""
raise NotImplementedError
def getmessageflags(self, uid):
"""Returns the flags for the specified message."""
raise NotImplementedError
def savemessageflags(self, uid, flags):
@ -308,6 +328,7 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
raise NotImplementedError
def addmessageflags(self, uid, flags):
@ -319,14 +340,15 @@ class BaseFolder(object):
dryrun mode.
:param flags: A set() of flags"""
newflags = self.getmessageflags(uid) | flags
self.savemessageflags(uid, newflags)
def addmessagesflags(self, uidlist, flags):
"""
Note that this function does not check against dryrun settings,
"""Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
for uid in uidlist:
self.addmessageflags(uid, flags)
@ -337,6 +359,7 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
newflags = self.getmessageflags(uid) - flags
self.savemessageflags(uid, newflags)
@ -345,10 +368,10 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
for uid in uidlist:
self.deletemessageflags(uid, flags)
def getmessagelabels(self, uid):
"""Returns the labels for the specified message."""
raise NotImplementedError
@ -359,6 +382,7 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
raise NotImplementedError
def addmessagelabels(self, uid, labels):
@ -370,14 +394,15 @@ class BaseFolder(object):
dryrun mode.
:param labels: A set() of labels"""
newlabels = self.getmessagelabels(uid) | labels
self.savemessagelabels(uid, newlabels)
def addmessageslabels(self, uidlist, labels):
"""
Note that this function does not check against dryrun settings,
"""Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
for uid in uidlist:
self.addmessagelabels(uid, labels)
@ -388,6 +413,7 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
newlabels = self.getmessagelabels(uid) - labels
self.savemessagelabels(uid, newlabels)
@ -396,12 +422,12 @@ class BaseFolder(object):
Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
for uid in uidlist:
self.deletemessagelabels(uid, labels)
def addmessageheader(self, content, linebreak, headername, headervalue):
"""
Adds new header to the provided message.
"""Adds new header to the provided message.
WARNING: This function is a bit tricky, and modifying it in the wrong way,
may easily lead to data-loss.
@ -454,9 +480,9 @@ class BaseFolder(object):
This is the body\n
next line\n
"""
self.ui.debug('',
'addmessageheader: called to add %s: %s' % (headername,
headervalue))
self.ui.debug('', 'addmessageheader: called to add %s: %s'%
(headername, headervalue))
insertionpoint = content.find(linebreak * 2)
if insertionpoint == -1:
@ -499,15 +525,14 @@ class BaseFolder(object):
def __find_eoh(self, content):
"""
Searches for the point where mail headers end.
""" Searches for the point where mail headers end.
Either double '\n', or end of string.
Arguments:
- content: contents of the message to search in
Returns: position of the first non-header byte.
"""
eoh_cr = content.find('\n\n')
if eoh_cr == -1:
eoh_cr = len(content)
@ -516,8 +541,7 @@ class BaseFolder(object):
def getmessageheader(self, content, name):
"""
Searches for the first occurence of the given header and returns
"""Searches for the first occurence of the given header and returns
its value. Header name is case-insensitive.
Arguments:
@ -525,8 +549,8 @@ class BaseFolder(object):
- name: name of the header to be searched
Returns: header value or None if no such header was found
"""
self.ui.debug('', 'getmessageheader: called to get %s'% name)
eoh = self.__find_eoh(content)
self.ui.debug('', 'getmessageheader: eoh = %d'% eoh)
@ -541,8 +565,7 @@ class BaseFolder(object):
def getmessageheaderlist(self, content, name):
"""
Searches for the given header and returns a list of values for
"""Searches for the given header and returns a list of values for
that header.
Arguments:
@ -550,8 +573,8 @@ class BaseFolder(object):
- name: name of the header to be searched
Returns: list of header values or emptylist if no such header was found
"""
self.ui.debug('', 'getmessageheaderlist: called to get %s' % name)
eoh = self.__find_eoh(content)
self.ui.debug('', 'getmessageheaderlist: eoh = %d' % eoh)
@ -562,16 +585,15 @@ class BaseFolder(object):
def deletemessageheaders(self, content, header_list):
"""
Deletes headers in the given list from the message content.
"""Deletes headers in the given list from the message content.
Arguments:
- content: message itself
- header_list: list of headers to be deleted or just the header name
We expect our message to have '\n' as line endings.
"""
if type(header_list) != type([]):
header_list = [header_list]
self.ui.debug('', 'deletemessageheaders: called to delete %s'% (header_list))
@ -609,16 +631,14 @@ class BaseFolder(object):
raise NotImplementedError
def deletemessage(self, uid):
"""
Note that this function does not check against dryrun settings,
"""Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
raise NotImplementedError
def deletemessages(self, uidlist):
"""
Note that this function does not check against dryrun settings,
"""Note that this function does not check against dryrun settings,
so you need to ensure that it is never called in a
dryrun mode."""
@ -686,9 +706,8 @@ class BaseFolder(object):
self.deletemessage(uid)
else:
raise OfflineImapError("Trying to save msg (uid %d) on folder "
"%s returned invalid uid %d" % (uid,
dstfolder.getvisiblename(), new_uid),
OfflineImapError.ERROR.MESSAGE)
"%s returned invalid uid %d"% (uid, dstfolder.getvisiblename(),
new_uid), OfflineImapError.ERROR.MESSAGE)
except (KeyboardInterrupt): # bubble up CTRL-C
raise
except OfflineImapError as e:
@ -697,8 +716,7 @@ class BaseFolder(object):
self.ui.error(e, exc_info()[2])
except Exception as e:
self.ui.error(e, exc_info()[2],
msg="Copying message %s [acc: %s]" %\
(uid, self.accountname))
msg = "Copying message %s [acc: %s]"% (uid, self.accountname))
raise #raise on unknown errors, so we can fix those
def __syncmessagesto_copy(self, dstfolder, statusfolder):
@ -714,6 +732,7 @@ class BaseFolder(object):
This function checks and protects us from action in ryrun mode.
"""
threads = []
copylist = filter(lambda uid: not \
@ -754,6 +773,7 @@ class BaseFolder(object):
This function checks and protects us from action in ryrun mode.
"""
deletelist = filter(lambda uid: uid>=0 \
and not self.uidexists(uid),
statusfolder.getmessageuidlist())
@ -776,6 +796,7 @@ class BaseFolder(object):
This function checks and protects us from action in ryrun mode.
"""
# For each flag, we store a list of uids to which it should be
# added. Then, we can call addmessagesflags() to apply them in
# bulk, rather than one call per message.
@ -854,8 +875,8 @@ class BaseFolder(object):
:param dstfolder: Folderinstance to sync the msgs to.
:param statusfolder: LocalStatus instance to sync against.
"""
for (passdesc, action) in self.syncmessagesto_passes:
# bail out on CTRL-C or SIGTERM
if offlineimap.accounts.Account.abort_NOW_signal.is_set():
@ -883,6 +904,7 @@ class BaseFolder(object):
MailDirFolder('foo') == IMAPFolder('foo') --> False
MailDirFolder('foo') == MaildirFolder('foo') --> False
"""
if isinstance(other, basestring):
return other == self.name
return id(self) == id(other)

View File

@ -20,6 +20,7 @@ import binascii
import re
import time
from sys import exc_info
from .Base import BaseFolder
from offlineimap import imaputil, imaplibutil, emailutil, OfflineImapError
from offlineimap import globals
@ -86,6 +87,7 @@ class IMAPFolder(BaseFolder):
UIDVALIDITY value will be cached on the first call.
:returns: The UIDVALIDITY as (long) number."""
if hasattr(self, '_uidvalidity'):
# use cached value if existing
return self._uidvalidity
@ -141,8 +143,7 @@ class IMAPFolder(BaseFolder):
def _msgs_to_fetch(self, imapobj):
"""
Determines sequence numbers of messages to be fetched.
"""Determines sequence numbers of messages to be fetched.
Message sequence numbers (MSNs) are more easily compacted
into ranges which makes transactions slightly faster.
@ -151,9 +152,8 @@ class IMAPFolder(BaseFolder):
- imapobj: instance of IMAPlib
Returns: range(s) for messages or None if no messages
are to be fetched.
are to be fetched."""
"""
res_type, imapdata = imapobj.select(self.getfullname(), True, True)
if imapdata == [None] or imapdata[0] == '0':
# Empty folder, no need to populate message list
@ -219,8 +219,8 @@ class IMAPFolder(BaseFolder):
# Get the flags and UIDs for these. single-quotes prevent
# imaplib2 from quoting the sequence.
res_type, response = imapobj.fetch("'%s'" % msgsToFetch,
'(FLAGS UID)')
res_type, response = imapobj.fetch("'%s'"%
msgsToFetch, '(FLAGS UID)')
if res_type != 'OK':
raise OfflineImapError("FETCHING UIDs in folder [%s]%s failed. "
"Server responded '[%s] %s'"% (
@ -255,16 +255,15 @@ class IMAPFolder(BaseFolder):
# Interface from BaseFolder
def getmessage(self, uid):
"""
Retrieve message with UID from the IMAP server (incl body)
"""Retrieve message with UID from the IMAP server (incl body)
After this function all CRLFs will be transformed to '\n'.
:returns: the message body or throws and OfflineImapError
(probably severity MESSAGE) if e.g. no message with
this UID could be found.
"""
imapobj = self.imapserver.acquireconnection()
try:
data = self._fetch_from_imap(imapobj, str(uid), 2)
@ -307,6 +306,7 @@ class IMAPFolder(BaseFolder):
headername == 'X-OfflineIMAP' and headervalue will be a
random string
"""
headername = 'X-OfflineIMAP'
# We need a random component too. If we ever upload the same
# mail twice (e.g. in different folders), we would still need to
@ -368,8 +368,8 @@ class IMAPFolder(BaseFolder):
We need to locate the UID just after mail headers containing our
X-OfflineIMAP line.
Returns UID when found, 0 when not found.
"""
Returns UID when found, 0 when not found."""
self.ui.debug('imap', '__savemessage_fetchheaders called for %s: %s'% \
(headername, headervalue))
@ -467,8 +467,8 @@ class IMAPFolder(BaseFolder):
# or something. Argh. It seems that Time2Internaldate
# will rause a ValueError if the year is 0102 but not 1902,
# but some IMAP servers nonetheless choke on 1902.
self.ui.debug('imap', "Message with invalid date %s. Server will use local time." \
% datetuple)
self.ui.debug('imap', "Message with invalid date %s. "
"Server will use local time."% datetuple)
return None
#produce a string representation of datetuple that works as
@ -507,6 +507,7 @@ class IMAPFolder(BaseFolder):
message is saved, but it's UID can not be found, it will
return 0. If the message can't be written (folder is
read-only for example) it will return -1."""
self.ui.savemessage('imap', uid, flags, self)
# already have it, just save modified flags
@ -544,7 +545,7 @@ class IMAPFolder(BaseFolder):
# insert a random unique header that we can fetch later
(headername, headervalue) = self.__generate_randomheader(
content)
self.ui.debug('imap', 'savemessage: header is: %s: %s' %\
self.ui.debug('imap', 'savemessage: header is: %s: %s'%
(headername, headervalue))
content = self.addmessageheader(content, CRLF, headername, headervalue)
@ -566,9 +567,8 @@ class IMAPFolder(BaseFolder):
#Do the APPEND
try:
(typ, dat) = imapobj.append(self.getfullname(),
imaputil.flagsmaildir2imap(flags),
date, content)
(typ, dat) = imapobj.append(fullname,
imaputil.flagsmaildir2imap(flags), date, content)
# This should only catch 'NO' responses since append()
# will raise an exception for 'BAD' responses:
if typ != 'OK':
@ -654,16 +654,15 @@ class IMAPFolder(BaseFolder):
def _fetch_from_imap(self, imapobj, uids, retry_num=1):
"""
Fetches data from IMAP server.
"""Fetches data from IMAP server.
Arguments:
- imapobj: IMAPlib object
- uids: message UIDS
- retry_num: number of retries to make
Returns: data obtained by this query.
"""
Returns: data obtained by this query."""
query = "(%s)"% (" ".join(self.imap_query))
fails_left = retry_num # retry on dropped connection
while fails_left:
@ -695,23 +694,21 @@ class IMAPFolder(BaseFolder):
def _store_to_imap(self, imapobj, uid, field, data):
"""
Stores data to IMAP server
"""Stores data to IMAP server
Arguments:
- imapobj: instance of IMAPlib to use
- uid: message UID
- field: field name to be stored/updated
- data: field contents
"""
imapobj.select(self.getfullname())
res_type, retdata = imapobj.uid('store', uid, field, data)
if res_type != 'OK':
severity = OfflineImapError.ERROR.MESSAGE
reason = "IMAP server '%s' failed to store %s for message UID '%d'."\
"Server responded: %s %s" % (self.getrepository(), field, uid,
res_type, retdata)
"Server responded: %s %s"% (
self.getrepository(), field, uid, res_type, retdata)
raise OfflineImapError(reason, severity)
return retdata[0]
@ -724,12 +721,11 @@ class IMAPFolder(BaseFolder):
dryrun mode."""
imapobj = self.imapserver.acquireconnection()
try:
result = self._store_to_imap(imapobj, str(uid), 'FLAGS', imaputil.flagsmaildir2imap(flags))
result = self._store_to_imap(imapobj, str(uid), 'FLAGS',
imaputil.flagsmaildir2imap(flags))
except imapobj.readonly:
self.ui.flagstoreadonly(self, [uid], flags)
return
finally:
self.imapserver.releaseconnection(imapobj)
@ -751,6 +747,7 @@ class IMAPFolder(BaseFolder):
"""This is here for the sake of UIDMaps.py -- deletemessages must
add flags and get a converted UID, and if we don't have noconvert,
then UIDMaps will try to convert it twice."""
self.__addmessagesflags_noconvert(uidlist, flags)
# Interface from BaseFolder
@ -770,8 +767,7 @@ class IMAPFolder(BaseFolder):
self.ui.flagstoreadonly(self, uidlist, flags)
return
r = imapobj.uid('store',
imaputil.uid_sequence(uidlist),
operation + 'FLAGS',
imaputil.uid_sequence(uidlist), operation + 'FLAGS',
imaputil.flagsmaildir2imap(flags))
assert r[0] == 'OK', 'Error with store: ' + '. '.join(r[1])
r = r[1]
@ -818,9 +814,9 @@ class IMAPFolder(BaseFolder):
"""Change the message from existing uid to new_uid
If the backend supports it. IMAP does not and will throw errors."""
raise OfflineImapError('IMAP backend cannot change a messages UID from '
'%d to %d' % (uid, new_uid),
OfflineImapError.ERROR.MESSAGE)
'%d to %d'% (uid, new_uid), OfflineImapError.ERROR.MESSAGE)
# Interface from BaseFolder
def deletemessage(self, uid):

View File

@ -118,6 +118,7 @@ class IMAPServer:
def getroot(self):
"""Returns this server's folder root. Can only be called after one
or more calls to acquireconnection."""
return self.root
@ -126,6 +127,7 @@ class IMAPServer:
:param drop_conn: If True, the connection will be released and
not be reused. This can be used to indicate broken connections."""
if connection is None: return #noop on bad connection
self.connectionlock.acquire()
self.assignedconnections.remove(connection)
@ -147,17 +149,16 @@ class IMAPServer:
return retval
def __loginauth(self, imapobj):
""" Basic authentication via LOGIN command """
""" Basic authentication via LOGIN command."""
self.ui.debug('imap', 'Attempting IMAP LOGIN authentication')
imapobj.login(self.username, self.__getpassword())
def __plainhandler(self, response):
"""
Implements SASL PLAIN authentication, RFC 4616,
http://tools.ietf.org/html/rfc4616
"""Implements SASL PLAIN authentication, RFC 4616,
http://tools.ietf.org/html/rfc4616"""
"""
authc = self.username
passwd = self.__getpassword()
authz = ''
@ -175,8 +176,8 @@ class IMAPServer:
try:
if self.gss_step == self.GSS_STATE_STEP:
if not self.gss_vc:
rc, self.gss_vc = kerberos.authGSSClientInit('imap@' +
self.hostname)
rc, self.gss_vc = kerberos.authGSSClientInit(
'imap@' + self.hostname)
response = kerberos.authGSSClientResponse(self.gss_vc)
rc = kerberos.authGSSClientStep(self.gss_vc, data)
if rc != kerberos.AUTH_GSS_CONTINUE:
@ -184,8 +185,8 @@ class IMAPServer:
elif self.gss_step == self.GSS_STATE_WRAP:
rc = kerberos.authGSSClientUnwrap(self.gss_vc, data)
response = kerberos.authGSSClientResponse(self.gss_vc)
rc = kerberos.authGSSClientWrap(self.gss_vc, response,
self.username)
rc = kerberos.authGSSClientWrap(
self.gss_vc, response, self.username)
response = kerberos.authGSSClientResponse(self.gss_vc)
except kerberos.GSSError as err:
# Kerberos errored out on us, respond with None to cancel the
@ -266,8 +267,7 @@ class IMAPServer:
def __authn_helper(self, imapobj):
"""
Authentication machinery for self.acquireconnection().
"""Authentication machinery for self.acquireconnection().
Raises OfflineImapError() of type ERROR.REPO when
there are either fatal problems or no authentications
@ -275,9 +275,7 @@ class IMAPServer:
If any authentication method succeeds, routine should exit:
warnings for failed methods are to be produced in the
respective except blocks.
"""
respective except blocks."""
# Authentication routines, hash keyed by method name
# with value that is a tuple with
@ -321,7 +319,7 @@ class IMAPServer:
continue
tried_to_authn = True
self.ui.debug('imap', 'Attempting '
self.ui.debug('imap', u'Attempting '
'%s authentication'% m)
try:
if func(imapobj):
@ -343,7 +341,7 @@ class IMAPServer:
lambda x: x[5:], filter(lambda x: x[0:5] == "AUTH=",
imapobj.capabilities)
))
raise OfflineImapError("Repository %s: no supported "
raise OfflineImapError(u"Repository %s: no supported "
"authentication mechanisms found; configured %s, "
"server advertises %s"% (self.repos,
", ".join(self.authmechs), methods),
@ -383,9 +381,8 @@ class IMAPServer:
self.connectionlock.release() # Release until need to modify data
""" Must be careful here that if we fail we should bail out gracefully
and release locks / threads so that the next attempt can try...
"""
# Must be careful here that if we fail we should bail out gracefully
# and release locks / threads so that the next attempt can try...
success = 0
try:
while not success:
@ -458,6 +455,7 @@ class IMAPServer:
"""If we are here then we did not succeed in getting a
connection - we should clean up and then re-raise the
error..."""
self.semaphore.release()
severity = OfflineImapError.ERROR.REPO
@ -503,13 +501,15 @@ class IMAPServer:
raise
def connectionwait(self):
"""Waits until there is a connection available. Note that between
the time that a connection becomes available and the time it is
requested, another thread may have grabbed it. This function is
mainly present as a way to avoid spawning thousands of threads
to copy messages, then have them all wait for 3 available connections.
It's OK if we have maxconnections + 1 or 2 threads, which is what
this will help us do."""
"""Waits until there is a connection available.
Note that between the time that a connection becomes available and the
time it is requested, another thread may have grabbed it. This function
is mainly present as a way to avoid spawning thousands of threads to
copy messages, then have them all wait for 3 available connections.
It's OK if we have maxconnections + 1 or 2 threads, which is what this
will help us do."""
self.semaphore.acquire()
self.semaphore.release()
@ -533,11 +533,13 @@ class IMAPServer:
self.gssapi = False
def keepalive(self, timeout, event):
"""Sends a NOOP to each connection recorded. It will wait a maximum
of timeout seconds between doing this, and will continue to do so
until the Event object as passed is true. This method is expected
to be invoked in a separate thread, which should be join()'d after
the event is set."""
"""Sends a NOOP to each connection recorded.
It will wait a maximum of timeout seconds between doing this, and will
continue to do so until the Event object as passed is true. This method
is expected to be invoked in a separate thread, which should be join()'d
after the event is set."""
self.ui.debug('imap', 'keepalive thread started')
while not event.isSet():
self.connectionlock.acquire()
@ -570,11 +572,11 @@ class IMAPServer:
return
def __verifycert(self, cert, hostname):
'''Verify that cert (in socket.getpeercert() format) matches hostname.
CRLs are not handled.
"""Verify that cert (in socket.getpeercert() format) matches hostname.
CRLs are not handled.
Returns error message if any problems are found and None on success."""
Returns error message if any problems are found and None on success.
'''
errstr = "CA Cert verifying failed: "
if not cert:
return ('%s no certificate received'% errstr)
@ -614,6 +616,7 @@ class IdleThread(object):
"""If invoked without 'folder', perform a NOOP and wait for
self.stop() to be called. If invoked with folder, switch to IDLE
mode and synchronize once we have a new message"""
self.parent = parent
self.folder = folder
self.stop_sig = Event()
@ -644,7 +647,7 @@ class IdleThread(object):
try:
imapobj.noop()
except imapobj.abort:
self.ui.warn('Attempting NOOP on dropped connection %s' % \
self.ui.warn('Attempting NOOP on dropped connection %s'%
imapobj.identifier)
self.parent.releaseconnection(imapobj, True)
imapobj = None

View File

@ -121,8 +121,7 @@ def imapsplit(imapstring):
arg = arg.replace('\\', '\\\\')
arg = arg.replace('"', '\\"')
arg = '"%s"' % arg
__debug("imapsplit() non-string [%d]: Appending %s" %\
(i, arg))
__debug("imapsplit() non-string [%d]: Appending %s"% (i, arg))
retval.append(arg)
else:
# Even -- we have a string that ends with a literal

View File

@ -23,6 +23,7 @@ import signal
import socket
import logging
from optparse import OptionParser
import offlineimap
from offlineimap import accounts, threadutil, syncmaster
from offlineimap import globals
@ -335,8 +336,8 @@ class OfflineImap:
" accounts are defined!"% account
else:
errormsg = "The account '%s' does not exist. Valid ac" \
"counts are: " % account
errormsg += ", ".join(allaccounts.keys())
"counts are: %s"% \
(account, ", ".join(allaccounts.keys()))
self.ui.terminate(1, errormsg=errormsg)
if account not in syncaccounts:
syncaccounts.append(account)

View File

@ -23,9 +23,7 @@ except:
pass
class LocalEval:
"""Here is a powerfull but very dangerous option, of course.
Assume source file to be ASCII encoded."""
"""Here is a powerfull but very dangerous option, of course."""
def __init__(self, path=None):
self.namespace = {}

View File

@ -167,6 +167,7 @@ class BaseRepository(CustomConfig.ConfigHelperMixin, object):
that forward and backward nametrans actually match up!
Configuring nametrans on BOTH repositories therefore could lead
to infinite folder creation cycles."""
if not self.get_create_folders() and not dst_repo.get_create_folders():
# quick exit if no folder creation is enabled on either side.
return

View File

@ -53,8 +53,8 @@ class LocalStatusRepository(BaseRepository):
self.LocalStatusFolderClass = self.backends[backend]['class']
else:
raise SyntaxWarning("Unknown status_backend '%s' for account '%s'" \
% (backend, self.account.name))
raise SyntaxWarning("Unknown status_backend '%s' for account '%s'"%
(backend, self.account.name))
def import_other_backend(self, folder):
for bk, dic in self.backends.items():
@ -68,8 +68,9 @@ class LocalStatusRepository(BaseRepository):
# if backend contains data, import it to folder.
if not folderbk.isnewfolder():
self.ui._msg('Migrating LocalStatus cache from %s to %s ' % (bk, self._backend) + \
'status folder for %s:%s' % (self.name, folder.name))
self.ui._msg('Migrating LocalStatus cache from %s to %s " \
"status folder for %s:%s'%
(bk, self._backend, self.name, folder.name))
folderbk.cachemessagelist()
folder.messagelist = folderbk.messagelist

View File

@ -32,7 +32,7 @@ class MaildirRepository(BaseRepository):
self.root = self.getlocalroot()
self.folders = None
self.ui = getglobalui()
self.debug("MaildirRepository initialized, sep is " + repr(self.getsep()))
self.debug("MaildirRepository initialized, sep is %s"% repr(self.getsep()))
self.folder_atimes = []
# Create the top-level folder if it doesn't exist
@ -128,6 +128,7 @@ class MaildirRepository(BaseRepository):
If necessary, scan and cache all foldernames to make sure that
we only return existing folders and that 2 calls with the same
name will return the same object."""
# getfolders() will scan and cache the values *if* necessary
folders = self.getfolders()
for f in folders:
@ -142,8 +143,9 @@ class MaildirRepository(BaseRepository):
:param root: (absolute) path to Maildir root
:param extension: (relative) subfolder to examine within root"""
self.debug("_GETFOLDERS_SCANDIR STARTING. root = %s, extension = %s" \
% (root, extension))
self.debug("_GETFOLDERS_SCANDIR STARTING. root = %s, extension = %s"%
(root, extension))
retval = []
# Configure the full path to this repository -- "toppath"

View File

@ -23,7 +23,7 @@ from offlineimap import banner
from offlineimap.ui.UIBase import UIBase
class TTYFormatter(logging.Formatter):
"""Specific Formatter that adds thread information to the log output"""
"""Specific Formatter that adds thread information to the log output."""
def __init__(self, *args, **kwargs):
#super() doesn't work in py2.6 as 'logging' uses old-style class
@ -31,7 +31,8 @@ class TTYFormatter(logging.Formatter):
self._last_log_thread = None
def format(self, record):
"""Override format to add thread information"""
"""Override format to add thread information."""
#super() doesn't work in py2.6 as 'logging' uses old-style class
log_str = logging.Formatter.format(self, record)
# If msg comes from a different thread than our last, prepend
@ -69,12 +70,12 @@ class TTYUI(UIBase):
return ch
def isusable(self):
"""TTYUI is reported as usable when invoked on a terminal"""
"""TTYUI is reported as usable when invoked on a terminal."""
return sys.stdout.isatty() and sys.stdin.isatty()
def getpass(self, accountname, config, errmsg=None):
"""TTYUI backend is capable of querying the password"""
"""TTYUI backend is capable of querying the password."""
if errmsg:
self.warn("%s: %s"% (accountname, errmsg))
@ -100,8 +101,7 @@ class TTYUI(UIBase):
This implementation in UIBase does not support this, but some
implementations return 0 for successful sleep and 1 for an
'abort', ie a request to sync immediately.
"""
'abort', ie a request to sync immediately."""
if sleepsecs > 0:
if remainingsecs//60 != (remainingsecs-sleepsecs)//60:

View File

@ -28,7 +28,8 @@ class DebuggingLock:
def acquire(self, blocking = 1):
self.print_tb("Acquire lock")
self.lock.acquire(blocking)
self.logmsg("===== %s: Thread %s acquired lock\n" % (self.name, currentThread().getName()))
self.logmsg("===== %s: Thread %s acquired lock\n"%
(self.name, currentThread().getName()))
def release(self):
self.print_tb("Release lock")