📄 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 "Mailbox.h"
#include "MagicDoc.h"
#include "MagicFrame.h"
#include "MailboxView.h"
#include "SecureString.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_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;
}
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;
sstrTmp.EncodeString( m_intClue, m_strPass ); 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.IsEmpty();
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 ) )
{
Create();
m_strLastError.Empty();
}
if( !STATE_FINAL( m_intState ) && STATE_FINAL( intState ) )
{
#if 0
// For the socket about to be closed.
SOCKET hDeadSocket = m_hSocket;
CAsyncSocket::Close();
// or for CSocket-derived class:
// CSocket::Close();
MSG msg;
CSocket::ProcessAuxQueue();
while(::PeekMessage(&msg,NULL,
WM_SOCKET_NOTIFY,WM_SOCKET_DEAD,PM_REMOVE))
{
::DispatchMessage(&msg);
if( (msg.message==WM_SOCKET_DEAD) &&
((SOCKET)msg.wParam==hDeadSocket))
{
break;
}
}
#else
Close();
#endif
CancelPendingJobs();
Change( COLUMN_MAIL );
}
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::SetSpecTOP( int nTOP)
{
BOOL bNow = GetBoolFlag(m_dwFlags, MBF_SPEC_TOP);
if( bNow == nTOP ) return;
SetBoolFlag(m_dwFlags, MBF_SPEC_TOP, nTOP);
Change( COLUMN_POLL );
SetClue();
}
void CMailbox::DisableAPOP( int nDisable )
{
BOOL bNow = GetBoolFlag(m_dwFlags, MBF_NO_APOP);
if( bNow == nDisable ) return;
SetBoolFlag(m_dwFlags, MBF_NO_APOP, nDisable);
Change( COLUMN_POLL );
SetClue();
}
void CMailbox::Disable( int nDisable )
{
BOOL bNow = GetBoolFlag(m_dwFlags, MBF_PASSIVE);
if( bNow == nDisable ) return;
SetBoolFlag(m_dwFlags, MBF_PASSIVE, nDisable);
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;
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();
}
void CMailbox::OnReceive( int nErrorCode )
{
char szPacket[ 1024 ];
if( nErrorCode ) { SetState( MBOX_NETWORK_FAILED ); return; }
while( TRUE )
{
switch( nErrorCode = Receive( szPacket, sizeof( szPacket )-1 ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -