From 48440b7c2751813da110689aff07b4e7ed4ac73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Fri, 31 Oct 2003 12:52:35 +0000 Subject: Patch #: Add POP3 over SSL support. --- Doc/lib/libpoplib.tex | 20 ++++++++++-- Lib/poplib.py | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++- Misc/ACKS | 1 + Misc/NEWS | 2 ++ 4 files changed, 110 insertions(+), 3 deletions(-) diff --git a/Doc/lib/libpoplib.tex b/Doc/lib/libpoplib.tex index f5da970..b056693 100644 --- a/Doc/lib/libpoplib.tex +++ b/Doc/lib/libpoplib.tex @@ -13,9 +13,12 @@ \indexii{POP3}{protocol} This module defines a class, \class{POP3}, which encapsulates a -connection to an POP3 server and implements the protocol as defined in +connection to a POP3 server and implements the protocol as defined in \rfc{1725}. The \class{POP3} class supports both the minimal and -optional command sets. +optional command sets. Additionally, this module provides a class +\class{POP3_SSL}, which provides support for connecting to POP3 +servers that use SSL as an underlying protocol layer. + Note that POP3, though widely supported, is obsolescent. The implementation quality of POP3 servers varies widely, and too many are @@ -31,6 +34,16 @@ created when the instance is initialized. If \var{port} is omitted, the standard POP3 port (110) is used. \end{classdesc} +\begin{classdesc}{POP3_SSL}{host\optional{, port\optional{, keyfile\optional{, certfile}}}} +This is a subclass of \class{POP3} that connects to the server over an +SSL encrypted socket. If \var{port} is not specified, 995, the +standard POP3-over-SSL port is used. \var{keyfile} and \var{certfile} +are also optional - they can contain a PEM formatted private key and +certificate chain file for the SSL connection. + +\versionadded{2.4} +\end{classdesc} + One exception is defined as an attribute of the \module{poplib} module: \begin{excdesc}{error_proto} @@ -143,6 +156,9 @@ otherwise result is list \code{(\var{response}, ['mesgnum uid', ...], \var{octets})}. \end{methoddesc} +Instances of \class{POP3_SSL} have no additional methods. The +interface of this subclass is identical to its parent. + \subsection{POP3 Example \label{pop3-example}} diff --git a/Lib/poplib.py b/Lib/poplib.py index 0b22b2e..c14b8b7 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -7,6 +7,7 @@ Based on the J. Myers POP3 draft, Jan. 96 # [heavily stealing from nntplib.py] # Updated: Piers Lauder [Jul '97] # String method conversion and test jig improvements by ESR, February 2001. +# Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia Aug 2003 # Example (see the test function at the end of this file) @@ -14,7 +15,7 @@ Based on the J. Myers POP3 draft, Jan. 96 import re, socket -__all__ = ["POP3","error_proto"] +__all__ = ["POP3","error_proto","POP3_SSL"] # Exception raised when an error or invalid response is received: @@ -23,6 +24,9 @@ class error_proto(Exception): pass # Standard Port POP3_PORT = 110 +# POP SSL PORT +POP3_SSL_PORT = 995 + # Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF) CR = '\r' LF = '\n' @@ -317,6 +321,90 @@ class POP3: return self._shortcmd('UIDL %s' % which) return self._longcmd('UIDL') +class POP3_SSL(POP3): + """POP3 client class over SSL connection + + Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None) + + hostname - the hostname of the pop3 over ssl server + port - port number + keyfile - PEM formatted file that countains your private key + certfile - PEM formatted certificate chain file + + See the methods of the parent class POP3 for more documentation. + """ + + def __init__(self, host, port = POP3_SSL_PORT, keyfile = None, certfile = None): + self.host = host + self.port = port + self.keyfile = keyfile + self.certfile = certfile + self.buffer = "" + msg = "getaddrinfo returns an empty list" + self.sock = None + for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + self.sock = socket.socket(af, socktype, proto) + self.sock.connect(sa) + except socket.error, msg: + if self.sock: + self.sock.close() + self.sock = None + continue + break + if not self.sock: + raise socket.error, msg + self.file = self.sock.makefile('rb') + self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile) + self._debugging = 0 + self.welcome = self._getresp() + + def _fillBuffer(self): + localbuf = self.sslobj.read() + if len(localbuf) == 0: + raise error_proto('-ERR EOF') + self.buffer += localbuf + + def _getline(self): + line = "" + renewline = re.compile(r'.*?\n') + match = renewline.match(self.buffer) + while not match: + self._fillBuffer() + match = renewline.match(self.buffer) + line = match.group(0) + self.buffer = renewline.sub('' ,self.buffer, 1) + if self._debugging > 1: print '*get*', `line` + + octets = len(line) + if line[-2:] == CRLF: + return line[:-2], octets + if line[0] == CR: + return line[1:-1], octets + return line[:-1], octets + + def _putline(self, line): + if self._debugging > 1: print '*put*', `line` + line += CRLF + bytes = len(line) + while bytes > 0: + sent = self.sslobj.write(line) + if sent == bytes: + break # avoid copy + line = line[sent:] + bytes = bytes - sent + + def quit(self): + """Signoff: commit changes on server, unlock mailbox, close connection.""" + try: + resp = self._shortcmd('QUIT') + except error_proto, val: + resp = val + self.sock.close() + del self.sslobj, self.sock + return resp + if __name__ == "__main__": import sys diff --git a/Misc/ACKS b/Misc/ACKS index c836df6..a8d645a 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -562,6 +562,7 @@ Stephen Turner Bill Tutt Doobee R. Tzeck Lionel Ulmer +Hector Urtubia Frank Vercruesse Jaap Vermeulen Al Vezza diff --git a/Misc/NEWS b/Misc/NEWS index 4bbbb57..970c814 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -101,6 +101,8 @@ Extension modules Library ------- +- poplib.POP3_SSL has been added. + - tmpfile.mkstemp now returns an absolute path even if dir is relative. - urlparse is RFC 2396 compliant. -- cgit v0.12