[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`)