[Twisted-Python] POP3 improvements
Abe Fettig
abe at fettig.net
Mon Dec 30 13:09:52 EST 2002
(diff attached to make it easier to see what I changed)
On Mon, 2002-12-30 at 11:48, Itamar Shtull-Trauring wrote:
>
> > Currently it works like this: When you send a command that returns a
> > multi-line response (LIST or RETR), you pass an optional file-like
> > object that the response should be written to. If no file argument is
> > supplied a StringIO is used. When the server is finished sending the
> > response, handle_COMMANDNAME is called, passing back the file object
> > containing the downloaded response.
>
> Instead of calling handle_COMMANDNAME, why not return a Deferred of the
> success?
Based on other Twisted protocol handlers I thought that the preferred
way to handle events in protocols was to create methods that get called
in response to events. That way you create a class that inherits from
POP3Client, and override the methods for events you want to handle.
Being able use classes and inheritance this way is one of the things I
really like about Twisted.
Also, that's the way it was in the original POP3 module.
>
> > At this point I'm still not correcting byte-stuffed lines in
> > downloaded messages, so I need to do that. Also, if it would be OK
> > with everyone, I think it might be nice to make POP3Client a little
> > higher-level, so that LIST, for example, would return an actual list
> > instead of a file(or, in the current implementation, a string) that
> > the implementer has to parse. And it might be good to offer support
> > for more POP3 commands like TOP.
>
> Or perhaps the Deferred should return that.
-------------- next part --------------
--- /usr/lib/python2.2/site-packages/twisted/protocols/pop3.py 2002-07-24 15:04:56.000000000 -0400
+++ pop3support.py 2002-12-30 10:56:14.000000000 -0500
@@ -21,6 +21,7 @@
from twisted.protocols import basic
import os, time, string, operator, stat, md5, binascii
from twisted.internet import protocol
+from cStringIO import StringIO
class POP3Error(Exception):
pass
@@ -167,11 +168,16 @@
welcomeRe = re.compile('<(.*)>')
def sendShort(self, command, params):
+ self.line_mode = 1
self.transport.write('%s %s\r\n' % (command, params))
self.command = command
self.mode = SHORT
- def sendLong(self, command, params):
+ def sendLong(self, command, params, dataFile=None):
+ if not dataFile: dataFile = StringIO()
+ self.dataFile = dataFile
+ self.dataFileTail = ""
+ self.line_mode = 1
self.transport.write('%s %s\r\n' % (command, params))
self.command = command
self.mode = FIRST_LONG
@@ -189,23 +195,41 @@
if m:
self.welcomeCode = m.group(1)
+ def rawDataReceived(self, data):
+ tail = self.dataFileTail + data[-5:]
+ if tail.endswith("\r\n.\r\n"):
+ self.dataFile.write(data[:-5])
+ method = getattr(self, 'handle_'+self.command, None)
+ if method is not None:
+ self.dataFile.seek(0)
+ method(self.dataFile)
+ else:
+ self.dataFile.write(data)
+ self.dataFileTail = data[-5:]
+
def lineReceived(self, line):
- if self.mode == SHORT or self.mode == FIRST_LONG:
+ if self.mode == SHORT:
self.mode = NEXT[self.mode]
method = getattr(self, 'handle_'+self.command, self.handle_default)
method(line)
- elif self.mode == LONG:
- if line == '.':
- self.mode = NEXT[self.mode]
- method = getattr(self, 'handle_'+self.command+'_end', None)
- if method is not None:
- method()
- return
- if line[:1] == '.':
- line = line[1:]
- method = getattr(self, 'handle_'+self.command+'_continue', None)
- if method is not None:
- method(line)
+ elif self.mode == FIRST_LONG:
+ self.mode = NEXT[self.mode]
+ self.line_mode = 0
+ method = getattr(self, 'handle_'+self.command+'_start', self.handle_default)
+ method(line)
+
+ #elif self.mode == LONG:
+ # if line == '.':
+ # self.mode = NEXT[self.mode]
+ # method = getattr(self, 'handle_'+self.command+'_end', None)
+ # if method is not None:
+ # method()
+ # return
+ # if line[:1] == '.':
+ # line = line[1:]
+ # method = getattr(self, 'handle_'+self.command+'_continue', None)
+ # if method is not None:
+ # method(line)
def apopAuthenticate(self, user, password):
digest = md5.new(magic+password).digest()
@@ -214,17 +238,24 @@
def apop(self, user, digest):
self.sendLong('APOP', user+' '+digest)
- def retr(self, i):
- self.sendLong('RETR', i)
+
+ def retr(self, i, destFile=None):
+ self.sendLong('RETR', i, destFile)
+
def dele(self, i):
self.sendShort('DELE', i)
+
def list(self, i=''):
self.sendLong('LIST', i)
+
def uidl(self, i=''):
self.sendLong('UIDL', i)
+
def user(self, name):
self.sendShort('USER', name)
+
def pass_(self, pass_):
self.sendShort('PASS', pass_)
+
def quit(self):
self.sendShort('QUIT', '')
More information about the Twisted-Python
mailing list