[Python-checkins] CVS: python/dist/src/Lib smtplib.py,1.41,1.42

Guido van Rossum gvanrossum@users.sourceforge.net
Fri, 14 Sep 2001 09:08:17 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv7651

Modified Files:
	smtplib.py 
Log Message:
SF patch #461413 (Gerhard Häring): Add STARTTLS feature to smtplib

   This patch adds the features from RFC 2487 (Secure SMTP 
   over TLS) to the smtplib module: 

   - A starttls() function 
   - Wrapper classes that simulate enough of sockets and 
     files for smtplib, but really wrap a SSLObject 
   - reset the list of known SMTP extensions at each call 
     of ehlo(). This should have been the case anyway. 


Index: smtplib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/smtplib.py,v
retrieving revision 1.41
retrieving revision 1.42
diff -C2 -d -r1.41 -r1.42
*** smtplib.py	2001/09/11 15:57:46	1.41
--- smtplib.py	2001/09/14 16:08:14	1.42
***************
*** 3,8 ****
  '''SMTP/ESMTP client class.
  
! This should follow RFC 821 (SMTP), RFC 1869 (ESMTP) and RFC 2554 (SMTP
! Authentication).
  
  Notes:
--- 3,8 ----
  '''SMTP/ESMTP client class.
  
! This should follow RFC 821 (SMTP), RFC 1869 (ESMTP), RFC 2554 (SMTP
! Authentication) and RFC 2487 (Secure SMTP over TLS).
  
  Notes:
***************
*** 125,128 ****
--- 125,163 ----
      """
  
+ class SSLFakeSocket:
+     """A fake socket object that really wraps a SSLObject.
+     
+     It only supports what is needed in smtplib.
+     """
+     def __init__(self, realsock, sslobj):
+         self.realsock = realsock
+         self.sslobj = sslobj
+ 
+     def send(self, str):
+         self.sslobj.write(str)
+         return len(str)
+ 
+     def close(self):
+         self.realsock.close()
+ 
+ class SSLFakeFile:
+     """A fake file like object that really wraps a SSLObject.
+     
+     It only supports what is needed in smtplib.
+     """
+     def __init__( self, sslobj):
+         self.sslobj = sslobj
+ 
+     def readline(self):
+         str = ""
+         chr = None
+         while chr != "\n":
+             chr = self.sslobj.read(1)
+             str += chr
+         return str
+ 
+     def close(self):
+         pass
+ 
  def quoteaddr(addr):
      """Quote a subset of the email addresses defined by RFC 821.
***************
*** 334,337 ****
--- 369,373 ----
          host.
          """
+         self.esmtp_features = {}
          if name:
              self.putcmd("ehlo", name)
***************
*** 507,510 ****
--- 543,562 ----
          return (code, resp)
  
+     def starttls(self, keyfile = None, certfile = None):
+         """Puts the connection to the SMTP server into TLS mode.
+         
+         If the server supports TLS, this will encrypt the rest of the SMTP
+         session. If you provide the keyfile and certfile parameters,
+         the identity of the SMTP server and client can be checked. This,
+         however, depends on whether the socket module really checks the
+         certificates.
+         """
+         (resp, reply) = self.docmd("STARTTLS") 
+         if resp == 220:
+             sslobj = socket.ssl(self.sock, keyfile, certfile)
+             self.sock = SSLFakeSocket(self.sock, sslobj)
+             self.file = SSLFakeFile(sslobj)
+         return (resp, reply)
+     
      def sendmail(self, from_addr, to_addrs, msg, mail_options=[],
                   rcpt_options=[]):