mxoemu/Dependencies/Sockets/SmtpdSocket.cpp
2010-08-28 06:30:32 +02:00

244 lines
4.7 KiB
C++

/**
** \file SmtpdSocket.cpp
** \date 2007-05-10
** \author grymse@alhem.net
**/
/*
Copyright (C) 2007-2010 Anders Hedstrom
This library is made available under the terms of the GNU GPL, with
the additional exemption that compiling, linking, and/or using OpenSSL
is allowed.
If you would like to use this library in a closed-source application,
a separate license agreement is available. For information about
the closed-source license agreement for the C++ sockets library,
please visit http://www.alhem.net/Sockets/license.html and/or
email license@alhem.net.
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 "SmtpdSocket.h"
#include "Parse.h"
#include "Utility.h"
#ifdef SOCKETS_NAMESPACE
namespace SOCKETS_NAMESPACE {
#endif
SmtpdSocket::SmtpdSocket(ISocketHandler& h)
:TcpSocket(h)
,m_hello(false)
,m_data(false)
,m_header(false)
{
SetLineProtocol();
}
void SmtpdSocket::OnAccept()
{
Send("220 ESMTP; \r\n");
}
void SmtpdSocket::OnLine(const std::string& line)
{
if (m_data)
{
if (m_header)
{
if (!line.size())
{
if (m_header_line.size())
{
Parse pa(m_header_line, ":");
std::string key = pa.getword();
OnHeader(key, pa.getrest());
}
m_header = false;
OnHeaderComplete();
}
else
if (line[0] == ' ' || line[0] == '\t')
{
m_header_line += line;
}
else
{
if (m_header_line.size())
{
Parse pa(m_header_line, ":");
std::string key = pa.getword();
OnHeader(key, pa.getrest());
}
m_header_line = line;
}
}
else
if (line == ".")
{
m_data = false;
if (OnDataComplete())
Send("250 OK\r\n");
else
Send("550 Failed\r\n");
}
else
if (line.size() && line[0] == '.')
{
OnData(line.substr(1));
}
else
{
OnData(line);
}
return;
}
Parse pa(line);
std::string cmd = Utility::ToUpper(pa.getword());
if (cmd == "EHLO")
{
if (!OnHello(pa.getrest()))
{
Send("550 Failed\r\n");
}
else
{
m_hello = true;
Send("250 mail.alhem.net\r\n");
}
}
else
if (cmd == "HELO")
{
if (!OnHello(pa.getrest()))
{
Send("550 Failed\r\n");
}
else
{
m_hello = true;
Send("250 mail.alhem.net\r\n");
}
}
else
if (!m_hello)
{
OnAbort(SMTP_NO_HELLO);
SetCloseAndDelete();
}
else
if (cmd == "MAIL") // mail from:
{
Parse pa(line, ":");
pa.getword(); // 'mail'
pa.getword(); // 'from'
std::string email = Utility::ToLower(pa.getrest());
EmailAddress addr( email );
if (addr.GetName().size() > 64)
{
OnAbort(SMTP_NAME_TOO_LONG);
Send("500 Name too long.\r\n");
return;
}
if (addr.GetDomain().size() > 64)
{
OnAbort(SMTP_DOMAIN_TOO_LONG);
Send("500 Domain too long.\r\n");
return;
}
if (!OnMailFrom( addr ))
{
Send("550 Failed\r\n");
}
else
{
Send("250 OK\r\n");
}
}
else
if (cmd == "RCPT") // rcpt to:
{
Parse pa(line, ":");
pa.getword(); // 'rcpt'
pa.getword(); // 'to'
std::string email = Utility::ToLower(pa.getrest());
// %! reject based on user / domain?
EmailAddress addr( email );
if (addr.GetName().size() > 64)
{
OnAbort(SMTP_NAME_TOO_LONG);
Send("500 Name too long.\r\n");
return;
}
if (addr.GetDomain().size() > 64)
{
OnAbort(SMTP_DOMAIN_TOO_LONG);
Send("500 Domain too long.\r\n");
return;
}
if (!OnRcptTo( addr ))
{
Send("553 Failed\r\n");
}
else
{
Send("250 OK\r\n");
}
}
else
if (cmd == "DATA")
{
Send("354 Enter mail, end with \".\" on a line by itself\r\n");
m_data = true;
m_header = false;
}
else
if (cmd == "RSET")
{
m_data = false;
m_header = false;
OnRset();
Send("250 OK\r\n"); // %! ???
}
else
if (cmd == "QUIT")
{
OnAbort(SMTP_QUIT);
Send("221 Bye Bye\r\n");
SetCloseAndDelete();
}
else
if (cmd == "NOOP")
{
Send("250 OK\r\n");
}
else
{
OnNotSupported(cmd, pa.getrest());
}
}
#ifdef SOCKETS_NAMESPACE
} // namespace SOCKETS_NAMESPACE {
#endif