offlineimap rev 569

"Automatic Subversion Change Mailer" <[email protected]> Fri, 15 Aug 2003 13:51:17 -0500 (CDT)
Newsgroups gmane.mail.imap.offlineimap.subversion
Message-ID <[email protected]>
You are receiving this message because
all commits get sent to this address.

Author: jgoerzen
Date: 2003-08-15 13:50:54 -0500 (Fri, 15 Aug 2003)
New Revision: 569

Modified:
  offlineimap/branches/twisted/offlineimap/accounts.py
  offlineimap/branches/twisted/offlineimap/folder/Base.py
  offlineimap/branches/twisted/offlineimap/folder/IMAP.py
  offlineimap/branches/twisted/offlineimap/folder/LocalStatus.py
  offlineimap/branches/twisted/offlineimap/folder/Maildir.py
  offlineimap/branches/twisted/offlineimap/imapserver.py
  offlineimap/branches/twisted/offlineimap/repository/Base.py
  offlineimap/branches/twisted/offlineimap/repository/IMAP.py
  offlineimap/branches/twisted/offlineimap/repository/Maildir.py
  offlineimap/branches/twisted/offlineimap/twistedutil.py
  offlineimap/branches/twisted/offlineimap/ui/TTY.py
  offlineimap/branches/twisted/offlineimap/ui/UIBase.py
  offlineimap/branches/twisted/offlineimap.sgml

Log:
Helped out the implementation of password prompting.  It now works better,
and expects a Deferred back from the UI module.

Moved rd() from imaputil to twistedutil() so that modules that want just
that don't have to import a whole big chunk of IMAP-related junk.

Added new debug type 'traffic' and documented it in offlineimap.sgml.


Diff:
Modified: offlineimap/branches/twisted/offlineimap/accounts.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/accounts.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/accounts.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -20,7 +20,7 @@
 from offlineimap.ui import UIBase
 import os
 from twisted.internet import defer
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 
 
 def getaccountlist(customconfig):

Modified: offlineimap/branches/twisted/offlineimap/folder/Base.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/folder/Base.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/folder/Base.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -19,7 +19,7 @@
 from threading import *
 from offlineimap.ui import UIBase
 import os.path, re
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 from twisted.internet import defer
 
 class BaseFolder:

Modified: offlineimap/branches/twisted/offlineimap/folder/IMAP.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/folder/IMAP.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/folder/IMAP.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -24,7 +24,7 @@
 from copy import copy
 from twisted.internet import defer
 from twisted.protocols.imap4 import Query
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 
 class IMAPFolder(BaseFolder, imaputil.AcquireMixin):
 

Modified: offlineimap/branches/twisted/offlineimap/folder/LocalStatus.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/folder/LocalStatus.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/folder/LocalStatus.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -18,7 +18,7 @@
 
 from Base import BaseFolder
 import os, threading
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 
 magicline = "OFFLINEIMAP LocalStatus CACHE DATA - DO NOT MODIFY - FORMAT 1"
 

Modified: offlineimap/branches/twisted/offlineimap/folder/Maildir.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/folder/Maildir.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/folder/Maildir.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -21,7 +21,7 @@
 from offlineimap.ui import UIBase
 from threading import Lock
 import os.path, os, re, time, socket, md5
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 
 
 foldermatchre = re.compile(',FMD5=([0-9a-f]{32})')

Modified: offlineimap/branches/twisted/offlineimap/imapserver.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/imapserver.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/imapserver.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -21,28 +21,34 @@
 import thread, hmac, os
 from twisted.internet import defer, protocol, reactor
 #from twisted.protocols.imap4 import IMAP4Client
-from twistedfixes.imap4 import IMAP4Client
+from twistedfixes.imap4 import IMAP4Client, IMAP4Exception
 from twisted.internet.ssl import ClientContextFactory
 from imaputil import rd
 import re
 
 def getname(object):
+    "Utility function designed to return a unique name for a given IMAP object."
+    
     name = str(object)
     return re.search(r'instance at 0x([0-9A-Za-z]+)>', name).group(1)
 
 class MyIMAP(IMAP4Client):
+    """This class adds a few debugging and processing features to the standard
+    Twisted IMAP4Client class."""
     def connectionMade(self):
-        #print "Connectionmade."
+        "Call us back once we're connected."
         self.factory.imapserver.connectionMade(self)
 
     def sendLine(self, line):
+        "Hook to log outbound traffic if debugging."
         ui = UIBase.getglobalui()
-        ui.debug('imap', getname(self) + ' Send: ' + str(line))
+        ui.debug('traffic', getname(self) + ' Send: ' + str(line))
         return IMAP4Client.sendLine(self, line)
 
     def lineReceived(self, line):
+        "Hook to log inbound traffic if debugging."
         ui = UIBase.getglobalui()
-        ui.debug('imap', getname(self) + ' Recv: ' + str(line))
+        ui.debug('traffic', getname(self) + ' Recv: ' + str(line))
         return IMAP4Client.lineReceived(self, line)
 
 
@@ -69,6 +75,10 @@
     protocol = IMAP4Client
 
 class IMAPServer:
+    """This class is designed to handle information necessary to keep track of
+    a connection or connections to a particular IMAP server.  It maintains
+    the pool of connections from which clients can request an open one, among
+    other things."""
     def __init__(self, config, reposname,
                  username = None, password = None, hostname = None,
                  port = None, ssl = 1, maxconnections = 1, tunnel = None,
@@ -98,18 +108,41 @@
         #self.semaphore = BoundedSemaphore(self.maxconnections)
         self.connectionlock = Lock()
         self.reference = reference
+        self.deferpassword = None
 
     def getpassword(self):
+        """Called to read in a password from the user, or use
+        a cached one if available.  Returns a Deferred that gets
+        called with the password.
+
+        ALL CALLBACKS ON THIS CHAIN MUST RETURN THE PASSWORD
+        AS IT WAS PASSED IN."""
+
         if self.password != None and self.passworderror == None:
-            return self.password
+            # We already have a valid password.  Just return it.
+            return rd(self.password)
 
-        self.password = UIBase.getglobalui().getpass(self.reposname,
-                                                     self.config,
-                                                     self.passworderror)
-        self.passworderror = None
+        if self.deferpassword != None:
+            # Another call to getpassword() is pending.  Let the caller
+            # chain on to it.
+            return self.deferpassword
 
-        return self.password
+        d = UIBase.getglobalui().getpass(self.reposname, self.config,
+                                         self.passworderror)
+        self.deferpassword = d
+        d.addCallback(self.cachepassword)
+        return d
 
+    def cachepassword(self, password):
+        """Called by the deferred from getpassword() to store the
+        user-supplied password for future uses.  Returns the password
+        so that callbacks from getpassword() can still get it the normal
+        way."""
+        self.password = password
+        self.passworderror = None       # Reset this before going on.
+        self.deferpassword = None       # Ditto.
+        return password
+    
     def getdelim(self):
         """Returns this server's folder delimiter.  Can only be called
         after one or more calls to acquireconnection."""
@@ -140,10 +173,15 @@
         return retval
 
     def plainauth(self, imapobj):
+        d = self.getpassword()
+        d.addCallback(self.plainauth_worker, imapobj)
+        return d
+
+    def plainauth_worker(self, password, imapobj):
         UIBase.getglobalui().debug('imap',
                                    'Attempting plain authentication')
         #print "imapobj is", imapobj
-        d = imapobj.login(self.username, self.getpassword())
+        d = imapobj.login(self.username, password)
         d.addErrback(self.plainautherror, imapobj)
         #print "reference is", self.reference
         d.addCallback(self.listcallback, imapobj, self.reference, '')
@@ -152,6 +190,12 @@
         d.addCallback(lambda x, imap: self._handleAvailableConnection(imap),
                       imapobj)
 
+    def plainautherror(self, error, imapobj):
+        error.trap(IMAP4Exception)
+        UIBase.getglobalui().warn(error.getErrorMessage())
+        self.passworderror = str(error.getErrorMessage())
+        return self.plainauth(imapobj)
+
     def _opened(self, discard = None):
         #print "opened"
         self.openingcount -= 1
@@ -177,10 +221,6 @@
             #print "listres is", listres
             self.delim, self.root = listres[0][1:]
 
-    def plainautherror(self, error, imapobj):
-        UIBase.getglobalui().warn(str(error))
-        self.plainauth(imapobj)
-
     def acquireconnection(self, d):
         """Fetches a connection from the pool, making sure to create a new one
         if needed, to obey the maximum connection limits, etc.

Modified: offlineimap/branches/twisted/offlineimap/repository/Base.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/repository/Base.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/repository/Base.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -19,7 +19,7 @@
 from offlineimap import CustomConfig
 import os.path
 from twisted.internet import defer
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 
 def LoadRepository(name, account, reqtype):
     from offlineimap.repository.IMAP import IMAPRepository, MappedIMAPRepository

Modified: offlineimap/branches/twisted/offlineimap/repository/IMAP.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/repository/IMAP.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/repository/IMAP.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -20,7 +20,7 @@
 from offlineimap import folder, imaputil, imapserver
 from offlineimap.folder.UIDMaps import MappedIMAPFolder
 import re, types, os
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 from twisted.internet import defer
 
 class IMAPRepository(BaseRepository, imaputil.AcquireMixin):

Modified: offlineimap/branches/twisted/offlineimap/repository/Maildir.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/repository/Maildir.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/repository/Maildir.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -18,7 +18,7 @@
 
 from Base import BaseRepository
 from offlineimap import folder, imaputil
-from offlineimap.imaputil import rd
+from offlineimap.twistedutil import rd
 from offlineimap.ui import UIBase
 from mailbox import Maildir
 import os

Added: offlineimap/branches/twisted/offlineimap/twistedutil.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/twistedutil.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/twistedutil.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -0,0 +1,26 @@
+# Twisted utility module
+# Copyright (C) 2003 John Goerzen
+# <[email protected]>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+from twisted.internet import defer
+
+def rd(val):
+    """Utility function to retern a deferred with its value set to val."""
+    d = defer.Deferred()
+    d.callback(val)
+    return d
+

Modified: offlineimap/branches/twisted/offlineimap/ui/TTY.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/ui/TTY.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/ui/TTY.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -20,35 +20,27 @@
 from getpass import getpass
 import select, sys
 from threading import *
+from offlineimap.twistedutil import rd
 
 class TTYUI(UIBase):
     def __init__(s, config, verbose = 0):
         UIBase.__init__(s, config, verbose)
         s.iswaiting = 0
-        s.outputlock = Lock()
 
     def isusable(s):
         return sys.stdout.isatty() and sys.stdin.isatty()
         
     def _display(s, msg):
-        s.outputlock.acquire()
-        try:
-            if (currentThread().getName() == 'MainThread'):
-                print msg
-            else:
-                print "%s:\n   %s" % (currentThread().getName(), msg)
-            sys.stdout.flush()
-        finally:
-            s.outputlock.release()
+        if (currentThread().getName() == 'MainThread'):
+            print msg
+        else:
+            print "%s:\n   %s" % (currentThread().getName(), msg)
+        sys.stdout.flush()
 
     def getpass(s, accountname, config, errmsg = None):
         if errmsg:
             s._msg("%s: %s" % (accountname, errmsg))
-        s.outputlock.acquire()
-        try:
-            return getpass("%s: Enter password: " % accountname)
-        finally:
-            s.outputlock.release()
+        return rd(getpass("%s: Enter password: " % accountname))
 
     def mainException(s):
         if isinstance(sys.exc_info()[1], KeyboardInterrupt) and \

Modified: offlineimap/branches/twisted/offlineimap/ui/UIBase.py
===================================================================
--- offlineimap/branches/twisted/offlineimap/ui/UIBase.py	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap/ui/UIBase.py	2003-08-15 18:50:54 UTC (rev 569)
@@ -23,7 +23,8 @@
 
 debugtypes = {'imap': 'IMAP protocol debugging',
               'maildir': 'Maildir repository debugging',
-              'thread': 'Threading debugging'}
+              'thread': 'Threading debugging',
+              'traffic': 'Network Traffic'}
 
 globalui = None
 def setglobalui(newui):
@@ -147,6 +148,7 @@
     ################################################## INPUT
 
     def getpass(s, accountname, config, errmsg = None):
+        """Returns Deferred."""
         raise NotImplementedError
 
     def folderlist(s, list):

Modified: offlineimap/branches/twisted/offlineimap.sgml
===================================================================
--- offlineimap/branches/twisted/offlineimap.sgml	2003-08-14 18:56:11 UTC (rev 568)
+++ offlineimap/branches/twisted/offlineimap.sgml	2003-08-15 18:50:54 UTC (rev 569)
@@ -363,10 +363,15 @@
 
 	    <para><option>-d</option> requires one or more debugtypes,
 	      separated by commas.  These define what exactly will be
-	      debugged, and include three options: <property>imap</property>,
+	      debugged, and include four options:
+	      <property>imap</property>,
+	      <property>traffic</property>,
 	      <property>maildir</property>, and <property>thread</property>.
 	      The <property>imap</property>
-	      option will enable IMAP protocol stream and parsing debugging.  Note
+	      option will enable IMAP activity debugging.  The
+	      <property>traffic</property> option will enable dumping
+	      of most traffic going back and forth between IMAP
+	      servers.  Note
 	      that the output may contain passwords, so take care to remove that
 	      from the debugging output before sending it to anyone else.  The
 	      <property>maildir</property> option will enable debugging for