[Twisted-Python] Simple multiplex-relayer with
Jp Calderone
exarkun at divmod.com
Fri Nov 26 10:57:35 MST 2004
On Fri, 26 Nov 2004 11:04:44 +0200, bostik at stinghorn.com (Mika Bostrom) wrote:
> Good day, hackers.
>
> I'm trying to implement a rather simple, localhost-bound mail relay
> with Twisted. The setup is follows:
>
> [snip]
>
> Code:
>
> [--snip--]
> #!/usr/bin/python
>
> from twisted.internet import reactor, protocol, defer
> from twisted.protocols import smtp
> from twisted.python import log
> import sys
>
>
> class RelayUtility:
> """Utility class for holding runtime values"""
>
> def __init__(self):
> self.maxconns =3D 20
> self.active =3D 0
>
> class RelayMessage(smtp.IMessage):
> def __init__(self):
> smtp.IMessage.__init__(self)
> self.msg =3D []
>
The above class is the most obvious problem I see here. Interfaces are not meant to be subclassed in this manner. What you really want is something more like:
class RelayMessage:
__implements__ = smtp.IMessage
def lineReceived(self, line):
# Do something with the line; perhaps buffer it in memory,
# perhaps try and send it to another connection.
def eomReceived(self):
# The message has been fully received; flush the buffer or take
# whatever other action is appropriate to ensure message delivery.
# Return a Deferred that fires when the message has been successfully
# delivered.
def connectionLost(self):
# Discard message content, delivery is a failure
>
>
> class RelayProtocol(smtp.ESMTP):
> """Relayer; sucks the mail in"""
>
> def __init__(self):
> self.util =3D util
> # Normal operations
> smtp.ESMTP.__init__(self)
> self.host =3D "nowhere.dot.invalid"
>
> def connectionLost(self, reason):
> self.util.active -=3D 1
>
> def connectionMade(self):
> # The easiest way. Increments upon connection, decrements
> # upon disconnection; In case of full queue, just kick the client
> self.util.active +=3D 1
> if (self.util.active <=3D self.util.maxconns):
> smtp.ESMTP.connectionMade(self)
> else:
> self.sendCode(430, "Queue full. Try again later.")
> self.transport.loseConnection()
>
>
> # This can't be right
> def validateFrom(self, helo, origin):
> return smtp.Address(origin, None)
>
> # This is certainly not right, DATA barks
> def validateTo(self, user):
> return RelayMessage
You _could_ do things this way, but a preferable way is probably:
class RelayDeliveryFactory:
__implements__ = smtp.IMessageDeliveryFactory
def getMessageDelivery(self):
return RelayDelivery()
class RelayDelivery:
__implements__ = smtp.IMessageDelivery
def receivedHeader(self, helo, origin, recipients):
return "Received: something"
def validateFrom(self, helo, origin):
return origin
def validateTo(self, user):
return RelayMessage
>
> class RelayFactory(smtp.SMTPFactory):
> protocol =3D RelayProtocol
>
Then add this buildProtocol method:
def buildProtocol(self, addr):
p = smtp.SMTPFactory.buildProtocol(self, addr)
p.deliveryFactory = RelayDeliveryFactory()
return p
ESMTP will call getMessageDelivery on its deliveryFactory attribute, now that it isn't None. On the object it returns, it will call receivedHeader, validateFrom, and validateTo. And on the object returned by calling the object returned by validateTo, it will pass the contents of the message being delivered, letting you relay it wherever is appropriate.
Hope this helps,
Jp
More information about the Twisted-Python
mailing list