summaryrefslogtreecommitdiff
path: root/src/leap/email/smtp
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/email/smtp')
-rw-r--r--src/leap/email/smtp/__init__.py0
-rw-r--r--src/leap/email/smtp/smtprelay.py126
2 files changed, 126 insertions, 0 deletions
diff --git a/src/leap/email/smtp/__init__.py b/src/leap/email/smtp/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/leap/email/smtp/__init__.py
diff --git a/src/leap/email/smtp/smtprelay.py b/src/leap/email/smtp/smtprelay.py
new file mode 100644
index 00000000..10020a54
--- /dev/null
+++ b/src/leap/email/smtp/smtprelay.py
@@ -0,0 +1,126 @@
+from zope.interface import implements
+from twisted.mail import smtp
+from twisted.internet.protocol import ServerFactory
+from twisted.internet import reactor
+from twisted.internet import defer
+from email.Header import Header
+from StringIO import StringIO
+
+
+class SMTPFactory(ServerFactory):
+ """
+ Factory for an SMTP server with encrypted relaying capabilities.
+ """
+
+ def buildProtocol(self, addr):
+ "Return a protocol suitable for the job."
+ smtpProtocol = smtp.SMTP(SMTPDelivery())
+ smtpProtocol.factory = self
+ return smtpProtocol
+
+
+class SMTPDelivery(object):
+ """
+ Validate email addresses and handle message delivery.
+ """
+
+ implements(smtp.IMessageDelivery)
+
+ def __init__(self):
+ self.gpgkey = ''
+
+ def receivedHeader(self, helo, origin, recipients):
+ myHostname, clientIP = helo
+ headerValue = "by %s from %s with ESMTP ; %s" % (
+ myHostname, clientIP, smtp.rfc822date( ))
+ # email.Header.Header used for automatic wrapping of long lines
+ return "Received: %s" % Header(headerValue)
+
+ def validateTo(self, user):
+ """Assert existence of GPG public key for a recipient."""
+ # for now just accept any receipient
+ print "Accepting mail for %s..." % user.dest
+ return lambda: EncryptedMessage(user, self.gpgkey)
+
+ def validateFrom(self, helo, originAddress):
+ # accept mail from anywhere. To reject an address, raise
+ # smtp.SMTPBadSender here.
+ return originAddress
+
+
+class EncryptedMessage():
+ """
+ Receive plaintext from client, encrypt it and send message to
+ recipients.
+ """
+ implements(smtp.IMessage)
+
+ SMTP_HOSTNAME = "mail.riseup.net"
+ SMTP_PORT = 25
+
+ def __init__(self, user, gpgkey):
+ self.user = user
+ self.gpgkey = gpgkey
+ self.getSMTPInfo()
+ self.lines = []
+
+ def lineReceived(self, line):
+ """Store email DATA lines as they arrive."""
+ self.lines.append(line)
+
+ def eomReceived(self):
+ """Encrypt and send message."""
+ print "Message data complete."
+ self.lines.append('') # add a trailing newline
+ return self.sendMail()
+
+ def connectionLost(self):
+ print "Connection lost unexpectedly!"
+ # unexpected loss of connection; don't save
+ del(self.lines)
+
+ def sendSuccess(self, r):
+ print r
+ reactor.stop()
+
+ def sendError(self, e):
+ print e
+ reactor.stop()
+
+ def sendMail(self):
+ self.lines = [self.lines[0]] + \
+ ["From: %s" % self.user.orig.addrstr] + \
+ ["To: %s" % self.user.dest.addrstr] + \
+ self.lines[1:]
+ msg = '\n'.join(self.lines)
+ d = defer.Deferred()
+ factory = smtp.ESMTPSenderFactory(self.smtp_username,
+ self.smtp_password,
+ self.smtp_username,
+ self.user.dest.addrstr,
+ StringIO(msg),
+ d)
+ # the next call is TSL-powered!
+ reactor.connectTCP(self.SMTP_HOSTNAME, self.SMTP_PORT, factory)
+ d.addCallback(self.sendSuccess)
+ d.addErrback(self.sendError)
+ #reactor.run()
+ return d
+
+
+ # this will be replaced by some other mechanism of obtaining credentials
+ # for SMTP server.
+ def getSMTPInfo(self):
+ f = open('/var/tmp/smtp-info.txt', 'r')
+ self.smtp_host = f.readline().rstrip()
+ self.smtp_port = f.readline().rstrip()
+ self.smtp_username = f.readline().rstrip()
+ self.smtp_password = f.readline().rstrip()
+ f.close()
+
+
+# run server
+if __name__ == "__main__":
+ import sys
+ reactor.listenTCP(25, SMTPFactory())
+ reactor.run()