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
|
# Copyright 2009 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""SMTP test helper."""
__metaclass__ = type
__all__ = [
'SMTPController',
]
import fcntl
import logging
import Queue as queue
from lazr.smtptest.controller import QueueController
from lazr.smtptest.server import QueueServer
log = logging.getLogger('lazr.smtptest')
class SMTPServer(QueueServer):
"""SMTP server which knows about Launchpad test specifics."""
def handle_message(self, message):
"""See `QueueServer.handle_message()`."""
message_id = message.get('message-id', 'n/a')
log.debug('msgid: %s, to: %s, beenthere: %s, from: %s, rcpt: %s',
message_id, message['to'],
message['x-beenthere'],
message['x-mailfrom'], message['x-rcptto'])
from Mailman.Utils import list_names
listnames = list_names()
try:
local, hostname = message['to'].split('@', 1)
log.debug('local: %s, hostname: %s, listnames: %s',
local, hostname, listnames)
except ValueError:
# There was no '@' sign in the email message, so ignore it.
log.debug('Bad To header: %s', message.get('to', 'n/a'))
return
# If the message came from Mailman, place it onto the queue. If the
# local part indicates that the message is destined for a Mailman
# mailing list, deliver it to Mailman's incoming queue.
# pylint: disable-msg=F0401
if local in listnames and 'x-beenthere' not in message:
# It's destined for a mailing list.
log.debug('delivered to Mailman: %s', message_id)
from Mailman.Post import inject
inject(local, message)
else:
# It came from Mailman and goes in the queue, or it's destined for
# a 'normal' user. Either way, it goes in the queue.
log.debug('delivered to upstream: %s', message_id)
self.queue.put(message)
def reset(self):
# Base class is old-style.
QueueServer.reset(self)
# Consume everything out of the queue.
while True:
try:
self.queue.get_nowait()
except queue.Empty:
break
class SMTPController(QueueController):
"""A controller for the `SMTPServer`."""
def _make_server(self, host, port):
"""See `QueueController`."""
self.server = SMTPServer(host, port, self.queue)
# Set FD_CLOEXEC on the port's file descriptor, so that forked
# processes like uuidd won't steal the port.
flags = fcntl.fcntl(self.server._fileno, fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.server._fileno, fcntl.F_SETFD, flags)
|