Reformat offlineimap/imapserver.py

Add some spaces, remove lines,... now format is better (lintian).
This commit is contained in:
Rodolfo García Peñas (kix) 2020-08-29 20:19:23 +02:00
parent 20a9837e26
commit b6a686e56f

View File

@ -34,9 +34,9 @@ import offlineimap.accounts
from offlineimap import imaplibutil, imaputil, threadutil, OfflineImapError from offlineimap import imaplibutil, imaputil, threadutil, OfflineImapError
from offlineimap.ui import getglobalui from offlineimap.ui import getglobalui
try: try:
import gssapi import gssapi
have_gss = True have_gss = True
except ImportError: except ImportError:
have_gss = False have_gss = False
@ -62,13 +62,13 @@ class IMAPServer(object):
self.preauth_tunnel = repos.getpreauthtunnel() self.preauth_tunnel = repos.getpreauthtunnel()
self.transport_tunnel = repos.gettransporttunnel() self.transport_tunnel = repos.gettransporttunnel()
if self.preauth_tunnel and self.transport_tunnel: if self.preauth_tunnel and self.transport_tunnel:
raise OfflineImapError('%s: '% repos + raise OfflineImapError('%s: ' % repos +
'you must enable precisely one ' 'you must enable precisely one '
'type of tunnel (preauth or transport), ' 'type of tunnel (preauth or transport), '
'not both', OfflineImapError.ERROR.REPO) 'not both', OfflineImapError.ERROR.REPO)
self.tunnel = \ self.tunnel = \
self.preauth_tunnel if self.preauth_tunnel \ self.preauth_tunnel if self.preauth_tunnel \
else self.transport_tunnel else self.transport_tunnel
self.username = \ self.username = \
None if self.preauth_tunnel else repos.getuser() None if self.preauth_tunnel else repos.getuser()
@ -94,18 +94,18 @@ class IMAPServer(object):
self.sslclientkey = repos.getsslclientkey() self.sslclientkey = repos.getsslclientkey()
self.sslcacertfile = repos.getsslcacertfile() self.sslcacertfile = repos.getsslcacertfile()
if self.sslcacertfile is None: if self.sslcacertfile is None:
self.__verifycert = None # Disable cert verification. self.__verifycert = None # Disable cert verification.
# This way of working sucks hard... # This way of working sucks hard...
self.fingerprint = repos.get_ssl_fingerprint() self.fingerprint = repos.get_ssl_fingerprint()
self.tlslevel = repos.gettlslevel() self.tlslevel = repos.gettlslevel()
self.sslversion = repos.getsslversion() self.sslversion = repos.getsslversion()
self.starttls = repos.getstarttls() self.starttls = repos.getstarttls()
if self.usessl \ if self.usessl \
and self.tlslevel != "tls_compat" \ and self.tlslevel != "tls_compat" \
and self.sslversion is None: and self.sslversion is None:
raise Exception("When 'tls_level' is not 'tls_compat' " raise Exception("When 'tls_level' is not 'tls_compat' "
"the 'ssl_version' must be set explicitly.") "the 'ssl_version' must be set explicitly.")
self.oauth2_refresh_token = repos.getoauth2_refresh_token() self.oauth2_refresh_token = repos.getoauth2_refresh_token()
self.oauth2_access_token = repos.getoauth2_access_token() self.oauth2_access_token = repos.getoauth2_access_token()
@ -164,32 +164,32 @@ class IMAPServer(object):
self.ui.warn("PySocks not installed, ignoring proxy option.") self.ui.warn("PySocks not installed, ignoring proxy option.")
except (AttributeError, ValueError) as e: except (AttributeError, ValueError) as e:
self.ui.warn("Bad proxy option %s for account %s: %s " self.ui.warn("Bad proxy option %s for account %s: %s "
"Ignoring %s option."% "Ignoring %s option." %
(proxy, self.repos.account.name, e, proxysection)) (proxy, self.repos.account.name, e, proxysection))
return dfltsocket return dfltsocket
def __getpassword(self): def __getpassword(self):
"""Returns the server password or None""" """Returns the server password or None"""
if self.goodpassword != None: # use cached good one first if self.goodpassword != None: # use cached good one first
return self.goodpassword return self.goodpassword
if self.password != None and self.passworderror == None: if self.password != None and self.passworderror == None:
return self.password # non-failed preconfigured one return self.password # non-failed preconfigured one
# get 1) configured password first 2) fall back to asking via UI # get 1) configured password first 2) fall back to asking via UI
self.password = self.repos.getpassword() or \ self.password = self.repos.getpassword() or \
self.ui.getpass(self.username, self.config, self.passworderror) self.ui.getpass(self.username, self.config, self.passworderror)
self.passworderror = None self.passworderror = None
return self.password return self.password
def __md5handler(self, response): def __md5handler(self, response):
challenge = response.strip() challenge = response.strip()
self.ui.debug('imap', '__md5handler: got challenge %s'% challenge) self.ui.debug('imap', '__md5handler: got challenge %s' % challenge)
passwd = self.__getpassword() passwd = self.__getpassword()
retval = self.username + ' ' + hmac.new(passwd, challenge).hexdigest() retval = self.username + ' ' + hmac.new(passwd, challenge).hexdigest()
self.ui.debug('imap', '__md5handler: returning %s'% retval) self.ui.debug('imap', '__md5handler: returning %s' % retval)
return retval return retval
def __loginauth(self, imapobj): def __loginauth(self, imapobj):
@ -205,7 +205,7 @@ class IMAPServer(object):
authc = self.username authc = self.username
if not authc: if not authc:
raise OfflineImapError("No username provided for '%s'" raise OfflineImapError("No username provided for '%s'"
% self.repos.getname(), % self.repos.getname(),
OfflineImapError.ERROR.REPO) OfflineImapError.ERROR.REPO)
passwd = self.__getpassword() passwd = self.__getpassword()
@ -216,7 +216,7 @@ class IMAPServer(object):
retval = NULL.join((authz, authc, passwd)) retval = NULL.join((authz, authc, passwd))
logsafe_retval = NULL.join((authz, authc, '(passwd hidden for log)')) logsafe_retval = NULL.join((authz, authc, '(passwd hidden for log)'))
self.ui.debug('imap', '__plainhandler: returning %s'% logsafe_retval) self.ui.debug('imap', '__plainhandler: returning %s' % logsafe_retval)
return retval return retval
def __xoauth2handler(self, response): def __xoauth2handler(self, response):
@ -229,8 +229,8 @@ class IMAPServer(object):
if self.oauth2_access_token is None: if self.oauth2_access_token is None:
if self.oauth2_request_url is None: if self.oauth2_request_url is None:
raise OfflineImapError("No remote oauth2_request_url for " raise OfflineImapError("No remote oauth2_request_url for "
"repository '%s' specified."% "repository '%s' specified." %
self, OfflineImapError.ERROR.REPO) self, OfflineImapError.ERROR.REPO)
# Generate new access token. # Generate new access token.
params = {} params = {}
@ -239,9 +239,9 @@ class IMAPServer(object):
params['refresh_token'] = self.oauth2_refresh_token params['refresh_token'] = self.oauth2_refresh_token
params['grant_type'] = 'refresh_token' params['grant_type'] = 'refresh_token'
self.ui.debug('imap', 'xoauth2handler: url "%s"'% self.ui.debug('imap', 'xoauth2handler: url "%s"' %
self.oauth2_request_url) self.oauth2_request_url)
self.ui.debug('imap', 'xoauth2handler: params "%s"'% params) self.ui.debug('imap', 'xoauth2handler: params "%s"' % params)
original_socket = socket.socket original_socket = socket.socket
socket.socket = self.authproxied_socket socket.socket = self.authproxied_socket
@ -250,30 +250,30 @@ class IMAPServer(object):
self.oauth2_request_url, urllib.parse.urlencode(params)).read() self.oauth2_request_url, urllib.parse.urlencode(params)).read()
except Exception as e: except Exception as e:
try: try:
msg = "%s (configuration is: %s)"% (e, str(params)) msg = "%s (configuration is: %s)" % (e, str(params))
except Exception as eparams: except Exception as eparams:
msg = "%s [cannot display configuration: %s]"% (e, eparams) msg = "%s [cannot display configuration: %s]" % (e, eparams)
six.reraise(type(e), type(e)(msg), exc_info()[2]) six.reraise(type(e), type(e)(msg), exc_info()[2])
finally: finally:
socket.socket = original_socket socket.socket = original_socket
resp = json.loads(response) resp = json.loads(response)
self.ui.debug('imap', 'xoauth2handler: response "%s"'% resp) self.ui.debug('imap', 'xoauth2handler: response "%s"' % resp)
if 'error' in resp: if 'error' in resp:
raise OfflineImapError("xoauth2handler got: %s"% resp, raise OfflineImapError("xoauth2handler got: %s" % resp,
OfflineImapError.ERROR.REPO) OfflineImapError.ERROR.REPO)
self.oauth2_access_token = resp['access_token'] self.oauth2_access_token = resp['access_token']
if 'expires_in' in resp: if 'expires_in' in resp:
self.oauth2_access_token_expires_at = now + datetime.timedelta( self.oauth2_access_token_expires_at = now + datetime.timedelta(
seconds=resp['expires_in']/2 seconds=resp['expires_in'] / 2
) )
self.ui.debug('imap', 'xoauth2handler: access_token "%s expires %s"'% ( self.ui.debug('imap', 'xoauth2handler: access_token "%s expires %s"' % (
self.oauth2_access_token, self.oauth2_access_token_expires_at)) self.oauth2_access_token, self.oauth2_access_token_expires_at))
auth_string = 'user=%s\1auth=Bearer %s\1\1'% ( auth_string = 'user=%s\1auth=Bearer %s\1\1' % (
self.username, self.oauth2_access_token) self.username, self.oauth2_access_token)
#auth_string = base64.b64encode(auth_string) # auth_string = base64.b64encode(auth_string)
self.ui.debug('imap', 'xoauth2handler: returning "%s"'% auth_string) self.ui.debug('imap', 'xoauth2handler: returning "%s"' % auth_string)
return auth_string return auth_string
# Perform the next step handling a GSSAPI connection. # Perform the next step handling a GSSAPI connection.
@ -330,25 +330,25 @@ class IMAPServer(object):
imapobj.starttls() imapobj.starttls()
except imapobj.error as e: except imapobj.error as e:
raise OfflineImapError("Failed to start " raise OfflineImapError("Failed to start "
"TLS connection: %s"% str(e), "TLS connection: %s" % str(e),
OfflineImapError.ERROR.REPO, None, exc_info()[2]) OfflineImapError.ERROR.REPO, None, exc_info()[2])
## All __authn_* procedures are helpers that do authentication. # All __authn_* procedures are helpers that do authentication.
## They are class methods that take one parameter, IMAP object. # They are class methods that take one parameter, IMAP object.
## #
## Each function should return True if authentication was # Each function should return True if authentication was
## successful and False if authentication wasn't even tried # successful and False if authentication wasn't even tried
## for some reason (but not when IMAP has no such authentication # for some reason (but not when IMAP has no such authentication
## capability, calling code checks that). # capability, calling code checks that).
## #
## Functions can also raise exceptions; two types are special # Functions can also raise exceptions; two types are special
## and will be handled by the calling code: # and will be handled by the calling code:
## #
## - imapobj.error means that there was some error that # - imapobj.error means that there was some error that
## comes from imaplib2; # comes from imaplib2;
## #
## - OfflineImapError means that function detected some # - OfflineImapError means that function detected some
## problem by itself. # problem by itself.
def __authn_gssapi(self, imapobj): def __authn_gssapi(self, imapobj):
if not have_gss: if not have_gss:
@ -388,8 +388,8 @@ class IMAPServer(object):
# (per RFC 2595) # (per RFC 2595)
if 'LOGINDISABLED' in imapobj.capabilities: if 'LOGINDISABLED' in imapobj.capabilities:
raise OfflineImapError("IMAP LOGIN is " raise OfflineImapError("IMAP LOGIN is "
"disabled by server. Need to use SSL?", "disabled by server. Need to use SSL?",
OfflineImapError.ERROR.REPO) OfflineImapError.ERROR.REPO)
else: else:
self.__loginauth(imapobj) self.__loginauth(imapobj)
return True return True
@ -415,11 +415,11 @@ class IMAPServer(object):
# - tryTLS flag, # - tryTLS flag,
# - check IMAP capability flag. # - check IMAP capability flag.
auth_methods = { auth_methods = {
"GSSAPI": (self.__authn_gssapi, False, True), "GSSAPI": (self.__authn_gssapi, False, True),
"XOAUTH2": (self.__authn_xoauth2, True, True), "XOAUTH2": (self.__authn_xoauth2, True, True),
"CRAM-MD5": (self.__authn_cram_md5, True, True), "CRAM-MD5": (self.__authn_cram_md5, True, True),
"PLAIN": (self.__authn_plain, True, True), "PLAIN": (self.__authn_plain, True, True),
"LOGIN": (self.__authn_login, True, False), "LOGIN": (self.__authn_login, True, False),
} }
# GSSAPI is tried first by default: we will probably go TLS after it and # GSSAPI is tried first by default: we will probably go TLS after it and
@ -427,7 +427,7 @@ class IMAPServer(object):
for m in self.authmechs: for m in self.authmechs:
if m not in auth_methods: if m not in auth_methods:
raise Exception("Bad authentication method %s, " raise Exception("Bad authentication method %s, "
"please, file OfflineIMAP bug" % m) "please, file OfflineIMAP bug" % m)
func, tryTLS, check_cap = auth_methods[m] func, tryTLS, check_cap = auth_methods[m]
@ -444,27 +444,27 @@ class IMAPServer(object):
tried_to_authn = True tried_to_authn = True
self.ui.debug('imap', 'Attempting ' self.ui.debug('imap', 'Attempting '
'%s authentication'% m) '%s authentication' % m)
try: try:
if func(imapobj): if func(imapobj):
return return
except (imapobj.error, OfflineImapError) as e: except (imapobj.error, OfflineImapError) as e:
self.ui.warn('%s authentication failed: %s'% (m, e)) self.ui.warn('%s authentication failed: %s' % (m, e))
exc_stack.append((m, e)) exc_stack.append((m, e))
if len(exc_stack): if len(exc_stack):
msg = "\n\t".join([": ".join((x[0], str(x[1]))) for x in exc_stack]) msg = "\n\t".join([": ".join((x[0], str(x[1]))) for x in exc_stack])
raise OfflineImapError("All authentication types " raise OfflineImapError("All authentication types "
"failed:\n\t%s"% msg, OfflineImapError.ERROR.REPO) "failed:\n\t%s" % msg, OfflineImapError.ERROR.REPO)
if not tried_to_authn: if not tried_to_authn:
methods = ", ".join([x[5:] for x in methods = ", ".join([x[5:] for x in
[x for x in imapobj.capabilities if x[0:5] == "AUTH="]]) [x for x in imapobj.capabilities if x[0:5] == "AUTH="]])
raise OfflineImapError("Repository %s: no supported " raise OfflineImapError("Repository %s: no supported "
"authentication mechanisms found; configured %s, " "authentication mechanisms found; configured %s, "
"server advertises %s"% (self.repos, "server advertises %s" % (self.repos,
", ".join(self.authmechs), methods), ", ".join(self.authmechs), methods),
OfflineImapError.ERROR.REPO) OfflineImapError.ERROR.REPO)
def __verifycert(self, cert, hostname): def __verifycert(self, cert, hostname):
"""Verify that cert (in socket.getpeercert() format) matches hostname. """Verify that cert (in socket.getpeercert() format) matches hostname.
@ -474,7 +474,7 @@ class IMAPServer(object):
errstr = "CA Cert verifying failed: " errstr = "CA Cert verifying failed: "
if not cert: if not cert:
return ('%s no certificate received'% errstr) return ('%s no certificate received' % errstr)
dnsname = hostname.lower() dnsname = hostname.lower()
certnames = [] certnames = []
@ -482,7 +482,7 @@ class IMAPServer(object):
notafter = cert.get('notAfter') notafter = cert.get('notAfter')
if notafter: if notafter:
if time.time() >= cert_time_to_seconds(notafter): if time.time() >= cert_time_to_seconds(notafter):
return '%s certificate expired %s'% (errstr, notafter) return '%s certificate expired %s' % (errstr, notafter)
# First read commonName # First read commonName
for s in cert.get('subject', []): for s in cert.get('subject', []):
@ -490,7 +490,7 @@ class IMAPServer(object):
if key == 'commonName': if key == 'commonName':
certnames.append(value.lower()) certnames.append(value.lower())
if len(certnames) == 0: if len(certnames) == 0:
return ('%s no commonName found in certificate'% errstr) return ('%s no commonName found in certificate' % errstr)
# Then read subjectAltName # Then read subjectAltName
for key, value in cert.get('subjectAltName', []): for key, value in cert.get('subjectAltName', []):
@ -500,10 +500,10 @@ class IMAPServer(object):
# And finally try to match hostname with one of these names # And finally try to match hostname with one of these names
for certname in certnames: for certname in certnames:
if (certname == dnsname or if (certname == dnsname or
'.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]): '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1]):
return None return None
return ('%s no matching domain name found in certificate'% errstr) return ('%s no matching domain name found in certificate' % errstr)
def acquireconnection(self): def acquireconnection(self):
"""Fetches a connection from the pool, making sure to create a new one """Fetches a connection from the pool, making sure to create a new one
@ -516,7 +516,7 @@ class IMAPServer(object):
curThread = currentThread() curThread = currentThread()
imapobj = None imapobj = None
if len(self.availableconnections): # One is available. if len(self.availableconnections): # One is available.
# Try to find one that previously belonged to this thread # Try to find one that previously belonged to this thread
# as an optimization. Start from the back since that's where # as an optimization. Start from the back since that's where
# they're popped on. # they're popped on.
@ -524,17 +524,17 @@ class IMAPServer(object):
tryobj = self.availableconnections[i] tryobj = self.availableconnections[i]
if self.lastowner[tryobj] == curThread.ident: if self.lastowner[tryobj] == curThread.ident:
imapobj = tryobj imapobj = tryobj
del(self.availableconnections[i]) del (self.availableconnections[i])
break break
if not imapobj: if not imapobj:
imapobj = self.availableconnections[0] imapobj = self.availableconnections[0]
del(self.availableconnections[0]) del (self.availableconnections[0])
self.assignedconnections.append(imapobj) self.assignedconnections.append(imapobj)
self.lastowner[imapobj] = curThread.ident self.lastowner[imapobj] = curThread.ident
self.connectionlock.release() self.connectionlock.release()
return imapobj return imapobj
self.connectionlock.release() # Release until need to modify data self.connectionlock.release() # Release until need to modify data
# Must be careful here that if we fail we should bail out gracefully # Must be careful here that if we fail we should bail out gracefully
# and release locks / threads so that the next attempt can try... # and release locks / threads so that the next attempt can try...
@ -549,13 +549,13 @@ class IMAPServer(object):
self.tunnel, self.tunnel,
timeout=socket.getdefaulttimeout(), timeout=socket.getdefaulttimeout(),
use_socket=self.proxied_socket, use_socket=self.proxied_socket,
) )
success = True success = True
elif self.usessl: elif self.usessl:
self.ui.connecting( self.ui.connecting(
self.repos.getname(), self.hostname, self.port) self.repos.getname(), self.hostname, self.port)
self.ui.debug('imap', "%s: level '%s', version '%s'"% self.ui.debug('imap', "%s: level '%s', version '%s'" %
(self.repos.getname(), self.tlslevel, self.sslversion)) (self.repos.getname(), self.tlslevel, self.sslversion))
imapobj = imaplibutil.WrappedIMAP4_SSL( imapobj = imaplibutil.WrappedIMAP4_SSL(
host=self.hostname, host=self.hostname,
port=self.port, port=self.port,
@ -569,7 +569,7 @@ class IMAPServer(object):
use_socket=self.proxied_socket, use_socket=self.proxied_socket,
tls_level=self.tlslevel, tls_level=self.tlslevel,
af=self.af, af=self.af,
) )
else: else:
self.ui.connecting( self.ui.connecting(
self.repos.getname(), self.hostname, self.port) self.repos.getname(), self.hostname, self.port)
@ -578,7 +578,7 @@ class IMAPServer(object):
timeout=socket.getdefaulttimeout(), timeout=socket.getdefaulttimeout(),
use_socket=self.proxied_socket, use_socket=self.proxied_socket,
af=self.af, af=self.af,
) )
if not self.preauth_tunnel: if not self.preauth_tunnel:
try: try:
@ -608,12 +608,12 @@ class IMAPServer(object):
# No Folders were returned. This occurs, e.g. if the # No Folders were returned. This occurs, e.g. if the
# 'reference' prefix does not exist on the mail # 'reference' prefix does not exist on the mail
# server. Raise exception. # server. Raise exception.
err = "Server '%s' returned no folders in '%s'"% \ err = "Server '%s' returned no folders in '%s'" % \
(self.repos.getname(), self.reference) (self.repos.getname(), self.reference)
self.ui.warn(err) self.ui.warn(err)
raise Exception(err) raise Exception(err)
self.delim, self.root = \ self.delim, self.root = \
imaputil.imapsplit(listres[0])[1:] imaputil.imapsplit(listres[0])[1:]
self.delim = imaputil.dequote(self.delim) self.delim = imaputil.dequote(self.delim)
self.root = imaputil.dequote(self.root) self.root = imaputil.dequote(self.root)
@ -630,11 +630,11 @@ class IMAPServer(object):
severity = OfflineImapError.ERROR.REPO severity = OfflineImapError.ERROR.REPO
if type(e) == gaierror: if type(e) == gaierror:
#DNS related errors. Abort Repo sync # DNS related errors. Abort Repo sync
#TODO: special error msg for e.errno == 2 "Name or service not known"? # TODO: special error msg for e.errno == 2 "Name or service not known"?
reason = "Could not resolve name '%s' for repository "\ reason = "Could not resolve name '%s' for repository " \
"'%s'. Make sure you have configured the ser"\ "'%s'. Make sure you have configured the ser" \
"ver name correctly and that you are online."%\ "ver name correctly and that you are online." % \
(self.hostname, self.repos) (self.hostname, self.repos)
six.reraise(OfflineImapError, six.reraise(OfflineImapError,
OfflineImapError(reason, severity), OfflineImapError(reason, severity),
@ -644,14 +644,14 @@ class IMAPServer(object):
# SSL unknown protocol error # SSL unknown protocol error
# happens e.g. when connecting via SSL to a non-SSL service # happens e.g. when connecting via SSL to a non-SSL service
if self.port != 993: if self.port != 993:
reason = "Could not connect via SSL to host '%s' and non-s"\ reason = "Could not connect via SSL to host '%s' and non-s" \
"tandard ssl port %d configured. Make sure you connect"\ "tandard ssl port %d configured. Make sure you connect" \
" to the correct port. Got: %s"% ( " to the correct port. Got: %s" % (
self.hostname, self.port, e) self.hostname, self.port, e)
else: else:
reason = "Unknown SSL protocol connecting to host '%s' for "\ reason = "Unknown SSL protocol connecting to host '%s' for " \
"repository '%s'. OpenSSL responded:\n%s"\ "repository '%s'. OpenSSL responded:\n%s" \
% (self.hostname, self.repos, e) % (self.hostname, self.repos, e)
six.reraise(OfflineImapError, six.reraise(OfflineImapError,
OfflineImapError(reason, severity), OfflineImapError(reason, severity),
exc_info()[2]) exc_info()[2])
@ -659,10 +659,10 @@ class IMAPServer(object):
elif isinstance(e, socket.error) and e.args[0] == errno.ECONNREFUSED: elif isinstance(e, socket.error) and e.args[0] == errno.ECONNREFUSED:
# "Connection refused", can be a non-existing port, or an unauthorized # "Connection refused", can be a non-existing port, or an unauthorized
# webproxy (open WLAN?) # webproxy (open WLAN?)
reason = "Connection to host '%s:%d' for repository '%s' was "\ reason = "Connection to host '%s:%d' for repository '%s' was " \
"refused. Make sure you have the right host and port "\ "refused. Make sure you have the right host and port " \
"configured and that you are actually able to access the "\ "configured and that you are actually able to access the " \
"network."% (self.hostname, self.port, self.repos) "network." % (self.hostname, self.port, self.repos)
six.reraise(OfflineImapError, six.reraise(OfflineImapError,
OfflineImapError(reason, severity), OfflineImapError(reason, severity),
exc_info()[2]) exc_info()[2])
@ -672,8 +672,7 @@ class IMAPServer(object):
six.reraise(OfflineImapError, six.reraise(OfflineImapError,
OfflineImapError( OfflineImapError(
"Could not connect to remote server '%s' " "Could not connect to remote server '%s' "
"for repository '%s'. Remote does not answer."% "for repository '%s'. Remote does not answer." % (self.hostname, self.repos),
(self.hostname, self.repos),
OfflineImapError.ERROR.REPO), OfflineImapError.ERROR.REPO),
exc_info()[2]) exc_info()[2])
else: else:
@ -690,7 +689,7 @@ class IMAPServer(object):
It's OK if we have maxconnections + 1 or 2 threads, which is what this It's OK if we have maxconnections + 1 or 2 threads, which is what this
will help us do.""" will help us do."""
self.semaphore.acquire() # Blocking until maxconnections has free slots. self.semaphore.acquire() # Blocking until maxconnections has free slots.
self.semaphore.release() self.semaphore.release()
def close(self): def close(self):
@ -728,8 +727,8 @@ class IMAPServer(object):
threads = [] threads = []
for i in range(numconnections): for i in range(numconnections):
self.ui.debug('imap', 'keepalive: processing connection %d of %d'% self.ui.debug('imap', 'keepalive: processing connection %d of %d' %
(i, numconnections)) (i, numconnections))
if len(self.idlefolders) > i: if len(self.idlefolders) > i:
# IDLE thread # IDLE thread
idler = IdleThread(self, self.idlefolders[i]) idler = IdleThread(self, self.idlefolders[i])
@ -751,7 +750,6 @@ class IMAPServer(object):
self.ui.debug('imap', 'keepalive: event is set; exiting') self.ui.debug('imap', 'keepalive: event is set; exiting')
return return
def releaseconnection(self, connection, drop_conn=False): def releaseconnection(self, connection, drop_conn=False):
"""Releases a connection, returning it to the pool. """Releases a connection, returning it to the pool.
@ -759,7 +757,7 @@ class IMAPServer(object):
not be reused. This can be used to indicate broken connections.""" not be reused. This can be used to indicate broken connections."""
if connection is None: if connection is None:
return # Noop on bad connection. return # Noop on bad connection.
self.connectionlock.acquire() self.connectionlock.acquire()
self.assignedconnections.remove(connection) self.assignedconnections.remove(connection)
@ -808,14 +806,14 @@ class IdleThread(object):
try: try:
imapobj.noop() imapobj.noop()
except imapobj.abort: except imapobj.abort:
self.ui.warn('Attempting NOOP on dropped connection %s'% self.ui.warn('Attempting NOOP on dropped connection %s' %
imapobj.identifier) imapobj.identifier)
self.parent.releaseconnection(imapobj, True) self.parent.releaseconnection(imapobj, True)
imapobj = None imapobj = None
finally: finally:
if imapobj: if imapobj:
self.parent.releaseconnection(imapobj) self.parent.releaseconnection(imapobj)
self.stop_sig.wait() # wait until we are supposed to quit self.stop_sig.wait() # wait until we are supposed to quit
def __dosync(self): def __dosync(self):
remoterepos = self.parent.repos remoterepos = self.parent.repos
@ -832,7 +830,7 @@ class IdleThread(object):
account.callhook(hook) account.callhook(hook)
ui = getglobalui() ui = getglobalui()
ui.unregisterthread(currentThread()) #syncfolder registered the thread ui.unregisterthread(currentThread()) # syncfolder registered the thread
def __idle(self): def __idle(self):
"""Invoke IDLE mode until timeout or self.stop() is invoked.""" """Invoke IDLE mode until timeout or self.stop() is invoked."""
@ -849,7 +847,7 @@ class IdleThread(object):
if exc_data is None and not self.stop_sig.isSet(): if exc_data is None and not self.stop_sig.isSet():
# No Exception, and we are not supposed to stop: # No Exception, and we are not supposed to stop:
self.needsync = True self.needsync = True
self.stop_sig.set() # Continue to sync. self.stop_sig.set() # Continue to sync.
def noop(imapobj): def noop(imapobj):
"""Factorize the noop code.""" """Factorize the noop code."""
@ -858,17 +856,16 @@ class IdleThread(object):
# End IDLE mode with noop, imapobj can point to a dropped conn. # End IDLE mode with noop, imapobj can point to a dropped conn.
imapobj.noop() imapobj.noop()
except imapobj.abort: except imapobj.abort:
self.ui.warn('Attempting NOOP on dropped connection %s'% self.ui.warn('Attempting NOOP on dropped connection %s' %
imapobj.identifier) imapobj.identifier)
self.parent.releaseconnection(imapobj, True) self.parent.releaseconnection(imapobj, True)
else: else:
self.parent.releaseconnection(imapobj) self.parent.releaseconnection(imapobj)
while not self.stop_sig.isSet(): while not self.stop_sig.isSet():
self.needsync = False self.needsync = False
success = False # Successfully selected FOLDER? success = False # Successfully selected FOLDER?
while not success: while not success:
imapobj = self.parent.acquireconnection() imapobj = self.parent.acquireconnection()
try: try:
@ -890,9 +887,9 @@ class IdleThread(object):
imapobj.idle(callback=callback) imapobj.idle(callback=callback)
else: else:
self.ui.warn("IMAP IDLE not supported on server '%s'." self.ui.warn("IMAP IDLE not supported on server '%s'."
"Sleep until next refresh cycle."% imapobj.identifier) "Sleep until next refresh cycle." % imapobj.identifier)
noop(imapobj) #XXX: why? noop(imapobj) # XXX: why?
self.stop_sig.wait() # self.stop() or IDLE callback are invoked. self.stop_sig.wait() # self.stop() or IDLE callback are invoked.
noop(imapobj) noop(imapobj)
if self.needsync: if self.needsync: