|
|
#include "emailer.h"
#include "Smtp.h"
class EMailer::Private
{
public:
Smtp smtp;
};
EMailer::EMailer(const string& smtpserver)
: impl(* new EMailer::Private)
{
impl.smtp.SmtpServer = smtpserver;
}
EMailer::~EMailer(void)
{
delete &impl;
}
void EMailer::Subject(const string& sub)
{
impl.smtp.Subject = sub;
}
void EMailer::ToAddress(const string& addr)
{
impl.smtp.To = addr;
}
void EMailer::FromAddress(const string& addr)
{
impl.smtp.From = addr;
}
void EMailer::Body(const string& text)
{
mBody += text;
}
void EMailer::Send()
{
impl.smtp.Content = mBody;
try
{
impl.smtp.Send();
}
catch(...)
{
}
impl.smtp.Close();
}
|
|
|
#pragma once
#include <string>
using std::string;
class EMailer
{
public:
explicit EMailer(const string& smtpserver);
~EMailer();
void Subject(const string& sub);
void ToAddress(const string& addr);
void FromAddress(const string& addr);
void Body(const string& text);
void Send();
private:
string mBody;
class Private;
Private& impl;
};
|
|
|
#include <string>
#include <winsock2.h>
using namespace std;
#include "Smtp.h"
#include "WSAInit.h"
WSAInit instance;
#include "SmtpException.h"
#include "SmtpHostInfo.h"
#include "SocketT.h"
typedef SocketT<SmtpHostInfo, SmtpException> SmartSocket;
#include "SmtpWriter.h"
class Smtp::Private
{
public:
SmartSocket mSocket;
} ;
Smtp::Smtp()
: impl(* new Smtp::Private)
{
}
Smtp::~Smtp()
{
impl.mSocket.Close();
delete &impl;
}
void Smtp::Send()
{
Create();
Connect();
WriteHello();
WriteFrom();
WriteTo();
WriteStartData();
WriteBody();
WriteQuit();
}
void Smtp::Close()
{
impl.mSocket.Close();
}
void Smtp::Create()
{
impl.mSocket.SetServer(SmtpServer);
impl.mSocket.Create();
}
void Smtp::Connect()
{
impl.mSocket.Connect();
CheckResponse("220");
}
void Smtp::WriteHello()
{
SmtpWriter writer(impl.mSocket);
writer.Line("HELO " + impl.mSocket.GetLocalAddr());
writer.Flush();
CheckResponse("250");
}
void Smtp::WriteFrom()
{
SmtpWriter writer(impl.mSocket);
writer.HeaderLine("MAIL FROM", From);
writer.Flush();
CheckResponse("250");
}
void Smtp::WriteTo()
{
SmtpWriter writer(impl.mSocket);
writer.HeaderLine("RCPT TO", To);
writer.Flush();
CheckResponse("250");
}
void Smtp::WriteStartData()
{
SmtpWriter writer(impl.mSocket);
writer.Line("DATA");
writer.Flush();
CheckResponse("354");
}
void Smtp::WriteBody()
{
SmtpWriter writer(impl.mSocket);
writer.Body(Subject, To, From, Content);
writer.Flush();
CheckResponse("250");
}
void Smtp::WriteQuit()
{
SmtpWriter writer(impl.mSocket);
writer.Line("QUIT");
writer.Flush();
CheckResponse("221");
}
void Smtp::CheckResponse(const string& s)
{
string response = impl.mSocket.Response();
if (response.find(s) == response.npos)
throw SmtpException("Expected: '" + s + "' actual: '" + response + "'");
}
|
|
|
#pragma once
#include <string>
using std::string;
class Smtp
{
public:
string Content;
string From;
string To;
string SmtpServer;
string Subject;
Smtp();
~Smtp();
void Send();
void Close();
private:
void Create();
void Connect();
void WriteHello();
void WriteFrom();
void WriteTo();
void WriteStartData();
void WriteBody();
void WriteQuit();
void CheckResponse(const string& s);
class Private;
Private& impl;
};
|
|
|
#pragma once
template <class HostInfoProvider, class SocketException>
class SocketT : public HostInfoProvider
{
public:
SocketT(SOCKET& s)
:mSocket(s)
{
}
SocketT()
: mSocket(INVALID_SOCKET)
{
}
~SocketT()
{
Close();
}
void Close()
{
if (mSocket == INVALID_SOCKET) return;
::closesocket(mSocket);
mSocket = INVALID_SOCKET;
}
void Write(const string& str)
{
int bytestosend = str.length();
int bytessent;
for (const char* s = str.c_str(); bytestosend; s += bytessent)
{
bytessent = ::send(mSocket, s, bytestosend, 0);
if (bytessent <= 0)
throw SocketException("Write: failed");
bytestosend -= bytessent;
}
};
string GetLocalAddr()
{
struct sockaddr_in local;
int n = sizeof(local);
::getsockname(mSocket, (struct sockaddr *)&local, &n);
struct hostent* h = ::gethostbyaddr((char*)&local.sin_addr, sizeof(local.sin_addr), AF_INET);
return h ? h->h_name : ::inet_ntoa(local.sin_addr);
}
void Create()
{
Close();
mSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (mSocket == INVALID_SOCKET)
throw SocketException("Create: returned invalid socket");
}
void Connect()
{
sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_port = GetPort();
sa.sin_addr.s_addr = GetAddr();
if (::connect(mSocket, (sockaddr *)&sa, sizeof(sa)) < 0)
throw SocketException("Connect: connection to host failed");
}
string Response()
{
string response;
int roundtrips = 0;
for(;;)
{
char buffer[1024];
int n = ::recv(mSocket, buffer, sizeof(buffer), 0);
if (n == -1)
throw SocketException("Response: socket read failed");
response += string(buffer, n);
if (response.find("\n") != response.npos)
{
return response;
}
roundtrips++;
if (roundtrips > 1000)
throw SocketException("socket read timeout");
}
}
private:
SOCKET mSocket;
};
|
|
|
#pragma once
#include <exception>
class SmtpException : public exception
{
string m_str;
public:
SmtpException()
:m_str("SMTP exception")
{
}
SmtpException(const string& str)
:m_str("SMTP exception: " + str)
{
}
virtual const char* what() const throw()
{
return m_str.c_str();
}
};
|
|
|
#pragma once
#include "SmtpException.h"
class SmtpHostInfo
{
public:
void SetServer(const string& server)
{
mServer = server;
}
unsigned long GetAddr()
{
hostent* host;
in_addr inaddr;
inaddr.s_addr = ::inet_addr(mServer.c_str());
if (inaddr.s_addr == INADDR_NONE)
host = ::gethostbyname(mServer.c_str());
else
host = ::gethostbyaddr((const char *)&inaddr, sizeof(inaddr), AF_INET);
if (host == NULL)
throw SmtpException("GetAddr: Invalid SMTP server");
return *((u_long*)host->h_addr_list[0]);
}
short GetPort()
{
struct servent* server = ::getservbyname("smtp", "tcp");
if (server == NULL)
throw SmtpException("GetPort: SMTP is an unknown TCP service");
return server->s_port;
}
private:
string mServer;
} ;
|
|
|
#pragma once
#include <sstream>
using std::stringstream;
class SmtpWriter
{
public:
SmtpWriter(SmartSocket& s)
: mSocket(s)
{
}
void Line(const string& s)
{
mOut << s << "\r\n";
}
void Flush()
{
mSocket.Write(mOut.str());
}
void HeaderLine(const string& hdr, const string& val)
{
NameValueLine(hdr, "<" + val + ">");
}
void Body(const string& subject, const string& to, const string& from, const string& content)
{
NameValueLine("Subject", subject);
NameValueLine("To", to);
NameValueLine("From", from);
StartOfContent();
Line(content);
EndOfContent();
}
private:
void NameValueLine(const string& name, const string& value)
{
Line(name + ": " + value);
}
void StartOfContent()
{
Line("");
}
void EndOfContent()
{
Line(".");
}
private:
stringstream mOut;
SmartSocket& mSocket;
} ;
|
|
|
#pragma once
class WSAInit
{
public:
WSAInit()
{
WORD w = MAKEWORD(1,1);
WSADATA wsadata;
::WSAStartup(w, &wsadata);
};
~WSAInit()
{
::WSACleanup();
};
} ;
|