You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1216 lines
36 KiB
1216 lines
36 KiB
/************************************************************************************************
|
|
|
|
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;
|
|
}
|
|
}
|