summaryrefslogtreecommitdiff
path: root/smtp.py
diff options
context:
space:
mode:
authoryvesf <yvesf@aurora.xapek.org>2010-02-20 20:14:56 +0100
committeryvesf <yvesf@aurora.xapek.org>2010-02-20 20:14:56 +0100
commitdf5b30b3820d927cc761782f8d6edf5795e89e3d (patch)
treee11df00ea6f925a2104f6ef77d353539b606cca8 /smtp.py
downloadfakesmtp-df5b30b3820d927cc761782f8d6edf5795e89e3d.tar.gz
fakesmtp-df5b30b3820d927cc761782f8d6edf5795e89e3d.zip
import
Diffstat (limited to 'smtp.py')
-rw-r--r--smtp.py105
1 files changed, 105 insertions, 0 deletions
diff --git a/smtp.py b/smtp.py
new file mode 100644
index 0000000..b1b2e67
--- /dev/null
+++ b/smtp.py
@@ -0,0 +1,105 @@
+import asynchat, asyncore, socket
+import pwd, os, sys
+import email
+from mailbox import Maildir,MaildirMessage
+
+class SMTPChannel(asynchat.async_chat):
+ def __init__(self, server, sock, addr):
+ asynchat.async_chat.__init__(self, sock)
+ self.server = server
+ self.set_terminator("\n")
+ self.data = ""
+ self.read_data = False
+
+ def collect_incoming_data(self, data):
+ if len(self.data) > 0:
+ self.data += "\n"
+ self.data += data
+ if self.data.__len__() > 16384:
+ print "too much data, shutdown"
+ self.close_when_done()
+
+ def found_terminator(self):
+ print self.data
+ if self.read_data:
+ if self.data.endswith("\n."):
+ self.push("250 Ok: queued as 12345\n")
+ self.read_data = False
+ mail = email.message_from_string(self.data)
+ self.server.maildir.add(mail)
+ self.server.maildir.flush()
+ self.data = ""
+
+ elif self.data.startswith("EHLO") \
+ or self.data.startswith("HELO"):
+ self.push("HELO there\n")
+ self.data = ""
+ elif self.data.startswith("DATA"):
+ self.push("354 End data with <CR><LF>.<CR><LF>\n")
+ self.read_data = True
+ self.data=""
+ elif self.data.startswith("QUIT"):
+ self.data = ""
+ self.push("221 Bye\n")
+ self.close_when_done()
+ else:
+ self.push("250 OK\n")
+ self.data = ""
+
+
+class SMTPServer(asyncore.dispatcher):
+ def __init__(self):
+ asyncore.dispatcher.__init__(self)
+ self.port = 25
+ self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.set_reuse_addr()
+ self.bind(("", self.port))
+ self.listen(5)
+ self.maildir = Maildir("Maildir", create=True)
+
+ def handle_accept(self):
+ conn, addr = self.accept()
+ SMTPChannel(self, conn, addr)
+
+
+
+if __name__ == '__main__':
+ s = SMTPServer()
+
+ #user change
+ pwinfo = pwd.getpwnam('nobody')
+ os.setregid(pwinfo[3],pwinfo[3])
+ os.setreuid(pwinfo[2],pwinfo[2])
+
+ #"Robustly turn into a UNIX daemon, running in our_home_dir."
+ # First fork
+ try:
+ pid = os.fork()
+ if pid > 0:
+ print "PID: %s" % pid
+ sys.exit(0) # kill off parent
+ except OSError, e:
+ sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
+ sys.exit(1)
+ os.setsid()
+ os.chdir('/')
+ os.umask(0)
+
+ # Second fork
+ try:
+ if os.fork() > 0:
+ os._exit(0)
+ except OSError, e:
+ sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
+ os._exit(1)
+
+ si = open('/dev/null', 'r')
+ so = open('/dev/null', 'a+', 0)
+ se = open('/dev/null', 'a+', 0)
+ os.dup2(si.fileno(), sys.stdin.fileno())
+ os.dup2(so.fileno(), sys.stdout.fileno())
+ os.dup2(se.fileno(), sys.stderr.fileno())
+ # Set custom file descriptors so that they get proper buffering.
+ sys.stdout, sys.stderr = so, se
+
+ asyncore.loop()