summaryrefslogtreecommitdiff
path: root/lib/MailServer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MailServer.cc')
-rw-r--r--lib/MailServer.cc205
1 files changed, 205 insertions, 0 deletions
diff --git a/lib/MailServer.cc b/lib/MailServer.cc
new file mode 100644
index 0000000..6b06219
--- /dev/null
+++ b/lib/MailServer.cc
@@ -0,0 +1,205 @@
+/*
+ * Baltisot
+ * Copyright (C) 1999-2008 Nicolas "Pixel" Noble
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <vector>
+#include <TaskMan.h>
+#include <MailServer.h>
+#include <BRegex.h>
+#include <CopyJob.h>
+#include <ReadJob.h>
+#include <Variables.h>
+
+const timeval timeout = { 8, 0 };
+
+const timeval timeout_sending = { 80, 0 };
+
+class ProcessSMTPRequest : public Task {
+ public:
+ ProcessSMTPRequest(const Socket & out) : s(out) {
+ SetBurst();
+ }
+ virtual ~ProcessSMTPRequest() {
+ }
+ virtual String GetName() {
+ return "Processing SMTP request";
+ }
+ protected:
+ virtual int Do() throw (GeneralException);
+ private:
+ Socket s;
+ Buffer b;
+ Task * c;
+ String from;
+ std::vector<String> tos;
+};
+
+static Regex single_dot("^\\.$"), dotted_line("^\\..+$");
+
+int ProcessSMTPRequest::Do() {
+ String l, cmd;
+ Buffer * out;
+
+ if (TaskMan::Event() == Task::EVT_TIMEOUT) {
+ Suspend(TASK_DONE);
+ }
+ RemoveTimeout();
+
+ switch (current) {
+ case 0:
+ if (!s.IsConnected()) return TASK_DONE;
+
+ b << "220 foo.bar Service Ready\r\n";
+ c = new CopyJob(&b, &s);
+ WaitFor(c);
+ current = 1;
+ WaitFor(timeout);
+ Suspend(TASK_ON_HOLD);
+
+ case 1:
+ delete c;
+
+ c = new ReadJob(&s, &b, any);
+ WaitFor(c);
+ current = 2;
+ WaitFor(timeout);
+ Suspend(TASK_ON_HOLD);
+
+ case 2:
+ delete c;
+
+ current = 1;
+
+ b >> l;
+ l.toupper();
+ cmd = l.extract(0, 3);
+
+ if (cmd == "HELO") {
+ b << "250 World.\r\n";
+ } else if (cmd == "MAIL") {
+ if (l.extract(0, 9) != "MAIL FROM:") {
+ b << "501 Syntax error.\r\n";
+ } else {
+ b << "250 Ok.\r\n";
+ from = l.extract(10).trim();
+ }
+ } else if (cmd == "RCPT") {
+ if (l.extract(0, 7) != "RCPT TO:") {
+ b << "501 Syntax error.\r\n";
+ } else {
+ b << "250 Ok.\r\n";
+ tos.push_back(l.extract(8).trim());
+ }
+ } else if (cmd == "DATA") {
+ current = 4;
+ b << "354 Ok, go ahead.\n";
+ } else if (cmd == "RSET") {
+ from = "";
+ tos.empty();
+ } else if (cmd == "NOOP") {
+ b << "250 Zzz.\r\n";
+ } else if (cmd == "QUIT") {
+ b << "221 Bye.\r\n";
+ current = 3;
+ } else {
+ b << "502 Unknow command.\r\n";
+ }
+
+ c = new CopyJob(&b, &s);
+ WaitFor(c);
+ WaitFor(timeout);
+ Suspend(TASK_ON_HOLD);
+
+ case 3:
+ delete c;
+ Suspend(TASK_DONE);
+
+ case 4:
+ delete c;
+
+ c = new ReadJob(&s, &b, single_dot);
+ WaitFor(c);
+ current = 5;
+ WaitFor(timeout_sending);
+ Suspend(TASK_ON_HOLD);
+
+ case 5:
+ delete c;
+
+ out = new Buffer();
+
+ for (;;) {
+ b >> l;
+ if (single_dot.Match(l))
+ break;
+ if (dotted_line.Match(l)) {
+ (*out) << l.extract(1);
+ } else {
+ (*out) << l;
+ }
+ }
+
+ // do something with out
+
+ delete out;
+
+ b << "250 Ok.\r\n";
+ c = new CopyJob(&b, &s);
+ WaitFor(c);
+ current = 1;
+ WaitFor(timeout);
+ Suspend(TASK_ON_HOLD);
+ }
+}
+
+MailServer::MailServer(int _port, const String & _name) throw (GeneralException) : name(_name), localport(_port) {
+ bool r;
+
+ r = Listener.SetLocal("", localport);
+ if (!r) {
+ throw GeneralException("Initialisation of the Mini SMTP-Server failed: can't bind");
+ }
+
+ r = Listener.Listen();
+
+ if (!r) {
+ throw GeneralException("Initialisation of the Mini SMTP-Server failed: can't listen");
+ }
+
+ Listener.SetNonBlock();
+ WaitFor(&Listener, W4_STICKY | W4_READING);
+}
+
+MailServer::~MailServer(void) {
+ Listener.close();
+}
+
+int MailServer::Do() throw (GeneralException) {
+ try {
+ Socket s = Listener.Accept();
+ s.SetNonBlock();
+ new ProcessSMTPRequest(s);
+ }
+ catch (GeneralException) {
+ }
+ return TASK_ON_HOLD;
+}
+
+String MailServer::GetName() {
+ return String("Mini SMTP-Server '") + name + "'";
+}