?? mailbox.cpp
字號:
// Copyright (C) 1997-2002 Valeriy Ovechkin
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// Mailbox.cpp : implementation file
//
/////////////////////////////////////////////////////////////////////
//
// File : Mailbox.cpp
// Description : basic connection code
//
// Modification history ( date, name, description ) :
// 1. 17.12.2002 Igor Green, mmm3@grigsoft.com
// Partial preview support
// 2. 22.01.2003 brendanryan59 (BRN)
// Fixed problem with -- in header data
//
//HISTORY_ENTRY_END:2!22.01.2003
/////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "MD5.h"
#include "Magic.h"
#include "Excerpt.h"
#include "MagicDoc.h"
#include "Mailbox.h"
#include "MagicFrame.h"
#include "MailboxView.h"
#include "SecureString.h"
#include "dpassword.h"
#include <afxpriv.h>
#undef IsLoggingEnabled // clashed with a class member
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
void CMailbox::RecoverString( CString &str )
{
str.MakeReverse();
srand( m_intClue ^ 0x55555555 );
for( int i = str.GetLength(); i; --i )
{
TCHAR ch = TCHAR(str.GetAt( i-1 ) ^ (TCHAR) rand());
str.SetAt( i-1, ch);
}
}
/////////////////////////////////////////////////////////////////////////////
// CMailbox
/* version history:
252: flag for new Doc version
251: added APOP disable flag
*/
IMPLEMENT_SERIAL( CMailbox, CAsyncSocket, 252 | VERSIONABLE_SCHEMA );
CMailbox::CMailbox()
: m_bitSelected(1),
m_bitCreated(1),
m_bitDeleted(0),
m_intOrder(0),
m_tServerSupportsAPOP( true ),
m_tServerSupportsUIDL( true ),
m_tServerSupportsBurstWrites( true ),
m_bLog( false )
{
InitializeServerTraits();
m_nStatTime = 0;
m_nStatCur = 0;
m_nStatMax = 0;
m_nUnread = 0;
m_hResolveJob = 0;
m_pResolveBuffer = NULL;
m_arrayExcerpt.SetSize( 0, 8 );
m_uMciID = 0;
m_hCmdID = 0;
m_intChanged = -1;
m_intState = MBOX_NOT_CHECKED;
m_intClue = 0xBadBabe ^ (int) this;
m_intPort = 110;
m_nExtraLines=0;
m_intPoll = 10;
m_dwFlags = MBF_DEFAULT;
m_intElapsed = theApp.intCheckImmediately ? -1 : 0;
m_intCommand = ACTION_DEFAULT;
m_intCommandRun = COMMAND_RUN_NORMAL;
m_intPlayback = ACTION_DEFAULT;
m_intPlaybackDevice = PLAYBACK_DEVICE_FILE;
m_intMessage = FALSE;
#ifdef USE_SSL
m_pSSL = NULL;
m_SSL.SetMailbox(this);
#endif
}
const CMailbox& CMailbox::operator=( const CMailbox& a)
{
m_intClue = a.m_intClue;
m_intPort = a.m_intPort;
m_intPoll = a.m_intPoll;
m_ulongIP = a.m_ulongIP;
m_intCommand = a.m_intCommand;
m_intCommandRun = a.m_intCommandRun;
m_intPlayback = a.m_intPlayback;
m_intPlaybackDevice = a.m_intPlaybackDevice;
m_intMessage = a.m_intMessage;
m_dwFlags = a.m_dwFlags;
m_nExtraLines = a.m_nExtraLines;
m_strPass = a.m_strPass;
m_strUser = a.m_strUser;
m_strHost = a.m_strHost;
m_strAlias = a.m_strAlias;
m_strCommand = a.m_strCommand;
m_strPlayback = a.m_strPlayback;
return *this;
}
CMailbox::~CMailbox()
{
CancelPendingJobs();
m_bitDeleted = 1;
Change( COLUMN_STATE );
CWnd *wnd = (CWnd*) AfxGetMainWnd();
if( wnd ) wnd->SendMessage( VM_UPDATEITEM, (WPARAM) this );
int i = m_arrayExcerpt.GetSize();
while( i ) delete m_arrayExcerpt[--i];
m_arrayExcerpt.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// CMailbox message handlers
void CMailbox::Serialize( CArchive& ar )
{
if( ar.IsLoading() ) // READ
{
int intVersion = ar.GetObjectSchema();
if( intVersion < 250 )
{
DWORD wordTmp;
ar >> wordTmp; m_intClue = (int) wordTmp;
ar >> wordTmp; m_intPort = (int) wordTmp;
ar >> wordTmp; m_intPoll = (int) wordTmp;
ar >> wordTmp; m_ulongIP = (int) wordTmp;
ar >> m_strPass;
ar >> m_strUser;
ar >> m_strHost;
if( 200 <= intVersion )
{
ar >> m_strAlias;
ar >> wordTmp; m_intCommand = (int) wordTmp;
ar >> wordTmp; m_intCommandRun = (int) wordTmp;
ar >> m_strCommand;
ar >> wordTmp; m_intPlayback = (int) wordTmp;
ar >> wordTmp; m_intPlaybackDevice = (int) wordTmp;
ar >> m_strPlayback;
ar >> wordTmp; m_intMessage = (int) wordTmp;
}
m_intClue ^= 0xAAAAAAAA;
m_intPort ^= m_intClue;
m_intPoll ^= m_intClue;
m_ulongIP ^= m_intClue;
m_intCommand ^= m_intClue;
m_intCommandRun ^= m_intClue;
m_intPlayback ^= m_intClue;
m_intPlaybackDevice ^= m_intClue;
m_intMessage ^= m_intClue;
RecoverString( m_strAlias );
RecoverString( m_strUser );
RecoverString( m_strHost );
RecoverString( m_strPass );
RecoverString( m_strCommand );
RecoverString( m_strPlayback );
}
else // if( 250 <= intVersion )
{
DWORD dwTmp;
ar >> dwTmp; m_intClue = (int) dwTmp;
ar >> dwTmp; m_intPort = (int) dwTmp;
ar >> dwTmp; m_intPoll = (int) dwTmp;
ar >> dwTmp; m_ulongIP = (int) dwTmp;
ar >> dwTmp; m_intCommand = (int) dwTmp;
ar >> dwTmp; m_intCommandRun = (int) dwTmp;
ar >> dwTmp; m_intPlayback = (int) dwTmp;
ar >> dwTmp; m_intPlaybackDevice = (int) dwTmp;
ar >> dwTmp; m_intMessage = (int) dwTmp;
if (intVersion >= 251)
{
ar >> m_dwFlags;
}
else
m_dwFlags = MBF_DEFAULT;
if (intVersion >= 252)
ar >> m_nExtraLines;
else
m_nExtraLines = 255;
// assure checksum
DWORD dwCheckSum = 0;
ar >> dwCheckSum;
dwCheckSum ^= m_intClue ^ m_intPort ^ m_intPoll ^ m_ulongIP ^
m_intCommand ^ m_intCommandRun ^
m_intPlayback ^ m_intPlaybackDevice ^
m_intMessage;
if( dwCheckSum ) AfxThrowArchiveException( CArchiveException::badIndex, _T("") );
CSecureString sstrTmp;
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strPass );
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strUser );
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strHost );
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strAlias );
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strCommand );
sstrTmp.Serialize( ar ); sstrTmp.DecodeString( m_intClue, m_strPlayback );
}
m_ulongIP = 0;
}
else // WRITE
{
ar << (DWORD) m_intClue;
ar << (DWORD) m_intPort;
ar << (DWORD) m_intPoll;
ar << (DWORD) m_ulongIP;
ar << (DWORD) m_intCommand;
ar << (DWORD) m_intCommandRun;
ar << (DWORD) m_intPlayback;
ar << (DWORD) m_intPlaybackDevice;
ar << (DWORD) m_intMessage;
ar << (DWORD) m_dwFlags;
if (m_nExtraLines==255)
m_nExtraLines = 0;
ar << (BYTE) m_nExtraLines;
// calculate checksum
DWORD dwCheckSum = 0;
dwCheckSum ^= m_intClue ^ m_intPort ^ m_intPoll ^ m_ulongIP ^
m_intCommand ^ m_intCommandRun ^ m_intPlayback ^
m_intPlaybackDevice ^ m_intMessage;
ar << dwCheckSum;
CSecureString sstrTmp;
CString sSavePass;
if ((m_dwFlags & MBF_ASK_PASS)==0)
sSavePass = m_strPass;
sstrTmp.EncodeString( m_intClue, sSavePass); sstrTmp.Serialize( ar );
sstrTmp.EncodeString( m_intClue, m_strUser ); sstrTmp.Serialize( ar );
sstrTmp.EncodeString( m_intClue, m_strHost ); sstrTmp.Serialize( ar );
sstrTmp.EncodeString( m_intClue, m_strAlias ); sstrTmp.Serialize( ar );
sstrTmp.EncodeString( m_intClue, m_strCommand ); sstrTmp.Serialize( ar );
sstrTmp.EncodeString( m_intClue, m_strPlayback ); sstrTmp.Serialize( ar );
}
}
void CMailbox::SetAlias( CString &strAlias )
{
if( m_strAlias == strAlias ) return;
m_strAlias = strAlias;
Change( COLUMN_ALIAS );
SetClue();
}
void CMailbox::SetUser( CString &strUser )
{
if( m_strUser == strUser ) return;
m_strUser = strUser;
Change( COLUMN_USER );
SetState( MBOX_NOT_CHECKED );
SetClue();
}
void CMailbox::SetHost( CString &strHost )
{
if( m_strHost == strHost ) return;
m_strHost = strHost;
Change( COLUMN_HOST );
InitializeServerTraits();
SetState( MBOX_NOT_CHECKED );
SetClue();
}
void CMailbox::SetPass( CString &strPass, BOOL bAsk )
{
if (bAsk)
m_strPass.Empty();
else
m_strPass = strPass;
SetBoolFlag(m_dwFlags, MBF_ASK_PASS, bAsk);
SetClue();
}
void CMailbox::SetState( int intState )
{
if( STATE_FINAL( m_intState ) && !STATE_FINAL( intState ) )
{
m_strLastError.Empty();
#ifdef USE_SSL
if (m_dwFlags & MBF_SSL)
{
m_pSSLctx = SSL_CTX_new(SSLv2_client_method());
m_pSSL = SSL_new(m_pSSLctx);
m_SSL.CreateConnector(m_pSSLctx);
m_SSL.Create();
}
else
#endif
Create();
}
if( !STATE_FINAL( m_intState ) && STATE_FINAL( intState ) )
{
Close();
CancelPendingJobs();
Change( COLUMN_MAIL );
#ifdef USE_SSL
if (m_pSSL)
{
m_SSL.Close();
SSL_shutdown(m_pSSL);
SSL_free(m_pSSL);
SSL_CTX_free(m_pSSLctx);
m_dwFlags &= ~0x1000;
}
#endif
}
m_intState = intState;
Change( COLUMN_STATE );
if( MBOX_CHECKED == intState )
{
Change( COLUMN_ELAPSED );
m_intElapsed = 0;
}
else if( MBOX_NOT_CHECKED == intState )
{
Change( COLUMN_MAIL );
Change( COLUMN_ELAPSED );
m_intElapsed = -1;
int i = m_arrayExcerpt.GetSize();
while( i ) delete m_arrayExcerpt[ --i ];
m_arrayExcerpt.RemoveAll();
}
else if( MBOX_INTERRUPTED_BY_USER )
{
}
}
void CMailbox::SetPort( int intPort )
{
if( m_intPort == intPort ) return;
m_intPort = intPort;
Change( COLUMN_PORT );
SetClue();
}
void CMailbox::SetFlag( int nFlag, int nSet)
{
BOOL bNow = GetBoolFlag(m_dwFlags, nFlag);
if( bNow == nSet ) return;
SetBoolFlag(m_dwFlags, nFlag, nSet);
Change( COLUMN_POLL );
SetClue();
}
void CMailbox::SetPoll( int intPoll )
{
if( m_intPoll == intPoll ) return;
m_intPoll = intPoll;
Change( COLUMN_POLL );
SetClue();
}
void CMailbox::BeginResolveHostByName()
{
if( m_strHost.IsEmpty() ) { SetState( MBOX_INVALID_HOST ); return; }
SetState( MBOX_RESOLVING );
ASSERT( !m_pResolveBuffer && !m_hResolveJob );
char szHost[256] = ""; CharToOem( m_strHost, szHost );
m_ulongIP = inet_addr( szHost );
if( INADDR_NONE == m_ulongIP )
{
m_ulongIP = 0;
m_pResolveBuffer = new char[ MAXGETHOSTSTRUCT ];
m_hResolveJob = WSAAsyncGetHostByName(
AfxGetMainWnd()->m_hWnd,
VM_END_RESOLVE_HOST_BY_NAME,
szHost,
m_pResolveBuffer,
MAXGETHOSTSTRUCT );
}
else
{
Check();
}
}
void CMailbox::EndResolveHostByName( WPARAM wParam, LPARAM lParam )
{
if( m_hResolveJob != (HANDLE) wParam ) return;
if( HIWORD( lParam ) ) SetState( MBOX_INVALID_HOST );
else
{
m_ulongIP = *(ULONG*) ( (struct hostent*) m_pResolveBuffer )->h_addr;
Check();
}
m_hResolveJob = 0;
delete m_pResolveBuffer;
m_pResolveBuffer = NULL;
}
void CMailbox::Check()
{
if( MBOX_CONNECTING == m_intState )
{
// MFC can't handle the case when Close is called before OnConnect had fired.
// as a result, an assertion occurs in sockcore.cpp on line 513.
// this measure will avoid the problem in the first place.
return;
}
if( !STATE_FINAL( m_intState ) )
{
SetState( MBOX_CANNOT_CHECK );
}
if( !m_ulongIP )
{
BeginResolveHostByName();
return;
}
SetState( MBOX_CONNECTING );
SOCKADDR_IN a;
a.sin_family = AF_INET;
a.sin_port = htons( (u_short)m_intPort );
a.sin_addr.S_un.S_addr = m_ulongIP;
#ifdef USE_SSL
if (m_pSSL && !m_SSL.Connect( (SOCKADDR*) &a, sizeof(a) ) &&
( WSAEWOULDBLOCK != GetLastError() ) )
{
TRACE2( "SSL Error #%d; [%s] cannot connect\n", GetLastError(), m_strAlias );
SetState( MBOX_SOCKET_ERROR );
}
else if (!m_pSSL)
#endif
if( !Connect( (SOCKADDR*) &a, sizeof(a) ) &&
( WSAEWOULDBLOCK != GetLastError() ) )
{
TRACE2( "Socket Error #%d; [%s] cannot connect\n", GetLastError(), m_strAlias );
SetState( MBOX_SOCKET_ERROR );
}
}
void CMailbox::StopChecking()
{
if( !STATE_FINAL( m_intState ) )
{
SetState( MBOX_INTERRUPTED_BY_USER );
}
// clear out all pending tasks
for( int i = m_arrayExcerpt.GetSize(); i; --i )
{
m_arrayExcerpt[i-1]->m_bitRemoveFromServer = false;
m_arrayExcerpt[i-1]->m_bitDownloadData = false;
m_arrayExcerpt[i-1]->m_bitPreviewData = false;
m_arrayExcerpt[i-1]->Change( COLUMN_MBOX );
}
}
void CMailbox::OnConnect( int nErrorCode )
{
if( nErrorCode )
{
TRACE2( "Socket Error #%d; [%s] OnConnect: cannot connect\n", nErrorCode, m_strAlias );
SetState( MBOX_CANNOT_CONNECT );
InitializeServerTraits();
}
else
{
TRACE1( "Socket connected #%d\n", m_hSocket );
}
//m_strLog.Empty();
// no initial answer over ssl?
if (m_pSSL && m_intState == MBOX_CONNECTING)
{
if ((m_dwFlags & 0x1000) == 0)
{
m_dwFlags |= 0x1000;
CString strPacket;
char szPacket[ 1024 ];
strPacket.Format( _T("USER %s\r\n"), m_strUser );
CharToOem( strPacket, szPacket );
SetState( Send( szPacket, strlen( szPacket ) ) ?
MBOX_WF_USER_RESPONSE_SSL : MBOX_CANNOT_SEND );
m_tServerSupportsAPOP = false;
}
}
}
void CMailbox::OnReceive( int nErrorCode )
{
char szPacket[ 1024 ];
if( nErrorCode ) { SetState( MBOX_NETWORK_FAILED ); return; }
while( TRUE )
{
#ifdef USE_SSL
if (m_pSSL)
{
nErrorCode = m_SSL.GetData( szPacket, sizeof( szPacket )-1 );
if (nErrorCode==0)
return;
}
else
#endif
nErrorCode = Receive( szPacket, sizeof( szPacket )-1 );
switch( nErrorCode )
{
case 0:
{
if( m_intState == MBOX_WF_USER_RESPONSE )
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -