Fix IMAP4_Tunnel to work with imaplib2
* 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@betacantrips.com> Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
parent
fdf22400b1
commit
9e734006f6
@ -22,6 +22,8 @@ Changes
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
* Fix IMAP4 tunnel with imaplib2.
|
||||
|
||||
|
||||
Pending for the next major release
|
||||
==================================
|
||||
|
@ -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()
|
||||
|
||||
def read(self, size):
|
||||
retval = ''
|
||||
while len(retval) < size:
|
||||
buf = self.infd.read(size - len(retval))
|
||||
if not buf:
|
||||
break
|
||||
retval += buf
|
||||
return retval
|
||||
self.set_nonblocking(self.read_fd)
|
||||
|
||||
def readline(self):
|
||||
return self.infd.readline()
|
||||
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):
|
||||
"""data = read(size)
|
||||
Read at most 'size' bytes from remote."""
|
||||
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user