⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smtpsocket.cpp

📁 DarkATLSmtp(SMTP COM 组件原创代码),注册后可在Delphi中发邮件。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// 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 + -