[PATCH] Fix IMAP4_Tunnel to work with imaplib2

Ethan Glasser-Camp ethan at betacantrips.com
Wed Apr 13 09:52:18 BST 2011


* IMAP4_Tunnel constructor should support base-class arguments, in
  order to support the timeout argument.

* IMAP4_Tunnel needs to store the member IMAP4.host, which is normally
  done in IMAP4.open().

* Update IMAP4_Tunnel.read() and IMAP4_Tunnel.send().  We turn on
  nonblocking mode for these sockets, so we can return immediately
  with whatever data is available.

Signed-off-by: Ethan Glasser-Camp <ethan at betacantrips.com>
---
 offlineimap/imaplibutil.py |   42 +++++++++++++++++++++++++++++++-----------
 1 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py
index 14b11c2..7c98fef 100644
--- a/offlineimap/imaplibutil.py
+++ b/offlineimap/imaplibutil.py
@@ -15,6 +15,8 @@
 #    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
+import fcntl
 import re
 import socket
 import time
@@ -67,32 +69,50 @@ class IMAP4_Tunnel(UsefulIMAPMixIn, IMAP4):
     tunnelcmd -- shell command to generate the tunnel.
     The result will be in PREAUTH stage."""
 
-    def __init__(self, tunnelcmd):
-        IMAP4.__init__(self, tunnelcmd)
+    def __init__(self, tunnelcmd, **kwargs):
+        IMAP4.__init__(self, tunnelcmd, **kwargs)
 
     def open(self, host, port):
         """The tunnelcmd comes in on host!"""
+        self.host = host
         self.process = subprocess.Popen(host, shell=True, close_fds=True,
                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
         (self.outfd, self.infd) = (self.process.stdin, self.process.stdout)
         # imaplib2 polls on this fd
         self.read_fd = self.infd.fileno()
 
+        self.set_nonblocking(self.read_fd)
+
+    def set_nonblocking(self, fd):
+        "Mark fd as nonblocking"
+        # get the file's current flag settings
+        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+        # clear non-blocking mode from flags
+        fl = fl & ~os.O_NONBLOCK
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl)
+
     def read(self, size):
-        retval = ''
-        while len(retval) < size:
-            buf = self.infd.read(size - len(retval))
-            if not buf:
-                break
-            retval += buf
-        return retval
+        """data = read(size)
+        Read at most 'size' bytes from remote."""
 
-    def readline(self):
-        return self.infd.readline()
+        if self.decompressor is None:
+            return os.read(self.read_fd, size)
+
+        if self.decompressor.unconsumed_tail:
+            data = self.decompressor.unconsumed_tail
+        else:
+            data = os.read(self.read_fd, 8192)
+
+        return self.decompressor.decompress(data, size)
 
     def send(self, data):
+        if self.compressor is not None:
+            data = self.compressor.compress(data)
+            data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
+
         self.outfd.write(data)
 
+
     def shutdown(self):
         self.infd.close()
         self.outfd.close()
-- 
1.7.1





More information about the OfflineIMAP-project mailing list