////////////////////////////////////////////////////////////////////////////////
// Original class CFastSmtp written by
// christopher w. backen <immortal@cox.net>
// More details at: http://www.codeproject.com/KB/IP/zsmtp.aspx
//
// Modifications introduced by Jakub Piwowarczyk:
// 1. name of the class and functions
// 2. new functions added: SendData,ReceiveData and more
// 3. authentication added
// 4. attachments added
// 5 .comments added
// 6. DELAY_IN_MS removed (no delay during sending the message)
// 7. non-blocking mode
// More details at: http://www.codeproject.com/KB/mcpp/CSmtp.aspx
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// SSL/TLS support added by John Tang by making use of OpenSSL: http://www.openssl.org/
// More details at: http://www.codeproject.com/KB/IP/smtp_ssl.aspx
//
// PLAIN, CRAM-MD5 and DIGESTMD5 authentication added by David Johns
//
// Revision History:
// - Version 2.1: Updated with fixes reported as of 26 Mar 2012
// > Fixed issue in main.cpp with referring to USE_TLS in the wrong scope discussed here: http://www.codeproject.com/Messages/4151405/Re-USE_SSL-no-member-of-CSmtp.aspx
// - Thanks to Alan P Brown!
// > Added modifications to allow it to compile in Debian Linux discussed here: http://www.codeproject.com/Messages/4132697/linux-port-patch.aspx
// - Thanks to Oleg Dolgov!
// > Added ability to change the character set, inspired by this post: http://www.codeproject.com/Messages/4238701/Re-The-subject-contains-the-Chinese-letters-could-.aspx
// - Thanks to LeonHuang0726 and John TWC for the suggestion!
// > Added ability to request a read receipt by calling SetReadReceipt as proposed here: http://www.codeproject.com/Messages/3938944/Disposition-Notification-To.aspx
// - Thanks to Gospa for the suggestion!
// > Added check for Linux when adding paths of attachments in the MIME header as suggested here: http://www.codeproject.com/Messages/4357144/portability-bug-w-attachment-name.aspx
// - Thanks to Spike!
// > Switched method of setting private std::string variables to use the = operator as suggested here: http://www.codeproject.com/Messages/4356937/portability-bugs-w-std-string-and-exceptions.aspx
// - Thanks to Spike!
// > Added SetLocalHostName function proposed here: http://www.codeproject.com/Messages/4092347/bug-fixes-GetLocalHostName-Send.aspx
// - Thanks to jerko!
// > Added the modifications to allow it to compile in Linux described here: http://www.codeproject.com/Messages/3878620/My-vote-of-5.aspx
// - Thanks to korisk!
// > Added the fix that corrects behavior when m_sNameFrom is empty described here: http://www.codeproject.com/Messages/4196071/Bug-Mail-sent-by-mail-domain-com.aspx
// - Thanks to agenua.grupoi68!
// - Version 2.0: Updated to all fixes reported as of 23 Jun 2011:
// > Added the m_bAuthenticate member variable to be able to disable authentication
// even though it may be supported by the server. It defaults to true so if it is
// not set the library will act as it would have before the addition.
// > Added the ability to pass the security type, m_type, the new m_Authenticate flag,
// the login and password into the ConnectRemoteServer function. If these new arguments
// are not included in the call the function will work as it did before.
// > Added the ability to pass the new m_Authenticate flag into the SetSMTPServer function.
// If not provided, the function will act as it would before the addition.
// > Added fix described here: http://www.codeproject.com/Messages/3681792/Bug-when-reading-answer.aspx
// - Thanks to Martin Kjallman!
// > Added fixes described here: http://www.codeproject.com/Messages/3707662/Mistakes.aspx
// - Thanks to Karpov Andrey!
// > Added fixes described here: http://www.codeproject.com/Messages/3587166/Re-Possible-Solution-To-Misc-EHLO-Errors.aspx
// - Thanks to Jakub Piwowarczyk!
// - Version 1.9: Started with Revion 6 in code project http://www.codeproject.com/script/Articles/ListVersions.aspx?aid=98355
////////////////////////////////////////////////////////////////////////////////
#include "CSmtp.h"
#include "base64.h"
#include "openssl/err.h"
#include <cassert>
#ifndef LINUX
//Add "openssl-0.9.8l\out32" to Additional Library Directories
#pragma comment(lib, "ssleay32.lib")
#pragma comment(lib, "libeay32.lib")
#endif
Command_Entry command_list[] =
{
{command_INIT, 0, 5*60, 220, ECSmtp::SERVER_NOT_RESPONDING},
{command_EHLO, 5*60, 5*60, 250, ECSmtp::COMMAND_EHLO},
{command_AUTHPLAIN, 5*60, 5*60, 334, ECSmtp::COMMAND_AUTH_PLAIN},
{command_AUTHLOGIN, 5*60, 5*60, 334, ECSmtp::COMMAND_AUTH_LOGIN},
{command_AUTHCRAMMD5, 5*60, 5*60, 334, ECSmtp::COMMAND_AUTH_CRAMMD5},
{command_AUTHDIGESTMD5, 5*60, 5*60, 334, ECSmtp::COMMAND_AUTH_DIGESTMD5},
{command_DIGESTMD5, 5*60, 5*60, 335, ECSmtp::COMMAND_DIGESTMD5},
{command_USER, 5*60, 5*60, 334, ECSmtp::UNDEF_XYZ_RESPONSE},
{command_PASSWORD, 5*60, 5*60, 235, ECSmtp::BAD_LOGIN_PASS},
{command_MAILFROM, 5*60, 5*60, 250, ECSmtp::COMMAND_MAIL_FROM},
{command_RCPTTO, 5*60, 5*60, 250, ECSmtp::COMMAND_RCPT_TO},
{command_DATA, 5*60, 2*60, 354, ECSmtp::COMMAND_DATA},
{command_DATABLOCK, 3*60, 0, 0, ECSmtp::COMMAND_DATABLOCK}, // Here the valid_reply_code is set to zero because there are no replies when sending data blocks
{command_DATAEND, 3*60, 10*60, 250, ECSmtp::MSG_BODY_ERROR},
{command_QUIT, 5*60, 5*60, 221, ECSmtp::COMMAND_QUIT},
{command_STARTTLS, 5*60, 5*60, 220, ECSmtp::COMMAND_EHLO_STARTTLS}
};
Command_Entry* FindCommandEntry(SMTP_COMMAND command)
{
Command_Entry* pEntry = NULL;
for(size_t i = 0; i < sizeof(command_list)/sizeof(command_list[0]); ++i)
{
if(command_list[i].command == command)
{
pEntry = &command_list[i];
break;
}
}
assert(pEntry != NULL);
return pEntry;
}
// A simple string match
bool IsKeywordSupported(const char* response, const char* keyword)
{
assert(response != NULL && keyword != NULL);
if(response == NULL || keyword == NULL)
return false;
int res_len = strlen(response);
int key_len = strlen(keyword);
if(res_len < key_len)
return false;
int pos = 0;
for(; pos < res_len - key_len + 1; ++pos)
{
if(_strnicmp(keyword, response+pos, key_len) == 0)
{
if(pos > 0 &&
(response[pos - 1] == '-' ||
response[pos - 1] == ' ' ||
response[pos - 1] == '='))
{
if(pos+key_len < res_len)
{
if(response[pos+key_len] == ' ' ||
response[pos+key_len] == '=')
{
return true;
}
else if(pos+key_len+1 < res_len)
{
if(response[pos+key_len] == '\r' &&
response[pos+key_len+1] == '\n')
{
return true;
}
}
}
}
}
}
return false;
}
unsigned char* CharToUnsignedChar(const char *strIn)
{
unsigned char *strOut;
unsigned long length,
i;
length = strlen(strIn);
strOut = new unsigned char[length+1];
if(!strOut) return NULL;
for(i=0; i<length; i++) strOut[i] = (unsigned char) strIn[i];
strOut[length]='\0';
return strOut;
}
////////////////////////////////////////////////////////////////////////////////
// NAME: CSmtp
// DESCRIPTION: Constructor of CSmtp class.
// ARGUMENTS: none
// USES GLOBAL: none
// MODIFIES GL: m_iXPriority, m_iSMTPSrvPort, RecvBuf, SendBuf
// RETURNS: none
// AUTHOR: Jakub Piwowarczyk
// AUTHOR/DATE: JP 2010-01-28
// JP 2010-07-08
////////////////////////////////////////////////////////////////////////////////
CSmtp: