--- Lib.orig/poplib.py 2008-11-30 17:04:44.000000000 +0100 +++ Lib/poplib.py 2008-11-30 16:46:22.000000000 +0100 @@ -15,6 +15,12 @@ import re, socket +try: + import ssl + HAVE_SSL=True +except ImportError: + HAVE_SSL=False + __all__ = ["POP3","error_proto"] # Exception raised when an error or invalid response is received: @@ -84,6 +90,7 @@ self.file = self.sock.makefile('rb') self._debugging = 0 self.welcome = self._getresp() + self._tls_established=False def _putline(self, line): @@ -252,8 +259,13 @@ except error_proto, val: resp = val self.file.close() + self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() del self.file, self.sock + if hasattr(self,'_sock') and self._sock: + self._sock.shutdown(socket.SHUT_RDWR) + self._sock.close() + del self._sock return resp #__del__ = quit @@ -308,11 +320,43 @@ return self._shortcmd('UIDL %s' % which) return self._longcmd('UIDL') -try: - import ssl -except ImportError: - pass -else: + def stls(self, keyfile = None, certfile = None): + if not HAVE_SSL: + raise error_proto('-ERR TLS support missing') + if self._tls_established: + raise error_proto('-ERR TLS session already established') + caps=self.capa() + if not 'STLS' in caps: + raise error_proto('-ERR STLS not supported by server') + try: + resp=self._shortcmd('STLS') + self._sock=self.sock + self.sock=ssl.wrap_socket(self._sock, keyfile, certfile) + self.file=self.sock.makefile('rb') + self._tls_established = True + except error_proto, val: + resp = val + return resp + + def ssl(self): + if self._tls_established: + return self.sock + else: + return None + + def capa(self): + try: + resp=self._longcmd('CAPA') + caplist=resp[1] + capabilities=dict([(lambda j: (j[0], + j[1:] if len(j) > 1 else []) + )(i.split()) for i in caplist]) + except error_proto, val: + raise error_proto('-ERR CAPA not supported by server') + return capabilities + + +if HAVE_SSL: class POP3_SSL(POP3): """POP3 client class over SSL connection @@ -338,65 +382,23 @@ 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) + self._sock = socket.socket(af, socktype, proto) + self._sock.connect(sa) except socket.error, msg: - if self.sock: - self.sock.close() - self.sock = None + if self._sock: + self._sock.shutdown(socket.SHUT_RDWR) + self._sock.close() + self._sock = None continue break - if not self.sock: + if not self._sock: raise socket.error, msg + self.sock = ssl.wrap_socket(self._sock, self.keyfile, self.certfile) self.file = self.sock.makefile('rb') - self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile) + self._tls_established = True 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*', repr(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*', repr(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 __all__.append("POP3_SSL")