-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.py
134 lines (93 loc) · 3.36 KB
/
handlers.py
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
127
128
129
130
131
132
import socket
import socketserver
from util import eprint, lookahead
class SMTPHandler(socketserver.StreamRequestHandler):
def setup(self):
super(SMTPHandler, self).setup()
self.reset_state()
def reset_state(self):
self.recipients = []
self.mail_from = None
def handle(self):
self.write_output(220, socket.gethostname(), "SimpleSMTPServer, how you doin'?")
for line in self.rfile:
command = line.decode("ascii").strip().split(" ")
action = command[0].upper()
if action == "QUIT":
self.write_output(221, "Bye")
break
elif action == "MAIL":
self.handle_mail(command)
elif action == "EHLO":
self.handle_ehlo(command)
elif action == "RCPT":
self.handle_rcpt(command)
elif action == "DATA":
self.handle_data(command)
else:
eprint("Unknown: ", *command)
self.write_output(502, "Error: command not recognized.")
def write_output(self, *args, sep=" "):
message = sep.join(str(x) for x in args)
message += "\r\n"
self.wfile.write(message.encode("ascii"))
def handle_ehlo(self, command):
# Verify hostname
try:
peer_ip, peer_port = self.request.getpeername()
_, _, valid_ips = socket.gethostbyname_ex(command[1])
if peer_ip not in valid_ips:
eprint("Warning: %s does not resolve to %s" % (command[1], peer_ip))
except socket.error:
eprint("Warning: unable to resolve peer name", command[1])
# Construct EHLO messages
ehlo_mesg = [
(socket.gethostname(), None),
("SIZE", 10 * (1 << 30)), # 10MB should be enough for everyone
]
for entry, last in lookahead(ehlo_mesg):
if last:
msg = "250 "
else:
msg = "250-"
key, value = entry
msg += str(key)
if value is not None:
msg += " " + str(value)
self.write_output(msg)
def handle_mail(self, command):
self.mail_from = command[1][6:-1]
self.recipients = []
self.send_ok()
def handle_rcpt(self, command):
recipient = command[1][4:-1]
self.recipients.append(recipient)
self.send_ok()
def handle_data(self, command):
if self.mail_from is None:
self.write_output(503, "No MAIL command")
return
elif not self.recipients:
self.write_output(503, "No recipients specified")
return
self.write_output(354, "Go ahead, send message")
message = ""
prev = None
crlf = "\r\n"
for line in self.rfile:
line = line.decode("ascii")
if prev == crlf and line == "." + crlf:
break
elif prev is not None:
message += prev
prev = line
self.send_ok()
params = (
self.mail_from,
"' and '".join(self.recipients),
message
)
eprint("Recieved message from '%s' to '%s':\n%s" % params)
self.reset_state()
def send_ok(self):
self.write_output(250, "Ok")