Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1081 lines
38 KiB

// P2EWorker.cpp: implementation of the CP2EWorker class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "P2EWorker.h"
#include "resource.h"
#include "resource2.h"
#include <sbs6base.h>
#include <P3Admin.h>
#include <pop3server.h>
#include <logutil.h>
#include <mailbox.h>
#include "UserInfo.h"
#include <AuthID.h>
#include <FormatMessage.h>
#include <atlbase.h>
#include <comdef.h>
#include <dsgetdc.h>
#include <lm.h>
#include <tchar.h>
#include <stdio.h>
#include <ws2tcpip.h>
//#include <mswsock.h>
#include <AuthUtil.h>
#ifndef ASSERT
#define ASSERT assert
#endif
LOGFILE(L"Pop2ExchLog.txt");
#define SMTP_BUFFERSIZE 2048
#define SMTP_QUIT "QUIT\r\n"
#define SMTP_DATA "DATA\r\n"
#define SMTP_DATA_END "\r\n.\r\n"
#define SMTP_RSET "RSET\r\n"
#define SMTP_MSG220 "220" // 220 <domain> Service ready
#define SMTP_MSG221 "221" // 221 <domain> Service ready
#define SMTP_MSG250 "250" // 250 Requested mail action okay, completed
#define SMTP_MSG354 "354" // 354 Start mail input; end with <CRLF>.<CRLF>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CP2EWorker::CP2EWorker() :
m_bSuppressPrintError( false )
{
}
CP2EWorker::~CP2EWorker()
{
}
//////////////////////////////////////////////////////////////////////
// Implementation : public
//////////////////////////////////////////////////////////////////////
int CP2EWorker::CreateUser(int argc, wchar_t *argv[], const bool bCreateUser, const bool bCreateMailbox)
{
USES_CONVERSION;
HRESULT hr;
VARIANT v;
BSTR bstrName, bstrEmailName;
_bstr_t _bstrDomainName;
CComPtr<IP3Config> spIConfig;
CComPtr<IP3Domains> spIDomains;
IP3Domain *pIDomain = NULL;
CComPtr<IEnumVARIANT> spIEnumVARIANT;
bool bErrors = false, bIgnoreErrors = false, bUnregisterDependencies = false;
char sPassword[MAX_PATH];
CUserInfo userInfoX;
if ( 4 != argc && 3 != argc )
return -1;
if ( 2 < argc ) // Since domain name is now required this is no longer a valid option
{ // But I'm going to leave the code in case we ever reverse this decision
if ( 0 == wcscmp( L"/i", argv[2] ) || ( 0 == wcscmp( L"-i", argv[2] )))
bIgnoreErrors = true;
else
_bstrDomainName = argv[2];
}
if ( 4 == argc )
{
if ( bIgnoreErrors )
_bstrDomainName = argv[3];
else if ( 0 == wcscmp( L"/i", argv[3] ) || ( 0 == wcscmp( L"-i", argv[3] )))
bIgnoreErrors = true;
else
return -1;
}
if ( 0 == _bstrDomainName.length() )
return -1;
{ // Log the command
LPWSTR ps2 = argv[2], ps3 = argv[3];
if ( NULL == ps2 )
{
ps2 = L"";
ps3 = NULL;
}
if ( NULL == ps3 )
{
ps3 = L"";
}
LOG( L"%s %s %s %s", argv[0], argv[1], ps2, ps3 );
}
VariantInit( &v );
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
if ( REGDB_E_CLASSNOTREG == hr )
{
hr = RegisterDependencies();
if ( S_OK == hr )
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
bUnregisterDependencies = true;
}
if ( S_OK == hr )
{
if ( bCreateUser ) // Only valid for the MD5 Authentication method
{
CComPtr<IAuthMethods> spIAuthMethods;
CComPtr<IAuthMethod> spIAuthMethod;
BSTR bstrID;
_variant_t _v;
long lValue;
WCHAR sBuffer[MAX_PATH];
hr = spIConfig->get_Authentication( &spIAuthMethods );
if ( REGDB_E_CLASSNOTREG == hr )
{
PrintMessage( IDS_ERROR_POP3REQUIRED );
m_bSuppressPrintError = true;
}
if ( S_OK == hr )
hr = spIAuthMethods->get_CurrentAuthMethod( &_v );
if ( S_OK == hr )
hr = spIAuthMethods->get_Item( _v, &spIAuthMethod );
if ( S_OK == hr )
hr = spIAuthMethod->get_ID( &bstrID );
if ( S_OK == hr )
{
if ( 0 != _wcsicmp( bstrID, SZ_AUTH_ID_MD5_HASH ))
hr = HRESULT_FROM_WIN32( ERROR_DS_INAPPROPRIATE_AUTH );
SysFreeString( bstrID );
}
}
}
if ( S_OK == hr )
hr = spIConfig->get_Domains( &spIDomains );
if ( S_OK == hr )
{
CComPtr<IP3Users> spIUsers;
CComPtr<IP3User> spIUser;
if ( 0 == _bstrDomainName.length() )
{ // For each domain
hr = spIDomains->get__NewEnum( &spIEnumVARIANT );
if ( S_OK == hr )
{
hr = spIEnumVARIANT->Next( 1, &v, NULL );
}
}
else
{ // Just for this domain
_variant_t _v( _bstrDomainName );
hr = spIDomains->get_Item( _v, &pIDomain );
}
while ( S_OK == hr )
{
if ( NULL != spIEnumVARIANT.p )
{
if ( VT_DISPATCH != V_VT( &v ))
hr = E_UNEXPECTED;
if ( S_OK == hr )
hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast<void**>( &pIDomain ));
VariantClear( &v );
}
if ( S_OK == hr )
hr = pIDomain->get_Name( &bstrName );
if ( S_OK == hr )
{
LOG( L"Domain: %s ", bstrName );
SysFreeString( bstrName );
}
// Enumerate the users
if ( S_OK == hr )
{
hr = pIDomain->get_Users( &spIUsers );
if ( S_OK == hr )
{ // List users
CComPtr<IEnumVARIANT> spIEnumVARIANT2;
hr = spIUsers->get__NewEnum( &spIEnumVARIANT2 );
if ( S_OK == hr )
hr = spIEnumVARIANT2->Next( 1, &v, NULL );
while ( S_OK == hr )
{
if ( VT_DISPATCH != V_VT( &v ))
hr = E_UNEXPECTED;
if ( S_OK == hr )
hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3User ), reinterpret_cast<void**>( &spIUser ));
VariantClear( &v );
hr = spIUser->get_Name( &bstrName );
if ( S_OK == hr )
{
if ( S_OK == hr )
hr = userInfoX.SetUserName( bstrName );
if ( S_OK == hr )
{
hr = spIUser->get_EmailName( &bstrEmailName );
if ( S_OK == hr )
{
hr = GetMD5Password( bstrEmailName, sPassword );
if ( S_OK == hr )
hr = userInfoX.SetPassword( A2W( sPassword ));
}
}
if ( S_OK == hr )
{
if ( bCreateUser )
{ // Create the user
hr = userInfoX.CreateAccount();
if ( S_OK == hr )
LOG( L"Create user: %s succeeded.", bstrName );
else
{
LOG( L"ERROR!: Create user %s failed. %s", bstrName, CFormatMessage(hr).c_str() );
if ( bIgnoreErrors )
{
hr = S_OK;
bErrors = true;
}
}
}
if ( bCreateMailbox )
{ // Create the mailbox
hr = userInfoX.CreateMailbox();
if ( S_OK == hr )
LOG( L"Create mailbox: %s succeeded.", bstrName );
else
{
LOG( L"ERROR!: Create mailbox %s failed. %s", bstrName, CFormatMessage(hr).c_str() );
if ( bIgnoreErrors )
{
hr = S_OK;
bErrors = true;
}
}
}
}
SysFreeString( bstrName );
}
if ( S_OK == hr )
hr = spIEnumVARIANT2->Next( 1, &v, NULL );
}
if ( S_FALSE == hr )
hr = S_OK; // Reached end of user enumeration
}
}
if ( S_OK == hr )
{
if ( NULL != spIEnumVARIANT.p )
{
hr = spIEnumVARIANT->Next( 1, &v, NULL );
if ( S_OK == hr )
pIDomain->Release();
}
else
hr = S_FALSE; // Were done.
}
}
if ( S_FALSE == hr )
hr = S_OK; // Reached end of domain enumeration
}
if ( NULL != pIDomain )
pIDomain->Release();
if ( bCreateUser )
{
if ( S_OK == hr )
{
PrintMessage( IDS_SUCCESS_CREATEUSER );
if ( bErrors )
PrintMessage( IDS_WARNING_ERRORSIGNORED );
}
else
PrintMessage( IDS_ERROR_CREATEUSER_FAILED );
}
if ( bCreateMailbox )
{
if ( S_OK == hr )
{
PrintMessage( IDS_SUCCESS_CREATEMAILBOX );
if ( bErrors )
PrintMessage( IDS_WARNING_ERRORSIGNORED );
}
else
PrintMessage( IDS_ERROR_CREATEMAILBOX_FAILED );
}
if ( bUnregisterDependencies )
UnRegisterDependencies();
return hr;
}
#define LOCALHOST L"localhost"
int CP2EWorker::Mail(int argc, wchar_t *argv[], bool bDelete /*= FALSE*/ )
{
USES_CONVERSION;
HRESULT hr = S_OK;
VARIANT v;
DWORD dwCount, dwIndex;
BSTR bstrName, bstrEmailName;
WSTRING sEmailDomain;
ASTRING sASCFROM;
_bstr_t _bstrDomainName;
CComPtr<IP3Config> spIConfig;
CComPtr<IP3Domains> spIDomains;
IP3Domain *pIDomain = NULL;
CComPtr<IEnumVARIANT> spIEnumVARIANT;
bool bErrors = false, bIgnoreErrors = false, bLocked = false, bUnregisterDependencies = false;
CMailBox mailboxX;
WCHAR sFilename[MAX_PATH];
ASTRING sASCComputerName;
WSTRING sComputerName;
DWORD dwFileNameSize = MAX_PATH;
LPWSTR psArgv;
LPSTR pszComputerName;
if ( 5 < argc || 3 > argc )
return -1;
for ( int i = 2; i < argc; i++ )
{
psArgv = argv[i];
if ( 0 == wcscmp( L"/i", psArgv ) || ( 0 == wcscmp( L"-i", psArgv )))
{
if ( bIgnoreErrors )
return -1;
bIgnoreErrors = true;
}
else if ( 0 == _wcsnicmp( L"/S:", psArgv, 3 ) || 0 == _wcsnicmp( L"-S:", psArgv, 3 ))
{
if ( 3 < wcslen( psArgv ))
{
if ( sComputerName.empty() )
sComputerName = psArgv + 3;
else
return -1;
}
else
return -1;
}
else
{
if ( 0 == _bstrDomainName.length() )
_bstrDomainName = psArgv;
else
return -1;
}
}
if ( 0 == _bstrDomainName.length() )
return -1;
if ( sComputerName.empty() )
sComputerName = LOCALHOST;
sASCComputerName = W2A(sComputerName.c_str());
{
LPWSTR ps2 = argv[2], ps3 = argv[3], ps4 = argv[4];
if ( NULL == ps2 )
{
ps2 = L"";
ps3 = L"";
ps4 = L"";
}
if ( NULL == ps3 )
{
ps3 = L"";
ps4 = L"";
}
if ( NULL == ps4 )
ps4 = L"";
LOG( L"%s %s %s %s %s", argv[0], argv[1], ps2, ps3, ps4 );
}
VariantInit( &v );
// Socket Initialization
WSADATA wsaData;
SOCKET socket = INVALID_SOCKET;
int iErr, iSize;
LPSTR psSendBuffer = new CHAR[SMTP_BUFFERSIZE];
if ( NULL == psSendBuffer )
return E_OUTOFMEMORY;
iErr = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
if( 0 != iErr )
{
wsaData.wVersion = 0;
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: WSAStartup. %s", CFormatMessage(iErr).c_str() );
}
else
{ // Confirm that the WinSock DLL supports 2.2.
// Note that if the DLL supports versions greater than 2.2 in addition to 2.2, it will still return
// 2.2 in wVersion since that is the version we requested.
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{ /* Tell the user that we could not find a usable WinSock DLL. */
LOG( L"ERROR!: WSAStartup. Unexpected version returned" );
hr = E_UNEXPECTED;
}
}
// Connect to port 25
if ( S_OK == hr )
{
socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0 );
if( INVALID_SOCKET == socket )
{
iErr = WSAGetLastError();
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: WSASocket. %s", CFormatMessage(iErr).c_str() );
}
else
{
addrinfo stHints;
addrinfo *pstAIHead = NULL, *pstAINext;
sockaddr_in stSAInServer;
ZeroMemory( &stSAInServer, sizeof( stSAInServer ));
ZeroMemory( &stHints, sizeof( stHints ));
stHints.ai_family = PF_INET;
stHints.ai_flags = AI_CANONNAME;
iErr = getaddrinfo( sASCComputerName.c_str(), "SMTP", &stHints, &pstAIHead );
if( 0 != iErr )
{
iErr = WSAGetLastError();
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: getaddrinfo. %s", CFormatMessage(iErr).c_str() );
}
else
{
memcpy( &stSAInServer, pstAIHead->ai_addr, sizeof( stSAInServer ));
pstAINext = pstAIHead;
while ( NULL != pstAINext )
{
pstAINext = pstAIHead->ai_next;
freeaddrinfo( pstAIHead );
pstAIHead = pstAINext;
}
iErr = connect( socket, reinterpret_cast<sockaddr*>( &stSAInServer ), sizeof( stSAInServer ));
if( 0 != iErr )
{
iErr = WSAGetLastError();
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: connect. %s", CFormatMessage(iErr).c_str() );
}
hr = RecvResp( socket, SMTP_MSG220 );
}
}
}
// Get the domain name we are sending to
if ( S_OK == hr )
{ // Get domain controller name
PDOMAIN_CONTROLLER_INFO pstDomainControllerInfo = NULL;
LPCWSTR psComputerName = ( sComputerName == LOCALHOST ) ? NULL:sComputerName.c_str();
DWORD dwRC = DsGetDcName( psComputerName, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &pstDomainControllerInfo );
if ( NO_ERROR != dwRC )
{
hr = HRESULT_FROM_WIN32( dwRC );
LOG( L"ERROR!: DsGetDcName. %s", CFormatMessage(dwRC).c_str() );
}
ASSERT(hr == S_OK && "DsGetDcName failed");
// cache the domain
if ( pstDomainControllerInfo )
{
sEmailDomain = pstDomainControllerInfo->DomainName;
// free memory
NetApiBufferFree( pstDomainControllerInfo );
}
}
// SMTP:HELO
if ( S_OK == hr )
{
iSize = _snprintf( psSendBuffer, 2048, "HELO %s\r\n", W2A( sEmailDomain.c_str() ));
if ( 0 < iSize )
hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
else
hr = E_UNEXPECTED;
}
// Process domains and mailboxes
if ( S_OK == hr )
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
if ( REGDB_E_CLASSNOTREG == hr )
{
hr = RegisterDependencies();
if ( S_OK == hr )
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
bUnregisterDependencies = true;
}
if ( S_OK == hr )
hr = spIConfig->get_Domains( &spIDomains );
if ( S_OK == hr )
{
CComPtr<IP3Users> spIUsers;
CComPtr<IP3User> spIUser;
if ( 0 == _bstrDomainName.length() )
{ // For each domain
hr = spIDomains->get__NewEnum( &spIEnumVARIANT );
if ( S_OK == hr )
{
hr = spIEnumVARIANT->Next( 1, &v, NULL );
}
}
else
{ // Just for this domain
_variant_t _v( _bstrDomainName );
hr = spIDomains->get_Item( _v, &pIDomain );
}
while ( S_OK == hr )
{
if ( NULL != spIEnumVARIANT.p )
{
if ( VT_DISPATCH != V_VT( &v ))
hr = E_UNEXPECTED;
if ( S_OK == hr )
hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3Domain ), reinterpret_cast<void**>( &pIDomain ));
VariantClear( &v );
}
if ( S_OK == hr )
hr = pIDomain->get_Name( &bstrName );
if ( S_OK == hr )
{
LOG( L"Domain: %s ", bstrName );
SysFreeString( bstrName );
}
// Enumerate the users
if ( S_OK == hr )
{
hr = pIDomain->get_Users( &spIUsers );
if ( S_OK == hr )
{ // List users
CComPtr<IEnumVARIANT> spIEnumVARIANT2;
hr = spIUsers->get__NewEnum( &spIEnumVARIANT2 );
if ( S_OK == hr )
hr = spIEnumVARIANT2->Next( 1, &v, NULL );
while ( S_OK == hr )
{
if ( VT_DISPATCH != V_VT( &v ))
hr = E_UNEXPECTED;
if ( S_OK == hr )
hr = V_DISPATCH( &v )->QueryInterface( __uuidof( IP3User ), reinterpret_cast<void**>( &spIUser ));
VariantClear( &v );
if ( S_OK == hr )
hr = spIUser->get_Name( &bstrName );
if ( S_OK == hr )
{
hr = spIUser->get_EmailName( &bstrEmailName );
if ( S_OK == hr )
{
hr = mailboxX.OpenMailBox( bstrEmailName ) ? S_OK : E_UNEXPECTED;
if ( S_OK == hr )
{
bLocked = mailboxX.LockMailBox() ? true : false;
hr = mailboxX.EnumerateMailBox() ? S_OK : E_UNEXPECTED;
}
if ( S_OK == hr )
dwCount = mailboxX.GetMailCount();
for ( dwIndex = 0; (S_OK == hr) && (dwIndex < dwCount); dwIndex++ )
{
if ( !mailboxX.GetMailFileName( dwIndex, sFilename, dwFileNameSize ))
hr = E_UNEXPECTED;
if ( S_OK == hr )
{
hr = GetMailFROM( sFilename, sASCFROM );
if ( S_OK != hr )
sASCFROM.erase();
}
if ( S_OK == hr )
{ // SMTP:MAIL
iSize = _snprintf( psSendBuffer, SMTP_BUFFERSIZE, "MAIL FROM:<%s>\r\n", sASCFROM.c_str() );
if ( 0 < iSize )
hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
else
hr = E_UNEXPECTED;
}
if ( S_OK == hr )
{ // SMTP:RCPT
iSize = _snprintf( psSendBuffer, SMTP_BUFFERSIZE, "RCPT TO:%s@%s\r\n", W2A( bstrName ), W2A( sEmailDomain.c_str() ));
if ( 0 < iSize )
hr = SendRecv( socket, psSendBuffer, iSize, SMTP_MSG250 );
else
hr = E_UNEXPECTED;
}
if ( S_OK == hr )
{ // SMTP:DATA
hr = SendRecv( socket, SMTP_DATA, iSize, SMTP_MSG354 );
}
if ( S_OK == hr )
{
iErr = mailboxX.TransmitMail( socket, dwIndex );
if ( ERROR_SUCCESS != iErr )
{
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: TransmitMail failed. %s", CFormatMessage(iErr).c_str() );
// Data probably wasn't terminated since TransmitMail failed.
SendRecv( socket, SMTP_DATA_END, iSize, SMTP_MSG250 );
}
else
{ // There should be a 250 OK reply waiting.
hr = RecvResp( socket, SMTP_MSG250 );
}
}
if ( S_OK != hr && bIgnoreErrors )
{
SendRecv( socket, SMTP_RSET, strlen( SMTP_RSET ), SMTP_MSG250 );
hr = S_OK;
bErrors = true;
}
}
if ( bLocked )
{
mailboxX.UnlockMailBox();
bLocked = false;
}
SysFreeString( bstrEmailName );
mailboxX.QuitAndClose();
}
SysFreeString( bstrName );
}
if ( S_OK == hr )
hr = spIEnumVARIANT2->Next( 1, &v, NULL );
}
if ( S_FALSE == hr )
hr = S_OK; // Reached end of user enumeration
}
}
if ( S_OK == hr )
{
if ( NULL != spIEnumVARIANT.p )
{
hr = spIEnumVARIANT->Next( 1, &v, NULL );
if ( S_OK == hr )
pIDomain->Release();
}
else
hr = S_FALSE; // Were done.
}
}
if ( S_FALSE == hr )
hr = S_OK; // Reached end of domain enumeration
}
if ( NULL != pIDomain )
pIDomain->Release();
// Cleanup
if( INVALID_SOCKET != socket )
{
// SMTP:QUIT
HRESULT hr2 = SendRecv( socket, SMTP_QUIT, strlen( SMTP_QUIT ), SMTP_MSG221 );
if ( S_OK == hr ) hr = hr2;
iErr = closesocket( socket );
if ( 0 != iErr ) LOG( L"ERROR!: closesocket. %s", CFormatMessage(iErr).c_str() );
assert( 0 == iErr );
}
if ( 0 != wsaData.wVersion )
{
iErr = WSACleanup( );
if ( 0 != iErr ) LOG( L"ERROR!: WSACleanup. %s", CFormatMessage(iErr).c_str() );
assert( 0 == iErr );
}
if ( S_OK == hr )
{
PrintMessage( IDS_SUCCESS_SENDMAIL );
if ( bErrors )
PrintMessage( IDS_WARNING_ERRORSIGNORED );
}
else
PrintMessage( IDS_ERROR_SENDMAIL_FAILED );
if ( bUnregisterDependencies )
UnRegisterDependencies();
return hr;
}
#define FROMFIELD "\r\nfrom:"
#define FROMFIELDEND "\r\n"
#define EOH "\r\n\r\n"
HRESULT CP2EWorker::GetMailFROM( LPCWSTR sFileName, ASTRING &sFrom )
{
HRESULT hr = S_OK;
bool isThereMoreToRead = true, isFromComplete = false;
char sBuffer[LOCAL_FILE_BUFFER_SIZE+1];
DWORD dwBytesToRead, dwBytesRead;
LPSTR ps, psEOH, psFrom;
DWORD dwStart;
ASTRING sFromFULL;
HANDLE hFile = CreateFile( sFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
hr = HRESULT_FROM_WIN32( GetLastError() );
// Read till we find the "\r\nFrom:"
dwStart = strlen( FROMFIELD );
dwBytesToRead = LOCAL_FILE_BUFFER_SIZE - dwStart;
if( ReadFile( hFile, sBuffer, LOCAL_FILE_BUFFER_SIZE, &dwBytesRead, NULL) )
sBuffer[dwBytesRead] = 0;
else
hr = HRESULT_FROM_WIN32( GetLastError() );
while( isThereMoreToRead && S_OK == hr )
{
if( dwBytesRead < dwBytesToRead )
isThereMoreToRead = false;
_strlwr( sBuffer );
ps = sBuffer;
psEOH = strstr( ps, EOH );
if ( NULL != psEOH )
{
*psEOH = 0;
isThereMoreToRead = false;
}
psFrom = strstr( ps, FROMFIELD );
if ( NULL != psFrom )
{ // Found the From Field, do we have it all?
psFrom += strlen( FROMFIELD );
ps = strstr( psFrom, FROMFIELDEND );
if ( NULL != ps )
{
*ps = 0;
isFromComplete = true;
}
sFromFULL = psFrom;
isThereMoreToRead = false;
}
if ( isThereMoreToRead )
{ // Copy end of buffer to beginning (to handle wrap around) then continue
memcpy( sBuffer, &(sBuffer[dwBytesToRead]), dwStart );
if( ReadFile( hFile, &(sBuffer[dwStart]), dwBytesToRead, &dwBytesRead, NULL) )
sBuffer[dwBytesRead + dwStart] = 0;
else
hr = HRESULT_FROM_WIN32( GetLastError() );
}
}
if ( !isFromComplete && NULL != psFrom )
{ // Should be able to get rest of FROM with next read
// Copy end of buffer to beginning (to handle wrap around) then continue
memcpy( sBuffer, &(sBuffer[dwBytesToRead]), dwStart );
if( ReadFile( hFile, &(sBuffer[dwStart]), dwBytesToRead, &dwBytesRead, NULL) )
{
sBuffer[dwBytesRead + dwStart] = 0;
ps = strstr( sBuffer, FROMFIELDEND );
if ( NULL != ps )
{
*ps = 0;
if ( ps > &(sBuffer[dwStart]) )
sFromFULL += sBuffer[dwStart];
else
{ // cleanup sFrom
ASTRING::size_type iPos = sFromFULL.find( '\r' );
if ( ASTRING::npos != iPos )
sFromFULL.resize( iPos );
}
}
}
else
hr = HRESULT_FROM_WIN32( GetLastError() );
}
if ( !sFromFULL.empty() && S_OK == hr )
{ // Look for the open bracket
ASTRING::size_type iStart = sFromFULL.find( '<' );
ASTRING::size_type iEnd = sFromFULL.find( '>' );
if ( WSTRING::npos != iStart )
{
if ( ASTRING::npos != iEnd )
sFrom = sFromFULL.substr( iStart + 1, iEnd - iStart - 1 );
}
else
sFrom = sFromFULL;
}
if ( INVALID_HANDLE_VALUE != hFile )
CloseHandle( hFile );
return hr;
}
void CP2EWorker::PrintError( int iRC )
{
if ( m_bSuppressPrintError || (E_FAIL == iRC) )
{
m_bSuppressPrintError = false;
return;
}
LPVOID lpMsgBuf;
if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iRC, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>( &lpMsgBuf ), 0, NULL ))
{
wprintf( reinterpret_cast<LPWSTR>( lpMsgBuf ) );
LocalFree( lpMsgBuf );
}
else
{
WCHAR sBuffer[32];
PrintMessage( IDS_ERROR_UNKNOWN );
wsprintf( sBuffer, L"%x", iRC );
PrintMessage( sBuffer );
}
}
void CP2EWorker::PrintMessage( LPWSTR psMessage, bool bCRLF /*= true*/ )
{
wprintf( psMessage );
if ( bCRLF )
wprintf( L"\r\n" );
}
void CP2EWorker::PrintMessage( int iID, bool bCRLF /*= true*/ )
{
WCHAR sBuffer[512];
if ( LoadString( NULL, iID, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ))
PrintMessage( sBuffer, bCRLF );
else
assert( false );
}
void CP2EWorker::PrintUsage()
{
WCHAR sBuffer[512];
for ( int i = IDS_POP2EXCH_USAGE1; i < IDS_POP2EXCH_USAGEEND; i++ )
{
if ( LoadString( NULL, i, sBuffer, sizeof( sBuffer )/sizeof(WCHAR) ))
{
if ( IDS_POP2EXCH_USAGE2 == i )
{
WCHAR sBuffer2[512];
if ( 0 > _snwprintf( sBuffer2, sizeof( sBuffer2 )/sizeof(WCHAR), sBuffer, POP3_SERVER_NAME_L ))
sBuffer2[(sizeof( sBuffer2 )/sizeof(WCHAR))-1] = 0;
wcscpy( sBuffer, sBuffer2 );
}
wprintf( sBuffer );
}
}
}
LPWSTR CP2EWorker::FormatLogString( LPWSTR psLogString )
{
if ( NULL == psLogString )
return psLogString;
LPWSTR psCRLF = wcsstr( psLogString, L"\r\n" );
while ( NULL != psCRLF )
{
*psCRLF = L' ';
*(psCRLF+1) = L' ';
psCRLF = wcsstr( psLogString, L"\r\n" );
}
return psLogString;
}
HRESULT CP2EWorker::RecvResp( SOCKET socket, LPCSTR psExpectedResp )
{
if ( NULL == psExpectedResp )
return E_INVALIDARG;
if ( 3 > strlen( psExpectedResp ))
return E_INVALIDARG;
CHAR sRecvBuffer[SMTP_BUFFERSIZE + 1];
USES_CONVERSION;
HRESULT hr = S_OK;
int iErr;
iErr = recv( socket, sRecvBuffer, SMTP_BUFFERSIZE, 0 );
if ( SOCKET_ERROR != iErr )
{
sRecvBuffer[iErr] = 0;
if ( (3 > iErr) || (0 != strncmp( sRecvBuffer, psExpectedResp, 3 )))
hr = E_UNEXPECTED;
LPWSTR ps = FormatLogString( A2W( sRecvBuffer ));
LOG( L"recv [%s].", ps );
}
else
{
iErr = WSAGetLastError();
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: recv failed. %s", CFormatMessage(iErr).c_str() );
}
return hr;
}
HRESULT CP2EWorker::RegisterDependencies()
{
HRESULT hr = S_OK;
HMODULE hDLL;
HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);
tstring strPath = _T("") ;
strPath = GetModulePath () ;
if ( strPath != _T("") )
strPath = strPath + _T("P3Admin.dll") ;
else
hr = E_FAIL ;
if ( S_OK == hr )
{
hDLL = LoadLibrary( strPath.c_str() );
if ( hDLL )
{
(FARPROC&)lpDllEntryPoint = GetProcAddress(hDLL,"DllRegisterServer");
if (lpDllEntryPoint != NULL)
hr = (*lpDllEntryPoint)();
else
hr = HRESULT_FROM_WIN32(GetLastError());
FreeLibrary( hDLL );
}
else
{
PrintMessage( IDS_ERROR_MUSTBERUNFROMCURDIR );
hr = HRESULT_FROM_WIN32(GetLastError());
m_bSuppressPrintError = true;
}
}
if ( S_OK == hr )
{
CComPtr<IP3Config> spIConfig;
WCHAR sBuffer[MAX_PATH+1];
hr = CoCreateInstance( __uuidof( P3Config ), NULL, CLSCTX_ALL, __uuidof( IP3Config ),reinterpret_cast<LPVOID *>( &spIConfig ));
if ( S_OK == hr )
{
DWORD dwRC = GetCurrentDirectoryW( sizeof(sBuffer)/sizeof(WCHAR), sBuffer );
if (( 0 != dwRC ) && ( (sizeof(sBuffer)/sizeof(WCHAR)) > dwRC ))
{
HKEY hKey;
long lRC = RegCreateKey( HKEY_LOCAL_MACHINE, POP3SERVER_SOFTWARE_SUBKEY, &hKey );
if ( ERROR_SUCCESS == lRC )
{
lRC = RegSetDWORD( POP3SERVER_SOFTWARE_SUBKEY, VALUENAME_VERSION, 0 );
if ( ERROR_SUCCESS != lRC )
hr = HRESULT_FROM_WIN32( lRC );
RegCloseKey( hKey );
}
else
hr = HRESULT_FROM_WIN32( lRC );
if ( S_OK == hr )
{
_bstr_t _bstrMailRoot = sBuffer;
hr = spIConfig->put_MailRoot( _bstrMailRoot );
}
}
else
hr = E_FAIL;
}
}
if ( S_OK != hr )
{
UnRegisterDependencies () ;
}
return hr;
}
HRESULT CP2EWorker::SendRecv( SOCKET socket, LPCSTR psSendBuffer, const int iSize, LPCSTR psExpectedResp )
{
if ( NULL == psSendBuffer )
return E_INVALIDARG;
USES_CONVERSION;
HRESULT hr = S_OK;
int iErr;
LPWSTR ps = FormatLogString( A2W( psSendBuffer ));
iErr = send( socket, psSendBuffer, iSize, 0 );
if ( SOCKET_ERROR != iErr )
{
LOG( L"send [%s].", ps );
}
else
{
iErr = WSAGetLastError();
hr = HRESULT_FROM_WIN32( iErr );
LOG( L"ERROR!: send [%s] failed. %s", ps, CFormatMessage(iErr).c_str() );
}
if ( S_OK == hr )
{
hr = RecvResp( socket, psExpectedResp );
}
return hr;
}
HRESULT CP2EWorker::UnRegisterDependencies()
{
HRESULT hr = S_OK;
HMODULE hDLL;
HRESULT (STDAPICALLTYPE * lpDllEntryPoint)(void);
tstring strPath = _T("") ;
strPath = GetModulePath () ;
if ( strPath != _T("") )
strPath = strPath + _T("P3Admin.dll") ;
else
hr = E_FAIL ;
if ( S_OK == hr )
{
hDLL = LoadLibrary( strPath.c_str() );
if ( hDLL )
{
(FARPROC&)lpDllEntryPoint = GetProcAddress(hDLL,"DllUnregisterServer");
if (lpDllEntryPoint != NULL)
hr = (*lpDllEntryPoint)();
else
hr = HRESULT_FROM_WIN32(GetLastError());
FreeLibrary( hDLL );
}
else
hr = HRESULT_FROM_WIN32(GetLastError());
}
if ( S_OK == hr )
{
long lRC = RegDeleteKey( HKEY_LOCAL_MACHINE, POP3SERVER_SOFTWARE_SUBKEY );
if ( ERROR_SUCCESS != lRC )
hr = HRESULT_FROM_WIN32( lRC );
}
return hr;
}
tstring CP2EWorker::GetModulePath ()
{
tstring strDir = _T("");
TCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME], szExt[_MAX_EXT] ;
DWORD dwSize = MAX_PATH;
TCHAR *szPath = new TCHAR[dwSize+1];
if (!szPath)
return strDir;
// Allocate more space if necessary
while( dwSize == GetModuleFileName( NULL, szPath, dwSize ) )
{
delete [] szPath;
dwSize *= 2;
szPath = new TCHAR[dwSize+1];
if (!szPath)
return strDir;
}
_tsplitpath ( szPath, szDrive, szDir, szFName, szExt ) ;
_tmakepath ( szPath, szDrive, szDir, _T(""), _T("") ) ; // Make the path without filename and extension.
if (_tcslen( szPath ))
strDir = szPath;
if ( szPath[_tcslen(szPath)-1] != '\\' )
strDir = strDir + _T("\\") ;
delete [] szPath;
return strDir;
}