use latest version of imaplib2

* fixes rh bz #510036
Signed-off-by: Christoph Höger <choeger@cs.tu-berlin.de>

[ per jgoerzen: rh bz #510036 is Kerberos issue.  also Closes: #535794 in Debian ]
This commit is contained in:
Christoph Höger 2009-07-11 11:17:37 +02:00 committed by John Goerzen
parent 5c11de5285
commit fadbd38ef9

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2.5
#!/usr/bin/env python
"""Threaded IMAP4 client.
@ -17,9 +17,9 @@ Public functions: Internaldate2Time
__all__ = ("IMAP4", "IMAP4_SSL", "IMAP4_stream",
"Internaldate2Time", "ParseFlags", "Time2Internaldate")
__version__ = "2.6"
__version__ = "2.11"
__release__ = "2"
__revision__ = "6"
__revision__ = "11"
__credits__ = """
Authentication code contributed by Donn Cave <donn@u.washington.edu> June 1998.
String method conversion by ESR, February 2001.
@ -29,11 +29,11 @@ GET/SETQUOTA contributed by Andreas Zeidler <az@kreativkombinat.de> June 2002.
PROXYAUTH contributed by Rick Holbert <holbert.13@osu.edu> November 2002.
IDLE via threads suggested by Philippe Normand <phil@respyre.org> January 2005.
GET/SETANNOTATION contributed by Tomas Lindroos <skitta@abo.fi> June 2005.
New socket open code from http://www.python.org/doc/lib/socket-example.html."""
COMPRESS/DEFLATE contributed by Bron Gondwana <brong@brong.net> May 2009."""
__author__ = "Piers Lauder <piers@janeelix.com>"
# Source URL: http://www.cs.usyd.edu.au/~piers/python/imaplib2
__URL__ = "http://janeelix.com/piers/python/imaplib2"
import binascii, os, Queue, random, re, select, socket, sys, time, threading
import binascii, os, Queue, random, re, select, socket, sys, time, threading, zlib
select_module = select
@ -62,6 +62,7 @@ Commands = {
'CAPABILITY': ((NONAUTH, AUTH, SELECTED), True),
'CHECK': ((SELECTED,), True),
'CLOSE': ((SELECTED,), False),
'COMPRESS': ((AUTH,), False),
'COPY': ((SELECTED,), True),
'CREATE': ((AUTH, SELECTED), True),
'DELETE': ((AUTH, SELECTED), True),
@ -264,6 +265,9 @@ class IMAP4(object):
self._accumulated_data = [] # Message data accumulated so far
self._literal_expected = None # Message data descriptor
self.compressor = None # COMPRESS/DEFLATE if not None
self.decompressor = None
# Create unique tag for this session,
# and compile tagged response matcher.
@ -358,7 +362,8 @@ class IMAP4(object):
def open_socket(self):
"""Open socket choosing first address family available."""
"""open_socket()
Open socket choosing first address family available."""
msg = (-1, 'could not open socket')
for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM):
@ -379,17 +384,38 @@ class IMAP4(object):
return s
def start_compressing(self):
"""start_compressing()
Enable deflate compression on the socket (RFC 4978)."""
# rfc 1951 - pure DEFLATE, so use -15 for both windows
self.decompressor = zlib.decompressobj(-15)
self.compressor = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
def read(self, size):
"""data = read(size)
Read at most 'size' bytes from remote."""
return self.sock.recv(size)
if self.decompressor is None:
return self.sock.recv(size)
if self.decompressor.unconsumed_tail:
data = self.decompressor.unconsumed_tail
else:
data = self.sock.recv(8192)
return self.decompressor.decompress(data, size)
def send(self, data):
"""send(data)
Send 'data' to remote."""
if self.compressor is not None:
data = self.compressor.compress(data)
data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
self.sock.sendall(data)
@ -411,6 +437,22 @@ class IMAP4(object):
# Utility methods
def enable_compression(self):
"""enable_compression()
Ask the server to start compressing the connection.
Should be called from user of this class after instantiation, as in:
if 'COMPRESS=DEFLATE' in imapobj.capabilities:
imapobj.enable_compression()"""
try:
typ, dat = self._simple_command('COMPRESS', 'DEFLATE')
if typ == 'OK':
self.start_compressing()
if __debug__: self._log(1, 'Enabled COMPRESS=DEFLATE')
finally:
self.state_change_pending.release()
def recent(self, **kw):
"""(typ, [data]) = recent()
Return most recent 'RECENT' responses if any exist,
@ -647,9 +689,9 @@ class IMAP4(object):
List mailbox names in directory matching pattern.
'data' is list of LIST responses.
NB: for 'pattern':
% matches all except separator ( so LIST "" "%" returns names at root)
* matches all (so LIST "" "*" returns whole directory tree from root)"""
NB: for 'pattern':
% matches all except separator ( so LIST "" "%" returns names at root)
* matches all (so LIST "" "*" returns whole directory tree from root)"""
name = 'LIST'
kw['untagged_response'] = name
@ -813,7 +855,7 @@ class IMAP4(object):
self.state = AUTH
if __debug__: self._log(1, 'state => AUTH')
if typ == 'BAD':
self._deliver_exc(self.error, '%s command error: %s %s' % (name, typ, dat), kw)
self._deliver_exc(self.error, '%s command error: %s %s. Data: %.100s' % (name, typ, dat, mailbox), kw)
return self._deliver_dat(typ, dat, kw)
self.state = SELECTED
if __debug__: self._log(1, 'state => SELECTED')
@ -1043,20 +1085,25 @@ class IMAP4(object):
literal = self.literal
if literal is not None:
self.literal = None
if isinstance(literal, str):
if isinstance(literal, basestring):
literator = None
data = '%s {%s}' % (data, len(literal))
else:
literator = literal
if __debug__: self._log(4, 'data=%s' % data)
rqb.data = '%s%s' % (data, CRLF)
self.ouq.put(rqb)
if literal is None:
self.ouq.put(rqb)
return rqb
# Must setup continuation expectancy *before* ouq.put
crqb = self._request_push(tag='continuation')
self.ouq.put(rqb)
while True:
# Wait for continuation response
@ -1076,6 +1123,10 @@ class IMAP4(object):
if literal is None:
break
if literator is not None:
# Need new request for next continuation response
crqb = self._request_push(tag='continuation')
if __debug__: self._log(4, 'write literal size %s' % len(literal))
crqb.data = '%s%s' % (literal, CRLF)
self.ouq.put(crqb)
@ -1083,10 +1134,6 @@ class IMAP4(object):
if literator is None:
break
self.commands_lock.acquire()
self.tagged_commands['continuation'] = crqb
self.commands_lock.release()
return rqb
@ -1098,7 +1145,7 @@ class IMAP4(object):
self._check_bye()
if typ == 'BAD':
if __debug__: self._print_log()
raise self.error('%s command error: %s %s' % (rqb.name, typ, dat))
raise self.error('%s command error: %s %s. Data: %.100s' % (rqb.name, typ, dat, rqb.data))
if 'untagged_response' in kw:
return self._untagged_response(typ, dat, kw['untagged_response'])
return typ, dat
@ -1122,12 +1169,11 @@ class IMAP4(object):
typ, dat = response
if typ == 'BAD':
if __debug__: self._print_log()
rqb.abort(self.error, '%s command error: %s %s' % (rqb.name, typ, dat))
rqb.abort(self.error, '%s command error: %s %s. Data: %.100s' % (rqb.name, typ, dat, rqb.data))
return
if 'untagged_response' in kw:
rqb.deliver(self._untagged_response(typ, dat, kw['untagged_response']))
else:
rqb.deliver(response)
response = self._untagged_response(typ, dat, kw['untagged_response'])
rqb.deliver(response)
def _deliver_dat(self, typ, dat, kw):
@ -1147,12 +1193,13 @@ class IMAP4(object):
def _end_idle(self):
irqb = self.idle_rqb
if irqb is not None:
self.idle_rqb = None
self.idle_timeout = None
irqb.data = 'DONE%s' % CRLF
self.ouq.put(irqb)
if __debug__: self._log(2, 'server IDLE finished')
if irqb is None:
return
self.idle_rqb = None
self.idle_timeout = None
irqb.data = 'DONE%s' % CRLF
self.ouq.put(irqb)
if __debug__: self._log(2, 'server IDLE finished')
def _match(self, cre, s):
@ -1337,7 +1384,7 @@ class IMAP4(object):
threading.currentThread().setName('hdlr')
time.sleep(0.1) # Don't start handling before main thread ready
time.sleep(0.1) # Don't start handling before main thread ready
if __debug__: self._log(1, 'starting')
@ -1366,7 +1413,7 @@ class IMAP4(object):
if line is None:
break
if not isinstance(line, str):
if not isinstance(line, basestring):
typ, val = line
break
@ -1664,7 +1711,12 @@ class IMAP4_SSL(IMAP4):
self.host = host is not None and host or ''
self.port = port is not None and port or IMAP4_SSL_PORT
self.sock = self.open_socket()
self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
try:
import ssl
self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
except ImportError:
self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
self.read_fd = self.sock.fileno()
@ -1673,13 +1725,25 @@ class IMAP4_SSL(IMAP4):
"""data = read(size)
Read at most 'size' bytes from remote."""
return self.sslobj.read(size)
if self.decompressor is None:
return self.sslobj.read(size)
if self.decompressor.unconsumed_tail:
data = self.decompressor.unconsumed_tail
else:
data = self.sslobj.read(8192)
return self.decompressor.decompress(data, size)
def send(self, data):
"""send(data)
Send 'data' to remote."""
if self.compressor is not None:
data = self.compressor.compress(data)
data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
# NB: socket.ssl needs a "sendall" method to match socket objects.
bytes = len(data)
while bytes > 0:
@ -1736,12 +1800,24 @@ class IMAP4_stream(IMAP4):
def read(self, size):
"""Read 'size' bytes from remote."""
return os.read(self.read_fd, size)
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):
"""Send data to remote."""
if self.compressor is not None:
data = self.compressor.compress(data)
data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
self.writefile.write(data)
self.writefile.flush()
@ -1920,7 +1996,7 @@ if __name__ == '__main__':
import getopt, getpass
try:
optlist, args = getopt.getopt(sys.argv[1:], 'd:l:s:p:')
optlist, args = getopt.getopt(sys.argv[1:], 'd:l:s:p:v')
except getopt.error, val:
optlist, args = (), ()
@ -1938,6 +2014,9 @@ if __name__ == '__main__':
elif opt == '-s':
stream_command = val
if not args: args = (stream_command,)
elif opt == '-v':
print __version__
sys.exit(0)
if not args: args = ('',)
if not port: port = (keyfile is not None) and IMAP4_SSL_PORT or IMAP4_PORT
@ -1947,7 +2026,7 @@ if __name__ == '__main__':
USER = getpass.getuser()
test_mesg = 'From: %(user)s@localhost%(lf)sSubject: IMAP4 test%(lf)s%(lf)s%(data)s' \
% {'user':USER, 'lf':'\n', 'data':open(__file__).read()}
% {'user':USER, 'lf':'\n', 'data':open(__file__).read()}
test_seq1 = [
('list', ('""', '%')),
('create', ('/tmp/imaplib2_test.0',)),
@ -2028,6 +2107,8 @@ if __name__ == '__main__':
test_seq1.insert(0, ('login', (USER, PASSWD)))
M._mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
M._mesg('CAPABILITIES = %r' % (M.capabilities,))
if 'COMPRESS=DEFLATE' in M.capabilities:
M.enable_compression()
for cmd,args in test_seq1:
run(cmd, args, cb=1)