77# [heavily stealing from nntplib.py]
88# Updated: Piers Lauder <[email protected] > [Jul '97] 99# String method conversion and test jig improvements by ESR, February 2001.
10+ # Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia <[email protected] > Aug 2003 1011
1112# Example (see the test function at the end of this file)
1213
1314# Imports
1415
1516import re , socket
1617
17- __all__ = ["POP3" ,"error_proto" ]
18+ __all__ = ["POP3" ,"error_proto" , "POP3_SSL" ]
1819
1920# Exception raised when an error or invalid response is received:
2021
@@ -23,6 +24,9 @@ class error_proto(Exception): pass
2324# Standard Port
2425POP3_PORT = 110
2526
27+ # POP SSL PORT
28+ POP3_SSL_PORT = 995
29+
2630# Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF)
2731CR = '\r '
2832LF = '\n '
@@ -317,6 +321,90 @@ def uidl(self, which=None):
317321 return self ._shortcmd ('UIDL %s' % which )
318322 return self ._longcmd ('UIDL' )
319323
324+ class POP3_SSL (POP3 ):
325+ """POP3 client class over SSL connection
326+
327+ Instantiate with: POP3_SSL(hostname, port=995, keyfile=None, certfile=None)
328+
329+ hostname - the hostname of the pop3 over ssl server
330+ port - port number
331+ keyfile - PEM formatted file that countains your private key
332+ certfile - PEM formatted certificate chain file
333+
334+ See the methods of the parent class POP3 for more documentation.
335+ """
336+
337+ def __init__ (self , host , port = POP3_SSL_PORT , keyfile = None , certfile = None ):
338+ self .host = host
339+ self .port = port
340+ self .keyfile = keyfile
341+ self .certfile = certfile
342+ self .buffer = ""
343+ msg = "getaddrinfo returns an empty list"
344+ self .sock = None
345+ for res in socket .getaddrinfo (self .host , self .port , 0 , socket .SOCK_STREAM ):
346+ af , socktype , proto , canonname , sa = res
347+ try :
348+ self .sock = socket .socket (af , socktype , proto )
349+ self .sock .connect (sa )
350+ except socket .error , msg :
351+ if self .sock :
352+ self .sock .close ()
353+ self .sock = None
354+ continue
355+ break
356+ if not self .sock :
357+ raise socket .error , msg
358+ self .file = self .sock .makefile ('rb' )
359+ self .sslobj = socket .ssl (self .sock , self .keyfile , self .certfile )
360+ self ._debugging = 0
361+ self .welcome = self ._getresp ()
362+
363+ def _fillBuffer (self ):
364+ localbuf = self .sslobj .read ()
365+ if len (localbuf ) == 0 :
366+ raise error_proto ('-ERR EOF' )
367+ self .buffer += localbuf
368+
369+ def _getline (self ):
370+ line = ""
371+ renewline = re .compile (r'.*?\n' )
372+ match = renewline .match (self .buffer )
373+ while not match :
374+ self ._fillBuffer ()
375+ match = renewline .match (self .buffer )
376+ line = match .group (0 )
377+ self .buffer = renewline .sub ('' ,self .buffer , 1 )
378+ if self ._debugging > 1 : print '*get*' , `line`
379+
380+ octets = len (line )
381+ if line [- 2 :] == CRLF :
382+ return line [:- 2 ], octets
383+ if line [0 ] == CR :
384+ return line [1 :- 1 ], octets
385+ return line [:- 1 ], octets
386+
387+ def _putline (self , line ):
388+ if self ._debugging > 1 : print '*put*' , `line`
389+ line += CRLF
390+ bytes = len (line )
391+ while bytes > 0 :
392+ sent = self .sslobj .write (line )
393+ if sent == bytes :
394+ break # avoid copy
395+ line = line [sent :]
396+ bytes = bytes - sent
397+
398+ def quit (self ):
399+ """Signoff: commit changes on server, unlock mailbox, close connection."""
400+ try :
401+ resp = self ._shortcmd ('QUIT' )
402+ except error_proto , val :
403+ resp = val
404+ self .sock .close ()
405+ del self .sslobj , self .sock
406+ return resp
407+
320408
321409if __name__ == "__main__" :
322410 import sys
0 commit comments