diff options
-rw-r--r-- | include/MailServer.h | 46 | ||||
-rw-r--r-- | lib/MailServer.cc | 205 |
2 files changed, 251 insertions, 0 deletions
diff --git a/include/MailServer.h b/include/MailServer.h new file mode 100644 index 0000000..df1f83a --- /dev/null +++ b/include/MailServer.h @@ -0,0 +1,46 @@ +/* + * 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 + */ + +#ifndef __MAILSERVER_H__ +#define __MAILSERVER_H__ + +#include <Socket.h> +#include <BString.h> +#include <Task.h> +#include <Handle.h> +#include <Buffer.h> +#include <Exceptions.h> +#include <Variables.h> + +class MailServer : public Task { + public: + MailServer(int = 2500, const String & = String("GruiK Server v0.2")) throw (GeneralException); + virtual ~MailServer(); + virtual String GetName(); + + protected: + virtual int Do() throw (GeneralException); + + private: + Socket Listener; + String name; + int localport; +}; + +#endif 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 + "'"; +} |