| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | """A POP3 client class.
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | Based on the J. Myers POP3 draft, Jan. 96 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-02-28 15:12:25 +00:00
										 |  |  | # Author: David Ascher <david_ascher@brown.edu> | 
					
						
							|  |  |  | #         [heavily stealing from nntplib.py] | 
					
						
							|  |  |  | # Updated: Piers Lauder <piers@cs.su.oz.au> [Jul '97] | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  | # String method conversion and test jig improvements by ESR, February 2001. | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  | # Added the POP3_SSL class. Methods loosely based on IMAP_SSL. Hector Urtubia <urtubia@mrbook.org> Aug 2003 | 
					
						
							| 
									
										
										
										
											2000-02-28 15:12:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | # Example (see the test function at the end of this file) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Imports | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  | import re, socket | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  | __all__ = ["POP3","error_proto","POP3_SSL"] | 
					
						
							| 
									
										
										
										
											2001-02-12 02:00:42 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | # Exception raised when an error or invalid response is received: | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class error_proto(Exception): pass | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Standard Port | 
					
						
							|  |  |  | POP3_PORT = 110 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  | # POP SSL PORT | 
					
						
							|  |  |  | POP3_SSL_PORT = 995 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | # Line terminators (we always output CRLF, but accept any of CRLF, LFCR, LF) | 
					
						
							|  |  |  | CR = '\r' | 
					
						
							|  |  |  | LF = '\n' | 
					
						
							|  |  |  | CRLF = CR+LF | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class POP3: | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     """This class supports both the minimal and optional command sets.
 | 
					
						
							|  |  |  |     Arguments can be strings or integers (where appropriate) | 
					
						
							|  |  |  |     (e.g.: retr(1) and retr('1') both work equally well. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Minimal Command Set: | 
					
						
							|  |  |  |             USER name               user(name) | 
					
						
							|  |  |  |             PASS string             pass_(string) | 
					
						
							|  |  |  |             STAT                    stat() | 
					
						
							|  |  |  |             LIST [msg]              list(msg = None) | 
					
						
							|  |  |  |             RETR msg                retr(msg) | 
					
						
							|  |  |  |             DELE msg                dele(msg) | 
					
						
							|  |  |  |             NOOP                    noop() | 
					
						
							|  |  |  |             RSET                    rset() | 
					
						
							|  |  |  |             QUIT                    quit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional Commands (some servers support these): | 
					
						
							|  |  |  |             RPOP name               rpop(name) | 
					
						
							|  |  |  |             APOP name digest        apop(name, digest) | 
					
						
							|  |  |  |             TOP msg n               top(msg, n) | 
					
						
							|  |  |  |             UIDL [msg]              uidl(msg = None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Raises one exception: 'error_proto'. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     Instantiate with: | 
					
						
							|  |  |  |             POP3(hostname, port=110) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     NB:     the POP protocol locks the mailbox from user | 
					
						
							|  |  |  |             authorization until QUIT, so be sure to get in, suck | 
					
						
							|  |  |  |             the messages, and quit, each time you access the | 
					
						
							|  |  |  |             mailbox. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             POP is a line-based protocol, which means large mail | 
					
						
							|  |  |  |             messages consume lots of python cycles reading them | 
					
						
							|  |  |  |             line-by-line. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             If it's available on your mail server, use IMAP4 | 
					
						
							|  |  |  |             instead, it doesn't suffer from the two problems | 
					
						
							|  |  |  |             above. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def __init__(self, host, port = POP3_PORT): | 
					
						
							| 
									
										
										
										
											2001-07-26 13:37:33 +00:00
										 |  |  |         self.host = host | 
					
						
							|  |  |  |         self.port = port | 
					
						
							| 
									
										
										
										
											2001-07-31 08:40:21 +00:00
										 |  |  |         msg = "getaddrinfo returns an empty list" | 
					
						
							| 
									
										
										
										
											2001-10-07 08:53:32 +00:00
										 |  |  |         self.sock = None | 
					
						
							| 
									
										
										
										
											2001-07-26 13:37:33 +00:00
										 |  |  |         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: | 
					
						
							| 
									
										
										
										
											2001-10-07 08:53:32 +00:00
										 |  |  |                 if self.sock: | 
					
						
							|  |  |  |                     self.sock.close() | 
					
						
							| 
									
										
										
										
											2001-07-26 13:37:33 +00:00
										 |  |  |                 self.sock = None | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             break | 
					
						
							|  |  |  |         if not self.sock: | 
					
						
							|  |  |  |             raise socket.error, msg | 
					
						
							|  |  |  |         self.file = self.sock.makefile('rb') | 
					
						
							|  |  |  |         self._debugging = 0 | 
					
						
							|  |  |  |         self.welcome = self._getresp() | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _putline(self, line): | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging > 1: print '*put*', repr(line) | 
					
						
							| 
									
										
										
										
											2002-02-16 23:06:19 +00:00
										 |  |  |         self.sock.sendall('%s%s' % (line, CRLF)) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: send one command to the server (through _putline()) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _putcmd(self, line): | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging: print '*cmd*', repr(line) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         self._putline(line) | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: return one line from the server, stripping CRLF. | 
					
						
							|  |  |  |     # This is where all the CPU time of this module is consumed. | 
					
						
							|  |  |  |     # Raise error_proto('-ERR EOF') if the connection is closed. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _getline(self): | 
					
						
							|  |  |  |         line = self.file.readline() | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging > 1: print '*get*', repr(line) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         if not line: raise error_proto('-ERR EOF') | 
					
						
							|  |  |  |         octets = len(line) | 
					
						
							|  |  |  |         # server can send any combination of CR & LF | 
					
						
							|  |  |  |         # however, 'readline()' returns lines ending in LF | 
					
						
							|  |  |  |         # so only possibilities are ...LF, ...CRLF, CR...LF | 
					
						
							|  |  |  |         if line[-2:] == CRLF: | 
					
						
							|  |  |  |             return line[:-2], octets | 
					
						
							|  |  |  |         if line[0] == CR: | 
					
						
							|  |  |  |             return line[1:-1], octets | 
					
						
							|  |  |  |         return line[:-1], octets | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: get a response from the server. | 
					
						
							|  |  |  |     # Raise 'error_proto' if the response doesn't start with '+'. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _getresp(self): | 
					
						
							|  |  |  |         resp, o = self._getline() | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging > 1: print '*resp*', repr(resp) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         c = resp[:1] | 
					
						
							|  |  |  |         if c != '+': | 
					
						
							|  |  |  |             raise error_proto(resp) | 
					
						
							|  |  |  |         return resp | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: get a response plus following text from the server. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _getlongresp(self): | 
					
						
							|  |  |  |         resp = self._getresp() | 
					
						
							|  |  |  |         list = []; octets = 0 | 
					
						
							|  |  |  |         line, o = self._getline() | 
					
						
							|  |  |  |         while line != '.': | 
					
						
							|  |  |  |             if line[:2] == '..': | 
					
						
							|  |  |  |                 o = o-1 | 
					
						
							|  |  |  |                 line = line[1:] | 
					
						
							|  |  |  |             octets = octets + o | 
					
						
							|  |  |  |             list.append(line) | 
					
						
							|  |  |  |             line, o = self._getline() | 
					
						
							|  |  |  |         return resp, list, octets | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: send a command and get the response | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _shortcmd(self, line): | 
					
						
							|  |  |  |         self._putcmd(line) | 
					
						
							|  |  |  |         return self._getresp() | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Internal: send a command and get the response plus following text | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def _longcmd(self, line): | 
					
						
							|  |  |  |         self._putcmd(line) | 
					
						
							|  |  |  |         return self._getlongresp() | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # These can be useful: | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def getwelcome(self): | 
					
						
							|  |  |  |         return self.welcome | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def set_debuglevel(self, level): | 
					
						
							|  |  |  |         self._debugging = level | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # Here are all the POP commands: | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def user(self, user): | 
					
						
							|  |  |  |         """Send user name, return response
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         (should indicate password required). | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._shortcmd('USER %s' % user) | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def pass_(self, pswd): | 
					
						
							|  |  |  |         """Send password, return response
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         (response includes message count, mailbox size). | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         NB: mailbox is locked by server from here to 'quit()' | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._shortcmd('PASS %s' % pswd) | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def stat(self): | 
					
						
							|  |  |  |         """Get mailbox status.
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Result is tuple of 2 ints (message count, mailbox size) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         retval = self._shortcmd('STAT') | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  |         rets = retval.split() | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging: print '*stat*', repr(rets) | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  |         numMessages = int(rets[1]) | 
					
						
							|  |  |  |         sizeMessages = int(rets[2]) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         return (numMessages, sizeMessages) | 
					
						
							| 
									
										
										
										
											1998-09-02 14:42:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def list(self, which=None): | 
					
						
							|  |  |  |         """Request listing, return result.
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Result without a message number argument is in form | 
					
						
							|  |  |  |         ['response', ['mesg_num octets', ...]]. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Result when a message number argument is given is a | 
					
						
							|  |  |  |         single response: the "scan listing" for that message. | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2002-06-01 16:07:16 +00:00
										 |  |  |         if which is not None: | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             return self._shortcmd('LIST %s' % which) | 
					
						
							|  |  |  |         return self._longcmd('LIST') | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def retr(self, which): | 
					
						
							|  |  |  |         """Retrieve whole message number 'which'.
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Result is in form ['response', ['line', ...], octets]. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._longcmd('RETR %s' % which) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def dele(self, which): | 
					
						
							|  |  |  |         """Delete message number 'which'.
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Result is 'response'. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._shortcmd('DELE %s' % which) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def noop(self): | 
					
						
							|  |  |  |         """Does nothing.
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         One supposes the response indicates the server is alive. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._shortcmd('NOOP') | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def rset(self): | 
					
						
							|  |  |  |         """Not sure what this does.""" | 
					
						
							|  |  |  |         return self._shortcmd('RSET') | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def quit(self): | 
					
						
							|  |  |  |         """Signoff: commit changes on server, unlock mailbox, close connection.""" | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             resp = self._shortcmd('QUIT') | 
					
						
							|  |  |  |         except error_proto, val: | 
					
						
							|  |  |  |             resp = val | 
					
						
							|  |  |  |         self.file.close() | 
					
						
							|  |  |  |         self.sock.close() | 
					
						
							|  |  |  |         del self.file, self.sock | 
					
						
							|  |  |  |         return resp | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     #__del__ = quit | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     # optional commands: | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def rpop(self, user): | 
					
						
							|  |  |  |         """Not sure what this does.""" | 
					
						
							|  |  |  |         return self._shortcmd('RPOP %s' % user) | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-19 19:56:27 +00:00
										 |  |  |     timestamp = re.compile(r'\+OK.*(<[^>]+>)') | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     def apop(self, user, secret): | 
					
						
							|  |  |  |         """Authorisation
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         - only possible if server has supplied a timestamp in initial greeting. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         Args: | 
					
						
							|  |  |  |                 user    - mailbox user; | 
					
						
							|  |  |  |                 secret  - secret shared between client and server. | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         NB: mailbox is locked by server from here to 'quit()' | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2001-01-19 19:56:27 +00:00
										 |  |  |         m = self.timestamp.match(self.welcome) | 
					
						
							|  |  |  |         if not m: | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             raise error_proto('-ERR APOP not supported by server') | 
					
						
							|  |  |  |         import md5 | 
					
						
							| 
									
										
										
										
											2001-01-19 19:56:27 +00:00
										 |  |  |         digest = md5.new(m.group(1)+secret).digest() | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  |         digest = ''.join(map(lambda x:'%02x'%ord(x), digest)) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         return self._shortcmd('APOP %s %s' % (user, digest)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def top(self, which, howmuch): | 
					
						
							|  |  |  |         """Retrieve message header of message number 'which'
 | 
					
						
							|  |  |  |         and first 'howmuch' lines of message body. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Result is in form ['response', ['line', ...], octets]. | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         return self._longcmd('TOP %s %s' % (which, howmuch)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def uidl(self, which=None): | 
					
						
							|  |  |  |         """Return message digest (unique id) list.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         If 'which', result contains unique id for that message | 
					
						
							|  |  |  |         in the form 'response mesgnum uid', otherwise result is | 
					
						
							|  |  |  |         the list ['response', ['mesgnum uid', ...], octets] | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2002-06-01 16:07:16 +00:00
										 |  |  |         if which is not None: | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |             return self._shortcmd('UIDL %s' % which) | 
					
						
							|  |  |  |         return self._longcmd('UIDL') | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging > 1: print '*get*', repr(line) | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         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): | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         if self._debugging > 1: print '*put*', repr(line) | 
					
						
							| 
									
										
										
										
											2003-10-31 12:52:35 +00:00
										 |  |  |         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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-09 13:50:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1998-04-06 18:27:27 +00:00
										 |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  |     import sys | 
					
						
							|  |  |  |     a = POP3(sys.argv[1]) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     print a.getwelcome() | 
					
						
							| 
									
										
										
										
											2001-02-09 06:56:56 +00:00
										 |  |  |     a.user(sys.argv[2]) | 
					
						
							|  |  |  |     a.pass_(sys.argv[3]) | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |     a.list() | 
					
						
							|  |  |  |     (numMsgs, totalSize) = a.stat() | 
					
						
							|  |  |  |     for i in range(1, numMsgs + 1): | 
					
						
							|  |  |  |         (header, msg, octets) = a.retr(i) | 
					
						
							| 
									
										
										
										
											2004-02-12 17:35:32 +00:00
										 |  |  |         print "Message %d:" % i | 
					
						
							| 
									
										
										
										
											2001-01-15 00:50:52 +00:00
										 |  |  |         for line in msg: | 
					
						
							|  |  |  |             print '   ' + line | 
					
						
							|  |  |  |         print '-----------------------' | 
					
						
							|  |  |  |     a.quit() |