diff --git a/Lib/poplib.py b/Lib/poplib.py new file mode 100644 index 00000000000..7b406d98273 --- /dev/null +++ b/Lib/poplib.py @@ -0,0 +1,201 @@ +"""A POP3 client class. Based on the J. Myers POP3 draft, Jan. 96 + +Author: David Ascher [heavily stealing from +nntplib.py] + +""" + +__version__ = "0.01a - Feb 1, 1996 (with formatting changes by GvR)" + +# Example (see the test function at the end of this file) + +TESTSERVER = "localhost" +TESTACCOUNT = "test" +TESTPASSWORD = "_passwd_" + +# Imports + +from types import StringType +import regex +import socket +import string + +# Exception raised when an error or invalid response is received: +error_proto = 'pop3.error_proto' # response does not begin with + + +# Standard Port +POP3_PORT = 110 + +# Line terminators (we always output CRLF, but accept any of CRLF, CR, LF) +CRLF = '\r\n' + +# This library 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) +# APOP name digest apop(name, digest) +# TOP msg n top(msg, n) +# UIDL [msg] uidl(msg = None) +# + + +class POP3: + def __init__(self, host, port = POP3_PORT): + self.host = host + self.port = port + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.connect(self.host, self.port) + self.file = self.sock.makefile('rb') + self._debugging = 0 + self.welcome = self._getresp() + + def _putline(self, line): + line = line + CRLF + if self._debugging > 1: print '*put*', `line` + self.sock.send(line) + + # Internal: send one command to the server (through _putline()) + def _putcmd(self, line): + if self._debugging: print '*cmd*', `line` + self._putline(line) + + # Internal: return one line from the server, stripping CRLF. + # Raise EOFError if the connection is closed + def _getline(self): + line = self.file.readline() + if self._debugging > 1: + print '*get*', `line` + if not line: raise EOFError + if line[-2:] == CRLF: line = line[:-2] + elif line[-1:] in CRLF: line = line[:-1] + return line + + # Internal: get a response from the server. + # Raise various errors if the response indicates an error + def _getresp(self): + resp = self._getline() + if self._debugging > 1: print '*resp*', `resp` + c = resp[:1] + if c != '+': + raise error_proto, resp + return resp + + # Internal: get a response plus following text from the server. + # Raise various errors if the response indicates an error + def _getlongresp(self): + resp = self._getresp() + list = [] + while 1: + line = self._getline() + if line == '.': + break + list.append(line) + return resp, list + + # Internal: send a command and get the response + def _shortcmd(self, line): + self._putcmd(line) + return self._getresp() + + # Internal: send a command and get the response plus following text + def _longcmd(self, line): + self._putcmd(line) + return self._getlongresp() + + # These can be useful: + + def getwelcome(self): + return self.welcome + + def set_debuglevel(self, level): + self._debugging = level + + # Here are all the POP commands: + + def user(self, user): + user = str(user) + return self._shortcmd('USER ' + user) + + def pass_(self, pswd): + pswd = str(pswd) + return self._shortcmd('PASS ' + pswd) + + def stat(self): + retval = self._shortcmd('STAT') + rets = string.split(retval) + numMessages = string.atoi(rets[1]) + sizeMessages = string.atoi(rets[2]) + return (numMessages, sizeMessages) + + def list(self, msg=None): + if msg: + msg = str(msg) + return self._longcmd('LIST ' + msg) + else: + return self._longcmd('LIST') + + def retr(self, which): + which = str(which) + return self._longcmd('RETR ' + which) + + def dele(self, which): + which = str(which) + return self._shortcmd('DELE ' + which) + + def noop(self): + return self._shortcmd('NOOP') + + def rset(self): + return self._shortcmd('RSET') + + # optional commands: + + def apop(self, digest): + digest = str(digest) + return self._shortcmd('APOP ' + digest) + + def top(self, which, howmuch): + which = str(which) + howmuch = str(howmuch) + return self._longcmd('TOP ' + which + ' ' + howmuch) + + def uidl(self, which = None): + if which: + which = str(which) + return self._longcmd('UIDL ' + which) + else: + return self._longcmd('UIDL') + + def quit(self): + resp = self._shortcmd('QUIT') + self.file.close() + self.sock.close() + del self.file, self.sock + return resp + +if __name__ == "__main__": + a = POP3(TESTSERVER) + print a.getwelcome() + a.user(TESTACCOUNT) + a.pass_(TESTPASSWORD) + a.list() + (numMsgs, totalSize) = a.stat() + for i in range(1, numMsgs + 1): + (header, msg, octets) = a.retr(i) + print "Message ", `i`, ':' + for line in msg: + print ' ' + line + print '-----------------------' + a.quit()