分享
 
 
 

VC下的CSmtp类,带验证,BASE64编码

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

具有发送、验证、BASE64编码功能,已经修改调试完成

想要具体说明请发信 aaachii@263.net

// CSmtp.cpp: implementation of the CSmtp class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.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/html" );

return s;

}

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:

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")},

// AUTHQUE_SUCCESS

{334, _T("SMTP server authentication error")},

// AUTH_SUCCESS

{235, _T("Error username or password")},

// 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::Auth()

{

CString sAuth;

if(!m_bConnected) return FALSE;

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;

}

sAuth.Format(_T( "auth login\r\n" )); file://construct auth quest

m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());

if(!get_response(AUTHQUE_SUCCESS)) {

m_sError="SMTP server with no auth";

m_bAuthed=TRUE;

return TRUE;

}

sAuth.Empty();

sAuth.Format(_T( "%s\r\n" ), m_sSMTPUser); file://m_sSMTPUser is an string encoded with CBASE64

m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());

if(!get_response(AUTHQUE_SUCCESS)) {

m_sError="Unknown Error";

m_wsSMTPServer.Close();

delete response_buf;

response_buf = NULL;

return FALSE;

}

sAuth.Empty();

sAuth.Format(_T( "%s\r\n" ), m_sSMTPPass); file://m_sSMTPPass is an string encoded with CBASE64

m_wsSMTPServer.Send((LPCTSTR)sAuth, sAuth.GetLength());

if(!get_response(AUTH_SUCCESS)) {

m_wsSMTPServer.Close();

delete response_buf;

response_buf = NULL;

return FALSE;

}

m_bAuthed = 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(!m_bAuthed) {

m_sError = _T("Must be authed");

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;

}

if(!m_bAuthed) {

m_sError = _T("Must be authed");

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;

}

// CSmtp.h: interface for the CSmtp class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED_)

#define AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

//////////////////////////////////////////////////////////////////////

// CMailMessage

// Formats a message compliant with RFC 822

#include <afxtempl.h>

class CMailMessage

{

public:

CMailMessage();

virtual ~CMailMessage();

void FormatMessage();

int GetNumRecipients();

BOOL GetRecipient(CString& sEmailAddress, CString& sFriendlyName, int nIndex = 0);

BOOL AddRecipient(LPCTSTR szEmailAddress, LPCTSTR szFriendlyName = "");

BOOL AddMultipleRecipients(LPCTSTR szRecipients = NULL);

UINT GetCharsPerLine();

void SetCharsPerLine(UINT nCharsPerLine);

CString m_sFrom;

CString m_sSubject;

CString m_sEnvelope;

CString m_sMailerName;

CString m_sHeader;

CTime m_tDateTime;

CString m_sBody;

CString m_sUser;

CString m_sPass;

private:

UINT m_nCharsPerLine;

class CRecipient

{

public:

CString m_sEmailAddress;

CString m_sFriendlyName;

};

CArray <CRecipient, CRecipient&> m_Recipients;

protected:

// When overriding prepare_header(), call base class

// version first, then add specialized

// add_header_line calls.

// This ensures that the base class has a chance to

// create the header lines it needs.

virtual void prepare_header();

virtual void prepare_body();

virtual void end_header();

virtual void start_header();

// This rarely needs overwriting, but is virtual just in case.

// Do not include the trailing CR/LF in parameter.

virtual void add_header_line(LPCTSTR szHeaderLine);

};

// CMIMEContentAgent

// Abstract base class. Content agents support MIME

// content types on behalf of CMIMEMessage

//

class CMIMEContentAgent

{

public:

CMIMEContentAgent(int nMIMEType);

virtual ~CMIMEContentAgent();

BOOL QueryType(int nContentType);

virtual BOOL AppendPart(LPCTSTR szContent,

LPCTSTR szParameters,

int nEncoding,

BOOL bPath,

CString& sDestination) = 0;

virtual CString GetContentTypeString() = 0;

protected:

virtual CString build_sub_header(LPCTSTR szContent,

LPCTSTR szParameters,

int nEncoding,

BOOL bPath) = 0;

private:

int m_nMIMETypeIHandle;

};

//////////////////////////////////////////////////////////////////////

// CMIMECode

class CMIMECode

{

public:

CMIMECode();

virtual ~CMIMECode();

virtual int Decode( LPCTSTR szDecoding, LPTSTR szOutput ) = 0;

virtual CString Encode( LPCTSTR szEncoding, int nSize ) = 0;

};

//////////////////////////////////////////////////////////////////////

// CBase64

// An encoding agent that handles Base64

class CBase64 : public CMIMECode

{

public:

CBase64();

virtual ~CBase64();

// Override the base class mandatory functions

virtual int Decode( LPCTSTR szDecoding, LPTSTR szOutput );

virtual CString Encode( LPCTSTR szEncoding, int nSize );

protected:

void write_bits( UINT nBits, int nNumBts, LPTSTR szOutput, int& lp );

UINT read_bits( int nNumBits, int* pBitsRead, int& lp );

int m_nInputSize;

int m_nBitsRemaining;

ULONG m_lBitStorage;

LPCTSTR m_szInput;

static int m_nMask[];

static CString m_sBase64Alphabet;

private:

};

//////////////////////////////////////////////////////////////////////

// CAppOctetStream

class CAppOctetStream : public CMIMEContentAgent

{

public:

virtual CString GetContentTypeString();

CAppOctetStream( int nContentType );

virtual ~CAppOctetStream();

virtual BOOL AppendPart( LPCTSTR szContent,

LPCTSTR szParameters,

int nEncoding,

BOOL bPath,

CString& sDestination );

protected:

virtual void attach_file( CStdioFile* pFileAtt, int nEncoding, CString& sDestination );

virtual CString build_sub_header( LPCTSTR szContent,

LPCTSTR szParameters,

int nEncoding,

BOOL bPath );

};

// CTextPlain

// A MIME content agent that handles the "text/plain"

// content type

class CTextPlain : public CMIMEContentAgent

{

public:

CTextPlain(int nContentType, UINT nWrapPos = 72);

virtual ~CTextPlain();

virtual BOOL AppendPart(LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath, CString& sDestination);

virtual CString GetContentTypeString();

protected:

UINT m_nWrapPos;

CString wrap_text(LPCTSTR szText);

virtual CString build_sub_header(LPCTSTR szContent, LPCTSTR szParameters, int nEncoding, BOOL bPath);

};

#include <afxmt.h>

// CMIMEMessage

// Formats a message using the MIME specification.

class CMIMEMessage : public CMailMessage

{

public:

CMIMEMessage();

virtual ~CMIMEMessage();

// MIME Type Codes

enum eMIMETypeCode {

TEXT_PLAIN = 0,

APPLICATION_OCTETSTREAM,

NEXT_FREE_MIME_CODE

};

enum eMIMEEncodingCode {

_7BIT = 0,

_8BIT,

BINARY,

QUOTED_PRINTABLE,

BASE64,

NEXT_FREE_ENCODING_CODE

};

BOOL AddMIMEPart(LPCTSTR szContent,

int nContentType = APPLICATION_OCTETSTREAM,

LPCTSTR szParameters = _T(""),

int nEncoding = BASE64,

BOOL bPath = TRUE);

protected:

void insert_message_end(CString& sText);

void register_mime_type(CMIMEContentAgent* pMIMEType);

void insert_boundary(CString& sText);

virtual void append_mime_parts();

virtual void prepare_header();

virtual void prepare_body();

CString m_sNoMIMEText;

CString m_sPartBoundary;

CString m_sMIMEContentType;

private:

class CMIMEPart

{

public:

int m_nEncoding;

int m_nContentType;

CString m_sParameters;

BOOL m_bPath;

CString m_sContent;

};

CList <CMIMEPart, CMIMEPart&> m_MIMEPartList;

class CMIMETypeManager

{

public:

CMIMEContentAgent* GetHandler(int nContentType);

void RegisterMIMEType(CMIMEContentAgent* pMIMEType);

virtual ~CMIMETypeManager();

CMIMETypeManager();

private:

CCriticalSection m_csAccess;

CList <CMIMEContentAgent*, CMIMEContentAgent*> m_MIMETypeList;

};

static CMIMETypeManager m_MIMETypeManager;

};

//////////////////////////////////////////////////////////////////////

// CSmtp

// Main class for SMTP

#include <afxsock.h>

#define SMTP_PORT 25 // Standard port for SMTP servers

#define RESPONSE_BUFFER_SIZE 1024

class CSmtp

{

public:

CSmtp(LPCTSTR szSMTPServerName, UINT nPort = SMTP_PORT);

virtual ~CSmtp();

void SetServerProperties(LPCTSTR szSMTPServerName, UINT nPort = SMTP_PORT);

CString GetLastError();

UINT GetPort();

BOOL Disconnect();

BOOL Connect();

virtual BOOL FormatMailMessage(CMailMessage* msg);

BOOL SendMessage(CMailMessage* msg);

CString GetServerHostName();

private:

BOOL get_response(UINT response_expected);

CString cook_body(CMailMessage* msg);

CString m_sError;

BOOL m_bConnected;

BOOL m_bAuthed;

UINT m_nPort;

CString m_sSMTPServerHostName;

CSocket m_wsSMTPServer;

protected:

virtual BOOL transmit_message(CMailMessage* msg);

//

// Helper Code

//

struct response_code {

UINT nResponse; // Response we're looking for

TCHAR* sMessage; // Error message if we don't get it

};

enum eResponse {

GENERIC_SUCCESS = 0,

CONNECT_SUCCESS,

DATA_SUCCESS,

QUIT_SUCCESS,

// Include any others here

LAST_RESPONSE // Do not add entries past this one

};

TCHAR* response_buf;

static response_code response_table[];

};

#endif // !defined(AFX_CSMTP_H__A0D4A072_65DE_11D2_9816_9523BDBAF506__INCLUDED_)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有