[PATCH] Remove superfluous class ConfigedIMAPServer

Sebastian Spaeth Sebastian at SSpaeth.de
Thu Aug 11 11:38:47 BST 2011


Remove a level of wrapper abstraction that is not needed. Just use
IMAPserver and be done with it.

We do this by passing in the IMAPRepository() instance rather than a
long list of single paramters to the IMAPServer instanciation. This way
we can retrieve all repository parameters ourselves, rather than passing
a dozen paramters into IMAPServer. Also, this enables us to pass the
repository() object into our WrappedIMAP4() instance, so that it can
query, e.g. the SSL fingerprint configuration.

Signed-off-by: Sebastian Spaeth <Sebastian at SSpaeth.de>
---
 Changelog.draft.rst            |    4 +-
 offlineimap/imapserver.py      |  136 ++++++++++++++++------------------------
 offlineimap/repository/IMAP.py |    2 +-
 3 files changed, 58 insertions(+), 84 deletions(-)

diff --git a/Changelog.draft.rst b/Changelog.draft.rst
index 3d20bcf..67cc3fc 100644
--- a/Changelog.draft.rst
+++ b/Changelog.draft.rst
@@ -16,10 +16,12 @@ New Features
 Changes
 -------
 
+* Refactor our IMAPServer class. Background work without user-visible
+  changes.
+
 Bug Fixes
 ---------
 
-
 * We protect more robustly against asking for inexistent messages from the
   IMAP server, when someone else deletes or moves messages while we sync.
 
diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py
index 10492cd..1736c94 100644
--- a/offlineimap/imapserver.py
+++ b/offlineimap/imapserver.py
@@ -37,58 +37,56 @@ except ImportError:
     pass
 
 class IMAPServer:
+    """Initializes all variables from an IMAPRepository() instance
+
+    Various functions, such as acquireconnection() return an IMAP4
+    object on which we can operate."""
     GSS_STATE_STEP = 0
     GSS_STATE_WRAP = 1
-    def __init__(self, config, reposname,
-                 username = None, password = None, hostname = None,
-                 port = None, ssl = 1, maxconnections = 1, tunnel = None,
-                 reference = '""', sslclientcert = None, sslclientkey = None,
-                 sslcacertfile = None, idlefolders = []):
+    def __init__(self, repos):
         self.ui = getglobalui()
-        self.reposname = reposname
-        self.config = config
-        self.username = username
-        self.password = password
+        self.repos = repos
+        self.config = repos.getconfig()
+        self.tunnel = repos.getpreauthtunnel()
+        self.usessl = repos.getssl()
+        self.username = repos.getuser()
+        self.password = None
         self.passworderror = None
         self.goodpassword = None
-        self.hostname = hostname
-        self.tunnel = tunnel
-        self.port = port
-        self.usessl = ssl
-        self.sslclientcert = sslclientcert
-        self.sslclientkey = sslclientkey
-        self.sslcacertfile = sslcacertfile
+        self.hostname = repos.gethost()
+        self.port = repos.getport()
+        if self.port == None:
+            self.port = 993 if self.usessl else 143
+        self.sslclientcert = repos.getsslclientcert()
+        self.sslclientkey = repos.getsslclientkey()
+        self.sslcacertfile = repos.getsslcacertfile()
         self.delim = None
         self.root = None
-        if port == None:
-            if ssl:
-                self.port = 993
-            else:
-                self.port = 143
-        self.maxconnections = maxconnections
+        self.maxconnections = repos.getmaxconnections()
         self.availableconnections = []
         self.assignedconnections = []
         self.lastowner = {}
         self.semaphore = BoundedSemaphore(self.maxconnections)
         self.connectionlock = Lock()
-        self.reference = reference
-        self.idlefolders = idlefolders
+        self.reference = repos.getreference()
+        self.idlefolders = repos.getidlefolders()
         self.gss_step = self.GSS_STATE_STEP
         self.gss_vc = None
         self.gssapi = False
 
     def getpassword(self):
-        if self.goodpassword != None:
+        """Returns the server password or None"""
+        if self.goodpassword != None: # use cached good one first
             return self.goodpassword
 
         if self.password != None and self.passworderror == None:
-            return self.password
+            return self.password # non-failed preconfigured one
 
-        self.password = self.ui.getpass(self.reposname,
-                                                     self.config,
-                                                     self.passworderror)
+        # get 1) configured password first 2) fall back to asking via UI
+        self.password = self.repos.getpassword() or \
+                        self.ui.getpass(self.repos.getname(), self.config,
+                                        self.passworderror)
         self.passworderror = None
-
         return self.password
 
     def getdelim(self):
@@ -199,7 +197,8 @@ class IMAPServer:
                     success = 1
                 elif self.usessl:
                     self.ui.connecting(self.hostname, self.port)
-                    imapobj = imaplibutil.WrappedIMAP4_SSL(self.hostname, self.port,
+                    imapobj = imaplibutil.WrappedIMAP4_SSL(self.hostname,
+                                                           self.port,
                                                            self.sslclientkey, self.sslclientcert,
                                                            timeout=socket.getdefaulttimeout(),
                                                            cacertfile = self.sslcacertfile)
@@ -248,7 +247,6 @@ class IMAPServer:
                     except imapobj.error, val:
                         self.passworderror = str(val)
                         raise
-                        #self.password = None
 
             if self.delim == None:
                 listres = imapobj.list(self.reference, '""')[1]
@@ -280,8 +278,6 @@ class IMAPServer:
             error..."""
             self.semaphore.release()
 
-            #Make sure that this can be retried the next time...
-            self.passworderror = None
             if(self.connectionlock.locked()):
                 self.connectionlock.release()
 
@@ -292,14 +288,36 @@ class IMAPServer:
                 reason = "Could not resolve name '%s' for repository "\
                          "'%s'. Make sure you have configured the ser"\
                          "ver name correctly and that you are online."\
-                         % (self.hostname, self.reposname)
+                         % (self.hostname, self.repos)
+                raise OfflineImapError(reason, severity)
+
+            elif isinstance(e, SSLError) and e.errno == 1:
+                # SSL unknown protocol error
+                # happens e.g. when connecting via SSL to a non-SSL service
+                if self.port != 443:
+                    reason = "Could not connect via SSL to host '%s' and non-s"\
+                        "tandard ssl port %d configured. Make sure you connect"\
+                        " to the correct port." % (self.hostname, self.port)
+                else:
+                    reason = "Unknown SSL protocol connecting to host '%s' for"\
+                         "repository '%s'. OpenSSL responded:\n%s"\
+                         % (self.hostname, self.repos, e)
+                raise OfflineImapError(reason, severity)
+
+            elif isinstance(e, socket.error) and e.args[0] == errno.ECONNREFUSED:
+                # "Connection refused", can be a non-existing port, or an unauthorized
+                # webproxy (open WLAN?)
+                reason = "Connection to host '%s:%d' for repository '%s' was "\
+                    "refused. Make sure you have the right host and port "\
+                    "configured and that you are actually able to access the "\
+                    "network." % (self.hostname, self.port, self.repos)
                 raise OfflineImapError(reason, severity)
             # Could not acquire connection to the remote;
             # socket.error(last_error) raised
             if str(e)[:24] == "can't open socket; error":
                 raise OfflineImapError("Could not connect to remote server '%s' "\
                     "for repository '%s'. Remote does not answer."
-                    % (self.hostname, self.reposname),
+                    % (self.hostname, self.repos),
                     OfflineImapError.ERROR.REPO)
             else:
                 # re-raise all other errors
@@ -451,49 +469,3 @@ class IdleThread(object):
             if self.needsync:
                 self.event.clear()
                 self.dosync()
-
-class ConfigedIMAPServer(IMAPServer):
-    """This class is designed for easier initialization given a ConfigParser
-    object and an account name.  The passwordhash is used if
-    passwords for certain accounts are known.  If the password for this
-    account is listed, it will be obtained from there."""
-    def __init__(self, repository, passwordhash = {}):
-        """Initialize the object.  If the account is not a tunnel,
-        the password is required."""
-        self.repos = repository
-        self.config = self.repos.getconfig()
-        usetunnel = self.repos.getpreauthtunnel()
-        if not usetunnel:
-            host = self.repos.gethost()
-            user = self.repos.getuser()
-            port = self.repos.getport()
-            ssl = self.repos.getssl()
-            sslclientcert = self.repos.getsslclientcert()
-            sslclientkey = self.repos.getsslclientkey()
-            sslcacertfile = self.repos.getsslcacertfile()
-        reference = self.repos.getreference()
-        idlefolders = self.repos.getidlefolders()
-        server = None
-        password = None
-        
-        if repository.getname() in passwordhash:
-            password = passwordhash[repository.getname()]
-
-        # Connect to the remote server.
-        if usetunnel:
-            IMAPServer.__init__(self, self.config, self.repos.getname(),
-                                tunnel = usetunnel,
-                                reference = reference,
-                                idlefolders = idlefolders,
-                                maxconnections = self.repos.getmaxconnections())
-        else:
-            if not password:
-                password = self.repos.getpassword()
-            IMAPServer.__init__(self, self.config, self.repos.getname(),
-                                user, password, host, port, ssl,
-                                self.repos.getmaxconnections(),
-                                reference = reference,
-                                idlefolders = idlefolders,
-                                sslclientcert = sslclientcert,
-                                sslclientkey = sslclientkey,
-                                sslcacertfile = sslcacertfile)
diff --git a/offlineimap/repository/IMAP.py b/offlineimap/repository/IMAP.py
index 82d9e32..f120d19 100644
--- a/offlineimap/repository/IMAP.py
+++ b/offlineimap/repository/IMAP.py
@@ -33,7 +33,7 @@ class IMAPRepository(BaseRepository):
         BaseRepository.__init__(self, reposname, account)
         # self.ui is being set by the BaseRepository
         self._host = None
-        self.imapserver = imapserver.ConfigedIMAPServer(self)
+        self.imapserver = imapserver.IMAPServer(self)
         self.folders = None
         self.nametrans = lambda foldername: foldername
         self.folderfilter = lambda foldername: 1
-- 
1.7.4.1





More information about the OfflineIMAP-project mailing list