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

📄 csmtp.cpp

📁 vc stmp email 邮件系统 企业应用
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// CSmtp.cpp: implementation of the CSmtp class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "smtp.h"
#include "CSmtp.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CMailMessage
// Formats a message compliant with RFC 822.

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

CMailMessage::CMailMessage()
{
	m_sMailerName = IDS_APPNAME;
	SetCharsPerLine(76);
}

CMailMessage::~CMailMessage()
{
}

BOOL CMailMessage::AddRecipient(LPCTSTR szEmailAddress, LPCTSTR szFriendlyName)
{
	ASSERT(szEmailAddress != NULL);
	ASSERT(szFriendlyName != NULL);
	CRecipient to;
	to.m_sEmailAddress = szEmailAddress;
	to.m_sFriendlyName = szFriendlyName;
	m_Recipients.Add(to);
	return TRUE;
}

// sEmailAddress and sFriendlyName are OUTPUT parameters.
// If the function fails, it will return FALSE, and the OUTPUT
// parameters will not be touched.
BOOL CMailMessage::GetRecipient(CString & sEmailAddress, CString & sFriendlyName, int nIndex)
{
	CRecipient to;
	if(nIndex < 0 || nIndex > m_Recipients.GetUpperBound())
		return FALSE;
	to = m_Recipients[nIndex];
	sEmailAddress = to.m_sEmailAddress;
	sFriendlyName = to.m_sFriendlyName;
	return TRUE;
}

int CMailMessage::GetNumRecipients()
{ return m_Recipients.GetSize(); }

BOOL CMailMessage::AddMultipleRecipients(LPCTSTR szRecipients)
{
	TCHAR* buf;
	UINT pos;
	UINT start;
	CString sTemp;
	CString sEmail;
	CString sFriendly;
	UINT length;
	int nMark;
	int nMark2;

	ASSERT(szRecipients != NULL);

	// Add Recipients
	length = strlen(szRecipients);
	buf = new TCHAR[length + 1];	// Allocate a work area (don't touch parameter itself)
	strcpy(buf, szRecipients);
	for(pos = 0, start = 0; pos <= length; pos++) {
		if(buf[pos] == ';' || buf[pos] == 0) {
			// First, pick apart the sub-strings (separated by ';')
			//  Store it in sTemp.
			buf[pos] = 0;	// Redundant when at the end of string, but who cares.
			sTemp = &buf[start];
			// Now divide the substring into friendly names and e-mail addresses.
			nMark = sTemp.Find('<');
			if(nMark >= 0) {
				sFriendly = sTemp.Left(nMark);
				nMark2 = sTemp.Find('>');
				if(nMark2 < nMark) {
					delete[] buf;
					return FALSE;
				}
				// End of mark at closing bracket or end of string
				nMark2 > -1 ? nMark2 = nMark2 : nMark2 = sTemp.GetLength() - 1;
				sEmail = sTemp.Mid(nMark + 1, nMark2 - (nMark + 1));
			} else {
				sEmail = sTemp;
				sFriendly = _T("");
			}
			AddRecipient(sEmail, sFriendly);
			start = pos + 1;
		}
	}
	delete[] buf;
	return TRUE;
}

void CMailMessage::FormatMessage()
{
	start_header();
	prepare_header();
	end_header();
	prepare_body();
}

void CMailMessage::SetCharsPerLine(UINT nCharsPerLine)
{ m_nCharsPerLine = nCharsPerLine; }	

UINT CMailMessage::GetCharsPerLine()
{
	return m_nCharsPerLine;
}

// Create header as per RFC 822
//
void CMailMessage::prepare_header()
{
	CString sTemp;
	sTemp = _T("");

	// From:
	sTemp = _T("From: ") + m_sFrom;
	add_header_line((LPCTSTR) sTemp);

	// To:
	sTemp = _T("To: ");
	CString sEmail = _T("");
	CString sFriendly = _T("");
	for(int i = 0; i < GetNumRecipients(); i++) {
		GetRecipient(sEmail, sFriendly, i);
		sTemp += (i > 0 ? _T(",") : _T(""));
		sTemp += sFriendly;
		sTemp += _T("<");
		sTemp += sEmail;
		sTemp += _T(">");
	}
	add_header_line((LPCTSTR) sTemp);

	// Date:
	m_tDateTime = m_tDateTime.GetCurrentTime();

	// Format: Mon, 01 Jun 98 01:10:30 GMT
	sTemp = _T("Date: ");
	sTemp += m_tDateTime.Format("%a, %d %b %y %H:%M:%S %Z");
	add_header_line((LPCTSTR) sTemp);

	// Subject:
	sTemp = _T("Subject: ") + m_sSubject;
	add_header_line((LPCTSTR) sTemp);

	// X-Mailer
	sTemp = _T("X-Mailer: ") + m_sMailerName;
	add_header_line((LPCTSTR) sTemp);
}

void CMailMessage::prepare_body()
{
	// Append a CR/LF to body if necessary.
	if(m_sBody.Right(2) != _T("\r\n"))
		m_sBody += _T("\r\n");

}

void CMailMessage::start_header()
{ m_sHeader = _T(""); }

void CMailMessage::end_header()
{ m_sHeader += _T("\r\n"); }

void CMailMessage::add_header_line(LPCTSTR szHeaderLine)
{
	CString sTemp;
	sTemp.Format(_T("%s\r\n"), szHeaderLine);
	m_sHeader += sTemp;
}

//////////////////////////////////////////////////////////////////////
// CMIMEContentAgent
//////////////////////////////////////////////////////////////////////

CMIMEContentAgent::CMIMEContentAgent(int nMIMEType)
{ m_nMIMETypeIHandle = nMIMEType; }

CMIMEContentAgent::~CMIMEContentAgent()
{}

BOOL CMIMEContentAgent::QueryType(int nContentType)
{ return nContentType == m_nMIMETypeIHandle ? TRUE : FALSE; }


//////////////////////////////////////////////////////////////////////
// CMIMECode
//////////////////////////////////////////////////////////////////////

CMIMECode::CMIMECode()
{
}

CMIMECode::~CMIMECode()
{
}

//////////////////////////////////////////////////////////////////////
// CBase64
//////////////////////////////////////////////////////////////////////
// Static Member Initializers
//

// The 7-bit alphabet used to encode binary information
CString CBase64::m_sBase64Alphabet = 
_T( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" );

int CBase64::m_nMask[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };

CBase64::CBase64()
{
}

CBase64::~CBase64()
{
}

CString CBase64::Encode(LPCTSTR szEncoding, int nSize)
{
	CString sOutput = _T( "" );
	int nNumBits = 6;
	UINT nDigit;
	int lp = 0;

	ASSERT( szEncoding != NULL );
	if( szEncoding == NULL )
		return sOutput;
	m_szInput = szEncoding;
	m_nInputSize = nSize;

	m_nBitsRemaining = 0;
	nDigit = read_bits( nNumBits, &nNumBits, lp );
	while( nNumBits > 0 )
	{
		sOutput += m_sBase64Alphabet[ (int)nDigit ];
		nDigit = read_bits( nNumBits, &nNumBits, lp );
	}
	// Pad with '=' as per RFC 1521
	while( sOutput.GetLength() % 4 != 0 )
	{
		sOutput += '=';
	}
	return sOutput;
}

// The size of the output buffer must not be less than
// 3/4 the size of the input buffer. For simplicity,
// make them the same size.
int CBase64::Decode(LPCTSTR szDecoding, LPTSTR szOutput)
{
	CString sInput;
    int c, lp =0;
	int nDigit;
    int nDecode[ 256 ];

	ASSERT( szDecoding != NULL );
	ASSERT( szOutput != NULL );
	if( szOutput == NULL )
		return 0;
	if( szDecoding == NULL )
		return 0;
	sInput = szDecoding;
	if( sInput.GetLength() == 0 )
		return 0;

	// Build Decode Table
	//
	for( int i = 0; i < 256; i++ ) 
		nDecode[i] = -2; // Illegal digit
	for( i=0; i < 64; i++ )
	{
		nDecode[ m_sBase64Alphabet[ i ] ] = i;
		nDecode[ m_sBase64Alphabet[ i ] | 0x80 ] = i; // Ignore 8th bit
		nDecode[ '=' ] = -1; 
		nDecode[ '=' | 0x80 ] = -1; // Ignore MIME padding char
    }

	// Clear the output buffer
	memset( szOutput, 0, sInput.GetLength() + 1 );

	// Decode the Input
	//
	for( lp = 0, i = 0; lp < sInput.GetLength(); lp++ )
	{
		c = sInput[ lp ];
		nDigit = nDecode[ c & 0x7F ];
		if( nDigit < -1 ) 
		{
			return 0;
		} 
		else if( nDigit >= 0 ) 
			// i (index into output) is incremented by write_bits()
			write_bits( nDigit & 0x3F, 6, szOutput, i );
    }	
	return i;
}




UINT CBase64::read_bits(int nNumBits, int * pBitsRead, int& lp)
{
    ULONG lScratch;
    while( ( m_nBitsRemaining < nNumBits ) && 
		   ( lp < m_nInputSize ) ) 
	{
		int c = m_szInput[ lp++ ];
        m_lBitStorage <<= 8;
        m_lBitStorage |= (c & 0xff);
		m_nBitsRemaining += 8;
    }
    if( m_nBitsRemaining < nNumBits ) 
	{
		lScratch = m_lBitStorage << ( nNumBits - m_nBitsRemaining );
		*pBitsRead = m_nBitsRemaining;
		m_nBitsRemaining = 0;
    } 
	else 
	{
		lScratch = m_lBitStorage >> ( m_nBitsRemaining - nNumBits );
		*pBitsRead = nNumBits;
		m_nBitsRemaining -= nNumBits;
    }
    return (UINT)lScratch & m_nMask[nNumBits];
}


void CBase64::write_bits(UINT nBits,
						 int nNumBits,
						 LPTSTR szOutput,
						 int& i)
{
	UINT nScratch;

	m_lBitStorage = (m_lBitStorage << nNumBits) | nBits;
	m_nBitsRemaining += nNumBits;
	while( m_nBitsRemaining > 7 ) 
	{
		nScratch = m_lBitStorage >> (m_nBitsRemaining - 8);
		szOutput[ i++ ] = nScratch & 0xFF;
		m_nBitsRemaining -= 8;
	}
}

//////////////////////////////////////////////////////////////////////
// CAppOctetStream
//////////////////////////////////////////////////////////////////////

// IMPORTANT: The number of bytes we read must be
//  a multiple of 3 because CBase64's Encode()
//  method will append padding characters ('=')
//  to make the output's size a multiple of 4.
//  (Base64 treats 3 8-bit bytes as 4 6-bit 'bytes').
//  MIME decoders are free to treat '=' as a signal
//  that there's no more data, so we don't want to pad
//  until we're supposed to.
// When at the end of the file, the # of bytes read
//  may not be a multiple of 3, but that's okay
//  because we DO want the padding chars then.

#define BYTES_TO_READ 54 // This number guarantess output won't
						 // won't exceed line-length limit

CAppOctetStream::CAppOctetStream(int nContentType)
	:CMIMEContentAgent(nContentType)
{
}

CAppOctetStream::~CAppOctetStream()
{
}

BOOL CAppOctetStream::AppendPart(LPCTSTR szContent, 
								 LPCTSTR szParameters, 
								 int nEncoding, 
								 BOOL bPath, 
								 CString & sDestination)
{
	CStdioFile fAttachment;

	ASSERT(szContent != NULL);
	// This class handles only file attachments, so
	// it ignores the bPath parameter.
	if(szContent == NULL)
		return FALSE;
	if(!fAttachment.Open(szContent, (CFile::modeRead|CFile::shareDenyWrite|CFile::typeBinary)))
		return FALSE;
	sDestination += build_sub_header(szContent,
								      szParameters,
									  nEncoding,
									  TRUE);
	attach_file(&fAttachment, CMIMEMessage::BASE64, sDestination );
	fAttachment.Close();
	return TRUE;
}


CString CAppOctetStream::build_sub_header(LPCTSTR szContent, 
										  LPCTSTR szParameters, 
										  int nEncoding, 
										  BOOL bPath)
{
	CString sSubHeader;
	CString sTemp;
	TCHAR szFName[ _MAX_FNAME ];
	TCHAR szExt[ _MAX_EXT ];

	_tsplitpath( szContent, NULL, NULL, szFName, szExt );

	// This class ignores szParameters and nEncoding.
	// It controls its own parameters and only handles
	// Base64 encoding.
	if( bPath )
		sTemp.Format( "; file=%s%s", szFName, szExt );
	else
		sTemp = _T( "" );
	sSubHeader.Format( _T( "Content-Type: %s%s\r\n" ),
						(LPCTSTR)GetContentTypeString(),
						(LPCTSTR)sTemp );
	sSubHeader += _T( "Content-Transfer-Encoding: base64\r\n" );
	sTemp.Format( _T( "Content-Disposition: attachment; filename=%s%s\r\n" ),
				  szFName, szExt );
	sSubHeader += sTemp;
	// Signal end of sub-header.
	sSubHeader += _T( "\r\n" ); // Warning: numerous concatenations
								// are inefficient.
	return sSubHeader;
}

CString CAppOctetStream::GetContentTypeString()
{
	CString s;
	s = _T( "application/octet-stream" );
	return s;
}

// Caller is responsible for opening and closing the file
void CAppOctetStream::attach_file(CStdioFile* pFileAtt, 
								  int nEncoding, 
								  CString & sDestination)
{
	CMIMECode* pEncoder;
	int nBytesRead;
	TCHAR szBuffer[ BYTES_TO_READ + 1 ];

	ASSERT( pFileAtt != NULL );
	if( pFileAtt == NULL )
		return;
	switch( nEncoding )
	{
		// This class handles only Base64 encoding, but others
		//  may be added here.
		default:
			// Fall through to...
		case CMIMEMessage::BASE64:
			try 
			{
				pEncoder = new CBase64;
			}
			catch( CMemoryException* e )
			{
				delete e;
				return;
			}
	}
	if( pEncoder == NULL )	// Old habits are hard to break
		return;
	do
	{
		try
		{
			nBytesRead = pFileAtt->Read( szBuffer, BYTES_TO_READ );
		}
		catch( CFileException* e )
		{
			delete e;
			break;
		}
		szBuffer[ nBytesRead ] = 0;	// Terminate the string
		sDestination += pEncoder->Encode( szBuffer, nBytesRead );
		sDestination += _T( "\r\n" );
	} while( nBytesRead == BYTES_TO_READ );
	sDestination += _T( "\r\n" );
	delete pEncoder;
}

//////////////////////////////////////////////////////////////////////
// CTextPlain
//////////////////////////////////////////////////////////////////////

CTextPlain::CTextPlain( int nContentType, UINT nWrapPos )
	:CMIMEContentAgent( nContentType )
{
	m_nWrapPos = nWrapPos;	
}

CTextPlain::~CTextPlain()
{

}

CString CTextPlain::GetContentTypeString()
{
	CString s;
	s = _T( "text/plain" );
	return s;
}

⌨️ 快捷键说明

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