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

📄 csmtp.cpp

📁 vc stmp email 邮件系统 企业应用
💻 CPP
📖 第 1 页 / 共 2 页
字号:
BOOL CTextPlain::AppendPart(LPCTSTR szContent, 
							LPCTSTR szParameters, 
							int nEncoding, 
							BOOL bPath, 
							CString & sDestination)
{
	CString sSubHeader;
	CString sWrapped;
	sSubHeader = build_sub_header( szContent,
								   szParameters,
								   nEncoding,
								   bPath );
	sWrapped = wrap_text( szContent );
	sDestination += (sSubHeader + sWrapped);
	return TRUE;
}

CString CTextPlain::build_sub_header(LPCTSTR szContent, 
									 LPCTSTR szParameters, 
									 int nEncoding, 
									 BOOL bPath)
{
	CString sSubHeader;
	sSubHeader.Format( _T( "Content-Type: %s%s\r\n" ),
					   (LPCTSTR)GetContentTypeString(),
					   szParameters );
	sSubHeader += _T( "Content-Transfer-Encoding: " );
	switch( nEncoding )
	{
		// This class handles only 7bit encoding, but others
		//  may be added here.
		default:
			//Fall through to...
		case CMIMEMessage::_7BIT:
			sSubHeader += _T( "7Bit" );
	}
	sSubHeader += _T( "\r\n\r\n" );
	return sSubHeader;
}

CString CTextPlain::wrap_text(LPCTSTR szText)
{
	CString sTemp;
	CString sLeft;
	CString sRight;
	int lp = 0;
	UINT nCount = 0;
	int nSpacePos = 0;

	ASSERT( szText != NULL );
	if( szText == NULL )
		return sTemp;
	sTemp = szText;
	while( lp < sTemp.GetLength() )
	{
		if( sTemp[ lp ] == ' ' )
			nSpacePos = lp;
		// Reset counter on newline
		if( sTemp.Mid( lp, 2 ) == _T( "\r\n" ) )
			nCount = 0;
		// Wrap text at last found space
		if( nCount > m_nWrapPos )
		{
			sLeft = sTemp.Left( nSpacePos );
			sRight = sTemp.Right( sTemp.GetLength() - nSpacePos );
			sLeft.TrimRight();
			sRight.TrimLeft();
			sLeft += _T( "\r\n" );
			sTemp = sLeft + sRight;
			nCount = 0;
		}
		else
			nCount++;
		lp++;
	}
	return sTemp;
}

//////////////////////////////////////////////////////////////////////
// CMIMEMessage
//////////////////////////////////////////////////////////////////////

// Static Member Initializers
CMIMEMessage::CMIMETypeManager CMIMEMessage::m_MIMETypeManager;

CMIMEMessage::CMIMEMessage()
{
	m_sMIMEContentType = _T( "multipart/mixed");
	m_sPartBoundary = _T( "WC_MAIL_PaRt_BoUnDaRy_05151998" );
	m_sNoMIMEText = _T( "This is a multi-part message in MIME format." );

	// Register the MIME types handled by this class
	//
	CMIMEContentAgent* pType;
	// These objects are deleted by CMIMTypeManager's destructor
	pType = new CTextPlain( TEXT_PLAIN, GetCharsPerLine() );
	register_mime_type( pType );
	pType = new CAppOctetStream( APPLICATION_OCTETSTREAM );
	register_mime_type( pType );
}

CMIMEMessage::~CMIMEMessage()
{
}

// This implementation adds the part to the part-list used
//  to build the body.
BOOL CMIMEMessage::AddMIMEPart(LPCTSTR szContent,
							   int nContentType, 
							   LPCTSTR szParameters, 
							   int nEncoding, 
							   BOOL bPath )
{
	CMIMEPart part;
	part.m_nContentType = nContentType;
	part.m_sParameters = szParameters;
	part.m_nEncoding = nEncoding;
	part.m_bPath = bPath;
	part.m_sContent = szContent;
	part.m_sContent.TrimLeft();
	part.m_sContent.TrimRight();
	if( nContentType == TEXT_PLAIN )
		m_MIMEPartList.AddHead( part );
	else
		m_MIMEPartList.AddTail( part );
	return TRUE;
}

void CMIMEMessage::prepare_header()
{
	CString sTemp;

	// Let the base class add its headers
	CMailMessage::prepare_header();
	
	add_header_line( _T( "MIME-Version: 1.0" ) );
	sTemp.Format( _T( "Content-Type: %s; boundary=%s" ),
				  (LPCTSTR)m_sMIMEContentType,
				  (LPCTSTR)m_sPartBoundary );
	add_header_line( (LPCTSTR)sTemp );
}

void CMIMEMessage::prepare_body()
{
	// Class user may have assigned body text directly.
	// Convert it to just another MIME part to be processed.
	// If this default Content-Type isn't good enough for the
	// class user, he or she should have used AddMIMEPart() instead.
	if( m_sBody != _T( "" ) )
		AddMIMEPart( (LPCTSTR)m_sBody, TEXT_PLAIN, "", _7BIT, FALSE );

	// Initialize the body (replace current contents).
	m_sBody = m_sNoMIMEText;
	m_sBody += _T( "\r\n\r\n" );
	append_mime_parts();
	insert_message_end( m_sBody );

	// Let the base class take me to Funky Town
	CMailMessage::prepare_body();
}

void CMIMEMessage::insert_boundary( CString& sText )
{
	CString sTemp;
	if( sText.Right( 2 ) != _T( "\r\n" ) )
		sText += _T( "\r\n" );
	sTemp.Format( _T( "--%s\r\n" ), (LPCTSTR)m_sPartBoundary );
	sText += sTemp;
}

void CMIMEMessage::insert_message_end( CString& sText )
{
	CString sTemp;
	if( sText.Right( 2 ) != _T( "\r\n" ) )
		sText += _T( "\r\n" );
	sTemp.Format( _T( "--%s--\r\n" ), (LPCTSTR)m_sPartBoundary );
	sText += sTemp;
}

void CMIMEMessage::register_mime_type(CMIMEContentAgent* pMIMEType)
{
	ASSERT( pMIMEType != NULL );
	if( pMIMEType == NULL )
		return;
	m_MIMETypeManager.RegisterMIMEType( pMIMEType );
}


void CMIMEMessage::append_mime_parts()
{
	POSITION part_position;
	CMIMEPart* pMIMEPart = NULL;
	CMIMEContentAgent* pMIMEType = NULL;

	part_position = m_MIMEPartList.GetHeadPosition();
	// Get each part from the list, retrieve a handler for it,
	//  and let the handler do its thing.
	while( part_position != NULL )
	{
		pMIMEPart = & m_MIMEPartList.GetNext( part_position );
		pMIMEType = m_MIMETypeManager.GetHandler( pMIMEPart->m_nContentType );
		if( pMIMEType != NULL )
		{
			insert_boundary( m_sBody );
			pMIMEType->AppendPart( pMIMEPart->m_sContent,
								   pMIMEPart->m_sParameters,
								   pMIMEPart->m_nEncoding,
								   pMIMEPart->m_bPath,
								   m_sBody );
		}
	}

}

//////////////////////////////////////////////////////////////////////
// CMIMETypeManager Implementation
//////////////////////////////////////////////////////////////////////

CMIMEMessage::CMIMETypeManager::CMIMETypeManager()
{
}

CMIMEMessage::CMIMETypeManager::~CMIMETypeManager()
{
	POSITION pos;
	CMIMEContentAgent* p;
	m_csAccess.Lock();
	pos = m_MIMETypeList.GetHeadPosition();
	while( pos != NULL )
	{
		p = m_MIMETypeList.GetNext( pos );
		delete p;
	}
}

void CMIMEMessage::CMIMETypeManager::RegisterMIMEType(CMIMEContentAgent *pMIMEType)
{
	ASSERT( pMIMEType != NULL );
	if( pMIMEType == NULL )
		return;
	m_csAccess.Lock();
	m_MIMETypeList.AddTail( pMIMEType );
}

CMIMEContentAgent* CMIMEMessage::CMIMETypeManager::GetHandler(int nContentType)
{
	POSITION pos;
	CMIMEContentAgent* pType = NULL;

	m_csAccess.Lock();
	pos = m_MIMETypeList.GetHeadPosition();
	while( pos != NULL )
	{
		pType = m_MIMETypeList.GetNext( pos );
		if( pType->QueryType( nContentType ) == TRUE )
			break;
	}
	return pType;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

// Static member initializers
//

// Note: the order of the entries is important.
//       They must be synchronized with eResponse entries. 
CSmtp::response_code CSmtp::response_table[] = {
	// GENERIC_SUCCESS
	{250, _T("SMTP server error")},
	// CONNECT_SUCCESS
	{220, _T("SMTP server not available")},
	// DATA_SUCCESS
	{354, _T("SMTP server not ready for data")},
	// QUIT_SUCCESS
	{221, _T("SMTP server didn't terminate session")}
};

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSmtp::CSmtp(LPCTSTR szSMTPServerName, UINT nPort)
{
	ASSERT(szSMTPServerName != NULL);
	AfxSocketInit();
	m_sSMTPServerHostName = szSMTPServerName;
	m_nPort = nPort;
	m_bConnected = FALSE;
	m_sError = _T("OK");
	response_buf = NULL;
}

CSmtp::~CSmtp()
{ Disconnect(); }

CString CSmtp::GetServerHostName()
{
	return m_sSMTPServerHostName;
}

BOOL CSmtp::Connect()
{
	CString sHello;
	TCHAR local_host[80];	// Warning: arbitrary size
	if(m_bConnected) return TRUE;

	try {
		// This will be deleted in Disconnect();
		response_buf = new TCHAR[RESPONSE_BUFFER_SIZE];
		// I can't count on all class users' applications
		// to have exception-throwing operator-new implementations,
		// so I'll soul-kiss the ones that don't.
		if(response_buf == NULL) {
			m_sError = _T("Not enough memory");
			return FALSE;
		}
	} catch(CException* e) {
		response_buf = NULL;
		m_sError = _T("Not enough memory");
		delete e;
		return FALSE;
	}

	if(!m_wsSMTPServer.Create()) {
		m_sError = _T("Unable to create the socket");
		delete response_buf;
		response_buf = NULL;
		return FALSE;
	}
	if( !m_wsSMTPServer.Connect(GetServerHostName(), GetPort())) {
		m_sError = _T("Unable to connect to server");
		m_wsSMTPServer.Close();
		delete response_buf;
		response_buf = NULL;
		return FALSE;
	}
	if(!get_response(CONNECT_SUCCESS)) {
		m_sError = _T( "Server didn't respond" );
		m_wsSMTPServer.Close();
		delete response_buf;
		response_buf = NULL;
		return FALSE;
	}
	gethostname(local_host, 80);
	sHello.Format(_T( "HELO %s\r\n" ), local_host);
	m_wsSMTPServer.Send((LPCTSTR)sHello, sHello.GetLength());
	if(!get_response(GENERIC_SUCCESS)) {
		m_wsSMTPServer.Close();
		delete response_buf;
		response_buf = NULL;
		return FALSE;
	}
	m_bConnected = TRUE;
	return TRUE;
}

BOOL CSmtp::Disconnect()
{
	BOOL ret;
	if(!m_bConnected) return TRUE;
	// Disconnect gracefully from the server and close the socket
	CString sQuit = _T("QUIT\r\n");
	m_wsSMTPServer.Send((LPCTSTR)sQuit, sQuit.GetLength());

	// No need to check return value here.
	// If it fails, the message is available with GetLastError
	ret = get_response(QUIT_SUCCESS);
	m_wsSMTPServer.Close();

	if(response_buf != NULL) {
		delete[] response_buf;
		response_buf = NULL;
	}
	m_bConnected = FALSE;
	return ret;
}

UINT CSmtp::GetPort()
{ return m_nPort; }

CString CSmtp::GetLastError()
{ return m_sError; }

BOOL CSmtp::SendMessage(CMailMessage* msg)
{
	ASSERT(msg != NULL);
	if(!m_bConnected) {
		m_sError = _T("Must be connected");
		return FALSE;
	}
	if(FormatMailMessage(msg) == FALSE) {
		return FALSE;
	}
	if(transmit_message(msg) == FALSE) {
		return FALSE;
	}
	return TRUE;
}

BOOL CSmtp::FormatMailMessage(CMailMessage* msg)
{
	ASSERT(msg != NULL);
	if(msg -> GetNumRecipients() == 0) {
		m_sError = _T("No Recipients");
		return FALSE;
	}
	msg -> FormatMessage();
	return TRUE;
}

void CSmtp::SetServerProperties(LPCTSTR szSMTPServerName, UINT nPort)
{
	ASSERT(szSMTPServerName != NULL);
	// Needs to be safe in non-debug too
	if(szSMTPServerName == NULL) return;
	m_sSMTPServerHostName = szSMTPServerName;
	m_nPort = nPort;
}


CString CSmtp::cook_body(CMailMessage* msg)
{
	ASSERT(msg != NULL);
	CString sTemp;
	CString sCooked = _T("");
	LPTSTR szBad = _T("\r\n.\r\n");
	LPTSTR szGood = _T("\r\n..\r\n");
	int nPos;
	int nStart = 0;
	int nBadLength = strlen(szBad);
	sTemp = msg -> m_sBody;
	if(sTemp.Left(3) == _T(".\r\n"))
		sTemp = _T(".") + sTemp;
	//
	// This is a little inefficient because it beings a search
	// at the beginning of the string each time. This was
	// the only thing I could think of that handled ALL variations.
	// In particular, the sequence "\r\n.\r\n.\r\n" is troublesome. 
	// (Even CStringEx's FindReplace wouldn't handle that situation
	// with the global flag set.)
	//
	while((nPos = sTemp.Find(szBad)) > -1) {
		sCooked = sTemp.Mid(nStart, nPos);
		sCooked += szGood;
		sTemp = sCooked + sTemp.Right(sTemp.GetLength() - (nPos + nBadLength));
	}
	return sTemp;
}

BOOL CSmtp::transmit_message(CMailMessage* msg)
{
	CString sFrom;
	CString sTo;
	CString sTemp;
	CString sEmail;

	ASSERT(msg != NULL);
	if(!m_bConnected) {
		m_sError = _T("Must be connected");
		return FALSE;
	}

	// Send the MAIL command
	sFrom.Format(_T( "MAIL From: <%s>\r\n" ), (LPCTSTR)msg->m_sFrom);
	m_wsSMTPServer.Send((LPCTSTR)sFrom, sFrom.GetLength());
	if(!get_response(GENERIC_SUCCESS)) return FALSE;

	// Send RCPT commands (one for each recipient)
	for(int i = 0; i < msg->GetNumRecipients(); i++) {
		msg->GetRecipient(sEmail, sTemp, i);
		sTo.Format(_T("RCPT TO: <%s>\r\n"), (LPCTSTR)sEmail);
		m_wsSMTPServer.Send((LPCTSTR)sTo, sTo.GetLength());
		get_response(GENERIC_SUCCESS);
	}

	// Send the DATA command
	sTemp = _T("DATA\r\n");
	m_wsSMTPServer.Send((LPCTSTR)sTemp, sTemp.GetLength());
	if( !get_response(DATA_SUCCESS)) {
		return FALSE;
	}

	// Send the header
	m_wsSMTPServer.Send((LPCTSTR)msg -> m_sHeader, msg -> m_sHeader.GetLength());

	// Send the body
	sTemp = cook_body(msg);
	m_wsSMTPServer.Send((LPCTSTR)sTemp, sTemp.GetLength());

	// Signal end of data
	sTemp = _T("\r\n.\r\n");
	m_wsSMTPServer.Send((LPCTSTR)sTemp, sTemp.GetLength());
	if( !get_response(GENERIC_SUCCESS)) {
		return FALSE;
	}
	return TRUE;
}

BOOL CSmtp::get_response(UINT response_expected)
{
	ASSERT(response_expected >= GENERIC_SUCCESS);
	ASSERT(response_expected < LAST_RESPONSE);

	CString sResponse;
	UINT response;
	response_code* pResp;	// Shorthand

	if(m_wsSMTPServer.Receive(response_buf, RESPONSE_BUFFER_SIZE) == SOCKET_ERROR) {
		m_sError = _T("Socket Error");
		return FALSE;
	}
	sResponse = response_buf;
	sscanf((LPCTSTR)sResponse.Left(3), _T("%d"), &response);
	pResp = &response_table[response_expected];
	if(response != pResp -> nResponse) {
		m_sError.Format( _T("%d:%s"), response, (LPCTSTR)pResp -> sMessage);
		return FALSE;
	}
	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -