Windows2003-3790/inetsrv/pop3/shared/mailbox/mailbox.cpp
2020-09-30 16:53:55 +02:00

1217 lines
36 KiB
C++

/************************************************************************************************
Copyright (c) 2001 Microsoft Corporation
File Name: MailBox.cpp
Abstract: Implementation of the CMailBox class, abstraction of mailbox storage
Notes:
History: 08/01/2001 Created by Hao Yu (haoyu)
************************************************************************************************/
#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <atlbase.h>
#include "Mailbox.h"
#include "Ntioapi.hxx"
#include <POP3Regkeys.h>
long CMailBox::m_lMailRootGuard=1;
WCHAR CMailBox::m_wszMailRoot[POP3_MAX_MAILROOT_LENGTH]=L"";
CMailBox::CMailBox()
{
m_cMailCount=0;
m_dwShowMailCount=0;
m_dwTotalSize=0;
m_dwSizeOfMailVector=0;
m_MailVector=NULL;
m_hMailBoxLock=NULL;
m_bMailBoxOpened=FALSE;
ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
}
CMailBox::~CMailBox()
{
}
/////////////////////////////////////////////////////////////////////////////
// BuildFilePath, public
//
// Purpose:
// common routine for building file paths
//
// Arguments:
// LPSTR *ppFilePath : allocates buffer and returns the file path here, caller must free this buffer
// LPSTR psFileName : file name to create path for
//
// Returns: true on success, false otherwise. Buffer must be freed by caller on success
bool CMailBox::BuildFilePath( LPWSTR psFilePathBuffer, LPWSTR psFileName, DWORD dwSizeOfFilePathBuffer )
{
if ( NULL == psFilePathBuffer )
return false;
if ( NULL == psFileName )
return false;
if ( dwSizeOfFilePathBuffer > 1 + wcslen( m_wszMailBoxPath ) + wcslen( psFileName ) )
{
wcscpy( psFilePathBuffer, m_wszMailBoxPath );
wcscat( psFilePathBuffer, L"\\" );
wcscat( psFilePathBuffer, psFileName );
return true;
}
return false;
}
/////////////////////////////////////////////////////////////////////////////
// CreateMailBox, public
//
// Purpose:
// Create a mail box in our store
// This involves:
// create the mailbox directory
// create a lock file in the mailbox
//
// Arguments:
// char *szEmailAddr : mailbox to add
//
// Returns: TRUE on success, FALSE otherwise
bool CMailBox::CreateMailBox(WCHAR *wszEmailAddr)
{
bool bRC;
WCHAR wszLockFilePath[POP3_MAX_PATH];
bRC = SetMailBoxPath( wszEmailAddr );
if ( bRC )
bRC = (CreateDirectory( m_wszMailBoxPath, NULL ) ? true:false);
if ( bRC )
{
wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
if ( 0 > _snwprintf( wszLockFilePath, sizeof(wszLockFilePath)/sizeof(WCHAR) - 1, L"%s\\%s", m_wszMailBoxPath, LOCK_FILENAME_W ))
bRC = false;
if ( bRC )
{
m_hMailBoxLock = CreateFile( wszLockFilePath, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, NULL );
if ( INVALID_HANDLE_VALUE != m_hMailBoxLock )
{
CloseHandle(m_hMailBoxLock);
m_hMailBoxLock=NULL;
}
else
bRC = false;
}
if ( !bRC )
RemoveDirectory( m_wszMailBoxPath ); // Don't care about return
}
return bRC;
}
/////////////////////////////////////////////////////////////////////////////
// RepairMailBox, public
//
// Purpose:
// Repair a mail box in our store
// This involves:
// create a lock file in the mailbox if it does not exist
//
// Returns: TRUE on success, FALSE otherwise
BOOL CMailBox::RepairMailBox()
{
bool bRC = true;
WCHAR wszLockFilePath[POP3_MAX_PATH];
wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
if ( 0 > _snwprintf( wszLockFilePath, sizeof(wszLockFilePath)/sizeof(WCHAR)-1, L"%s\\%s", m_wszMailBoxPath, LOCK_FILENAME_W ))
bRC = false;
if ( bRC )
{
m_hMailBoxLock = CreateFile( wszLockFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL );
if ( INVALID_HANDLE_VALUE != m_hMailBoxLock )
{
CloseHandle(m_hMailBoxLock);
m_hMailBoxLock=NULL;
}
else
bRC = false;
}
return bRC;
}
BOOL CMailBox::OpenMailBox(WCHAR *wszEmailAddr)
{
if ( !SetMailBoxPath( wszEmailAddr ))
return FALSE;
if(ERROR_NO_FILE_ATTR == GetFileAttributes(m_wszMailBoxPath))
{ // Mailbox does not exist!
return FALSE;
}
m_bMailBoxOpened=TRUE;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// isMailboxInUse, public
//
// Purpose:
// Determine if someone is already logged on to the mailbox
// This involves:
// checking if the Lock file has been opened for WRITE access
//
// Returns: true if we determine it is in use, false otherwise
bool CMailBox::isMailboxInUse()
{
bool bRC = true;
if ( LockMailBox() )
{
UnlockMailBox();
bRC = false;
}
return bRC;
}
BOOL CMailBox::LockMailBox()
{
WCHAR wszLockFilePath[POP3_MAX_PATH];
assert(m_bMailBoxOpened);
assert(m_wszMailRoot[0]!=L'\0');
wszLockFilePath[sizeof(wszLockFilePath)/sizeof(WCHAR)-1] = 0;
if ( 0 > _snwprintf(wszLockFilePath,
sizeof(wszLockFilePath)/sizeof(WCHAR)-1,
L"%s\\%s",
m_wszMailBoxPath,
LOCK_FILENAME_W ))
return FALSE;
m_hMailBoxLock=CreateFile(wszLockFilePath,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_DELETE, // Only one writer (only one Locker via this method of locking)
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_HIDDEN,
NULL);
if(INVALID_HANDLE_VALUE == m_hMailBoxLock)
{
//Can not open mail box
return FALSE;
}
else
{
return TRUE;
}
}
/////////////////////////////////////////////////////////////////////////////
// UnlockMailBox, public
//
// Purpose:
// Unlock a mail box in our store
//
// Returns: TRUE on success, FALSE otherwise
void CMailBox::UnlockMailBox()
{
if(NULL != m_hMailBoxLock)
{
CloseHandle(m_hMailBoxLock);
m_hMailBoxLock=NULL;
}
}
BOOL CMailBox::EnumerateMailBox(DWORD dwMaxMsg)
{
PMAIL_ITEM pMail=NULL;
WCHAR wszMailFilter[POP3_MAX_PATH+6];
HANDLE hFind;
DWORD dwLastErr;
WIN32_FIND_DATA FileInfo;
assert(m_bMailBoxOpened);
assert(m_wszMailRoot[0]!=L'\0');
wsprintf(wszMailFilter,
L"%s\\*.eml",
m_wszMailBoxPath);
hFind=FindFirstFile(wszMailFilter,
&(FileInfo));
if(INVALID_HANDLE_VALUE == hFind)
{
dwLastErr= GetLastError();
if(ERROR_FILE_NOT_FOUND == dwLastErr ||
ERROR_SUCCESS == dwLastErr)
{
// No mail in the mail box
m_cMailCount=0;
return TRUE;
}
else
{
return FALSE;
}
}
BOOL bMoreFile=TRUE;
while(bMoreFile)
{
// To exclude hidden files
// which are mails being delivered
if( ! (FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) )
{
pMail = new (MAIL_ITEM);
if(NULL == pMail)
{
//Log mem err
return FALSE;
}
pMail->hFile=NULL;
pMail->dwStatus=NO_PENDING_OP;
pMail->bstrFileName=SysAllocString(FileInfo.cFileName);
if(NULL == pMail->bstrFileName )
{
FindClose(hFind);
delete pMail;
return FALSE;
}
pMail->dwFileSize=FileInfo.nFileSizeLow;
if(!PushMailToVector(pMail))
{
assert(NULL != pMail->bstrFileName);
SysFreeString(pMail->bstrFileName);
delete pMail;
return FALSE;
}
m_cMailCount++;
m_dwTotalSize+=FileInfo.nFileSizeLow;
}
if( (!dwMaxMsg) || (m_cMailCount != dwMaxMsg) )
{
bMoreFile=FindNextFile(hFind,&FileInfo);
}
else
{
bMoreFile=FALSE;
SetLastError(ERROR_NO_MORE_FILES);
}
}
m_dwShowMailCount=m_cMailCount;
dwLastErr= GetLastError();
FindClose(hFind);
if(ERROR_NO_MORE_FILES == dwLastErr)
{
return TRUE;
}
else
{
// Unexpected Error
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////
// GetMailboxFromStoreNameW, public
//
// Purpose:
// Convert the Store Name to the Mailbox name
//
// Arguments:
// LPWSTR psStoreName: The Store name for the mailbox, this string will be modified
//
// Returns: Mailbox name on success, NULL otherwise.
LPWSTR CMailBox::GetMailboxFromStoreNameW( LPWSTR psStoreName )
{
if ( NULL == psStoreName )
return NULL;
if ( wcslen( psStoreName ) <= (wcslen( MAILBOX_PREFIX_W ) + wcslen( MAILBOX_EXTENSION_W )) )
return NULL;
// Validate psStoreName
if ( 0 != _wcsnicmp( psStoreName, MAILBOX_PREFIX_W, wcslen( MAILBOX_PREFIX_W ) ))
return NULL;
if ( 0 != _wcsnicmp( psStoreName + wcslen( psStoreName ) - wcslen( MAILBOX_EXTENSION_W ), MAILBOX_EXTENSION_W, wcslen( MAILBOX_EXTENSION_W )))
return NULL;
psStoreName[wcslen( psStoreName ) - wcslen( MAILBOX_EXTENSION_W )] = 0;
return psStoreName + wcslen( MAILBOX_PREFIX_W );
}
bool CMailBox::GetMailFileName( int iIndex, LPWSTR psFilename, DWORD dwSize )
{
bool bRC = false;
if ( iIndex < 0 || iIndex >= m_cMailCount )
return false;
if ( DEL_PENDING == m_MailVector[iIndex]->dwStatus )
return false;
if ( 0 < _snwprintf( psFilename, dwSize, L"%s\\%s",
m_wszMailBoxPath , m_MailVector[iIndex]->bstrFileName ))
bRC = true;
return bRC;
}
bool CMailBox::GetEncyptedPassword( LPBYTE pbBuffer, const DWORD dwBufferSize, LPDWORD pdwBytesRead )
{
if ( NULL == pbBuffer )
return false;
if ( NULL == pdwBytesRead )
return false;
if ( NULL == m_hMailBoxLock )
return false;
if ( !ReadFile( m_hMailBoxLock, pbBuffer, dwBufferSize, pdwBytesRead, NULL ) || (dwBufferSize == *pdwBytesRead) )
return false;
return true;
}
bool CMailBox::SetEncyptedPassword( LPBYTE pbBuffer, DWORD dwBytesToWrite, LPDWORD pdwBytesWritten )
{
if ( NULL == pbBuffer )
return false;
if ( NULL == pdwBytesWritten )
return false;
if ( NULL == m_hMailBoxLock )
return false;
if ( !WriteFile( m_hMailBoxLock, pbBuffer, dwBytesToWrite, pdwBytesWritten, NULL ))
return false;
// In case the file is shorter
if ( !SetEndOfFile(m_hMailBoxLock) )
return false;
return true;
}
void CMailBox::Reset()
{
for(int i=0;i<m_cMailCount; i++)
{
if(m_MailVector[i]->dwStatus==DEL_PENDING)
{
m_MailVector[i]->dwStatus=NO_PENDING_OP;
m_dwTotalSize+=m_MailVector[i]->dwFileSize;
}
}
m_dwShowMailCount=m_cMailCount;
}
DWORD CMailBox::DeleteMail(int iIndex)
{
if(iIndex<0 || iIndex >= m_cMailCount)
{
return ERR_NO_SUCH_MSG;
}
if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
{
return ERR_MSG_ALREADY_DELETED;
}
else
{
( m_MailVector[iIndex] )->dwStatus=DEL_PENDING;
m_dwShowMailCount--;
m_dwTotalSize-=m_MailVector[iIndex]->dwFileSize;
return ERROR_SUCCESS;
}
}
DWORD CMailBox::TransmitMail(PIO_CONTEXT pIoContext, int iIndex,int iLines)
{
assert(NULL!=pIoContext);
WCHAR wszFileName[POP3_MAX_PATH];
char szRespBuf[MAX_PATH];
DWORD dwTotalBytesToSend=0;
TRANSMIT_FILE_BUFFERS TransmitBuf;
int iErr;
if( iIndex < 0 ||
iIndex >= m_cMailCount )
{
return ERR_NO_SUCH_MSG;
}
if( m_MailVector[iIndex]->dwStatus==DEL_PENDING)
{
return ERR_MSG_ALREADY_DELETED;
}
else
{
sprintf(szRespBuf,
"+OK %d octects\r\n",
m_MailVector[iIndex]->dwFileSize);
TransmitBuf.Head = szRespBuf;
TransmitBuf.HeadLength = strlen(szRespBuf);
TransmitBuf.Tail = RESP_END_OF_MULTILINE;
TransmitBuf.TailLength = strlen(RESP_END_OF_MULTILINE);
//Send the mail through the network
if(m_MailVector[iIndex]->hFile == NULL)
{
if(0>_snwprintf(wszFileName,
sizeof(wszFileName)/sizeof(WCHAR)-1,
L"%s\\%s",
m_wszMailBoxPath,
m_MailVector[iIndex]->bstrFileName))
{
return E_UNEXPECTED;
}
wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
m_MailVector[iIndex]->hFile=
CreateFile( wszFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if(INVALID_HANDLE_VALUE == m_MailVector[iIndex]->hFile )
{
//Error
m_MailVector[iIndex]->hFile=NULL;
return GetLastError();
}
}
else
{
if( INVALID_SET_FILE_POINTER ==
SetFilePointer(m_MailVector[iIndex]->hFile,
0,NULL, FILE_BEGIN))
{
//Error
return GetLastError();
}
}
if(iLines>=0)
{
//For TOP command, calculate bytes to send
if(!ReadTopLines(iLines, m_MailVector[iIndex]->hFile, &dwTotalBytesToSend))
{
return GetLastError();
}
if( INVALID_SET_FILE_POINTER ==
SetFilePointer(m_MailVector[iIndex]->hFile,
0,NULL, FILE_BEGIN))
{
//Error
return GetLastError();
}
}
if(!TransmitFile(pIoContext->m_hAsyncIO,
m_MailVector[iIndex]->hFile,
dwTotalBytesToSend,
0,
&(pIoContext->m_Overlapped),
&TransmitBuf,
TF_USE_KERNEL_APC ) )
{
int iErr = WSAGetLastError();
if(WSA_IO_PENDING!=iErr)
{
//Error
return iErr;
}
}
return ERROR_SUCCESS;
}
}
DWORD CMailBox::TransmitMail(SOCKET hSocket, int iIndex)
{
WCHAR wszFileName[POP3_MAX_PATH];
char szRespBuf[MAX_PATH];
DWORD dwTotalBytesToSend=0;
TRANSMIT_FILE_BUFFERS TransmitBuf;
int iErr;
if( iIndex < 0 ||
iIndex >= m_cMailCount )
{
return ERR_NO_SUCH_MSG;
}
if( m_MailVector[iIndex]->dwStatus==DEL_PENDING)
{
return ERR_MSG_ALREADY_DELETED;
}
else
{
sprintf(szRespBuf,
"+OK %d octects\r\n",
m_MailVector[iIndex]->dwFileSize);
TransmitBuf.Head = szRespBuf;
TransmitBuf.HeadLength = strlen(szRespBuf);
TransmitBuf.Tail = RESP_END_OF_MULTILINE;
TransmitBuf.TailLength = strlen(RESP_END_OF_MULTILINE);
//Send the mail through the network
if(m_MailVector[iIndex]->hFile == NULL)
{
if(0>_snwprintf(wszFileName,
sizeof(wszFileName)/sizeof(WCHAR)-1,
L"%s\\%s\0",
m_wszMailBoxPath,
m_MailVector[iIndex]->bstrFileName))
{
return E_UNEXPECTED;
}
wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
m_MailVector[iIndex]->hFile=
CreateFile( wszFileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED |
FILE_FLAG_NO_BUFFERING ,
NULL);
if(INVALID_HANDLE_VALUE == m_MailVector[iIndex]->hFile )
{
//Error
m_MailVector[iIndex]->hFile=NULL;
return GetLastError();
}
}
else
{
if( INVALID_SET_FILE_POINTER ==
SetFilePointer(m_MailVector[iIndex]->hFile,
0,NULL, FILE_BEGIN))
{
//Error
return GetLastError();
}
}
if(!TransmitFile( hSocket,
m_MailVector[iIndex]->hFile,
dwTotalBytesToSend,
0,
NULL,
&TransmitBuf,
TF_USE_KERNEL_APC ) )
{
int iErr = WSAGetLastError();
if(WSA_IO_PENDING!=iErr)
{
//Error
return iErr;
}
}
return ERROR_SUCCESS;
}
}
BOOL CMailBox::CommitAndClose()
{
BOOL bRetVal=TRUE;
WCHAR wszFileName[POP3_MAX_PATH];
for(int i=0; i<m_cMailCount; i++)
{
if(NULL != m_MailVector[i])
{
if(NULL != m_MailVector[i]->hFile)
{
CloseHandle( m_MailVector[i]->hFile );
}
if( m_MailVector[i]->dwStatus == DEL_PENDING )
{
wszFileName[sizeof(wszFileName)/sizeof(WCHAR)-1]=0;
if(0> _snwprintf ( wszFileName,
sizeof(wszFileName)/sizeof(WCHAR)-1,
L"%s\\%s\0",
m_wszMailBoxPath,
m_MailVector[i]->bstrFileName))
{
bRetVal=FALSE;
}
else if(FALSE==DeleteFile( wszFileName ) )
{
//Error log
bRetVal=FALSE;
}
}
if(NULL != m_MailVector[i]->bstrFileName)
{
SysFreeString(m_MailVector[i]->bstrFileName);
}
delete (m_MailVector[i]);
m_MailVector[i]=NULL;
}
}
delete[] m_MailVector;
m_MailVector=NULL;
m_dwSizeOfMailVector=0;
if(NULL != m_hMailBoxLock)
{
CloseHandle(m_hMailBoxLock);
m_hMailBoxLock=NULL;
}
m_cMailCount=0;
m_dwShowMailCount=0;
m_dwTotalSize=0;
ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
return bRetVal;
}
void CMailBox::CloseMailBox()
{
m_bMailBoxOpened=FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CreateMail, public
//
// Purpose:
// Create a new empty mail file and return the handle. The returned file handle
// should be closed using CloseMail, unless special options are being used as documented
// in the CloseMail function below.
//
// Arguments:
// LPSTR *szTargetFileName: File name (just the file name path will be prepended)
// DWORD dwFlagsAndAttributes: [in] Specifies the file attributes and flags for the CreateFile api.
//
// Returns: file handle on success, INVALID_HANDLE_VALUE otherwise
HANDLE CMailBox::CreateMail( LPWSTR wszTargetFileName, DWORD dwFlagsAndAttributes /*= 0*/ )
{
if ( NULL == wszTargetFileName )
return INVALID_HANDLE_VALUE;
assert(TRUE == m_bMailBoxOpened);
HANDLE hNewMail = INVALID_HANDLE_VALUE;
HANDLE hf;
DWORD dwBytes, dwSize;
WCHAR wszFileNameBuffer[POP3_MAX_PATH];
LPBYTE pSIDOwner = NULL;
PSECURITY_ATTRIBUTES psa = NULL;
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
// Set the Security Attributes to set the owner to the quota owner
if ( BuildFilePath( wszFileNameBuffer, QUOTA_FILENAME, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
{
hf = CreateFile( wszFileNameBuffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_HIDDEN, NULL );
if ( INVALID_HANDLE_VALUE != hf )
{
dwSize = GetFileSize( hf, NULL );
if ( INVALID_FILE_SIZE != dwSize )
{
pSIDOwner = new BYTE[dwSize];
if ( NULL != pSIDOwner )
{
SetLastError( ERROR_SUCCESS );
ReadFile( hf, pSIDOwner, dwSize, &dwBytes, NULL ); // No need to check return code here, the GetLastError check below covers it!
} // |
else // |
SetLastError( ERROR_OUTOFMEMORY ); // |
} // |
CloseHandle( hf ); // |
if ( ERROR_SUCCESS == GetLastError() ) // <--------------------+
{
if ( InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ))
{ // Set the ownership for a new file
if ( SetSecurityDescriptorOwner( &sd, pSIDOwner, FALSE ))
{
sa.nLength = sizeof( sa );
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
psa = &sa;
}
}
}
}
}
if ( BuildFilePath( wszFileNameBuffer, wszTargetFileName, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
hNewMail = CreateFile( wszFileNameBuffer, GENERIC_ALL, 0, psa, CREATE_NEW, dwFlagsAndAttributes|FILE_ATTRIBUTE_HIDDEN, NULL );
if ( NULL != pSIDOwner )
delete [] pSIDOwner;
return hNewMail;
}
/////////////////////////////////////////////////////////////////////////////
// CloseMail, public
//
// Purpose:
// Close the mail file created using CreateMail.
//
// Arguments:
// LPSTR *szTargetFileName: File name (just the file name path will be prepended)
// DWORD dwFlagsAndAttributes: If the FILE_FLAG_OVERLAPPED bit is set the file handle will not be closed.
// In this case it is the responsibility of the calling process to ReleaseContext( PFIO_CONTEXT* )
// which also closes the file handle.
//
// Returns: ERROR_SUCCESS on success, the applicable error otherwise.
DWORD CMailBox::CloseMail(HANDLE hMailFile,DWORD dwFlagsAndAttributes /*= 0*/)
{
assert( !(INVALID_HANDLE_VALUE == hMailFile));
if (INVALID_HANDLE_VALUE == hMailFile)
{
return ERROR_INVALID_HANDLE;
}
DWORD dwRC;
IO_STATUS_BLOCK IoStatusBlock;
dwRC = NtFlushBuffersFile( hMailFile, &IoStatusBlock );
if ( ERROR_SUCCESS == dwRC )
{ // Remove the FILE_ATTRIBUTE_HIDDEN
FILE_BASIC_INFORMATION BasicInfo;
ZeroMemory( &BasicInfo, sizeof(BasicInfo) );
BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
dwRC = NtSetInformationFile( hMailFile, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation );
}
// Now close the handle, if appropriate
if (!(FILE_FLAG_OVERLAPPED & dwFlagsAndAttributes))
{
if( !CloseHandle(hMailFile) )
dwRC = GetLastError();
}
return dwRC;
}
/////////////////////////////////////////////////////////////////////////////
// DeleteMail, public
//
// Purpose:
// Delete a mail file. This method is really meant for deleting files that were
// created but not successfully delivered.
//
// Arguments:
// LPSTR *szTargetFileName: File name (just the file name path will be prepended)
//
// Returns: true on success, false otherwise
bool CMailBox::DeleteMail( LPWSTR wszTargetFileName )
{
if ( NULL == wszTargetFileName )
return false;
if ( 0 == wcslen( wszTargetFileName ))
return false;
if ( !m_bMailBoxOpened )
return false;
bool bRC = false;
WCHAR wszFileNameBuffer[POP3_MAX_PATH];
if ( BuildFilePath( wszFileNameBuffer, wszTargetFileName, sizeof(wszFileNameBuffer)/sizeof(WCHAR) ))
{
bRC = DeleteFile( wszFileNameBuffer ) ? true : false;
}
return bRC;
}
void CMailBox::QuitAndClose()
{
for(int i=0; i<m_cMailCount; i++ )
{
if(NULL != m_MailVector[i])
{
if(NULL != m_MailVector[i]->hFile)
{
CloseHandle( m_MailVector[i]->hFile );
m_MailVector[i]->hFile=NULL;
}
if(NULL != m_MailVector[i]->bstrFileName )
{
SysFreeString(m_MailVector[i]->bstrFileName);
}
delete (m_MailVector[i]);
m_MailVector[i]=NULL;
}
}
if(NULL != m_hMailBoxLock)
{
CloseHandle(m_hMailBoxLock);
m_hMailBoxLock=NULL;
}
delete[] m_MailVector;
m_MailVector=NULL;
m_dwSizeOfMailVector=0;
m_cMailCount=0;
m_dwShowMailCount=0;
m_dwTotalSize=0;
ZeroMemory(m_wszMailBoxPath, sizeof(m_wszMailBoxPath));
}
DWORD CMailBox::ListMail(int iIndex, char *szBuf, DWORD dwSize)
{
assert(NULL!=szBuf);
if( iIndex<0 ||
iIndex >= m_cMailCount)
{
return ERR_NO_SUCH_MSG;
}
if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
{
return ERR_MSG_ALREADY_DELETED;
}
else
{
if(0> _snprintf(szBuf,
dwSize-1,
"%d %d\r\n",
iIndex+1,
m_MailVector[iIndex]->dwFileSize))
{
return ERROR_INVALID_DATA;
}
szBuf[dwSize-1]=0;
return ERROR_SUCCESS;
}
}
DWORD CMailBox::UidlMail(int iIndex, char *szBuf, DWORD dwSize)
{
assert(NULL!=szBuf);
if( iIndex<0 ||
iIndex >= m_cMailCount)
{
return ERR_NO_SUCH_MSG;
}
if(m_MailVector[iIndex]->dwStatus==DEL_PENDING)
{
return ERR_MSG_ALREADY_DELETED;
}
else
{
if( 0>_snprintf(szBuf,
dwSize-1,
"%d %S",
iIndex+1,
(m_MailVector[iIndex]->bstrFileName)+3))
{
return ERROR_INVALID_DATA;
}
szBuf[dwSize-1]=0;
//To cut the .eml file extention
int iFileExt=strlen(szBuf)-4;
szBuf[iFileExt++]='\r';
szBuf[iFileExt++]='\n';
szBuf[iFileExt]='\0';
return ERROR_SUCCESS;
}
}
BOOL CMailBox::SetMailRoot(const WCHAR *wszMailRoot)
{
BOOL bRtVal=FALSE;
if(1==InterlockedExchange(&m_lMailRootGuard, 0))
{
WCHAR sMailRoot[POP3_MAX_PATH];
if ( wszMailRoot )
{
if ( sizeof(sMailRoot)/sizeof(WCHAR) > wcslen( wszMailRoot ))
{
wcscpy( sMailRoot, wszMailRoot );
bRtVal=TRUE;
}
}
else
{ // Read the mailroot from the registry
if ( ERROR_SUCCESS == RegQueryMailRoot( sMailRoot, sizeof( sMailRoot )/sizeof(WCHAR) ) )
{
bRtVal=TRUE;
}
}
if ( bRtVal )
{
if ( 0 == wcsncmp( sMailRoot, L"\\\\", 2 ))
{
if ( sizeof( m_wszMailRoot )/sizeof(WCHAR) > wcslen( sMailRoot ) + 7 )
{
wcscpy( m_wszMailRoot, L"\\\\?\\UNC" );
wcscat( m_wszMailRoot, &( sMailRoot[1] ));
}
else
bRtVal = FALSE;
}
else
{
if ( sizeof( m_wszMailRoot )/sizeof(WCHAR) > wcslen( sMailRoot ) + 5 )
{
wcscpy( m_wszMailRoot, L"\\\\?\\" );
wcscat( m_wszMailRoot, sMailRoot );
}
else
bRtVal = FALSE;
}
}
InterlockedExchange(&m_lMailRootGuard, 1);
}
else
{
//Some other thread is doing the job
while(0==m_lMailRootGuard)
{
Sleep(100);
}
if(L'\0'!=m_wszMailRoot[0])
{
bRtVal=TRUE;
}
}
return bRtVal;
}
///////////////////////////////////////////////////////////////
// Implementation: private
///////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// SetMailBoxPath, private
//
// Purpose:
// Build the Mailbox Path, validate the EmailAddr.
//
// Arguments:
// char *szEmailAddr : mailbox to build path for
//
// Returns: true on success, false otherwise
bool CMailBox::SetMailBoxPath(WCHAR *wszEmailAddr)
{
WCHAR *wszDomain=NULL;
WCHAR *wszAccount=NULL;
WCHAR wszNotAllowedSet[]=L"\\/:*?\",>|";
WCHAR wszMailBox[POP3_MAX_ADDRESS_LENGTH];
WCHAR wszMailDomain[POP3_MAX_DOMAIN_LENGTH];
int iLen;
while(iswspace(*wszEmailAddr))
{
wszEmailAddr++;
}
wszDomain=wcschr(wszEmailAddr, '@');
if(wszDomain==NULL)
{ //Error
return false;
}
iLen=wcslen(wszDomain);
if( 1 == iLen || iLen>=POP3_MAX_DOMAIN_LENGTH ) // Is there anything after the @?
{ //Error
return false;
}
wcscpy(wszMailDomain, wszDomain+1);
wszMailDomain[iLen]='\0';
iLen=(int)(wszDomain-wszEmailAddr);
wcsncpy(wszMailBox, wszEmailAddr,iLen);
wszMailBox[iLen]='\0';
if(L'\0'==m_wszMailRoot[0])
{
if(!SetMailRoot())
{
return false;
}
}
//Check if the mail domain and account is valid
if( (NULL != wcspbrk(wszMailDomain, wszNotAllowedSet))
|| (NULL != wcspbrk(wszMailBox, wszNotAllowedSet))
|| (sizeof(m_wszMailBoxPath)/sizeof(WCHAR) <= wcslen(m_wszMailRoot) +
wcslen(wszMailDomain) +
wcslen(wszMailBox) +
wcslen(MAILBOX_PREFIX_W) +
wcslen(MAILBOX_EXTENSION_W) + 3 /*2 \\ and \0 */ ) )
{
return false;
}
//build the path to the mail dir
m_bMailBoxOpened = FALSE;
m_wszMailBoxPath[sizeof(m_wszMailBoxPath)/sizeof(WCHAR)-1] = 0;
if ( 0 > _snwprintf(m_wszMailBoxPath,
sizeof(m_wszMailBoxPath)/sizeof(WCHAR) - 1,
L"%s\\%s\\%s%s%s",
m_wszMailRoot,
wszMailDomain,
MAILBOX_PREFIX_W,
wszMailBox,
MAILBOX_EXTENSION_W ))
return false;
return true;
}
bool CMailBox::ReadTopLines(int iLines, HANDLE hFile, DWORD *pdwBytesToRead)
{
assert(INVALID_HANDLE_VALUE!=hFile);
assert(NULL != pdwBytesToRead);
assert(NULL != hFile);
assert(iLines>=0);
BOOL bHeadersDone=FALSE;
(*pdwBytesToRead)=0;
BOOL bMoreToRead=TRUE;
char szBuffer[LOCAL_FILE_BUFFER_SIZE+1];
char *pLastNewLine=NULL;
char chLastChr[3];
DWORD dwBytesRead;
DWORD dwIndex=0;
char szEmpLine[5];
chLastChr[0]='\0';
chLastChr[1]='\0';
chLastChr[2]='\0';
szEmpLine[4]='\0';
while(bMoreToRead)
{
if( !ReadFile(hFile,
szBuffer,
LOCAL_FILE_BUFFER_SIZE,
&dwBytesRead,
NULL) )
{
return FALSE;
}
szBuffer[dwBytesRead]='\0';
if(dwBytesRead < LOCAL_FILE_BUFFER_SIZE)
{
bMoreToRead=FALSE;
}
for( dwIndex=0;dwIndex<dwBytesRead && (!bHeadersDone || iLines >0); dwIndex++)
{
if('\n'==szBuffer[dwIndex])
{
if(bHeadersDone)
{
//The headers are done
//Count the lines now
if(dwIndex>0)
{
if('\r'==szBuffer[dwIndex-1])
{
iLines--;
}
}
else
{
if('\r'==chLastChr[2])
{
iLines--;
chLastChr[2]='\0';
}
}
}
else
{
int i=4;
do
{
i--;
szEmpLine[i]=szBuffer[dwIndex+i-3];
}while((dwIndex+i-3>0) && i>0 );
if(i>0)
{
i--;
for(int j=2; i>=0 && j>=0; j--,i--)
{
szEmpLine[i]=chLastChr[j];
}
}
if(0==strcmp(szEmpLine, "\r\n\r\n"))
{
bHeadersDone=TRUE;
}
}
}
}
if(iLines==0)
{
(*pdwBytesToRead)+=dwIndex;
bMoreToRead=FALSE;
}
else
{
(*pdwBytesToRead)+=dwBytesRead;
chLastChr[2]=szBuffer[dwIndex-1];
if(!bHeadersDone)
{
chLastChr[1]=szBuffer[dwIndex-2];
chLastChr[0]=szBuffer[dwIndex-3];
}
}
}
if(iLines>0)
{
(*pdwBytesToRead)=0;
}
return TRUE;
}
bool CMailBox::PushMailToVector(PMAIL_ITEM pMail)
{
PMAIL_ITEM *pTemp;
DWORD dwNewMailVectorSize=0;
if(pMail==NULL)
{
return false;
}
if(m_cMailCount>=m_dwSizeOfMailVector)
{
if(m_MailVector)
{
dwNewMailVectorSize=m_dwSizeOfMailVector*2;
pTemp=new PMAIL_ITEM[dwNewMailVectorSize];
if(pTemp)
{
memset(pTemp, 0, dwNewMailVectorSize*sizeof(PMAIL_ITEM));
memcpy(pTemp, m_MailVector, m_dwSizeOfMailVector*sizeof(PMAIL_ITEM));
delete[] m_MailVector;
m_MailVector=pTemp;
m_dwSizeOfMailVector=dwNewMailVectorSize;
m_MailVector[m_cMailCount]=pMail;
}
else
{
return false;
}
}
else
{
m_MailVector=new PMAIL_ITEM[DEFAULT_MAIL_VECTOR_SIZE];
if(m_MailVector)
{
memset(m_MailVector, 0, DEFAULT_MAIL_VECTOR_SIZE*sizeof(PMAIL_ITEM));
m_MailVector[m_cMailCount]=pMail;
m_dwSizeOfMailVector=DEFAULT_MAIL_VECTOR_SIZE;
}
else
{
return false;
}
}
return true;
}
else
{
m_MailVector[m_cMailCount]=pMail;
return true;
}
}