summaryrefslogtreecommitdiffstats
path: root/Lib/imaplib.py
diff options
context:
space:
mode:
authorPiers Lauder <piers@cs.su.oz.au>2002-11-22 05:53:04 (GMT)
committerPiers Lauder <piers@cs.su.oz.au>2002-11-22 05:53:04 (GMT)
commite0273de4329d0f442c696891b856d91721816d72 (patch)
tree7272958ca96ace775ec6a4b8ebb35c7923c9f248 /Lib/imaplib.py
parentd3c821ee71b6eeb79357469e52976913b847c616 (diff)
downloadcpython-e0273de4329d0f442c696891b856d91721816d72.zip
cpython-e0273de4329d0f442c696891b856d91721816d72.tar.gz
cpython-e0273de4329d0f442c696891b856d91721816d72.tar.bz2
added new IMAP4_stream class; added proxyauth command; added login_cram_md5 method
Diffstat (limited to 'Lib/imaplib.py')
-rw-r--r--Lib/imaplib.py121
1 files changed, 109 insertions, 12 deletions
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 75878b9..da456d6 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -17,10 +17,11 @@ Public functions: Internaldate2tuple
# GET/SETACL contributed by Anthony Baxter <anthony@interlink.com.au> April 2001.
# 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.53"
+__version__ = "2.54"
-import binascii, re, socket, time, random, sys
+import binascii, os, random, re, socket, sys, time
__all__ = ["IMAP4", "IMAP4_SSL", "Internaldate2tuple",
"Int2AP", "ParseFlags", "Time2Internaldate"]
@@ -58,6 +59,7 @@ Commands = {
'NAMESPACE': ('AUTH', 'SELECTED'),
'NOOP': ('NONAUTH', 'AUTH', 'SELECTED', 'LOGOUT'),
'PARTIAL': ('SELECTED',), # NB: obsolete
+ 'PROXYAUTH': ('AUTH',),
'RENAME': ('AUTH', 'SELECTED'),
'SEARCH': ('SELECTED',),
'SELECT': ('AUTH', 'SELECTED'),
@@ -111,7 +113,10 @@ class IMAP4:
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.
+ 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>").
IMAP4 server errors raise <instance>.abort("<reason>"),
@@ -325,8 +330,8 @@ class IMAP4:
"""
mech = mechanism.upper()
cap = 'AUTH=%s' % mech
- if not cap in self.capabilities:
- raise self.error("Server doesn't allow %s authentication." % 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)
if typ != 'OK':
@@ -461,8 +466,6 @@ class IMAP4:
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':
raise self.error(dat[-1])
@@ -470,6 +473,21 @@ class IMAP4:
return typ, dat
+ 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.
@@ -511,7 +529,7 @@ class IMAP4:
def noop(self):
"""Send NOOP command.
- (typ, data) = <instance>.noop()
+ (typ, [data]) = <instance>.noop()
"""
if __debug__:
if self.debug >= 3:
@@ -531,10 +549,23 @@ class IMAP4:
return self._untagged_response(typ, dat, 'FETCH')
+ 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)
+ (typ, [data]) = <instance>.rename(oldmailbox, newmailbox)
"""
return self._simple_command('RENAME', oldmailbox, newmailbox)
@@ -1107,6 +1138,58 @@ class IMAP4_SSL(IMAP4):
+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:
"""Private class to provide en/decoding
@@ -1251,16 +1334,24 @@ def Time2Internaldate(date_time):
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:')
+ optlist, args = getopt.getopt(sys.argv[1:], 'd:s:')
except getopt.error, val:
- pass
+ 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 = ('',)
@@ -1301,10 +1392,16 @@ if __name__ == '__main__':
M._mesg('%s %s' % (cmd, args))
typ, dat = apply(getattr(M, cmd), args)
M._mesg('%s => %s %s' % (cmd, typ, dat))
+ if typ == 'NO': raise dat[0]
return dat
try:
- M = IMAP4(host)
+ 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`)