864 lines
25 KiB
C++
864 lines
25 KiB
C++
#define INCL_INETSRV_INCS
|
|
#include "smtpinc.h"
|
|
#include "remoteq.hxx"
|
|
#include "dropdir.hxx"
|
|
|
|
DWORD g_dwDropFileCounter = 0;
|
|
CPool CDropDir::m_Pool(DROPDIR_SIG);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DropDirWriteCompletion(
|
|
PVOID pvContext,
|
|
DWORD cbWritten,
|
|
DWORD dwCompletionStatus,
|
|
OVERLAPPED * lpo
|
|
)
|
|
{
|
|
DECL_TRACE((LPARAM) 0xC0DEC0DE, "DropDirWriteCompletion");
|
|
BOOL WasProcessed = TRUE;
|
|
CDropDir *pCC = (CDropDir *) pvContext;
|
|
|
|
_ASSERT(pCC);
|
|
|
|
pCC->SetHr( pCC->OnIoWriteCompletion(cbWritten, dwCompletionStatus, lpo) );
|
|
|
|
SAFE_RELEASE( pCC );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
VOID
|
|
DropDirReadCompletion(
|
|
PFIO_CONTEXT pContext,
|
|
PFH_OVERLAPPED lpo,
|
|
DWORD cbRead,
|
|
DWORD dwCompletionStatus
|
|
)
|
|
{
|
|
DECL_TRACE((LPARAM) 0xC0DEC0DE, "DropDirReadCompletion");
|
|
BOOL WasProcessed = TRUE;
|
|
DROPDIR_READ_OVERLAPPED *p = (DROPDIR_READ_OVERLAPPED *) lpo;
|
|
CDropDir *pCC = (CDropDir*) p->ThisPtr;
|
|
|
|
_ASSERT(pCC);
|
|
|
|
pCC->SetHr( pCC->OnIoReadCompletion(cbRead, dwCompletionStatus, (LPOVERLAPPED)lpo) );
|
|
|
|
SAFE_RELEASE( pCC );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CDropDir::CDropDir()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::CDropDir");
|
|
|
|
m_dwSig = DROPDIR_SIG;
|
|
m_cRef = 1;
|
|
m_NumRcpts = 0;
|
|
m_hDrop = INVALID_HANDLE_VALUE;
|
|
m_hMail = NULL;
|
|
m_AdvContext = NULL;
|
|
m_rgRcptIndexList = NULL;
|
|
m_pIMsg = NULL;
|
|
m_pBindInterface = NULL;
|
|
m_pAtqContext = NULL;
|
|
CopyMemory( m_acCrLfDotCrLf, "\r\n.\r\n", 5 );
|
|
ZeroMemory( m_acLastBytes, 5 );
|
|
m_pIMsgRecips = NULL;
|
|
m_hr = S_OK;
|
|
m_cbWriteOffset = 0;
|
|
m_cbReadOffset = 0;
|
|
m_cbMsgWritten = 0;
|
|
m_idxRecips = 0;
|
|
ZeroMemory( &m_WriteOverlapped, sizeof( m_WriteOverlapped ) );
|
|
ZeroMemory( &m_ReadOverlapped, sizeof( m_ReadOverlapped ) );
|
|
m_szDropDir[0] = '\0';
|
|
m_pISMTPConnection = NULL;
|
|
m_ReadState = DROPDIR_READ_NULL;
|
|
m_WriteState = DROPDIR_WRITE_NULL;
|
|
m_pParentInst = NULL;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
CDropDir::~CDropDir()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::~CDropDir");
|
|
|
|
SAFE_RELEASE( m_pIMsgRecips );
|
|
|
|
if(m_pBindInterface)
|
|
{
|
|
m_pBindInterface->ReleaseContext();
|
|
SAFE_RELEASE(m_pBindInterface);
|
|
}
|
|
|
|
m_MsgAck.pIMailMsgProperties = m_pIMsg;
|
|
m_MsgAck.pvMsgContext = (DWORD *) m_AdvContext;
|
|
|
|
if(SUCCEEDED(m_hr))
|
|
{
|
|
m_MsgAck.dwMsgStatus = MESSAGE_STATUS_ALL_DELIVERED;
|
|
}
|
|
else
|
|
{
|
|
m_MsgAck.dwMsgStatus = MESSAGE_STATUS_RETRY_ALL;
|
|
}
|
|
|
|
m_MsgAck.dwStatusCode = 0;
|
|
m_pISMTPConnection->AckMessage(&m_MsgAck);
|
|
SAFE_RELEASE(m_pIMsg);
|
|
|
|
if(SUCCEEDED(m_hr))
|
|
{
|
|
BUMP_COUNTER( m_pParentInst, DirectoryDrops);
|
|
}
|
|
|
|
if(SUCCEEDED(m_hr))
|
|
{
|
|
m_pISMTPConnection->AckConnection(CONNECTION_STATUS_OK);
|
|
}
|
|
else
|
|
{
|
|
DeleteFile(m_szDropFile);
|
|
SetLastError( 0x0000FFFF & m_hr );
|
|
m_pISMTPConnection->AckConnection(CONNECTION_STATUS_FAILED);
|
|
}
|
|
|
|
PATQ_CONTEXT pAtqContext = (PATQ_CONTEXT)InterlockedExchangePointer( (PVOID *)&m_pAtqContext, NULL);
|
|
if ( pAtqContext != NULL )
|
|
{
|
|
if(m_hDrop != INVALID_HANDLE_VALUE)
|
|
AtqCloseFileHandle( pAtqContext );
|
|
AtqFreeContext( pAtqContext, TRUE );
|
|
}
|
|
|
|
//
|
|
// Now get the next message on this connection and
|
|
// copy it to drop directory.
|
|
//
|
|
|
|
if (m_szDropDir[0])
|
|
AsyncCopyMailToDropDir( m_pISMTPConnection, m_szDropDir, m_pParentInst );
|
|
|
|
SAFE_RELEASE( m_pISMTPConnection );
|
|
|
|
m_dwSig = DROPDIR_SIG_FREE;
|
|
}
|
|
|
|
|
|
//---[ CDropDir::CopyMailToDropDir ]-------------------------------------------
|
|
//
|
|
//
|
|
// Description:
|
|
//
|
|
// Entry point to the Async writing to the mail file. When this is called
|
|
// it sets up a series of alternating reads and writes (read from the queue
|
|
// and write to the mail file). The (rough description of the) algorithm is
|
|
// as follows:
|
|
//
|
|
// WriteHeaders()
|
|
// Post Async Read from MailFile
|
|
// return
|
|
//
|
|
// Read Completion function()
|
|
// Post Async Write of Data to DropDir
|
|
// return
|
|
//
|
|
// Write Completion function()
|
|
// Post Async Read from MailFile
|
|
// return
|
|
//
|
|
// Called by
|
|
// AsyncCopyMailToDropDir()
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History:
|
|
// Created by PGOPI
|
|
// 3/25/99 - MikeSwa modified for checkin
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
HRESULT CDropDir::CopyMailToDropDir(
|
|
ISMTPConnection *pISMTPConnection,
|
|
const char *DropDirectory,
|
|
IMailMsgProperties *pIMsg,
|
|
PVOID AdvContext,
|
|
DWORD NumRcpts,
|
|
DWORD *rgRcptIndexList,
|
|
SMTP_SERVER_INSTANCE *pParentInst)
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::CopyMailToDropDir");
|
|
HRESULT hr = S_OK;
|
|
|
|
m_pISMTPConnection = pISMTPConnection;
|
|
SAFE_ADDREF( m_pISMTPConnection );
|
|
m_pIMsg = pIMsg;
|
|
SAFE_ADDREF( m_pIMsg );
|
|
m_pParentInst = pParentInst;
|
|
m_AdvContext = AdvContext;
|
|
m_NumRcpts = NumRcpts;
|
|
m_rgRcptIndexList = rgRcptIndexList;
|
|
|
|
if (!DropDirectory)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
return ( hr );
|
|
}
|
|
|
|
//Copy drop directory now... so we have a copy in the destructor
|
|
//even if this message cannot be dropped
|
|
lstrcpy(m_szDropDir, DropDirectory);
|
|
|
|
hr = m_pIMsg->QueryInterface(IID_IMailMsgBind, (void **)&m_pBindInterface);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
ErrorTrace( (LPARAM)this, "m_pIMsg->QueryInterface for IID_IMailMsgBind return hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
hr = m_pBindInterface->GetBinding(&m_hMail, NULL);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
ErrorTrace( (LPARAM)this, "GetBinding return hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
hr = m_pIMsg->QueryInterface( IID_IMailMsgRecipients, (PVOID *) &m_pIMsgRecips);
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "QueryInterface for IID_IMailMsgRecipients failed hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
if( CheckIfAllRcptsHandled() )
|
|
{
|
|
return( S_OK );
|
|
}
|
|
|
|
|
|
DebugTrace((LPARAM)this, "Dropping file to: %s", DropDirectory);
|
|
|
|
m_hDrop = CreateDropFile(DropDirectory);
|
|
|
|
if (m_hDrop == INVALID_HANDLE_VALUE)
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
ErrorTrace( (LPARAM)this, "Unable to create drop directory (%s) : 0x%x", DropDirectory, hr);
|
|
return( hr );
|
|
}
|
|
|
|
if (!AtqAddAsyncHandle( &m_pAtqContext,
|
|
NULL,
|
|
(LPVOID) this,
|
|
DropDirWriteCompletion,
|
|
INFINITE,
|
|
m_hDrop))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
ErrorTrace((LPARAM)this, "Error 0x%x while adding async handle to ATQ", hr);
|
|
return( hr );
|
|
}
|
|
|
|
// Output the x-headers
|
|
|
|
if (FAILED( hr = CreateXHeaders() ) )
|
|
{
|
|
ErrorTrace( (LPARAM)this, " Error while creating x-headers hr = 0x%x", hr);
|
|
return( hr );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HANDLE CDropDir::CreateDropFile(const char * DropDir)
|
|
{
|
|
HANDLE FileHandle = INVALID_HANDLE_VALUE;
|
|
DWORD dwStrLen;
|
|
FILETIME ftTime;
|
|
DWORD Error = 0;
|
|
|
|
DECL_TRACE((LPARAM)this, "CDropDir::CreateDropFile");
|
|
|
|
dwStrLen = lstrlen(DropDir);
|
|
lstrcpy(m_szDropFile, DropDir);
|
|
|
|
do
|
|
{
|
|
GetSystemTimeAsFileTime(&ftTime);
|
|
wsprintf(&m_szDropFile[dwStrLen],
|
|
"%08x%08x%08x%s",
|
|
ftTime.dwLowDateTime,
|
|
ftTime.dwHighDateTime,
|
|
InterlockedIncrement((PLONG)&g_dwDropFileCounter),
|
|
".eml");
|
|
|
|
FileHandle = CreateFile(m_szDropFile,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
if (FileHandle != INVALID_HANDLE_VALUE)
|
|
break;
|
|
|
|
if((Error = GetLastError()) != ERROR_FILE_EXISTS)
|
|
{
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
ErrorTrace( (LPARAM)this, "CreateFile returns err = %u", Error );
|
|
break;
|
|
}
|
|
|
|
} while( (FileHandle == INVALID_HANDLE_VALUE) && !m_pParentInst->IsShuttingDown());
|
|
|
|
return (FileHandle);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::ReadFile(
|
|
IN LPVOID pBuffer,
|
|
IN DWORD cbSize
|
|
)
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::ReadFile");
|
|
HRESULT hr = S_OK;
|
|
|
|
_ASSERT(pBuffer != NULL);
|
|
|
|
m_ReadOverlapped.Overlapped.Offset = LODWORD( m_cbReadOffset );
|
|
m_ReadOverlapped.Overlapped.OffsetHigh = HIDWORD( m_cbReadOffset );
|
|
m_ReadOverlapped.Overlapped.pfnCompletion = DropDirReadCompletion;
|
|
m_ReadOverlapped.ThisPtr = (PVOID)this;
|
|
|
|
AddRef();
|
|
|
|
BOOL fRet = FIOReadFile( m_hMail,
|
|
pBuffer, // Buffer
|
|
cbSize, // BytesToRead
|
|
(PFH_OVERLAPPED)&m_ReadOverlapped) ;
|
|
|
|
if(!fRet)
|
|
{
|
|
DWORD err = GetLastError();
|
|
if( err != ERROR_IO_PENDING )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( err );
|
|
|
|
ErrorTrace( (LPARAM)this, "FIOReadFile return hr = 0x%x", hr );
|
|
}
|
|
|
|
}
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::WriteFile(
|
|
IN LPVOID pBuffer,
|
|
IN DWORD cbSize
|
|
)
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::WriteFile");
|
|
CDropDir *p = this;
|
|
_ASSERT(pBuffer != NULL);
|
|
_ASSERT(cbSize > 0);
|
|
HRESULT hr = S_OK;
|
|
|
|
m_WriteOverlapped.Offset = LODWORD( m_cbWriteOffset );
|
|
m_WriteOverlapped.OffsetHigh = HIDWORD( m_cbWriteOffset );
|
|
|
|
AddRef();
|
|
|
|
BOOL fRet = AtqWriteFile( m_pAtqContext, // Atq context
|
|
pBuffer, // Buffer
|
|
cbSize, // BytesToRead
|
|
(OVERLAPPED *) &m_WriteOverlapped) ;
|
|
|
|
if(!fRet)
|
|
{
|
|
DWORD err = GetLastError();
|
|
if( err != ERROR_IO_PENDING )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( err );
|
|
|
|
ErrorTrace( (LPARAM)this, "AtqWriteFile return hr = 0x%x", hr );
|
|
}
|
|
|
|
}
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Release();
|
|
}
|
|
return( hr );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::OnIoWriteCompletion( DWORD cbSize, DWORD dwErr, OVERLAPPED *lpo )
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::OnIoWriteCompletion");
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
if( dwErr != NO_ERROR )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "OnIoWriteCompletion got err = %u", dwErr );
|
|
return( HRESULT_FROM_WIN32( dwErr ) );
|
|
}
|
|
|
|
m_cbWriteOffset += cbSize;
|
|
|
|
switch( m_ReadState )
|
|
{
|
|
case DROPDIR_READ_X_SENDER:
|
|
_ASSERT(!"Invalid State READ_X_SENDER");
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
case DROPDIR_READ_X_RECEIVER:
|
|
hr = CreateXRecvHeaders();
|
|
break;
|
|
case DROPDIR_READ_DATA:
|
|
hr = OnCopyMessageWrite( cbSize);
|
|
break;
|
|
default:
|
|
_ASSERT(!"INVALID read STATE");
|
|
hr = E_INVALIDARG;
|
|
ErrorTrace( (LPARAM)this, "Invalid ReadState" );
|
|
break;
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::OnIoReadCompletion( DWORD cbSize, DWORD dwErr, OVERLAPPED *lpo )
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::OnIoReadCompletion");
|
|
HRESULT hr = S_OK;
|
|
|
|
if( ( dwErr != NO_ERROR ) && ( dwErr != ERROR_HANDLE_EOF ) )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( dwErr );
|
|
|
|
ErrorTrace( (LPARAM)this, "OnIOReadCompletion got hr = 0x%x", hr );
|
|
}
|
|
else
|
|
{
|
|
m_cbReadOffset += cbSize;
|
|
hr = OnCopyMessageRead( cbSize, dwErr );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::CreateXHeaders()
|
|
{
|
|
|
|
DECL_TRACE(((LPARAM) this), "CDropDir::CreateXHeaders");
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace( (LPARAM)this, "Setting m_ReadState = DROPDIR_READ_X_SENDER" );
|
|
|
|
m_ReadState = DROPDIR_READ_X_SENDER;
|
|
|
|
strcpy( m_szBuffer, X_SENDER_HEADER );
|
|
|
|
hr = m_pIMsg->GetStringA( IMMPID_MP_SENDER_ADDRESS_SMTP, MAX_INTERNET_NAME, &m_szBuffer[ sizeof(X_SENDER_HEADER) - 1] );
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
strcat( m_szBuffer, X_HEADER_EOLN);
|
|
|
|
//
|
|
// this WriteFile will complete async, so set the next read state.
|
|
// Make Sure that no class member variables are acessed after calling
|
|
// WriteFile or ReadFile as they complete async & there is no critical
|
|
// section protecting access.To do this trace through all paths
|
|
// thru which ReadFile and WriteFile are called and make sure no member
|
|
// variables are accessed.
|
|
|
|
m_ReadState = DROPDIR_READ_X_RECEIVER;
|
|
|
|
DebugTrace( (LPARAM)this, "Setting m_ReadState = DROPDIR_READ_X_RECEIVER" );
|
|
//
|
|
|
|
if( FAILED( hr = WriteFile( m_szBuffer, strlen( m_szBuffer ) ) ) )
|
|
{
|
|
ErrorTrace((LPARAM)this, "Error %d writing x-sender line %s", hr, m_szBuffer);
|
|
|
|
return( hr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
|
|
hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
|
|
|
|
ErrorTrace((LPARAM)this, "Could not get Sender Address returning hr = 0x%x", hr);
|
|
|
|
return( hr );
|
|
}
|
|
|
|
return( hr );
|
|
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::CreateXRecvHeaders()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::CreateXRecvHeaders");
|
|
HRESULT hr = S_OK;
|
|
DWORD dwRecipientFlags = 0;
|
|
BOOL fPendingWrite = FALSE;
|
|
|
|
strcpy( m_szBuffer, X_RECEIVER_HEADER );
|
|
|
|
while( m_idxRecips < m_NumRcpts )
|
|
{
|
|
hr = m_pIMsgRecips->GetDWORD( m_rgRcptIndexList[m_idxRecips], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
|
|
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
|
|
{
|
|
hr = m_pIMsgRecips->GetStringA( m_rgRcptIndexList[m_idxRecips],
|
|
IMMPID_RP_ADDRESS_SMTP,
|
|
MAX_INTERNET_NAME,
|
|
&m_szBuffer[ sizeof(X_RECEIVER_HEADER) - 1 ]);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
strcat(m_szBuffer, X_HEADER_EOLN);
|
|
|
|
|
|
|
|
// Make Sure that no class member variables are acessed after calling
|
|
// WriteFile or ReadFile as they complete async & there is no critical
|
|
// section protecting access.To do this trace through all paths
|
|
// thru which ReadFile and WriteFile are called and make sure no member
|
|
// variables are accessed.
|
|
|
|
m_idxRecips++;
|
|
|
|
if(FAILED( hr = WriteFile(m_szBuffer, strlen(m_szBuffer) ) ) )
|
|
|
|
{
|
|
ErrorTrace( (LPARAM)this, "WriteFile return hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
fPendingWrite = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace( (LPARAM)this, "GetStringA for IMMPID_RP_ADDRESS_SMTP returns hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_idxRecips++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ErrorTrace( (LPARAM)this, "GetDWORD for IMMPID_RP_RECIPIENT_FLAGS returns hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
}
|
|
|
|
if( !fPendingWrite )
|
|
{
|
|
m_ReadState = DROPDIR_READ_DATA;
|
|
m_WriteState = DROPDIR_WRITE_DATA;
|
|
DebugTrace( (LPARAM)this, "Setting m_WriteState & m_ReadState to WRITE_DATA & READ_DATA respectively" );
|
|
return( CopyMessage() );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::CopyMessage()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::CopyMessage");
|
|
|
|
// Make Sure that no class member variables are acessed after calling
|
|
// WriteFile or ReadFile as they complete async & there is no critical
|
|
// section protecting access.To do this trace through all paths
|
|
// thru which ReadFile and WriteFile are called and make sure no member
|
|
// variables are accessed.
|
|
|
|
HRESULT hr = ReadFile( m_szBuffer, sizeof( m_szBuffer ) );
|
|
|
|
if( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) )
|
|
{
|
|
m_WriteState = DROPDIR_WRITE_CRLF;
|
|
|
|
DebugTrace( (LPARAM)this, "ReadFile returns err = ERROR_HANDLE_EOF, Setting m_WriteState = DROPDIR_WRITE_CRLF" );
|
|
|
|
return( DoLastFileOp() );
|
|
}
|
|
|
|
return( hr );
|
|
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::OnCopyMessageRead( DWORD dwBytesRead, DWORD dwErr )
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::OnCopyMessageRead");
|
|
HRESULT hr = S_OK;
|
|
|
|
if (dwBytesRead )
|
|
{
|
|
if (dwBytesRead > 4)
|
|
{
|
|
CopyMemory(m_acLastBytes, &m_szBuffer[dwBytesRead-5], 5);
|
|
}
|
|
else
|
|
{
|
|
MoveMemory(m_acLastBytes, &m_acLastBytes[dwBytesRead], 5-dwBytesRead);
|
|
CopyMemory(&m_acLastBytes[5-dwBytesRead], m_szBuffer, dwBytesRead);
|
|
}
|
|
|
|
//
|
|
// the write file will complete async & then we'll do the
|
|
// last fileop.
|
|
//
|
|
|
|
if( dwErr == ERROR_HANDLE_EOF )
|
|
{
|
|
DebugTrace( (LPARAM)this, " Interesting case err = ERROR_HANDLE_EOF, Setting m_WriteState = DROPDIR_WRITE_CRLF" );
|
|
|
|
m_WriteState = DROPDIR_WRITE_CRLF;
|
|
}
|
|
|
|
// Make Sure that no class member variables are acessed after calling
|
|
// WriteFile or ReadFile as they complete async & there is no critical
|
|
// section protecting access.To do this trace through all paths
|
|
// thru which ReadFile and WriteFile are called and make sure no member
|
|
// variables are accessed.
|
|
|
|
if ( FAILED( hr = WriteFile(m_szBuffer, dwBytesRead ) ) )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "WriteFile return hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
m_WriteState = DROPDIR_WRITE_CRLF;
|
|
|
|
DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_CRLF" );
|
|
|
|
return( DoLastFileOp() );
|
|
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::OnCopyMessageWrite( DWORD cbWritten )
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::OnCopyMessageWrite");
|
|
HRESULT hr = S_OK;
|
|
|
|
m_cbMsgWritten += cbWritten;
|
|
|
|
switch( m_WriteState )
|
|
{
|
|
case DROPDIR_WRITE_DATA:
|
|
return( CopyMessage() );
|
|
break;
|
|
case DROPDIR_WRITE_CRLF:
|
|
return( DoLastFileOp() );
|
|
break;
|
|
case DROPDIR_WRITE_SETPOS:
|
|
return( AdjustFilePos() );
|
|
break;
|
|
default:
|
|
_ASSERT(!"Invalid WriteState");
|
|
ErrorTrace( (LPARAM)this, "Invalid WriteState" );
|
|
hr = E_INVALIDARG;
|
|
break;
|
|
}
|
|
|
|
return( hr );
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::DoLastFileOp()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::DoLastFileOp");
|
|
HRESULT hr = S_OK;
|
|
DebugTrace( (LPARAM)this, "DoLastFileOp called" );
|
|
|
|
// Now, see if the file ends with a CRLF, if not, add it
|
|
if ((m_cbMsgWritten > 1) && memcmp(&m_acLastBytes[3], &m_acCrLfDotCrLf[3], 2))
|
|
{
|
|
//
|
|
// the write will complete async. set next write state
|
|
//
|
|
|
|
DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_SETPOS" );
|
|
|
|
m_WriteState = DROPDIR_WRITE_SETPOS;
|
|
|
|
// Make Sure that no class member variables are acessed after calling
|
|
// WriteFile or ReadFile as they complete async & there is no critical
|
|
// section protecting access.To do this trace through all paths
|
|
// thru which ReadFile and WriteFile are called and make sure no member
|
|
// variables are accessed.
|
|
|
|
// Add the trailing CRLF
|
|
if(FAILED( hr = WriteFile(m_acCrLfDotCrLf, 2 ) ) )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "WriteFile returns hr = 0x%x", hr );
|
|
return(hr);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DebugTrace( (LPARAM)this, "Setting m_WriteState = DROPDIR_WRITE_SETPOS" );
|
|
|
|
m_WriteState = DROPDIR_WRITE_SETPOS;
|
|
|
|
return( AdjustFilePos() );
|
|
}
|
|
|
|
|
|
return( hr );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::AdjustFilePos()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::AdjustFilePos");
|
|
HRESULT hr = S_OK;
|
|
|
|
DebugTrace( (LPARAM)this, "AdjustFilePos called" );
|
|
|
|
//If file ends with CRLF.CRLF, remove the trailing .CRLF
|
|
//Do not modify the file otherwise
|
|
|
|
DWORD dwLo = LODWORD( m_cbWriteOffset );
|
|
DWORD dwHi = HIDWORD( m_cbWriteOffset );
|
|
|
|
if ((m_cbMsgWritten > 4) && !memcmp(m_acLastBytes, m_acCrLfDotCrLf, 5))
|
|
{
|
|
DebugTrace( (LPARAM)this, "Removing the trailing CRLF-DOT-CRLF" );
|
|
|
|
// Remove the trailing .CRLF
|
|
if ((SetFilePointer(m_hDrop, dwLo-3, (LONG*)&dwHi, FILE_BEGIN) == 0xffffffff) ||
|
|
!SetEndOfFile(m_hDrop))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
ErrorTrace( (LPARAM)this, "SetFilePointer or SetEndofFile return hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
}
|
|
|
|
//We need to flush the context before ACK'ing the message
|
|
if (!FlushFileBuffers(m_hDrop))
|
|
{
|
|
hr = HRESULT_FROM_WIN32( GetLastError() );
|
|
if (SUCCEEDED(hr))
|
|
hr = E_FAIL;
|
|
ErrorTrace( (LPARAM)this, "FlushFileBuffers failed with hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
hr = SetAllRcptsHandled();
|
|
if( FAILED( hr ) )
|
|
{
|
|
ErrorTrace( (LPARAM)this, "SetAllRcptsHandledreturn hr = 0x%x", hr );
|
|
return( hr );
|
|
}
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL CDropDir::CheckIfAllRcptsHandled()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::CheckIfAllRcptsHandled");
|
|
BOOL fRet = TRUE;
|
|
|
|
for( DWORD i = 0; i < m_NumRcpts; i++ )
|
|
{
|
|
if ( m_rgRcptIndexList[i] != INVALID_RCPT_IDX_VALUE)
|
|
{
|
|
DWORD dwRecipientFlags = 0;
|
|
HRESULT hr = m_pIMsgRecips->GetDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
|
|
if (FAILED(hr))
|
|
{
|
|
fRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
|
|
{
|
|
fRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return( fRet );
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CDropDir::SetAllRcptsHandled()
|
|
{
|
|
DECL_TRACE((LPARAM) this, "CDropDir::SetAllRcptsHandled");
|
|
HRESULT hr = S_OK;
|
|
|
|
for( DWORD i = 0; i < m_NumRcpts; i++ )
|
|
{
|
|
if (m_rgRcptIndexList[i] != INVALID_RCPT_IDX_VALUE)
|
|
{
|
|
DWORD dwRecipientFlags = 0;
|
|
hr = m_pIMsgRecips->GetDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,&dwRecipientFlags);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( RP_HANDLED != ( dwRecipientFlags & RP_HANDLED ) )
|
|
{
|
|
dwRecipientFlags |= RP_DELIVERED;
|
|
|
|
|
|
hr = m_pIMsgRecips->PutDWORD(m_rgRcptIndexList[i], IMMPID_RP_RECIPIENT_FLAGS,dwRecipientFlags);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
return( hr );
|
|
}
|