Reformat offlineimap/imapserver.py
Add some spaces, remove lines,... now format is better (lintian).
This commit is contained in:
parent
20a9837e26
commit
b6a686e56f
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user