SMTP.cpp
资源名称:ZapMail.rar [点击查看]
上传用户:xmpantheon
上传日期:2016-10-20
资源大小:7502k
文件大小:7k
源码类别:
Email服务器
开发平台:
Visual C++
- // SMTP.cpp: implementation of the CSMTP class.
- // Copyright (c) 1998, Wes Clyburn
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "SMTP.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
- // 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 %srn" ), 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( "QUITrn" );
- 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( "rn.rn" );
- LPTSTR szGood = _T( "rn..rn" );
- int nPos;
- int nStart = 0;
- int nBadLength = strlen( szBad );
- sTemp = msg->m_sBody;
- if( sTemp.Left( 3 ) == _T( ".rn" ) )
- 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 "rn.rn.rn" 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>rn" ), (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>rn" ), (LPCTSTR)sEmail );
- m_wsSMTPServer.Send( (LPCTSTR)sTo, sTo.GetLength() );
- get_response( GENERIC_SUCCESS );
- }
- // Send the DATA command
- sTemp = _T( "DATArn" );
- 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( "rn.rn" );
- 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;
- }