[Python-checkins] python/dist/src/Lib imaplib.py,1.56,1.57
pierslauder@users.sourceforge.net
pierslauder@users.sourceforge.net
Thu, 21 Nov 2002 21:53:07 -0800
Update of /cvsroot/python/python/dist/src/Lib
In directory sc8-pr-cvs1:/tmp/cvs-serv23367/dist/src/Lib
Modified Files:
imaplib.py
Log Message:
added new IMAP4_stream class; added proxyauth command; added login_cram_md5 method
Index: imaplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/imaplib.py,v
retrieving revision 1.56
retrieving revision 1.57
diff -C2 -d -r1.56 -r1.57
*** imaplib.py 30 Oct 2002 06:20:37 -0000 1.56
--- imaplib.py 22 Nov 2002 05:53:04 -0000 1.57
***************
*** 18,25 ****
# IMAP4_SSL contributed by Tino Lange <Tino.Lange@isg.de> March 2002.
# GET/SETQUOTA contributed by Andreas Zeidler <az@kreativkombinat.de> June 2002.
! __version__ = "2.53"
! import binascii, re, socket, time, random, sys
__all__ = ["IMAP4", "IMAP4_SSL", "Internaldate2tuple",
--- 18,26 ----
# IMAP4_SSL contributed by Tino Lange <Tino.Lange@isg.de> March 2002.
# GET/SETQUOTA contributed by Andreas Zeidler <az@kreativkombinat.de> June 2002.
+ # PROXYAUTH contributed by Rick Holbert <holbert.13@osu.edu> November 2002.
! __version__ = "2.54"
! import binascii, os, random, re, socket, sys, time
__all__ = ["IMAP4", "IMAP4_SSL", "Internaldate2tuple",
***************
*** 59,62 ****
--- 60,64 ----
'NOOP': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
'PARTIAL': ('SELECTED',), # NB: obsolete
+ 'PROXYAUTH': ('AUTH',),
'RENAME': ('AUTH', 'SELECTED'),
'SEARCH': ('SELECTED',),
***************
*** 112,116 ****
Each command returns a tuple: (type, [data, ...]) where 'type'
is usually 'OK' or 'NO', and 'data' is either the text from the
! tagged response, or untagged results from command.
Errors raise the exception class <instance>.error("<reason>").
--- 114,121 ----
Each command returns a tuple: (type, [data, ...]) where 'type'
is usually 'OK' or 'NO', and 'data' is either the text from the
! tagged response, or untagged results from command. Each 'data'
! is either a string, or a tuple. If a tuple, then the first part
! is the header of the response, and the second part contains
! the data (ie: 'literal' value).
Errors raise the exception class <instance>.error("<reason>").
***************
*** 326,331 ****
mech = mechanism.upper()
cap = 'AUTH=%s' % mech
! if not cap in self.capabilities:
! raise self.error("Server doesn't allow %s authentication." % mech)
self.literal = _Authenticator(authobject).process
typ, dat = self._simple_command('AUTHENTICATE', mech)
--- 331,336 ----
mech = mechanism.upper()
cap = 'AUTH=%s' % mech
! #if not cap in self.capabilities: # Let the server decide!
! # raise self.error("Server doesn't allow %s authentication." % mech)
self.literal = _Authenticator(authobject).process
typ, dat = self._simple_command('AUTHENTICATE', mech)
***************
*** 462,467 ****
NB: 'password' will be quoted.
"""
- #if not 'AUTH=LOGIN' in self.capabilities:
- # raise self.error("Server doesn't allow LOGIN authentication." % mech)
typ, dat = self._simple_command('LOGIN', user, self._quote(password))
if typ != 'OK':
--- 467,470 ----
***************
*** 471,474 ****
--- 474,492 ----
+ def login_cram_md5(self, user, password):
+ """ Force use of CRAM-MD5 authentication.
+
+ (typ, [data]) = <instance>.login_cram_md5(user, password)
+ """
+ self.user, self.password = user, password
+ return self.authenticate('CRAM-MD5', self._CRAM_MD5_AUTH)
+
+
+ def _CRAM_MD5_AUTH(self, challenge):
+ """ Authobject to use with CRAM-MD5 authentication. """
+ import hmac
+ return self.user + " " + hmac.HMAC(self.password, challenge).hexdigest()
+
+
def logout(self):
"""Shutdown connection to server.
***************
*** 512,516 ****
"""Send NOOP command.
! (typ, data) = <instance>.noop()
"""
if __debug__:
--- 530,534 ----
"""Send NOOP command.
! (typ, [data]) = <instance>.noop()
"""
if __debug__:
***************
*** 532,539 ****
def rename(self, oldmailbox, newmailbox):
"""Rename old mailbox name to new.
! (typ, data) = <instance>.rename(oldmailbox, newmailbox)
"""
return self._simple_command('RENAME', oldmailbox, newmailbox)
--- 550,570 ----
+ def proxyauth(self, user):
+ """Assume authentication as "user".
+
+ Allows an authorised administrator to proxy into any user's
+ mailbox.
+
+ (typ, [data]) = <instance>.proxyauth(user)
+ """
+
+ name = 'PROXYAUTH'
+ return self._simple_command('PROXYAUTH', user)
+
+
def rename(self, oldmailbox, newmailbox):
"""Rename old mailbox name to new.
! (typ, [data]) = <instance>.rename(oldmailbox, newmailbox)
"""
return self._simple_command('RENAME', oldmailbox, newmailbox)
***************
*** 1108,1111 ****
--- 1139,1194 ----
+ class IMAP4_stream(IMAP4):
+
+ """IMAP4 client class over a stream
+
+ Instantiate with: IMAP4_stream(command)
+
+ where "command" is a string that can be passed to os.popen2()
+
+ for more documentation see the docstring of the parent class IMAP4.
+ """
+
+
+ def __init__(self, command):
+ self.command = command
+ IMAP4.__init__(self)
+
+
+ def open(self, host = None, port = None):
+ """Setup a stream connection.
+ This connection will be used by the routines:
+ read, readline, send, shutdown.
+ """
+ self.host = None # For compatibility with parent class
+ self.port = None
+ self.sock = None
+ self.file = None
+ self.writefile, self.readfile = os.popen2(self.command)
+
+
+ def read(self, size):
+ """Read 'size' bytes from remote."""
+ return self.readfile.read(size)
+
+
+ def readline(self):
+ """Read line from remote."""
+ return self.readfile.readline()
+
+
+ def send(self, data):
+ """Send data to remote."""
+ self.writefile.write(data)
+ self.writefile.flush()
+
+
+ def shutdown(self):
+ """Close I/O established in "open"."""
+ self.readfile.close()
+ self.writefile.close()
+
+
+
class _Authenticator:
***************
*** 1252,1265 ****
if __name__ == '__main__':
import getopt, getpass
try:
! optlist, args = getopt.getopt(sys.argv[1:], 'd:')
except getopt.error, val:
! pass
for opt,val in optlist:
if opt == '-d':
Debug = int(val)
if not args: args = ('',)
--- 1335,1356 ----
if __name__ == '__main__':
+ # To test: invoke either as 'python imaplib.py [IMAP4_server_hostname]'
+ # or 'python imaplib.py -s "rsh IMAP4_server_hostname exec /etc/rimapd"'
+ # to test the IMAP4_stream class
+
import getopt, getpass
try:
! optlist, args = getopt.getopt(sys.argv[1:], 'd:s:')
except getopt.error, val:
! optlist, args = (), ()
+ stream_command = None
for opt,val in optlist:
if opt == '-d':
Debug = int(val)
+ elif opt == '-s':
+ stream_command = val
+ if not args: args = (stream_command,)
if not args: args = ('',)
***************
*** 1302,1309 ****
typ, dat = apply(getattr(M, cmd), args)
M._mesg('%s => %s %s' % (cmd, typ, dat))
return dat
try:
! M = IMAP4(host)
M._mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
M._mesg('CAPABILITIES = %s' % `M.capabilities`)
--- 1393,1406 ----
typ, dat = apply(getattr(M, cmd), args)
M._mesg('%s => %s %s' % (cmd, typ, dat))
+ if typ == 'NO': raise dat[0]
return dat
try:
! if stream_command:
! M = IMAP4_stream(stream_command)
! else:
! M = IMAP4(host)
! if M.state == 'AUTH':
! test_seq1 = test_seq1[1:] # Login not needed
M._mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
M._mesg('CAPABILITIES = %s' % `M.capabilities`)