📄 smtpsocket.cpp
字号:
// SmtpSocket.cpp: implementation of the CSmtpSocket class.
//作者:高越 邮箱:darkprince@v.cn
//QQ:1738387 (本人只接受技术探讨以及软件项目合作事宜,其他误扰)
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "darksmtp.h"
#include "SmtpSocket.h"
#include "DakComPtrList.h"
#include "ProxyConnectSocket.h"
#include "MailCode.h"
#include "Resource.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSmtpSocket::CSmtpSocket()
{
#ifdef _DEBUG
m_dwTimeout = DP_DEFAULT_TIMEOUT; //default timeout of 60 seconds when debugging
#else
m_dwTimeout = DP_SHUTDOWN_RECV_TIMEOUT; //default timeout of 2 seconds for normal release code
#endif
m_hSocket=0;
m_bConnected = FALSE;//是否连接
m_strLastCommandResponse="";//SMTPSERVER上一次返回的指令
m_strAbout="<p>本邮件程序由<a href=http://www.leadsky.com>沈阳力天科技信息有限公司</a>开发<br>尚处于测试阶段,如遇到问题,请与<a href=mailto:gaoyue@leadsky.com>开发人员</a>(gaoyue@leadsky.com)联系</p>";
}
CSmtpSocket::~CSmtpSocket()
{
}
//REMARK: 与远程主机SMTP连接,并进行用户验证
//IN: 远程主机名称或IP,用户名称,用户密码
//OUT: 返回错误提示
BOOL CSmtpSocket::Connect(LPCTSTR pszHostName, LPCTSTR pszUser,
LPCTSTR pszPassword, int nPort,
int nProxyType,BOOL bProxyNeedAuth,
LPCTSTR pszProxyUserName,LPCTSTR pszProxyPassWord,
LPCTSTR pszProxyHostName,int nProxyPort,
CString& strErrorText)
{
//For correct operation of the T2A macro, see MFC Tech Note 59
strErrorText="";
USES_CONVERSION;
BOOL bResult=FALSE;
if(m_hSocket!=INVALID_SOCKET&&m_hSocket!=0)
DPCloseSocket(m_hSocket);
char* pszAsciiHostName=T2A((LPTSTR)pszHostName);
char* pszAsciiProxyUserName=T2A((LPTSTR)pszProxyUserName);
char* pszAsciiProxyPassWord=T2A((LPTSTR)pszProxyPassWord);
char* pszAsciiProxyHostName=T2A((LPTSTR)pszProxyHostName);
CProxyConnectSocket clsConnect;
TAG_CONNECTINFO tagConnectInfo;
tagConnectInfo.bNeedAuth=bProxyNeedAuth;
tagConnectInfo.nProxyPort=nProxyPort;
tagConnectInfo.nProxyType=(ENUM_PROXYTYPE)nProxyType;
tagConnectInfo.strProxyIp=pszAsciiProxyHostName;
tagConnectInfo.strUserName=pszAsciiProxyUserName;
tagConnectInfo.strPassWord=pszAsciiProxyPassWord;
tagConnectInfo.strServerIp=pszAsciiHostName;
tagConnectInfo.nServerPort=nPort;
DWORD dwErrorCode=0;
m_hSocket=clsConnect.CreateConnectSocket(&tagConnectInfo,dwErrorCode);
//与远程主机连接
if(m_hSocket==SOCKET_ERROR||m_hSocket==0)
{
strErrorText.Format("不能连接到指定的SMTP邮件服务器\n",
GetLastError());
ATLTRACE(strErrorText);
return bResult;
}
//We're now connected !!
m_bConnected = TRUE;
//check the response
if (!ReadCommandResponse())
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
//Send the SMTP username and check the response
char sBuf[128];
sprintf(sBuf, "EHLO LocalHost\r\n");
int nResult=0;
if(nResult=DPSendData_Event(m_hSocket,sBuf,strlen(sBuf),m_dwTimeout)<=0)
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
sprintf(sBuf, "AUTH LOGIN\r\n");
//Mayby the smtp server don't accept the 'AUTH' command
if(nResult=DPSendData_Event(m_hSocket,sBuf,strlen(sBuf),m_dwTimeout)<=0)
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
return TRUE;
if(strlen(pszUser)<=0||strlen(pszPassword)<=0)
{
strErrorText="指定的SMTP邮件服务器需要用户验证\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
//Send the SMTP username and check the response
char* pszAsciiUser = T2A((LPTSTR) pszUser);
ATLASSERT(strlen(pszAsciiUser) < 100);
int nSize=0;
nSize=CMailCode::Base64EncodeSize(strlen(pszAsciiUser));
char* pEncodeStr=new char[nSize+1];
CMailCode::base64_encode(pszAsciiUser,strlen(pszAsciiUser),pEncodeStr);
pEncodeStr[nSize]='\0';
sprintf(sBuf, "%s\r\n", pEncodeStr);
delete []pEncodeStr;
if(nResult=DPSendData_Event(m_hSocket,sBuf,strlen(sBuf),m_dwTimeout)<=0)
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
{
strErrorText="指定的SMTP邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
char* pszAsciiPassword = T2A((LPTSTR) pszPassword);
ASSERT(strlen(pszAsciiPassword) < 100);
nSize=CMailCode::Base64EncodeSize(strlen(pszAsciiPassword));
pEncodeStr=new char[nSize+1];
CMailCode::base64_encode(pszAsciiPassword,strlen(pszAsciiPassword),pEncodeStr);
pEncodeStr[nSize]='\0';
sprintf(sBuf, "%s\r\n", pEncodeStr);
delete []pEncodeStr;
if (nResult=DPSendData_Event(m_hSocket,sBuf,strlen(sBuf),m_dwTimeout)<=0)
{
strErrorText="指定的POP3接收邮件服务器系统错误\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
if (!ReadCommandResponse())
{
strErrorText="请确认您的邮件用户密码是否正确\n";
ATLTRACE(strErrorText);
Disconnect();
return FALSE;
}
return TRUE;
}
BOOL CSmtpSocket::ReadCommandResponse(void)
{
LPSTR pszOverFlowBuffer = NULL;
char sBuf[2000];
BOOL bSuccess = ReadResponse(sBuf, 2000, KEY_LINE_BOUNDARY, &pszOverFlowBuffer);
if (pszOverFlowBuffer)
delete [] pszOverFlowBuffer;
return bSuccess;
}
//REMARK:读取POP3SERVER返回的信息,如果指定的空间不够,那么每次重新生成一定的空间
// 来保持对所有数据的接收支持,但注意调用该函数后必须释放OVERFLOWBUFFER的指针
//IN:BUFFER指针,BUFFER大小,终止符号,新增的缓冲指针,每次新增缓冲大小
//OUT:BOOL
BOOL CSmtpSocket::ReadResponse(LPSTR pszBuffer, int nInitialBufSize,
LPSTR pszTerminator, LPSTR* ppszOverFlowBuffer,
int nGrowBy)
{
ATLASSERT(m_hSocket!=0&&m_hSocket!=INVALID_SOCKET);
ATLASSERT(ppszOverFlowBuffer); //Must have a valid string pointer
ATLASSERT(*ppszOverFlowBuffer == NULL); //Initially it must point to a NULL string
//must have been created first
ATLASSERT(m_bConnected);
int nTerminatorLen = strlen(pszTerminator);
//The local variables which will receive the data
LPSTR pszRecvBuffer = pszBuffer;
int nBufSize = nInitialBufSize;
//retrieve the reponse using until we
//get the terminator or a timeout occurs
BOOL bFoundTerminator = FALSE;
int nReceived = 0;
while (!bFoundTerminator)
{
//receive the data from the socket
int nBufRemaining = nBufSize-nReceived-1; //Allows allow one space for the NULL terminator
if (nBufRemaining<0)
nBufRemaining = 0;
int nData = DPRecvData_Event(m_hSocket,pszRecvBuffer+nReceived,nBufRemaining,m_dwTimeout);
//Reset the idle timeout if data was received
if (nData > 0)
//Increment the count of data received
nReceived += nData;
//If an error occurred receiving the data
if (nData<=0)
{
//NULL terminate the data received
if (pszRecvBuffer)
pszBuffer[nReceived] = '\0';
m_strLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
return FALSE;
}
else
{
//NULL terminate the data received
if (pszRecvBuffer)
pszRecvBuffer[nReceived] = '\0';
if (nBufRemaining-nData == 0) //No space left in the current buffer
{
//Allocate the new receive buffer
nBufSize += nGrowBy; //Grow the buffer by the specified amount
char* pszNewBuf = new char[nBufSize];
//copy the old contents over to the new buffer and assign
//the new buffer to the local variable used for retreiving
//from the socket
if (pszRecvBuffer)
strcpy(pszNewBuf, pszRecvBuffer);
pszRecvBuffer = pszNewBuf;
//delete the old buffer if it was allocated
if (*ppszOverFlowBuffer)
delete [] *ppszOverFlowBuffer;
//Remember the overflow buffer for the next time around
*ppszOverFlowBuffer = pszNewBuf;
}
}
//Check to see if the terminator character(s) have been found
bFoundTerminator = (strncmp(&pszRecvBuffer[nReceived - nTerminatorLen], pszTerminator, nTerminatorLen) == 0);
}
//Remove the terminator from the response data
pszRecvBuffer[nReceived - nTerminatorLen] = '\0';
//determine if the response is an error
BOOL bSuccess = !(strnicmp(pszRecvBuffer,"5", 1) == 0);
if (!bSuccess)
{
SetLastError(WSAEPROTONOSUPPORT);
m_strLastCommandResponse = pszRecvBuffer; //Hive away the last command reponse
}
return bSuccess;
}
//REMARK: 与远程断开连接
//IN: 无
//OUT:BOOL
BOOL CSmtpSocket::Disconnect(void)
{
ATLASSERT(m_hSocket!=0&&m_hSocket!=INVALID_SOCKET);
BOOL bSuccess = FALSE;
//disconnect from the POP3 server if connected
int nResult=0;
if (m_bConnected)
{
char sBuf[10];
strcpy(sBuf, "QUIT\r\n");
if(nResult=DPSendData_Event(m_hSocket,sBuf,strlen(sBuf),m_dwTimeout)<=0)
ATLTRACE(_T("Failed to send the QUIT command to the SMTP server\n"));
//Check the reponse
bSuccess = ReadCommandResponse();
//Reset all the state variables
m_bConnected = FALSE;
}
else
ATLTRACE(_T("CSmtpSocket, Already disconnected\n"));
//free up our socket
//if(m_hSocket!=0&&m_hSocket!=INVALID_SOCKET)
// DPCloseSocket(m_hSocket);
return bSuccess;
}
CString CSmtpSocket::EncodeByGB2312(CString strContent)
{
CString strReturn="";
if(strContent.IsEmpty())
return strReturn;
strReturn="=?gb2312?B?";
strReturn.SetAt(1,63);
strReturn.SetAt(8,63);
strReturn.SetAt(10,63);
int nSize=CMailCode::Base64EncodeSize(strContent.GetLength());
char* pDest=new char[nSize+1];
CMailCode::base64_encode(strContent.GetBuffer(0),strContent.GetLength(),pDest);
strContent.ReleaseBuffer();
pDest[nSize]='\0';
strReturn+=pDest;
strReturn+="?=";
strReturn.SetAt(strReturn.GetLength()-2,63);
delete []pDest;
return strReturn;
}
#define N_SENDSTRINGARRAY_MAXCOUNT 1000
BOOL CSmtpSocket::SendMail(CSmtpMessage& message)
{
ATLASSERT(m_hSocket!=0&&m_hSocket!=INVALID_SOCKET);
//Must be connected to retrieve a message
ASSERT(m_bConnected);
if(m_hSocket==0||m_hSocket==INVALID_SOCKET||!m_bConnected)
return FALSE;
USES_CONVERSION;
CString s[N_SENDSTRINGARRAY_MAXCOUNT];
int n = 0;
int i=0;int j=0;
_tzset();
char szTimeZone[40];
BOOL bNegative = FALSE;
time_t ltime;
struct tm *today;
int zone=0;
char szBuffer[512];
sprintf( szBuffer, "MAIL FROM: <%s>\r\n",message.m_strFrom);
int nResult=0;
if(nResult=DPSendData_Event(m_hSocket,szBuffer,strlen(szBuffer),m_dwTimeout)<=0)
goto CLEAR;
if (!ReadCommandResponse())
goto CLEAR;
// Add recipients
for(j=0;j<message.m_pArrTo->GetCount();j++)
{
LPTAG_ADDRINFO pAddrInfo=(LPTAG_ADDRINFO)message.m_pArrTo->GetAt(message.m_pArrTo->FindIndex(j));
if(pAddrInfo==NULL)
continue;
CString strTempTo="";
strTempTo.Format("RCPT TO: <%s>\r\n",pAddrInfo->strStringAddr);
s[n++]=strTempTo;
if(n>=N_SENDSTRINGARRAY_MAXCOUNT)
goto CLEAR;
}
for(j=0;j<message.m_pArrCC->GetCount();j++)
{
LPTAG_ADDRINFO pAddrInfo=(LPTAG_ADDRINFO)message.m_pArrCC->GetAt(message.m_pArrCC->FindIndex(j));
if(pAddrInfo==NULL)
continue;
CString strTempTo="";
strTempTo.Format("RCPT TO: <%s>\r\n",pAddrInfo->strStringAddr);
s[n++]=strTempTo;
if(n>=N_SENDSTRINGARRAY_MAXCOUNT)
goto CLEAR;
}
for(j=0;j<message.m_pArrBCC->GetCount();j++)
{
LPTAG_ADDRINFO pAddrInfo=(LPTAG_ADDRINFO)message.m_pArrBCC->GetAt(message.m_pArrBCC->FindIndex(j));
if(pAddrInfo==NULL)
continue;
CString strTempTo="";
strTempTo.Format("RCPT TO: <%s>\r\n",pAddrInfo->strStringAddr);
s[n++]=strTempTo;
if(n>=N_SENDSTRINGARRAY_MAXCOUNT)
goto CLEAR;
}
//Send the 'RCPT' command
for(i=0;i<n;i++)
{
if(nResult=DPSendData_Event(m_hSocket,s[i].GetBuffer(0),s[i].GetLength(),m_dwTimeout)<=0)
goto CLEAR;
s[i].ReleaseBuffer();
if (!ReadCommandResponse())
goto CLEAR;
}
n=0;
//Send the 'DATA' command
sprintf( szBuffer, "DATA\r\n");
if(nResult=DPSendData_Event(m_hSocket,szBuffer,strlen(szBuffer),m_dwTimeout)<=0)
goto CLEAR;
if (!ReadCommandResponse())
goto CLEAR;
if( message.m_strFromName.GetLength()> 0 )
sprintf(szBuffer, "FROM: \"%s\" <%s>\r\n", EncodeByGB2312(message.m_strFromName),message.m_strFrom);
else
sprintf(szBuffer, "FROM: <%s>\r\n", message.m_strFrom );
s[n++] = szBuffer;
// Build the TO: list
// Build the "TO:" list
if( message.m_pArrTo->GetCount() > 0 )
{
CString strTo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -