Windows2003-3790/inetsrv/pop3/setup/oc/pop3oc.cpp
2020-09-30 16:53:55 +02:00

1630 lines
45 KiB
C++

/*
* Copyright (c) 2001 Microsoft Corporation
*
* Module Name:
*
* POP3oc.cpp
*
* Abstract:
*
* This file handles all messages passed by the OC Manager
*
* Author:
*
* Paolo Raden (paolora) Nov-20-2001
*
* Environment:
*
* User Mode
*/
#define _POP3OC_CPP_
#include <windows.h>
#include <stdlib.h>
#include <assert.h>
#include <tchar.h>
#include <shlobj.h>
#include <objbase.h>
#include <shlwapi.h>
#include <lm.h>
#include <objidl.h>
#include <psapi.h>
#include "pop3oc.h"
#include "ServiceUtil.h"
#include "Pop3RegKeysUtil.h"
#include <isexchng.h>
#include <p3admin.h>
#include <Pop3Server.h>
#define _ASSERT(x) {}
#include <ServUtil.h>
#include <smtpinet.h>
#pragma hdrstop
// also referred to in pop3oc.h // forward reference
DWORD OnPreinitialize();
DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc);
DWORD OnSetLanguage();
DWORD_PTR OnQueryImage();
DWORD OnSetupRequestPages(UINT type, PVOID srp);
DWORD OnQuerySelStateChange(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state, UINT flags);
DWORD OnCalcDiskSpace(LPCTSTR ComponentId, LPCTSTR SubcomponentId, DWORD addComponent, HDSKSPC dspace);
DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue);
DWORD OnNotificationFromQueue();
DWORD OnQueryStepCount();
DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId);
DWORD OnCleanup();
DWORD OnQueryState(LPCTSTR ComponentId, LPCTSTR SubcomponentId, UINT state);
DWORD OnNeedMedia();
DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId);
DWORD OnQuerySkipPage();
DWORD OnWizardCreated();
DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per);
PPER_COMPONENT_DATA AddNewComponent(LPCTSTR ComponentId);
PPER_COMPONENT_DATA LocateComponent(LPCTSTR ComponentId);
VOID RemoveComponent(LPCTSTR ComponentId);
BOOL StateInfo(PPER_COMPONENT_DATA cd, LPCTSTR SubcomponentId, BOOL *state);
DWORD RegisterServers(HINF hinf, LPCTSTR component, DWORD state);
DWORD EnumSections(HINF hinf, const TCHAR *component, const TCHAR *key, DWORD index, INFCONTEXT *pic, TCHAR *name);
DWORD RegisterServices(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
DWORD CleanupNetShares(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
DWORD RunExternalProgram(PPER_COMPONENT_DATA cd, LPCTSTR component, DWORD state);
HRESULT CreateLink( const TCHAR *sourcePath, const TCHAR *linkPath, const TCHAR *args, const TCHAR *sDesc );
// POP 3 custom
DWORD KillPop3Snapins();
// for registering dlls
typedef HRESULT (__stdcall *pfn)(void);
#define KEYWORD_REGSVR TEXT("RegSvr")
#define KEYWORD_UNREGSVR TEXT("UnregSvr")
#define KEYWORD_UNINSTALL TEXT("Uninstall")
#define KEYWORD_SOURCEPATH TEXT("SourcePath")
#define KEYWORD_DELSHARE TEXT("DelShare")
#define KEYWORD_ADDSERVICE TEXT("AddService")
#define KEYWORD_DELSERVICE TEXT("DelService")
#define KEYWORD_SHARENAME TEXT("Share")
#define KEYWORD_RUN TEXT("Run")
#define KEYVAL_SYSTEMSRC TEXT("SystemSrc")
#define KEYWORD_COMMANDLINE TEXT("CommandLine")
#define KEYWORD_TICKCOUNT TEXT("TickCount")
// Services keywords/options
#define KEYWORD_SERVICENAME TEXT("ServiceName")
#define KEYWORD_DISPLAYNAME TEXT("DisplayName")
#define KEYWORD_SERVICETYPE TEXT("ServiceType")
#define KEYWORD_STARTTYPE TEXT("StartType")
#define KEYWORD_ERRORCONTROL TEXT("ErrorControl")
#define KEYWORD_IMAGEPATH TEXT("BinaryPathName")
#define KEYWORD_LOADORDER TEXT("LoadOrderGroup")
#define KEYWORD_DEPENDENCIES TEXT("Dependencies")
#define KEYWORD_STARTNAME TEXT("ServiceStartName")
#define KEYWORD_PASSWORD TEXT("Password")
#define KEYVAL_ON TEXT("on")
#define KEYVAL_OFF TEXT("off")
#define KEYVAL_DEFAULT TEXT("default")
const char gszRegisterSvrRoutine[] = "DllRegisterServer";
const char gszUnregisterSvrRoutine[] = "DllUnregisterServer";
BOOL g_fRebootNeed = FALSE;
BOOL g_fExchange = FALSE;
CServiceUtil *g_pServiceUtil = NULL;
CServiceUtil *g_pServiceUtilWMI = NULL;
CPop3RegKeysUtil *g_pPopRegKeys = NULL;
PPER_COMPONENT_DATA _cd=NULL;
/*
* called by CRT when _DllMainCRTStartup is the DLL entry point
*/
BOOL
WINAPI
DllMain(
IN HINSTANCE hinstance,
IN DWORD reason,
IN LPVOID reserved
)
{
BOOL b;
UNREFERENCED_PARAMETER(reserved);
b = true;
switch(reason)
{
case DLL_PROCESS_ATTACH:
ghinst = hinstance;
loginit();
// Fall through to process first thread
case DLL_THREAD_ATTACH:
b = true;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
}
return(b);
}
DWORD_PTR
OcEntry(
IN LPCTSTR ComponentId,
IN LPCTSTR SubcomponentId,
IN UINT Function,
IN UINT Param1,
IN OUT PVOID Param2
)
{
DWORD_PTR rc;
DebugTraceOCNotification(Function, ComponentId);
logOCNotification(Function, ComponentId);
switch(Function)
{
case OC_PREINITIALIZE:
rc = OnPreinitialize();
break;
case OC_INIT_COMPONENT:
rc = OnInitComponent(ComponentId, (PSETUP_INIT_COMPONENT)Param2);
break;
case OC_EXTRA_ROUTINES:
rc = OnExtraRoutines(ComponentId, (PEXTRA_ROUTINES)Param2);
break;
case OC_SET_LANGUAGE:
rc = OnSetLanguage();
break;
case OC_QUERY_IMAGE:
rc = OnQueryImage();
break;
case OC_REQUEST_PAGES:
rc = OnSetupRequestPages(Param1, Param2);
break;
case OC_QUERY_CHANGE_SEL_STATE:
rc = OnQuerySelStateChange(ComponentId, SubcomponentId, Param1, (UINT)((UINT_PTR)Param2));
break;
case OC_CALC_DISK_SPACE:
rc = OnCalcDiskSpace(ComponentId, SubcomponentId, Param1, Param2);
break;
case OC_QUEUE_FILE_OPS:
rc = OnQueueFileOps(ComponentId, SubcomponentId, (HSPFILEQ)Param2);
break;
case OC_NOTIFICATION_FROM_QUEUE:
rc = OnNotificationFromQueue();
break;
case OC_QUERY_STEP_COUNT:
rc = OnQueryStepCount();
break;
case OC_COMPLETE_INSTALLATION:
rc = OnCompleteInstallation(ComponentId, SubcomponentId);
break;
case OC_CLEANUP:
rc = OnCleanup();
break;
case OC_QUERY_STATE:
rc = OnQueryState(ComponentId, SubcomponentId, Param1);
break;
case OC_NEED_MEDIA:
rc = OnNeedMedia();
break;
case OC_ABOUT_TO_COMMIT_QUEUE:
rc = OnAboutToCommitQueue(ComponentId,SubcomponentId);
break;
case OC_QUERY_SKIP_PAGE:
rc = OnQuerySkipPage();
break;
case OC_WIZARD_CREATED:
rc = OnWizardCreated();
break;
default:
rc = NO_ERROR;
break;
}
DebugTrace(1, TEXT("processing completed"));
logOCNotificationCompletion();
return rc;
}
/*-------------------------------------------------------*/
/*
* OC Manager message handlers
*
*-------------------------------------------------------*/
/* OnPreinitialize()
*
* handler for OC_PREINITIALIZE
*/
DWORD
OnPreinitialize(
VOID
)
{
#ifdef ANSI
return OCFLAG_ANSI;
#else
return OCFLAG_UNICODE;
#endif
}
/*
* OnInitComponent()
*
* handler for OC_INIT_COMPONENT
*/
DWORD OnInitComponent(LPCTSTR ComponentId, PSETUP_INIT_COMPONENT psc)
{
PPER_COMPONENT_DATA cd;
INFCONTEXT context;
TCHAR buf[256];
HINF hinf;
BOOL rc;
// We should only uninstall if exchange is on the box
g_fExchange = _IsExchangeInstalled();
// add component to linked list
if (!(cd = AddNewComponent(ComponentId)))
return ERROR_NOT_ENOUGH_MEMORY;
// store component inf handle
cd->hinf = (psc->ComponentInfHandle == INVALID_HANDLE_VALUE)
? NULL
: psc->ComponentInfHandle;
// open the inf
if (cd->hinf)
SetupOpenAppendInfFile(NULL, cd->hinf,NULL);
// copy helper routines and flags
cd->HelperRoutines = psc->HelperRoutines;
cd->Flags = psc->SetupData.OperationFlags;
cd->SourcePath = NULL;
// play
srand(GetTickCount());
return NO_ERROR;
}
/*
* OnExtraRoutines()
*
* handler for OC_EXTRA_ROUTINES
*/
DWORD OnExtraRoutines(LPCTSTR ComponentId, PEXTRA_ROUTINES per)
{
PPER_COMPONENT_DATA cd;
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
memcpy(&cd->ExtraRoutines, per, per->size);
return NO_ERROR;
}
/*
* OnSetLanguage()
*
* handler for OC_SET_LANGUAGE
*/
DWORD OnSetLanguage()
{
return false;
}
/*
* OnSetLanguage()
*
* handler for OC_SET_LANGUAGE
*/
DWORD_PTR OnQueryImage()
{
return (DWORD_PTR)LoadBitmap(NULL,MAKEINTRESOURCE(32754)); // OBM_CLOSE
}
/*
* OnSetupRequestPages
*
* Prepares wizard pages and returns them to the OC Manager
*/
DWORD OnSetupRequestPages(UINT type, PVOID srp)
{
return 0;
}
/*
* OnWizardCreated()
*/
DWORD OnWizardCreated()
{
return NO_ERROR;
}
/*
* OnQuerySkipPage()
*
* don't let the user deselect the sam component
*/
DWORD OnQuerySkipPage()
{
return false;
}
/*
* OnQuerySelStateChange()
*
* don't let the user deselect the sam component
*/
DWORD OnQuerySelStateChange(LPCTSTR ComponentId,
LPCTSTR SubcomponentId,
UINT state,
UINT flags)
{
if (g_fExchange && (flags & OCQ_ACTUAL_SELECTION) && state)
{
log( TEXT("POP3OC: user tried to install %s while exchange is installed. Not supported."), SubcomponentId);
MsgBox(NULL, IDS_ERR_EXCHANGE_INSTALLED, MB_OK);
return FALSE;
}
return TRUE;
}
/*
* OnCalcDiskSpace()
*
* handler for OC_ON_CALC_DISK_SPACE
*/
DWORD OnCalcDiskSpace(LPCTSTR ComponentId,
LPCTSTR SubcomponentId,
DWORD addComponent,
HDSKSPC dspace)
{
DWORD rc = NO_ERROR;
TCHAR section[S_SIZE];
PPER_COMPONENT_DATA cd;
//
// Param1 = 0 if for removing component or non-0 if for adding component
// Param2 = HDSKSPC to operate on
//
// Return value is Win32 error code indicating outcome.
//
// In our case the private section for this component/subcomponent pair
// is a simple standard inf install section, so we can use the high-level
// disk space list api to do what we want.
//
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
_tcscpy(section, SubcomponentId);
if (addComponent)
{
rc = SetupAddInstallSectionToDiskSpaceList(dspace,
cd->hinf,
NULL,
section,
0,
0);
}
else
{
rc = SetupRemoveInstallSectionFromDiskSpaceList(dspace,
cd->hinf,
NULL,
section,
0,
0);
}
if (!rc)
rc = GetLastError();
else
rc = NO_ERROR;
return rc;
}
/*
* OnQueueFileOps()
*
* handler for OC_QUEUE_FILE_OPS
*/
DWORD OnQueueFileOps(LPCTSTR ComponentId, LPCTSTR SubcomponentId, HSPFILEQ queue)
{
PPER_COMPONENT_DATA cd;
BOOL state;
BOOL rc;
INFCONTEXT context;
TCHAR section[256];
TCHAR srcpathbuf[256];
TCHAR *srcpath;
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId)
return NO_ERROR;
cd->queue = queue;
if (!StateInfo(cd, SubcomponentId, &state))
return NO_ERROR;
wsprintf(section, SubcomponentId);
rc = TRUE;
if (!state) {
// being uninstalled. Fetch uninstall section name.
rc = SetupFindFirstLine(cd->hinf,
SubcomponentId,
KEYWORD_UNINSTALL,
&context);
if (rc) {
rc = SetupGetStringField(&context,
1,
section,
sizeof(section) / sizeof(TCHAR),
NULL);
}
// POP3 Server Custom code goes here
if (!_wcsicmp( SubcomponentId, L"Pop3Service"))
{
// Winpop Init 0
TCHAR szSource[MAX_PATH+1];
if (0 != GetSystemDirectory( szSource, MAX_PATH+1 ))
{
TCHAR szAppName[MAX_PATH+30];
TCHAR szCommandLine[MAX_PATH+50];
_tcscpy( szAppName, szSource );
_tcscat( szAppName, _T("\\winpop.exe") );
_tcscpy( szCommandLine, szAppName );
_tcscat( szCommandLine, _T(" INIT 0") );
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
DWORD dwRet;
if (CreateProcess( szAppName, szCommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi ))
do
{
dwRet = MsgWaitForMultipleObjects( 1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT );
if( dwRet == WAIT_OBJECT_0 + 1 )
{
MSG msg;
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
while( dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
}
// Kill all Pop3 snapins
KillPop3Snapins();
// also, unregister the dlls and kill services before deletion
SetupInstallServicesFromInfSection(cd->hinf, section, 0);
SetupInstallFromInfSection(NULL,cd->hinf,section,SPINST_UNREGSVR,NULL,NULL,0,NULL,NULL,NULL,NULL);
}
if (rc) {
// if uninstalling, don't use version checks
rc = SetupInstallFilesFromInfSection(cd->hinf,
NULL,
queue,
section,
cd->SourcePath,
state ? SP_COPY_NEWER : 0);
}
if (!rc)
return GetLastError();
return NO_ERROR;
}
/*
* OnNotificationFromQueue()
*
* handler for OC_NOTIFICATION_FROM_QUEUE
*
* NOTE: although this notification is defined,
* it is currently unimplemented in oc manager
*/
DWORD OnNotificationFromQueue()
{
return NO_ERROR;
}
/*
* OnQueryStepCount
*
* handler forOC_QUERY_STEP_COUNT
*/
DWORD OnQueryStepCount()
{
return 2;
}
/*
* OnCompleteInstallation
*
* handler for OC_COMPLETE_INSTALLATION
*/
DWORD OnCompleteInstallation(LPCTSTR ComponentId, LPCTSTR SubcomponentId)
{
PPER_COMPONENT_DATA cd;
INFCONTEXT context;
TCHAR section[256];
BOOL state;
BOOL rc;
DWORD Error = NO_ERROR;
// Do post-installation processing in the cleanup section.
// This way we know all compoents queued for installation
// have beein installed before we do our stuff.
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId)
return NO_ERROR;
if (!StateInfo(cd, SubcomponentId, &state))
return NO_ERROR;
wsprintf(section, SubcomponentId);
rc = TRUE;
if (!state) {
// being uninstalled. Fetch uninstall section name.
rc = SetupFindFirstLine(cd->hinf,
SubcomponentId,
KEYWORD_UNINSTALL,
&context);
if (rc) {
rc = SetupGetStringField(&context,
1,
section,
sizeof(section) / sizeof(TCHAR),
NULL);
}
}
if (state) {
//
// installation
//
if (rc) {
if ( NULL == g_pPopRegKeys )
{
g_pPopRegKeys = new CPop3RegKeysUtil();
g_pPopRegKeys->Save();
}
// process the inf file
rc = SetupInstallFromInfSection(NULL, // hwndOwner
cd->hinf, // inf handle
section, // name of component
SPINST_ALL & ~SPINST_FILES,
NULL, // relative key root
NULL, // source root path
0, // copy flags
NULL, // callback routine
NULL, // callback routine context
NULL, // device info set
NULL); // device info struct
if (rc) {
rc = SetupInstallServicesFromInfSection(cd->hinf, section, 0);
Error = GetLastError();
if (!rc && Error == ERROR_SECTION_NOT_FOUND) {
rc = TRUE;
Error = NO_ERROR;
}
if (rc) {
if (Error == ERROR_SUCCESS_REBOOT_REQUIRED) {
cd->HelperRoutines.SetReboot(cd->HelperRoutines.OcManagerContext,TRUE);
}
Error = NO_ERROR;
rc = RunExternalProgram(cd, section, state);
}
}
}
} else {
//
// uninstallation
//
if (rc)
{
rc = RunExternalProgram(cd, section, state);
}
if (rc) {
rc = CleanupNetShares(cd, section, state);
}
}
HRESULT hr = CoInitialize( NULL );
// POP3 Server Custom code goes here
if (!_wcsicmp( SubcomponentId, L"Pop3Service"))
{
// installing
TCHAR szSnapinName[64];
int iLen=LoadString(ghinst, IDS_SNAPIN_NAME, szSnapinName, sizeof(szSnapinName)/sizeof(TCHAR));
if(0==iLen)
{
_tcscpy(szSnapinName, _T("POP3 Service"));
}
if (state)
{
// Tooltip
TCHAR szTooltip[INFOTIPSIZE];
ZeroMemory( szTooltip, sizeof(szTooltip)/sizeof(TCHAR) );
LoadString(ghinst, IDS_SHORTCUT_TOOLTIP, szTooltip, sizeof(szTooltip)/sizeof(TCHAR) );
// Create the shortcut
TCHAR szDest[MAX_PATH+70];
if (TRUE == SHGetSpecialFolderPath( 0, szDest, CSIDL_COMMON_ADMINTOOLS, FALSE ))
{
TCHAR szSource[MAX_PATH+1];
if (0 != GetSystemDirectory( szSource, MAX_PATH+1 ))
{
_tcscat( szSource, _T("\\p3server.msc") );
_tcscat( szDest, _T("\\") );
_tcscat( szDest, szSnapinName);
_tcscat( szDest, _T(".lnk") );
CreateLink( szSource, szDest, 0, szTooltip );
}
}
// Winpop Init 1
TCHAR szSource[MAX_PATH+1];
if (0 != GetSystemDirectory( szSource, MAX_PATH+1 ))
{
TCHAR szAppName[MAX_PATH+30];
TCHAR szCommandLine[MAX_PATH+50];
_tcscpy( szAppName, szSource );
_tcscat( szAppName, _T("\\winpop.exe") );
_tcscpy( szCommandLine, szAppName );
_tcscat( szCommandLine, _T(" INIT 1") );
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
DWORD dwRet;
if (CreateProcess( szAppName, szCommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi ))
do
{
dwRet = MsgWaitForMultipleObjects( 1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT );
if( dwRet == WAIT_OBJECT_0 + 1 )
{
MSG msg;
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
while( dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
// Add perf counters
if (0 != GetSystemDirectory( szSource, MAX_PATH+1 ))
{
TCHAR szAppName[MAX_PATH+30];
TCHAR szCommandLine[MAX_PATH*2+50];
_tcscpy( szAppName, szSource );
_tcscat( szAppName, _T("\\lodctr.exe") );
_tcscpy( szCommandLine, szAppName );
_tcscat( szCommandLine, _T(" ") );
_tcscat( szCommandLine, szSource );
_tcscat( szCommandLine, _T("\\POP3Server\\pop3perf.ini") );
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
DWORD dwRet;
if (CreateProcess( szAppName, szCommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi ))
do
{
dwRet = MsgWaitForMultipleObjects( 1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT );
if( dwRet == WAIT_OBJECT_0 + 1 )
{
MSG msg;
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
while( dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
// Restore the regkeys to their original state for uninstall
if ( NULL != g_pPopRegKeys )
{
g_pPopRegKeys->Restore();
g_pPopRegKeys = NULL;
}
}
// removing
else
{
// delete the shortcut
TCHAR szPath[MAX_PATH+70];
if (TRUE == SHGetSpecialFolderPath( 0, szPath, CSIDL_COMMON_ADMINTOOLS, FALSE ))
{
_tcscat( szPath, _T("\\") );
_tcscat( szPath, szSnapinName);
_tcscat( szPath, _T(".lnk") );
DeleteFile( szPath );
}
TCHAR szSource[MAX_PATH+1];
TCHAR szStoreDllName[MAX_PATH+30];
// Remove perf counters
if (0 != GetSystemDirectory( szSource, MAX_PATH+1 ))
{
TCHAR szAppName[MAX_PATH+30];
TCHAR szCommandLine[MAX_PATH*2+50];
_tcscpy( szAppName, szSource );
_tcscat( szAppName, _T("\\unlodctr.exe") );
_tcscpy( szCommandLine, szAppName );
_tcscat( szCommandLine, _T(" pop3svc") );
_tcscpy( szStoreDllName, szSource);
_tcscat( szStoreDllName, _T("\\POP3Server\\P3Store.dll"));
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
DWORD dwRet;
if (CreateProcess( szAppName, szCommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi ))
do
{
dwRet = MsgWaitForMultipleObjects( 1, &pi.hProcess, FALSE, INFINITE, QS_ALLINPUT );
if( dwRet == WAIT_OBJECT_0 + 1 )
{
MSG msg;
while( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
while( dwRet != WAIT_OBJECT_0 && dwRet != WAIT_FAILED );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
//Before we restore the service, wait max of 30 seconds for p3store.dll to be deleted
int iCountDown=15;
while( ( INVALID_FILE_ATTRIBUTES != GetFileAttributes(szStoreDllName) ) &&
( iCountDown >0 ) )
{
Sleep(2000);
iCountDown--;
}
if ( NULL != g_pServiceUtil )
{
g_pServiceUtil->RestoreServiceState( IISADMIN_SERVICE_NAME );
delete g_pServiceUtil;
g_pServiceUtil = NULL;
}
if ( NULL != g_pServiceUtilWMI )
{
g_pServiceUtilWMI->RestoreServiceState( WMI_SERVICE_NAME );
delete g_pServiceUtilWMI;
g_pServiceUtilWMI = NULL;
}
// Remove Dirs for files
if (0 != GetSystemDirectory( szPath, MAX_PATH+1 ))
{
_tcscat( szPath, _T("\\POP3Server") );
RemoveDirectory( szPath );
}
}
}
// POP3 Admin
else if (!_wcsicmp( SubcomponentId, L"Pop3Admin" ))
{
// installing
if (state)
{
}
// removing
else
{
TCHAR szPath[MAX_PATH+1];
if (0 != GetSystemDirectory( szPath, MAX_PATH+1 ))
{
_tcscat( szPath, _T("\\ServerAppliance\\Web\\Mail") );
RemoveDirectory( szPath );
}
}
// stop the elementmgr service
if ( _IsServiceRunning( _T("elementmgr")))
{
hr = _StopService( _T("elementmgr"), FALSE );
if ( S_OK != hr )
log( _T("POP3OC:OnCompleteInstallation: Unable to stop elementmgr.\r\n") );
}
}
CoUninitialize();
if (!rc && (Error == NO_ERROR) ) {
Error = GetLastError( );
}
return Error;
}
/*
* OnCleanup()
*
* handler for OC_CLEANUP
*/
DWORD OnCleanup()
{
return NO_ERROR;
}
/*
* OnQueryState()
*
* handler for OC_QUERY_STATE
*/
DWORD OnQueryState(LPCTSTR ComponentId,
LPCTSTR SubcomponentId,
UINT state)
{
return SubcompUseOcManagerDefault;
}
/*
* OnNeedMedia()
*
* handler for OC_NEED_MEDIA
*/
DWORD OnNeedMedia()
{
return false;
}
/*
* OnAboutToCommitQueue()
*
* handler for OC_ABOUT_TO_COMMIT_QUEUE
*/
DWORD OnAboutToCommitQueue(LPCTSTR ComponentId, LPCTSTR SubcomponentId)
{
PPER_COMPONENT_DATA cd;
BOOL state;
BOOL rc;
INFCONTEXT context;
TCHAR section[256];
TCHAR srcpathbuf[256];
TCHAR *srcpath;
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
if (!SubcomponentId || !*SubcomponentId)
return NO_ERROR;
if (!StateInfo(cd, SubcomponentId, &state))
return NO_ERROR;
//
// only do stuff on uninstall
//
if (state) {
return NO_ERROR;
}
// Fetch uninstall section name.
rc = SetupFindFirstLine(
cd->hinf,
SubcomponentId,
KEYWORD_UNINSTALL,
&context);
if (rc) {
rc = SetupGetStringField(
&context,
1,
section,
sizeof(section) / sizeof(TCHAR),
NULL);
}
// POP3 Server Custom code goes here
if (rc)
{
if (!_wcsicmp( SubcomponentId, L"Pop3Service"))
{ // Stop IISAdmin so that we can complete uninstall
if ( NULL == g_pServiceUtil )
{
g_pServiceUtil = new CServiceUtil();
if ( NULL != g_pServiceUtil )
{
g_pServiceUtil->StopService( IISADMIN_SERVICE_NAME );
}
}
}
// Stop WMI so that we can complete uninstall
if ( NULL == g_pServiceUtilWMI )
{
g_pServiceUtilWMI = new CServiceUtil();
if ( NULL != g_pServiceUtilWMI )
{
g_pServiceUtilWMI->StopService( WMI_SERVICE_NAME );
}
}
}
// Move Migration stuff to Mailroot
// We will not fail uninstall if something fails in this section
HKEY hKey;
DWORD dwType = REG_SZ, dwSize;
UINT uiRC;
long lRC;
TCHAR sCopyFrom[MAX_PATH+1], sCopyTo[MAX_PATH+1];
// Get the mail root
lRC = RegOpenKeyEx( HKEY_LOCAL_MACHINE, POP3SERVER_SOFTWARE_SUBKEY, 0, KEY_QUERY_VALUE, &hKey );
if ( ERROR_SUCCESS == lRC )
{
dwSize = sizeof( sCopyTo )/sizeof(TCHAR);
lRC = RegQueryValueEx( hKey, VALUENAME_MAILROOT, 0, &dwType, reinterpret_cast<LPBYTE>( sCopyTo ), &dwSize );
RegCloseKey( hKey );
}
// Get the current location
if ( ERROR_SUCCESS == lRC )
{
dwSize = sizeof( sCopyFrom )/sizeof(TCHAR);
uiRC = GetSystemDirectory( sCopyFrom, dwSize );
if ( 0 != uiRC && dwSize > uiRC )
lRC = ERROR_SUCCESS;
else
lRC = GetLastError();
}
if (rc)
rc = SetupInstallServicesFromInfSection(cd->hinf, section, 0);
if (rc) {
rc = SetupInstallFromInfSection(
NULL,
cd->hinf,
section,
SPINST_ALL & ~SPINST_FILES,
NULL,
NULL,
0,
NULL,
NULL,
NULL,
NULL);
}
if (rc) {
SetLastError(NO_ERROR);
}
return GetLastError();
}
/*
* AddNewComponent()
*
* add new compononent to the top of the component list
*/
PPER_COMPONENT_DATA AddNewComponent(LPCTSTR ComponentId)
{
PPER_COMPONENT_DATA data;
data = (PPER_COMPONENT_DATA)LocalAlloc(LPTR,sizeof(PER_COMPONENT_DATA));
if (!data)
return data;
data->ComponentId = (TCHAR *)LocalAlloc(LMEM_FIXED,
(_tcslen(ComponentId) + 1) * sizeof(TCHAR));
if(data->ComponentId)
{
_tcscpy((TCHAR *)data->ComponentId, ComponentId);
// Stick at head of list
data->Next = gcd;
gcd = data;
}
else
{
LocalFree((HLOCAL)data);
data = NULL;
}
return(data);
}
/*
* LocateComponent()
*
* returns a compoent struct that matches the
* passed component id.
*/
PPER_COMPONENT_DATA LocateComponent(LPCTSTR ComponentId)
{
PPER_COMPONENT_DATA p;
for (p = gcd; p; p=p->Next)
{
if (!_tcsicmp(p->ComponentId, ComponentId))
return p;
}
return NULL;
}
/*
* RemoveComponent()
*
* yanks a component from our linked list of components
*/
VOID RemoveComponent(LPCTSTR ComponentId)
{
PPER_COMPONENT_DATA p, prev;
for (prev = NULL, p = gcd; p; prev = p, p = p->Next)
{
if (!_tcsicmp(p->ComponentId, ComponentId))
{
LocalFree((HLOCAL)p->ComponentId);
if (p->SourcePath)
LocalFree((HLOCAL)p->SourcePath);
if (prev)
prev->Next = p->Next;
else
gcd = p->Next;
LocalFree((HLOCAL)p);
return;
}
}
}
// loads current selection state info into "state" and
// returns whether the selection state was changed
BOOL
StateInfo(
PPER_COMPONENT_DATA cd,
LPCTSTR SubcomponentId,
BOOL *state
)
{
BOOL rc = TRUE;
assert(state);
// otherwise, check for a change in installation state
*state = cd->HelperRoutines.QuerySelectionState(cd->HelperRoutines.OcManagerContext,
SubcomponentId,
OCSELSTATETYPE_CURRENT);
if (*state == cd->HelperRoutines.QuerySelectionState(cd->HelperRoutines.OcManagerContext,
SubcomponentId,
OCSELSTATETYPE_ORIGINAL))
{
// no change
rc = FALSE;
}
// if this is gui mode setup, presume the state has changed to force
// an installation (or uninstallation)
if (!(cd->Flags & SETUPOP_STANDALONE) && *state)
rc = TRUE;
return rc;
}
/*
* EnumSections()
*
* finds the name of a section for a specified keyword
*/
DWORD
EnumSections(
HINF hinf,
const TCHAR *component,
const TCHAR *key,
DWORD index,
INFCONTEXT *pic,
TCHAR *name
)
{
TCHAR section[S_SIZE];
if (!SetupFindFirstLine(hinf, component, NULL, pic))
return 0;
if (!SetupFindNextMatchLine(pic, key, pic))
return 0;
if (index > SetupGetFieldCount(pic))
return 0;
if (!SetupGetStringField(pic, index, section, sizeof(section)/sizeof(TCHAR), NULL))
return 0;
if (name)
_tcscpy(name, section);
return SetupFindFirstLine(hinf, section, NULL, pic);
}
DWORD
OcLog(
LPCTSTR ComponentId,
UINT level,
LPCTSTR sz
)
{
TCHAR fmt[5000];
PPER_COMPONENT_DATA cd;
if (!(cd = LocateComponent(ComponentId)))
return NO_ERROR;
assert(cd->ExtraRoutines.LogError);
assert(level);
assert(sz);
_tcscpy(fmt, TEXT("%s: %s"));
return cd->ExtraRoutines.LogError(cd->HelperRoutines.OcManagerContext,
level,
fmt,
ComponentId,
sz);
}
DWORD
CleanupNetShares(
PPER_COMPONENT_DATA cd,
LPCTSTR component,
DWORD state)
{
INFCONTEXT ic;
TCHAR sname[S_SIZE];
DWORD section;
TCHAR *keyword;
if (state) {
return NO_ERROR;
} else {
keyword = KEYWORD_DELSHARE;
}
for (section = 1;
EnumSections(cd->hinf, component, keyword, section, &ic, sname);
section++)
{
INFCONTEXT sic;
NET_API_STATUS netStat;
CHAR Temp[SBUF_SIZE];
TCHAR ShareName[ SBUF_SIZE ];
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_SHARENAME, &sic))
{
log( TEXT("POP3OC: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_SHARENAME );
continue;
}
if (!SetupGetStringField(&sic, 1, ShareName, SBUF_SIZE, NULL))
{
log( TEXT("POP3OC: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_SHARENAME );
continue;
}
#ifdef UNICODE
netStat = NetShareDel( NULL, ShareName, 0 );
#else // UNICODE
WCHAR ShareNameW[ SBUF_SIZE ];
mbstowcs( ShareNameW, ShareName, lstrlen(ShareName));
netStat = NetShareDel( NULL, ShareNameW, 0 );
#endif // UNICODE
if ( netStat != NERR_Success )
{
log( TEXT("POP3OC: Failed to remove %s share. Error 0x%08x\r\n"), ShareName, netStat );
continue;
}
log( TEXT("POP3OC: %s share removed successfully.\r\n"), ShareName );
}
return TRUE;
}
DWORD
RunExternalProgram(
PPER_COMPONENT_DATA cd,
LPCTSTR component,
DWORD state)
{
INFCONTEXT ic;
TCHAR sname[S_SIZE];
DWORD section;
TCHAR *keyword;
keyword = KEYWORD_RUN;
for (section = 1;
EnumSections(cd->hinf, component, keyword, section, &ic, sname);
section++)
{
INFCONTEXT sic;
TCHAR CommandLine[ SBUF_SIZE ];
CHAR szTickCount[ SBUF_SIZE ];
ULONG TickCount;
BOOL b;
STARTUPINFO startupinfo;
PROCESS_INFORMATION process_information;
DWORD dwErr;
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_COMMANDLINE , &sic))
{
log( TEXT("POP3OC: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_COMMANDLINE );
continue;
}
if (!SetupGetStringField(&sic, 1, CommandLine, SBUF_SIZE, NULL))
{
log( TEXT("POP3OC: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_COMMANDLINE );
continue;
}
if (!SetupFindFirstLine(cd->hinf, sname, KEYWORD_TICKCOUNT, &sic))
{
log( TEXT("POP3OC: %s INF error - unable to find %s\r\n"), keyword, KEYWORD_TICKCOUNT );
continue;
}
if (!SetupGetStringFieldA(&sic, 1, szTickCount, SBUF_SIZE, NULL))
{
log( TEXT("POP3OC: %s INF error - incorrect %s line\r\n"), keyword, KEYWORD_TICKCOUNT );
continue;
}
TickCount = atoi( szTickCount );
ZeroMemory( &startupinfo, sizeof(startupinfo) );
startupinfo.cb = sizeof(startupinfo);
startupinfo.dwFlags = STARTF_USESHOWWINDOW;
startupinfo.wShowWindow = SW_HIDE | SW_SHOWMINNOACTIVE;
b = CreateProcess( NULL,
CommandLine,
NULL,
NULL,
FALSE,
CREATE_DEFAULT_ERROR_MODE,
NULL,
NULL,
&startupinfo,
&process_information );
if ( !b )
{
log( TEXT("POP3OC: failed to spawn %s process.\r\n"), CommandLine );
continue;
}
dwErr = WaitForSingleObject( process_information.hProcess, TickCount * 1000 );
if ( dwErr != NO_ERROR )
{
log( TEXT("POP3OC: WaitForSingleObject() failed. Error 0x%08x\r\n"), dwErr );
TerminateProcess( process_information.hProcess, -1 );
CloseHandle( process_information.hProcess );
CloseHandle( process_information.hThread );
continue;
}
CloseHandle( process_information.hProcess );
CloseHandle( process_information.hThread );
log( TEXT("POP3OC: %s successfully completed within %u seconds.\r\n"), CommandLine, TickCount );
}
return TRUE;
}
HRESULT CreateLink( const TCHAR *sourcePath, const TCHAR *linkPath, const TCHAR *args, const TCHAR *sDesc )
{
CoInitialize( NULL );
IShellLink* pShellLink = NULL;
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLink, reinterpret_cast<void**>(&pShellLink));
if (FAILED(hr))
return hr;
hr = pShellLink->SetPath(sourcePath);
if (FAILED(hr))
return hr;
hr = pShellLink->SetArguments(args);
if (FAILED(hr))
return hr;
hr = pShellLink->SetDescription(sDesc);
if (FAILED(hr))
return hr;
IPersistFile* pPersistFile = NULL;
hr = pShellLink->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&pPersistFile));
if (FAILED(hr))
return hr;
TCHAR* szTemp = new TCHAR[(sizeof(TCHAR) * _tcslen(linkPath)) + sizeof(TCHAR)];
if (!szTemp)
return E_OUTOFMEMORY;
_tcscpy( szTemp, linkPath );
hr = pPersistFile->Save(szTemp, TRUE);
if (FAILED(hr))
return hr;
pPersistFile->Release();
pShellLink->Release();
CoUninitialize();
delete [] szTemp;
return S_OK;
}
//Get a complete
int GetProcesses (DWORD ** lplp)
{
*lplp = NULL;
// according to docs (and other places), there's no scheme to tell,
// a priori, how many procs there are. So use loop below:
DWORD * lpids = NULL;
DWORD dwcb = sizeof(DWORD), dwcbNeeded;
do {
// alloc based on current dwcb.
lpids = (DWORD *)malloc (dwcb);
if (!lpids)
return 0;
dwcbNeeded = 0;
BOOL b = EnumProcesses (lpids, dwcb, &dwcbNeeded);
if ((b == FALSE) || (dwcbNeeded == 0)) {
// error!
free (lpids);
return 0;
}
if (dwcbNeeded == dwcb) {
free (lpids);
dwcb *= 2;
continue;
}
// if we got here, we have a complete list of procs
break;
} while (1);
*lplp = lpids;
return dwcbNeeded/sizeof(DWORD);
}
int GetModules (HANDLE hProcess, HMODULE ** lplp)
{
*lplp = NULL;
HMODULE * lpMods = NULL;
DWORD dwcb = sizeof(HMODULE), dwcbNeeded;
do {
// alloc based on current dwcb.
lpMods = (HMODULE *)malloc (dwcb);
if (!lpMods)
return 0;
dwcbNeeded = 0;
BOOL b = EnumProcessModules (hProcess, lpMods, dwcb, &dwcbNeeded);
if ((b == FALSE) || (dwcbNeeded == 0)) {
// error!
free (lpMods);
return 0;
}
// unlike calls to EnumProcesses, the last param of EnumProcessModules
// is actually useful: so, use it.
if (dwcbNeeded > dwcb) {
free (lpMods);
dwcb = dwcbNeeded;
continue;
}
// if we got here, we have a complete list of modules
break;
} while (1);
*lplp = lpMods;
return dwcbNeeded/sizeof(HMODULE);
}
DWORD KillPop3Snapins()
{
DWORD * lpProcs = NULL;
int iProcs = GetProcesses (&lpProcs);
if (!lpProcs)
return false;
bool b = false;
HANDLE hProcess;
HMODULE hModule;
DWORD cbReturned;
TCHAR szName[MAX_PATH];
HMODULE *lpMods;
int iMods;
// for each proc, get its name, and see if it's MMC
for (int i=0; i<iProcs; i++)
{
hProcess = OpenProcess (PROCESS_ALL_ACCESS, FALSE, lpProcs[i]);
if (hProcess != NULL)
{ // first module is the .exe....
hModule = NULL;
cbReturned = 0;
if ( EnumProcessModules (hProcess, &hModule, sizeof(hModule), &cbReturned ))
{ // get .exe name
szName[0] = 0;
GetModuleBaseName (hProcess, hModule, szName, MAX_PATH);
if ( 0 == _tcsicmp (szName, _T("mmc.exe")))
{ // get all modules (.dlls)
lpMods = NULL;
iMods = GetModules (hProcess, &lpMods);
if (lpMods != NULL)
{
for (int j=1; !b && j<iMods; j++)
{
GetModuleBaseName (hProcess, lpMods[j], szName, MAX_PATH);
if (!_tcsicmp( szName, _T("Pop3Snap.dll") ) )
{
b = true;
}
}
}
free (lpMods);
}
}
if(b)
{
//This is mmc.exe with pop3snap.dll
TerminateProcess(hProcess, 0 );
b=FALSE;
}
CloseHandle( hProcess);
}
}
free (lpProcs);
return b;
}