summaryrefslogtreecommitdiff
path: root/src/leap/email/smtp/smtprelay.py
blob: 10020a543e174867e004aa6c31ad66d91a2683d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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()