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 + "'"; +}  | 
