//////////////////////////////////////////////////////////////////////
// Original class CFastSmtp written by
// christopher w. backen <immortal@cox.net>
// More details at: http://www.codeproject.com/KB/IP/zsmtp.aspx
//
// Modifications:
// 1. name of the class and some functions
// 2. new functions added: SendData,ReceiveData and more
// 3. authentication added
// 4. attachments added
// introduced by Jakub Piwowarczyk <podsaski@gmail.com>
// More details at: http://www.codeproject.com/KB/mcpp/CSmtp.aspx
//////////////////////////////////////////////////////////////////////
#include "CSmtp.h"
#pragma warning(push)
#pragma warning(disable:4786)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSmtp::CSmtp()
{
// Initialize variables
m_bCon = false;
m_oError = CSMTP_NO_ERROR;
m_iXPriority = XPRIORITY_NORMAL;
m_pcLocalHostName = NULL;
m_pcRemoteHostName = NULL;
m_pcMailFrom = NULL;
m_pcNameFrom = NULL;
m_pcSubject = NULL;
m_pcMsgBody = NULL;
m_pcXMailer = NULL;
m_pcReplyTo = NULL;
m_pcLogin = NULL;
m_pcPassword = NULL;
RecvBuf = new char[BUFFER_SIZE];
SendBuf = new char[BUFFER_SIZE];
// Initialize WinSock
WORD wVer = MAKEWORD(2,2);
if (WSAStartup(wVer,&wsaData) != NO_ERROR)
{
m_oError = CSMTP_WSA_STARTUP;
return;
}
if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
m_oError = CSMTP_WSA_VER;
WSACleanup();
return;
}
}
CSmtp::~CSmtp()
{
// Clear vectors
Recipients.clear();
CCRecipients.clear();
BCCRecipients.clear();
Attachments.clear();
// Free memory
if (m_pcLocalHostName)
delete[] m_pcLocalHostName;
if (m_pcRemoteHostName)
delete[] m_pcRemoteHostName;
if (m_pcMailFrom)
delete[] m_pcMailFrom;
if (m_pcNameFrom)
delete[] m_pcNameFrom;
if (m_pcSubject)
delete[] m_pcSubject;
if (m_pcMsgBody)
delete[] m_pcMsgBody;
if (m_pcXMailer)
delete[] m_pcXMailer;
if (m_pcReplyTo)
delete[] m_pcReplyTo;
if (m_pcLogin)
delete[] m_pcLogin;
if (m_pcPassword)
delete[] m_pcPassword;
delete[] SendBuf;
delete[] RecvBuf;
// Close connection
if (m_bCon)
Disconnect();
// Cleanup
WSACleanup();
}
//////////////////////////////////////////////////////////////////////
// Methods
//////////////////////////////////////////////////////////////////////
bool CSmtp::AddAttachment(const char *path)
{
std::string str(path);
Attachments.insert(Attachments.end(),str);
return true;
}
bool CSmtp::AddRecipient(const char *email, const char *name)
{
assert(email);
if(!email)
return false;
Recipent recipent;
recipent.Mail.insert(0,email);
name!=NULL ? recipent.Name.insert(0,name) : recipent.Name.insert(0,"");
Recipients.insert(Recipients.end(), recipent);
return true;
}
bool CSmtp::AddCCRecipient(const char *email, const char *name)
{
assert(email);
if(!email)
return false;
Recipent recipent;
recipent.Mail.insert(0,email);
name!=NULL ? recipent.Name.insert(0,name) : recipent.Name.insert(0,"");
CCRecipients.insert(CCRecipients.end(), recipent);
return true;
}
bool CSmtp::AddBCCRecipient(const char *email, const char *name)
{
assert(email);
if(!email)
return false;
Recipent recipent;
recipent.Mail.insert(0,email);
name!=NULL ? recipent.Name.insert(0,name) : recipent.Name.insert(0,"");
BCCRecipients.insert(BCCRecipients.end(), recipent);
return true;
}
bool CSmtp::Disconnect()
{
if (!m_bCon)
return false;
// QUIT <CRLF>
strcpy(SendBuf,"QUIT\r\n");
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
switch(SmtpXYZdigits())
{
case 221:
break;
default:
m_oError = CSMTP_COMMAND_QUIT;
m_bCon = false;
hSocket = NULL;
return false;
}
m_bCon = false;
hSocket = NULL;
return true;
}
bool CSmtp::Send()
{
unsigned int i,rcpt_count,res,FileId;
char *FileBuf = NULL, *FileName = NULL;
FILE* hFile = NULL;
unsigned long int FileSize,TotalSize,MsgPart;
// MAIL <SP> FROM:<reverse-path> <CRLF>
if(m_pcMailFrom == NULL)
{
m_oError = CSMTP_UNDEF_MAILFROM;
return false;
}
sprintf(SendBuf,"MAIL FROM:<%s>\r\n",m_pcMailFrom);
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
switch(SmtpXYZdigits())
{
case 250:
break;
default:
m_oError = CSMTP_COMMAND_MAIL_FROM;
return false;
}
// RCPT <SP> TO:<forward-path> <CRLF>
rcpt_count = Recipients.size();
for(i=0;i<Recipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(Recipients.at(i).Mail).c_str());
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
switch(SmtpXYZdigits())
{
case 250:
break;
default:
m_oError = CSMTP_COMMAND_RCPT_TO;
rcpt_count--;
}
}
if(!rcpt_count)
return false;
for(i=0;i<CCRecipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(CCRecipients.at(i).Mail).c_str());
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
}
for(i=0;i<BCCRecipients.size();i++)
{
sprintf(SendBuf,"RCPT TO:<%s>\r\n",(BCCRecipients.at(i).Mail).c_str());
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
}
// DATA <CRLF>
strcpy(SendBuf,"DATA\r\n");
if(!SendData())
return false;
Sleep(DELAY_IN_MS);
if(!ReceiveData())
return false;
switch(SmtpXYZdigits())
{
case 354:
break;
default:
m_oError = CSMTP_COMMAND_DATA;
return false;
}
// send header(s)
if(!FormatHeader(SendBuf))
{
m_oError = CSMTP_UNDEF_MSG_HEADER;
return false;
}
if(!SendData())
return false;
// send text message
sprintf(SendBuf,"%s\r\n",m_pcMsgBody); // NOTICE: each line ends with <CRLF>
if(!SendData())
return false;
// next goes attachments (if they are)
FileBuf = new char[55];
FileName = new char[255];
TotalSize = 0;
for(FileId=0;FileId<Attachments.size();FileId++)
{
strcpy(FileName,Attachments[FileId].c_str());
sprintf(SendBuf,"--%s\r\n",BOUNDARY_TEXT);
strcat(SendBuf,"Content-Type: application/x-msdownload; name=\"");
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"Content-Transfer-Encoding: base64\r\n");
strcat(SendBuf,"Content-Disposition: attachment; filename=\"");
strcat(SendBuf,&FileName[Attachments[FileId].find_last_of("\\") + 1]);
strcat(SendBuf,"\"\r\n");
strcat(SendBuf,"\r\n");
if(!SendData())
return false;
// opening the file:
hFile = fopen(FileName,"rb");
if(hFile == NULL)
{
m_oError = CSMTP_FILE_NOT_EXIST;
break;
}
// checking file size:
FileSize = 0;
while(!feof(hFile))
FileSize += fread(FileBuf,sizeof(char),54,hFile);
TotalSize += FileSize;
// sending the file:
if(TotalSize/1024 > MSG_SIZE_IN_MB*1024)
m_oError = CSMTP_MSG_TOO_BIG;
else
{
fseek (hFile,0,SEEK_SET);
MsgPart = 0;
for(i=0;i<FileSize/54+1;i++)
{
res = fread(FileBuf,sizeof(char),54,hFile);
MsgPart ? strcat(SendBuf,base64_encode(reinterpret_cast<const unsigned char*>(FileBuf),res).c_str())
: strcpy(SendBuf,base64_encode(reinterpret_cast<const unsigned char*>(FileBuf),res).c_str());
strcat(SendBuf,"\r\n");
MsgPart += res + 2;
if(MsgPart >= BUFFER_SIZE/2)
{ // sending part of the message
MsgPart = 0;
if(!SendData())
{
delete[] FileBuf;
delete[] FileName;
fclose(hFile);
return false;
}
}
}
if(MsgPart)
{
if(!SendData())
{
delete[] FileBuf;
delete[] FileName;
fclose(hFile);