2291 lines
57 KiB
C++
2291 lines
57 KiB
C++
|
|
#include "stdafx.h"
|
|
|
|
#include "userenv.h"
|
|
#include "userenvp.h"
|
|
|
|
#include "shlobj.h"
|
|
#include "utils.h"
|
|
|
|
#include "mddefw.h"
|
|
#include "mdkey.h"
|
|
|
|
#include "wizpages.h"
|
|
|
|
#include "ocmanage.h"
|
|
#include "setupapi.h"
|
|
#include "k2suite.h"
|
|
|
|
#include "ndmgr.h"
|
|
#include "mycomput.h"
|
|
|
|
extern OCMANAGER_ROUTINES gHelperRoutines;
|
|
|
|
// This function provides StrChr functionality
|
|
LPTSTR MyStrChr(LPCTSTR szString, TCHAR tcChar)
|
|
{
|
|
while (*szString != _T('\0'))
|
|
{
|
|
if (*szString == tcChar)
|
|
return((LPTSTR)szString);
|
|
szString++;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
// This function finds the first non-whitespace
|
|
LPTSTR NextNonSpace(LPTSTR szString)
|
|
{
|
|
while ((*szString == _T(' ')) || (*szString == _T('\t')))
|
|
{
|
|
if (!*szString)
|
|
return(NULL);
|
|
*szString++;
|
|
}
|
|
return(szString);
|
|
}
|
|
|
|
// This function finds the first whitespace
|
|
LPTSTR NextSpace(LPTSTR szString)
|
|
{
|
|
while ((*szString != _T(' ')) && (*szString != _T('\t')) &&
|
|
(*szString != _T('\0')))
|
|
{
|
|
*szString++;
|
|
}
|
|
return(szString);
|
|
}
|
|
|
|
BOOL ParseInfLineArguments(LPCTSTR szLine, LPTSTR szAttribute, LPTSTR szValue)
|
|
{
|
|
LPTSTR pEqual, pAttrStart, pValueStart;
|
|
TCHAR tcTemp;
|
|
|
|
pAttrStart = NextNonSpace((LPTSTR)szLine);
|
|
if (!pAttrStart)
|
|
return(FALSE);
|
|
|
|
pEqual = MyStrChr(szLine, _T('='));
|
|
if (pEqual)
|
|
{
|
|
// Found equal sign
|
|
if (pAttrStart >= pEqual)
|
|
return(FALSE);
|
|
|
|
pValueStart = NextNonSpace(pEqual + 1);
|
|
if (pValueStart)
|
|
lstrcpy(szValue, pValueStart);
|
|
}
|
|
else
|
|
*szValue = _T('\0');
|
|
|
|
// Find the end of the attribute name
|
|
pValueStart = NextSpace(pAttrStart);
|
|
tcTemp = *pValueStart;
|
|
*pValueStart = _T('\0');
|
|
lstrcpy(szAttribute, pAttrStart);
|
|
*pValueStart = tcTemp;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// This function obtains the root directory of a directory
|
|
BOOL GetRootDirectory(LPCTSTR szDirectory, LPTSTR szRootDir, DWORD cbLength)
|
|
{
|
|
DWORD dwLen = lstrlen(szDirectory);
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
if (dwLen < 2)
|
|
return(FALSE);
|
|
|
|
if (szDirectory[0] == _T('\\') &&
|
|
szDirectory[1] == _T('\\'))
|
|
{
|
|
LPTSTR lpTemp;
|
|
|
|
// This is a UNC, get the share name. We find the 4th
|
|
// backslash and take everything before that.
|
|
lpTemp = MyStrChr(szDirectory + 2, _T('\\'));
|
|
if (!lpTemp)
|
|
return(FALSE);
|
|
|
|
lpTemp = MyStrChr(lpTemp + 1, _T('\\'));
|
|
if (!lpTemp)
|
|
return(FALSE);
|
|
|
|
// Get how many bytes to copy
|
|
dwLen = (DWORD)(lpTemp - szDirectory + 1);
|
|
if (cbLength < dwLen)
|
|
{
|
|
SetLastError(ERROR_MORE_DATA);
|
|
return(FALSE);
|
|
}
|
|
|
|
lstrcpyn(szRootDir, szDirectory, dwLen);
|
|
}
|
|
else
|
|
{
|
|
if (cbLength < 4)
|
|
{
|
|
SetLastError(ERROR_MORE_DATA);
|
|
return(FALSE);
|
|
}
|
|
|
|
// This is a drive specification
|
|
if (szDirectory[1] != _T(':'))
|
|
return(FALSE);
|
|
|
|
if (dwLen == 2)
|
|
{
|
|
lstrcpy(szRootDir, szDirectory);
|
|
lstrcat(szRootDir, _T("\\"));
|
|
}
|
|
else
|
|
{
|
|
if (szDirectory[2] != _T('\\'))
|
|
return(FALSE);
|
|
|
|
lstrcpyn(szRootDir, szDirectory, 4);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// This function uses a WIN32 function to check for bad directory names
|
|
// Hacky, but works :-)
|
|
BOOL IsDirectoryLexicallyValid(LPCTSTR szPath)
|
|
{
|
|
HANDLE hDir;
|
|
BOOL fRet = FALSE;
|
|
|
|
hDir = FindFirstChangeNotification(szPath, FALSE, FILE_NOTIFY_CHANGE_SECURITY);
|
|
if (hDir == INVALID_HANDLE_VALUE || hDir == NULL)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
}
|
|
else
|
|
{
|
|
fRet = TRUE;
|
|
FindCloseChangeNotification(hDir);
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
// This funciton determines if a volume is NTFS
|
|
BOOL IsVolumeNtfs(LPCTSTR szDisk)
|
|
{
|
|
TCHAR szVolume[MAX_PATH];
|
|
TCHAR szFileSystem[MAX_PATH];
|
|
DWORD lSerial, lMaxLen, lFlags;
|
|
|
|
if (GetVolumeInformation(szDisk, szVolume, MAX_PATH,
|
|
&lSerial, &lMaxLen, &lFlags,
|
|
szFileSystem, MAX_PATH))
|
|
{
|
|
if(!lstrcmpi(szFileSystem, _T("NTFS")))
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// This funciton determines if a the local machine constains at
|
|
// least one NTFS volume
|
|
BOOL AnyNtfsVolumesOnLocalMachine(LPTSTR szFirstNtfsVolume)
|
|
{
|
|
TCHAR szDrives[256];
|
|
TCHAR *lpCurrentDrive;
|
|
DWORD dwLength, dwType;
|
|
|
|
*szFirstNtfsVolume = _T('\0');
|
|
|
|
dwLength = GetLogicalDriveStrings(256, szDrives);
|
|
if (dwLength)
|
|
{
|
|
lpCurrentDrive = szDrives;
|
|
|
|
while (*lpCurrentDrive != _T('\0'))
|
|
{
|
|
// Make sure this is not removable media
|
|
dwType = GetDriveType(lpCurrentDrive);
|
|
if (dwType & DRIVE_FIXED)
|
|
{
|
|
// Fixed media, see if it is NTFS ...
|
|
if (IsVolumeNtfs(lpCurrentDrive))
|
|
{
|
|
lstrcpy(szFirstNtfsVolume, lpCurrentDrive);
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Next drive
|
|
lpCurrentDrive += (lstrlen(lpCurrentDrive) + 1);
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
DWORD GetUnattendedMode(HANDLE hUnattended, LPCTSTR szSubcomponent)
|
|
{
|
|
BOOL b = FALSE;
|
|
TCHAR szLine[1024];
|
|
DWORD dwMode = SubcompUseOcManagerDefault;
|
|
CString csMsg;
|
|
|
|
csMsg = _T("GetUnattendedMode ");
|
|
csMsg += szSubcomponent;
|
|
csMsg += _T("\n");
|
|
DebugOutput((LPCTSTR)csMsg);
|
|
|
|
// Try to get the line of interest
|
|
if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE))
|
|
{
|
|
b = SetupGetLineText(NULL, hUnattended, _T("Components"),
|
|
szSubcomponent, szLine, sizeof(szLine), NULL);
|
|
if (b)
|
|
{
|
|
csMsg = szSubcomponent;
|
|
csMsg += _T(" = ");
|
|
csMsg += szLine;
|
|
csMsg += _T("\n");
|
|
DebugOutput((LPCTSTR)csMsg);
|
|
|
|
// Parse the line
|
|
if (!lstrcmpi(szLine, _T("on")))
|
|
{
|
|
dwMode = SubcompOn;
|
|
}
|
|
else if (!lstrcmpi(szLine, _T("off")))
|
|
{
|
|
dwMode = SubcompOff;
|
|
}
|
|
else if (!lstrcmpi(szLine, _T("default")))
|
|
{
|
|
dwMode = SubcompUseOcManagerDefault;
|
|
}
|
|
}
|
|
else
|
|
DebugOutput(_T("SetupGetLineText failed.\n"));
|
|
}
|
|
|
|
return(dwMode);
|
|
}
|
|
|
|
DWORD GetUnattendedModeFromSetupMode(
|
|
HANDLE hUnattended,
|
|
DWORD dwComponent,
|
|
LPCTSTR szSubcomponent)
|
|
{
|
|
BOOL b = FALSE;
|
|
TCHAR szProperty[64];
|
|
TCHAR szLine[1024];
|
|
DWORD dwMode = SubcompUseOcManagerDefault;
|
|
DWORD dwSetupMode;
|
|
|
|
DebugOutput(_T("GetUnattendedModeFromSetupMode %s"), szSubcomponent);
|
|
|
|
// Try to get the line of interest
|
|
if (hUnattended && (hUnattended != INVALID_HANDLE_VALUE))
|
|
{
|
|
dwSetupMode = GetIMSSetupMode();
|
|
switch (dwSetupMode)
|
|
{
|
|
case IIS_SETUPMODE_MINIMUM:
|
|
case IIS_SETUPMODE_TYPICAL:
|
|
case IIS_SETUPMODE_CUSTOM:
|
|
// One of the fresh modes
|
|
lstrcpy(szProperty, _T("FreshMode"));
|
|
break;
|
|
|
|
case IIS_SETUPMODE_UPGRADEONLY:
|
|
case IIS_SETUPMODE_ADDEXTRACOMPS:
|
|
// One of the upgrade modes
|
|
lstrcpy(szProperty, _T("UpgradeMode"));
|
|
break;
|
|
|
|
case IIS_SETUPMODE_ADDREMOVE:
|
|
case IIS_SETUPMODE_REINSTALL:
|
|
case IIS_SETUPMODE_REMOVEALL:
|
|
// One of the maintenance modes
|
|
lstrcpy(szProperty, _T("MaintanenceMode"));
|
|
break;
|
|
|
|
default:
|
|
// Error! Use defaults
|
|
return(SubcompUseOcManagerDefault);
|
|
}
|
|
|
|
// Get the specified line
|
|
b = SetupGetLineText(
|
|
NULL,
|
|
hUnattended,
|
|
_T("Global"),
|
|
szProperty,
|
|
szLine,
|
|
sizeof(szLine),
|
|
NULL);
|
|
if (b)
|
|
{
|
|
DWORD dwOriginalMode;
|
|
|
|
DebugOutput(_T("%s = %s\n"), szProperty, szLine);
|
|
|
|
// See which setup mode we will end up with
|
|
if (!lstrcmpi(szLine, _T("Minimal")))
|
|
dwSetupMode = IIS_SETUPMODE_MINIMUM;
|
|
else if (!lstrcmpi(szLine, _T("Typical")))
|
|
dwSetupMode = IIS_SETUPMODE_TYPICAL;
|
|
else if (!lstrcmpi(szLine, _T("Custom")))
|
|
dwSetupMode = IIS_SETUPMODE_CUSTOM;
|
|
else if (!lstrcmpi(szLine, _T("AddRemove")))
|
|
dwSetupMode = IIS_SETUPMODE_ADDREMOVE;
|
|
else if (!lstrcmpi(szLine, _T("RemoveAll")))
|
|
dwSetupMode = IIS_SETUPMODE_REMOVEALL;
|
|
else if (!lstrcmpi(szLine, _T("UpgradeOnly")))
|
|
dwSetupMode = IIS_SETUPMODE_UPGRADEONLY;
|
|
else if (!lstrcmpi(szLine, _T("AddExtraComps")))
|
|
dwSetupMode = IIS_SETUPMODE_ADDEXTRACOMPS;
|
|
else
|
|
return(SubcompUseOcManagerDefault);
|
|
|
|
// Get the custom unattended setting
|
|
dwMode = GetUnattendedMode(hUnattended, szSubcomponent);
|
|
|
|
// Do the right thing based on the setup mode
|
|
SetIMSSetupMode(dwSetupMode);
|
|
switch (dwSetupMode)
|
|
{
|
|
case IIS_SETUPMODE_MINIMUM:
|
|
case IIS_SETUPMODE_TYPICAL:
|
|
// Minimum & typical means the same:
|
|
// Install all for SMTP, none for NNTP
|
|
DebugOutput(_T("Unattended mode is MINIMUM/TYPICAL"));
|
|
if (dwComponent == MC_IMS)
|
|
dwMode = SubcompOn;
|
|
else
|
|
dwMode = SubcompOff;
|
|
break;
|
|
|
|
case IIS_SETUPMODE_CUSTOM:
|
|
// For custom we use the custom setting
|
|
DebugOutput(_T("Unattended mode is CUSTOM"));
|
|
break;
|
|
|
|
case IIS_SETUPMODE_UPGRADEONLY:
|
|
// Return the original state
|
|
DebugOutput(_T("Unattended mode is UPGRADEONLY"));
|
|
dwMode = gHelperRoutines.QuerySelectionState(
|
|
gHelperRoutines.OcManagerContext,
|
|
szSubcomponent,
|
|
OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff;
|
|
break;
|
|
|
|
case IIS_SETUPMODE_ADDEXTRACOMPS:
|
|
// Turn it on only if the old state is off and the
|
|
// custom state is on
|
|
DebugOutput(_T("Unattended mode is ADDEXTRACOMPS"));
|
|
dwOriginalMode = gHelperRoutines.QuerySelectionState(
|
|
gHelperRoutines.OcManagerContext,
|
|
szSubcomponent,
|
|
OCSELSTATETYPE_ORIGINAL) ? SubcompOn : SubcompOff;
|
|
if (dwOriginalMode == SubcompOff &&
|
|
dwMode == SubcompOn)
|
|
dwMode = SubcompOn;
|
|
else
|
|
dwMode = dwOriginalMode;
|
|
break;
|
|
|
|
case IIS_SETUPMODE_ADDREMOVE:
|
|
// Return the custom setting
|
|
DebugOutput(_T("Unattended mode is ADDREMOVE"));
|
|
break;
|
|
|
|
case IIS_SETUPMODE_REMOVEALL:
|
|
// Kill everything
|
|
DebugOutput(_T("Unattended mode is REMOVEALL"));
|
|
dwMode = SubcompOff;
|
|
break;
|
|
}
|
|
|
|
DebugOutput(_T("Unattended state for %s is %s"),
|
|
szSubcomponent,
|
|
(dwMode == SubcompOn)?_T("ON"):_T("OFF"));
|
|
}
|
|
else
|
|
DebugOutput(_T("SetupGetLineText failed (%u).\n"), GetLastError());
|
|
}
|
|
|
|
return(dwMode);
|
|
}
|
|
|
|
BOOL DetectExistingSmtpServers()
|
|
{
|
|
// Detect other mail servers
|
|
CRegKey regMachine = HKEY_LOCAL_MACHINE;
|
|
|
|
// System\CurrentControlSet\Services\MsExchangeIMC\Parameters
|
|
CRegKey regSMTPParam( regMachine, REG_EXCHANGEIMCPARAMETERS, KEY_READ );
|
|
if ((HKEY) regSMTPParam )
|
|
{
|
|
CString csCaption;
|
|
|
|
DebugOutput(_T("IMC detected, suppressing SMTP"));
|
|
|
|
if (!theApp.m_fIsUnattended && !theApp.m_fNTGuiMode)
|
|
{
|
|
MyLoadString(IDS_MESSAGEBOX_TEXT, csCaption);
|
|
PopupOkMessageBox(IDS_SUPPRESS_SMTP, csCaption);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
DebugOutput(_T("No other SMTP servers detected, installing IMS."));
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL DetectExistingIISADMIN()
|
|
{
|
|
//
|
|
// Detect is IISADMIN service exists
|
|
//
|
|
// This is to make sure we don't do any metabase operation if
|
|
// IISADMIN doesn't exists, especially in the uninstall cases.
|
|
//
|
|
DWORD dwStatus = 0;
|
|
dwStatus = InetQueryServiceStatus(SZ_MD_SERVICENAME);
|
|
if (0 == dwStatus)
|
|
{
|
|
// some kind of error occur during InetQueryServiceStatus.
|
|
DebugOutput(_T("DetectExistingIISADMIN() return FALSE\n"));
|
|
return (FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL InsertSetupString( LPCSTR REG_PARAMETERS )
|
|
{
|
|
// set up registry values
|
|
CRegKey regMachine = HKEY_LOCAL_MACHINE;
|
|
|
|
// System\CurrentControlSet\Services\NNTPSVC\Parameters
|
|
CRegKey regParam( (LPCTSTR) REG_PARAMETERS, regMachine );
|
|
if ((HKEY) regParam) {
|
|
regParam.SetValue( _T("MajorVersion"), (DWORD)STAXNT5MAJORVERSION );
|
|
regParam.SetValue( _T("MinorVersion"), (DWORD)STAXNT5MINORVERSION );
|
|
regParam.SetValue( _T("InstallPath"), theApp.m_csPathInetsrv );
|
|
|
|
switch (theApp.m_eNTOSType) {
|
|
case OT_NTW:
|
|
regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5WKSB3 );
|
|
break;
|
|
|
|
default:
|
|
_ASSERT(!"Unknown OS type");
|
|
// Fall through
|
|
|
|
case OT_NTS:
|
|
case OT_PDC_OR_BDC:
|
|
case OT_PDC:
|
|
case OT_BDC:
|
|
regParam.SetValue( _T("SetupString"), REG_SETUP_STRING_NT5SRVB3 );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Scans a multi-sz and finds the first occurrence of the
|
|
// specified string
|
|
LPTSTR ScanMultiSzForSz(LPTSTR szMultiSz, LPTSTR szSz)
|
|
{
|
|
LPTSTR lpTemp = szMultiSz;
|
|
|
|
do
|
|
{
|
|
if (!lstrcmpi(lpTemp, szSz))
|
|
return(lpTemp);
|
|
|
|
lpTemp += lstrlen(lpTemp);
|
|
lpTemp++;
|
|
|
|
} while (*lpTemp != _T('\0'));
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// Removes the said string from a MultiSz
|
|
// This places a lot of faith in the caller!
|
|
void RemoveSzFromMultiSz(LPTSTR szSz)
|
|
{
|
|
LPTSTR lpScan = szSz;
|
|
TCHAR tcLastChar;
|
|
|
|
lpScan += lstrlen(szSz);
|
|
lpScan++;
|
|
|
|
tcLastChar = _T('x');
|
|
while ((tcLastChar != _T('\0')) ||
|
|
(*lpScan != _T('\0')))
|
|
{
|
|
tcLastChar = *lpScan;
|
|
*szSz++ = *lpScan++;
|
|
}
|
|
|
|
*szSz++ = _T('\0');
|
|
|
|
// Properly terminate it if it's the last one
|
|
if (*lpScan == _T('\0'))
|
|
*szSz = _T('\0');
|
|
}
|
|
|
|
// This walks the multi-sz and returns a pointer between
|
|
// the last string of a multi-sz and the second terminating
|
|
// NULL
|
|
LPTSTR GetEndOfMultiSz(LPTSTR szMultiSz)
|
|
{
|
|
LPTSTR lpTemp = szMultiSz;
|
|
|
|
do
|
|
{
|
|
lpTemp += lstrlen(lpTemp);
|
|
lpTemp++;
|
|
|
|
} while (*lpTemp != _T('\0'));
|
|
|
|
return(lpTemp);
|
|
}
|
|
|
|
// This appends a string to the end of a multi-sz
|
|
// The buffer must be long enough
|
|
BOOL AppendSzToMultiSz(LPTSTR szMultiSz, LPTSTR szSz, DWORD dwMaxSize)
|
|
{
|
|
LPTSTR szTemp = szMultiSz;
|
|
DWORD dwLength = lstrlen(szSz);
|
|
|
|
// If the string is empty, do not append!
|
|
if (*szMultiSz == _T('\0') &&
|
|
*(szMultiSz + 1) == _T('\0'))
|
|
szTemp = szMultiSz;
|
|
else
|
|
{
|
|
szTemp = GetEndOfMultiSz(szMultiSz);
|
|
dwLength += (DWORD)(szTemp - szMultiSz);
|
|
}
|
|
|
|
if (dwLength >= dwMaxSize)
|
|
return(FALSE);
|
|
|
|
lstrcpy(szTemp, szSz);
|
|
szMultiSz += dwLength;
|
|
*szMultiSz = _T('\0');
|
|
*(szMultiSz + 1) = _T('\0');
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL AddServiceToDispatchList(LPTSTR szServiceName)
|
|
{
|
|
TCHAR szMultiSz[4096];
|
|
DWORD dwSize = 4096;
|
|
|
|
CRegKey RegInetInfo(REG_INETINFOPARAMETERS, HKEY_LOCAL_MACHINE);
|
|
if ((HKEY)RegInetInfo)
|
|
{
|
|
// Default to empty string if not exists
|
|
szMultiSz[0] = _T('\0');
|
|
szMultiSz[1] = _T('\0');
|
|
|
|
if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR)
|
|
{
|
|
// Walk the list to see if the value is already there
|
|
if (ScanMultiSzForSz(szMultiSz, szServiceName))
|
|
return(TRUE);
|
|
}
|
|
|
|
// Create the value and add it to the list
|
|
if (!AppendSzToMultiSz(szMultiSz, szServiceName, dwSize))
|
|
return(FALSE);
|
|
|
|
// Get the size of the new Multi-sz
|
|
dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1;
|
|
|
|
// Write the value back to the registry
|
|
if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR)
|
|
return(TRUE);
|
|
}
|
|
|
|
// If the InetInfo key is not here, there isn't much we can do ...
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOL RemoveServiceFromDispatchList(LPTSTR szServiceName)
|
|
{
|
|
TCHAR szMultiSz[4096];
|
|
DWORD dwSize = 4096;
|
|
LPTSTR szTemp;
|
|
BOOL fFound = FALSE;
|
|
|
|
CRegKey RegInetInfo(HKEY_LOCAL_MACHINE, REG_INETINFOPARAMETERS);
|
|
if ((HKEY)RegInetInfo)
|
|
{
|
|
if (RegInetInfo.QueryValue(SZ_INETINFODISPATCH, szMultiSz, dwSize) == NO_ERROR)
|
|
{
|
|
// Walk the list to see if the value is already there
|
|
while (szTemp = ScanMultiSzForSz(szMultiSz, szServiceName))
|
|
{
|
|
RemoveSzFromMultiSz(szTemp);
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
// Write the value back to the registry if necessary, note we
|
|
// will indicate success if the string is not found
|
|
if (!fFound)
|
|
return(TRUE);
|
|
|
|
// Get the size of the new Multi-sz
|
|
dwSize = (DWORD)(GetEndOfMultiSz(szMultiSz) - szMultiSz) + 1;
|
|
|
|
// Write the value back to the registry
|
|
if (RegInetInfo.SetValue(SZ_INETINFODISPATCH, szMultiSz, dwSize * (DWORD) sizeof(TCHAR)) == NO_ERROR)
|
|
return(TRUE);
|
|
}
|
|
|
|
// If the InetInfo key is not here, there isn't much we can do ...
|
|
return(FALSE);
|
|
}
|
|
|
|
void GetIISProgramGroup(CString &csGroupName, BOOL fIsMcisGroup)
|
|
{
|
|
TCHAR szName[_MAX_PATH];
|
|
CString csTempName;
|
|
UINT uType, uSize;
|
|
|
|
if (fIsMcisGroup) {
|
|
csGroupName = "";
|
|
} else {
|
|
// Get the NT program group name from the private data
|
|
uSize = _MAX_PATH * sizeof(TCHAR);
|
|
#if 0
|
|
//11/30/98 - Don't even try to do this, just get the default
|
|
if ((gHelperRoutines.GetPrivateData(gHelperRoutines.OcManagerContext,
|
|
_T("iis"),
|
|
_T("NTProgramGroup"),
|
|
(LPVOID)szName,
|
|
&uSize,
|
|
&uType) != NO_ERROR) ||
|
|
(uType != REG_SZ))
|
|
#endif
|
|
{
|
|
// We use the default group name
|
|
MyLoadString(IDS_DEFAULT_NT_PROGRAM_GROUP, csTempName);
|
|
lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH));
|
|
csTempName.ReleaseBuffer();
|
|
}
|
|
csGroupName = szName;
|
|
csGroupName += _T("\\");
|
|
|
|
// Get the IIS program group name from the private data
|
|
uSize = _MAX_PATH * sizeof(TCHAR);
|
|
#if 0
|
|
//11/30/98 - Don't even try to do this, just get the default
|
|
if ((gHelperRoutines.GetPrivateData(gHelperRoutines.OcManagerContext,
|
|
_T("iis"),
|
|
_T("IISProgramGroup"),
|
|
(LPVOID)szName,
|
|
&uSize,
|
|
&uType) != NO_ERROR) ||
|
|
(uType != REG_SZ))
|
|
#endif
|
|
{
|
|
// We use the default group name
|
|
MyLoadString(IDS_DEFAULT_IIS_PROGRAM_GROUP, csTempName);
|
|
lstrcpy(szName, csTempName.GetBuffer(_MAX_PATH));
|
|
csTempName.ReleaseBuffer();
|
|
}
|
|
csGroupName += szName;
|
|
}
|
|
}
|
|
|
|
void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath);
|
|
|
|
BOOL GetFullPathToProgramGroup(DWORD dwMainComponent, CString &csGroupName, BOOL fIsMcisGroup)
|
|
{
|
|
// add items to the program group
|
|
CString csTemp;
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
// Get the program group name from the private data
|
|
GetIISProgramGroup(csTemp, fIsMcisGroup);
|
|
|
|
// Get the system path to this menu item
|
|
MyGetGroupPath((LPCTSTR)csTemp, szPath);
|
|
csGroupName = szPath;
|
|
|
|
// Load up the resource string for the group
|
|
if (fIsMcisGroup)
|
|
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
|
|
else
|
|
MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp);
|
|
|
|
// Build the program group
|
|
csGroupName += csTemp;
|
|
|
|
DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL GetFullPathToAdminGroup(DWORD dwMainComponent, CString &csGroupName)
|
|
{
|
|
// add items to the program group
|
|
CString csTemp;
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
// Get the program group name from the private data
|
|
MyLoadString( IDS_PROGGROUP_ADMINTOOLS, csTemp );
|
|
|
|
// Get the system path to this menu item
|
|
MyGetGroupPath((LPCTSTR)csTemp, szPath);
|
|
csGroupName = szPath;
|
|
|
|
DebugOutput(_T("Program group loaded: %s"), (LPCTSTR)csGroupName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveProgramGroupIfEmpty(DWORD dwMainComponent, BOOL fIsMcisGroup)
|
|
{
|
|
// add items to the program group
|
|
CString csGroupName;
|
|
CString csTemp;
|
|
TCHAR szPath[MAX_PATH];
|
|
BOOL fResult;
|
|
|
|
// Get the program group name from the private data
|
|
GetIISProgramGroup(csTemp, fIsMcisGroup);
|
|
|
|
// Get the system path to this menu item
|
|
MyGetGroupPath((LPCTSTR)csTemp, szPath);
|
|
csGroupName = szPath;
|
|
|
|
// Load up the resource string for the group
|
|
if (fIsMcisGroup)
|
|
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
|
|
else
|
|
MyLoadString(dwMainComponent == MC_IMS?IDS_PROGGROUP_MAIL:IDS_PROGGROUP_NEWS, csTemp);
|
|
|
|
// Build the program group
|
|
csGroupName += csTemp;
|
|
|
|
DebugOutput(_T("Removing Program group: %s"), (LPCTSTR)csGroupName);
|
|
|
|
fResult = RemoveDirectory((LPCTSTR)csGroupName);
|
|
if (fResult && fIsMcisGroup)
|
|
{
|
|
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0);
|
|
|
|
csGroupName = szPath;
|
|
MyLoadString(IDS_MCIS_2_0, csTemp);
|
|
csGroupName += csTemp;
|
|
fResult = RemoveDirectory((LPCTSTR)csGroupName);
|
|
}
|
|
if (fResult)
|
|
{
|
|
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, (LPCTSTR)csGroupName, 0);
|
|
}
|
|
|
|
return(fResult);
|
|
}
|
|
|
|
BOOL CreateInternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, int dwUrlId, BOOL fIsMcisGroup)
|
|
{
|
|
CString csItemPath;
|
|
CString csDisplayName;
|
|
CString csUrl;
|
|
HANDLE hShortcut;
|
|
DWORD dwLength, dwWritten;
|
|
char szBuffer[1000];
|
|
char szContent[1024];
|
|
BOOL fRet = FALSE;
|
|
|
|
MyLoadString(dwDisplayNameId, csDisplayName);
|
|
MyLoadString(dwUrlId, csUrl);
|
|
|
|
// Build the full path to the program link
|
|
GetFullPathToProgramGroup(dwMainComponent, csItemPath, fIsMcisGroup);
|
|
|
|
// Make sure our directory is there
|
|
CreateLayerDirectory(csItemPath);
|
|
|
|
csItemPath += _T("\\");
|
|
csItemPath += csDisplayName;
|
|
csItemPath += _T(".url");
|
|
|
|
DebugOutput(_T("Creating shortcut file: %s"), (LPCTSTR)csItemPath);
|
|
|
|
// Create the file in the directory
|
|
hShortcut = CreateFile((LPCTSTR)csItemPath,
|
|
GENERIC_WRITE, 0,
|
|
NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
if (hShortcut == INVALID_HANDLE_VALUE)
|
|
{
|
|
DebugOutput(_T("CreateFile failed with error %u\n"), GetLastError());
|
|
return(fRet);
|
|
}
|
|
|
|
// Convert the Unicode string to ANSI
|
|
if (WideCharToMultiByte(CP_ACP, 0,
|
|
(LPCTSTR)csUrl,
|
|
-1,
|
|
szBuffer,
|
|
sizeof(szBuffer),
|
|
NULL, NULL))
|
|
{
|
|
dwLength = sprintf(szContent, "[InternetShortcut]\nURL=http://localhost/%s\n", szBuffer);
|
|
DebugOutput(_T(" Shortcut: %s"), (LPCTSTR)csUrl);
|
|
if (dwLength)
|
|
{
|
|
if (WriteFile(hShortcut, szContent, dwLength, &dwWritten, NULL) &&
|
|
(dwWritten == dwLength))
|
|
{
|
|
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugOutput(_T("WideCharToMultiByte failed with error %u\n"), GetLastError());
|
|
}
|
|
CloseHandle(hShortcut);
|
|
return(fRet);
|
|
}
|
|
|
|
#if 0 // Dead code
|
|
BOOL CreateNt5InternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, int dwUrlId)
|
|
{
|
|
CString csItemPath;
|
|
CString csDisplayName;
|
|
CString csUrl;
|
|
HANDLE hShortcut;
|
|
DWORD dwLength, dwWritten;
|
|
char szBuffer[1000];
|
|
char szContent[1024];
|
|
BOOL fRet = FALSE;
|
|
|
|
MyLoadString(dwDisplayNameId, csDisplayName);
|
|
MyLoadString(dwUrlId, csUrl);
|
|
|
|
// Build the full path to the program link
|
|
GetFullPathToAdminGroup(dwMainComponent, csItemPath);
|
|
|
|
// Make sure our directory is there
|
|
CreateLayerDirectory(csItemPath);
|
|
|
|
csItemPath += _T("\\");
|
|
csItemPath += csDisplayName;
|
|
csItemPath += _T(".url");
|
|
|
|
DebugOutput(_T("Creating shortcut file: %s"), (LPCTSTR)csItemPath);
|
|
|
|
// Create the file in the directory
|
|
hShortcut = CreateFile((LPCTSTR)csItemPath,
|
|
GENERIC_WRITE, 0,
|
|
NULL, CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL);
|
|
if (hShortcut == INVALID_HANDLE_VALUE)
|
|
{
|
|
DebugOutput(_T("CreateFile failed with error %u\n"), GetLastError());
|
|
return(fRet);
|
|
}
|
|
|
|
// Convert the Unicode string to ANSI
|
|
if (WideCharToMultiByte(CP_ACP, 0,
|
|
(LPCTSTR)csUrl,
|
|
-1,
|
|
szBuffer,
|
|
sizeof(szBuffer),
|
|
NULL, NULL))
|
|
{
|
|
dwLength = sprintf(szContent, "[InternetShortcut]\nURL=http://localhost/%s\n", szBuffer);
|
|
DebugOutput(_T(" Shortcut: %s"), (LPCTSTR)csUrl);
|
|
if (dwLength)
|
|
{
|
|
if (WriteFile(hShortcut, szContent, dwLength, &dwWritten, NULL) &&
|
|
(dwWritten == dwLength))
|
|
{
|
|
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugOutput(_T("WideCharToMultiByte failed with error %u\n"), GetLastError());
|
|
}
|
|
CloseHandle(hShortcut);
|
|
return(fRet);
|
|
}
|
|
#endif
|
|
|
|
BOOL RemoveInternetShortcut(DWORD dwMainComponent, int dwDisplayNameId, BOOL fIsMcisGroup)
|
|
{
|
|
CString csItemPath;
|
|
CString csDisplayName;
|
|
|
|
MyLoadString(dwDisplayNameId, csDisplayName);
|
|
|
|
// Build the full path to the program link
|
|
GetFullPathToProgramGroup(dwMainComponent, csItemPath, fIsMcisGroup);
|
|
csItemPath += _T("\\");
|
|
csItemPath += csDisplayName;
|
|
csItemPath += _T(".url");
|
|
|
|
DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath);
|
|
|
|
DeleteFile((LPCTSTR)csItemPath);
|
|
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
|
|
|
|
RemoveProgramGroupIfEmpty(dwMainComponent, fIsMcisGroup);
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveNt5InternetShortcut(DWORD dwMainComponent, int dwDisplayNameId)
|
|
{
|
|
CString csItemPath;
|
|
CString csDisplayName;
|
|
|
|
MyLoadString(dwDisplayNameId, csDisplayName);
|
|
|
|
// Build the full path to the program link
|
|
GetFullPathToAdminGroup(dwMainComponent, csItemPath);
|
|
csItemPath += _T("\\");
|
|
csItemPath += csDisplayName;
|
|
csItemPath += _T(".url");
|
|
|
|
DebugOutput(_T("Removing shortcut file: %s"), (LPCTSTR)csItemPath);
|
|
|
|
DeleteFile((LPCTSTR)csItemPath);
|
|
SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, (LPCTSTR)csItemPath, 0);
|
|
|
|
#if 0
|
|
RemoveProgramGroupIfEmpty(dwMainComponent,FALSE);
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveMCIS10MailProgramGroup()
|
|
{
|
|
CString csGroupName;
|
|
CString csNiceName;
|
|
|
|
MyLoadString(IDS_PROGGROUP_MCIS10_MAIL, csGroupName);
|
|
|
|
MyLoadString(IDS_PROGITEM_MCIS10_MAIL_STARTPAGE, csNiceName);
|
|
MyDeleteItem(csGroupName, csNiceName);
|
|
|
|
MyLoadString(IDS_PROGITEM_MCIS10_MAIL_WEBADMIN, csNiceName);
|
|
MyDeleteItemEx(csGroupName, csNiceName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveMCIS10NewsProgramGroup()
|
|
{
|
|
CString csGroupName;
|
|
CString csNiceName;
|
|
|
|
// BINLIN:
|
|
// BUGBUG: need to figure out how to get
|
|
// the old MCIS 1.0 program group path
|
|
MyLoadString(IDS_PROGGROUP_MCIS10_NEWS, csGroupName);
|
|
|
|
MyLoadString(IDS_PROGITEM_MCIS10_NEWS_STARTPAGE, csNiceName);
|
|
MyDeleteItem(csGroupName, csNiceName);
|
|
|
|
MyLoadString(IDS_PROGITEM_MCIS10_NEWS_WEBADMIN, csNiceName);
|
|
MyDeleteItemEx(csGroupName, csNiceName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL CreateUninstallEntries(LPCTSTR szInfFile, LPCTSTR szDisplayName)
|
|
{
|
|
// We have one or more components installed, so we
|
|
// will create the Add/Remove options in the control panel
|
|
CString csUninstall;
|
|
CString AddRemoveRegPath = REG_UNINSTALL;
|
|
|
|
AddRemoveRegPath += _T("\\");
|
|
AddRemoveRegPath += szInfFile;
|
|
csUninstall = theApp.m_csSysDir + _T("\\sysocmgr.exe /i:");
|
|
csUninstall += theApp.m_csSysDir;
|
|
csUninstall += _T("\\setup\\");
|
|
csUninstall += szInfFile;
|
|
|
|
CRegKey regAddRemove(AddRemoveRegPath, HKEY_LOCAL_MACHINE);
|
|
if ( (HKEY)regAddRemove )
|
|
{
|
|
regAddRemove.SetValue( _T("DisplayName"), szDisplayName );
|
|
regAddRemove.SetValue( _T("UninstallString"), csUninstall );
|
|
}
|
|
else
|
|
return(FALSE);
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveUninstallEntries(LPCTSTR szInfFile)
|
|
{
|
|
// All components are removed, we will have to remove
|
|
// the Add/Remove option from the control panel
|
|
CRegKey regUninstall( HKEY_LOCAL_MACHINE, REG_UNINSTALL);
|
|
if ((HKEY)regUninstall)
|
|
regUninstall.DeleteTree(szInfFile);
|
|
else
|
|
return(FALSE);
|
|
return(TRUE);
|
|
}
|
|
|
|
void SetProductName()
|
|
{
|
|
// The product name is rather complicated ...
|
|
CString csProdName, csAppName;
|
|
|
|
if (theApp.m_hInfHandle[MC_IMS] && theApp.m_hInfHandle[MC_INS])
|
|
{
|
|
MyLoadString(IDS_MAIL_AND_NEWS, csProdName);
|
|
MyLoadString(IDS_MAIL_AND_NEWS_SETUP, csAppName);
|
|
}
|
|
else if (theApp.m_hInfHandle[MC_IMS])
|
|
{
|
|
// NT5 - For SMTP, use the default K2 name
|
|
if (theApp.m_fIsMcis)
|
|
{
|
|
MyLoadString(IDS_MCIS_MAIL_ONLY, csProdName);
|
|
MyLoadString(IDS_MCIS_MAIL_ONLY_SETUP, csAppName);
|
|
}
|
|
else
|
|
{
|
|
MyLoadString(IDS_MAIL_ONLY, csProdName);
|
|
MyLoadString(IDS_MAIL_ONLY_SETUP, csAppName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// NT5 - Use m_eNTOSType.
|
|
// TODO: Need to figure out the name for NT5 Server and NT5 Workstation NNTP service
|
|
if (theApp.m_eNTOSType == OT_NTS)
|
|
{
|
|
MyLoadString(IDS_MCIS_NEWS_ONLY, csProdName);
|
|
MyLoadString(IDS_MCIS_NEWS_ONLY_SETUP, csAppName);
|
|
}
|
|
else
|
|
{
|
|
MyLoadString(IDS_NEWS_ONLY, csProdName);
|
|
MyLoadString(IDS_NEWS_ONLY_SETUP, csAppName);
|
|
}
|
|
}
|
|
|
|
// Setup the name for the IIS Program group
|
|
MyLoadString(IDS_MAIL_AND_NEWS, theApp.m_csGroupName);
|
|
|
|
theApp.m_csProdName = csProdName;
|
|
theApp.m_csAppName = csAppName;
|
|
}
|
|
|
|
HRESULT MyCreateLink(LPCTSTR lpszPath, LPCTSTR lpszArgs, LPCTSTR lpszTarget, LPCTSTR lpszDir)
|
|
{
|
|
HRESULT hres;
|
|
IShellLink* pShellLink;
|
|
|
|
CoInitialize(NULL);
|
|
//CoInitialize must be called before this
|
|
// Get a pointer to the IShellLink interface.
|
|
hres = CoCreateInstance( CLSID_ShellLink,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink,
|
|
(LPVOID*)&pShellLink);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IPersistFile* pPersistFile;
|
|
|
|
// Set the path to the shortcut target, and add the description.
|
|
pShellLink->SetPath(lpszPath);
|
|
pShellLink->SetArguments(lpszArgs);
|
|
pShellLink->SetWorkingDirectory(lpszDir);
|
|
|
|
|
|
// Query IShellLink for the IPersistFile interface for saving the
|
|
// shortcut in persistent storage.
|
|
hres = pShellLink->QueryInterface(IID_IPersistFile, (LPVOID*)&pPersistFile);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
WCHAR wsz[MAX_PATH];
|
|
|
|
#if defined(UNICODE) || defined(_UNICODE)
|
|
lstrcpy(wsz, lpszTarget);
|
|
#else
|
|
// Ensure that the string is WCHAR.
|
|
MultiByteToWideChar( CP_ACP,
|
|
0,
|
|
lpszTarget,
|
|
-1,
|
|
wsz,
|
|
MAX_PATH);
|
|
#endif
|
|
|
|
// Save the link by calling IPersistFile::Save.
|
|
hres = pPersistFile->Save(wsz, TRUE);
|
|
|
|
pPersistFile->Release();
|
|
}
|
|
|
|
pShellLink->Release();
|
|
}
|
|
CoUninitialize();
|
|
return hres;
|
|
}
|
|
|
|
BOOL MyDeleteLink(LPTSTR lpszShortcut)
|
|
{
|
|
TCHAR szFile[_MAX_PATH];
|
|
SHFILEOPSTRUCT fos;
|
|
|
|
ZeroMemory(szFile, sizeof(szFile));
|
|
lstrcpy(szFile, lpszShortcut);
|
|
|
|
// only call SHFileOperation if this file/link exists
|
|
if (0xFFFFFFFF != GetFileAttributes(szFile))
|
|
{
|
|
ZeroMemory(&fos, sizeof(fos));
|
|
fos.hwnd = NULL;
|
|
fos.wFunc = FO_DELETE;
|
|
fos.pFrom = szFile;
|
|
fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
|
|
SHFileOperation(&fos);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void MyGetGroupPath(LPCTSTR szGroupName, LPTSTR szPath)
|
|
{
|
|
int nLen = 0;
|
|
LPITEMIDLIST pidlPrograms;
|
|
|
|
szPath[0] = NULL;
|
|
|
|
SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlPrograms);
|
|
|
|
SHGetPathFromIDList(pidlPrograms, szPath);
|
|
nLen = lstrlen(szPath);
|
|
if (szGroupName) {
|
|
if (nLen == 0 || szPath[nLen-1] != _T('\\'))
|
|
lstrcat(szPath, _T("\\"));
|
|
lstrcat(szPath, szGroupName);
|
|
}
|
|
return;
|
|
}
|
|
|
|
BOOL MyAddGroup(LPCTSTR szGroupName)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
CString csPath;
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
csPath = szPath;
|
|
CreateLayerDirectory(csPath);
|
|
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, szPath, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL MyIsGroupEmpty(LPCTSTR szGroupName)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szFile[MAX_PATH];
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE hFind;
|
|
BOOL bFindFile = TRUE;
|
|
BOOL fReturn = TRUE;
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
|
|
lstrcpy(szFile, szPath);
|
|
lstrcat(szFile, _T("\\*.*"));
|
|
|
|
hFind = FindFirstFile(szFile, &FindData);
|
|
if (INVALID_HANDLE_VALUE != hFind)
|
|
{
|
|
while (bFindFile)
|
|
{
|
|
if(*(FindData.cFileName) != _T('.'))
|
|
{
|
|
fReturn = FALSE;
|
|
break;
|
|
}
|
|
|
|
//find the next file
|
|
bFindFile = FindNextFile(hFind, &FindData);
|
|
}
|
|
|
|
FindClose(hFind);
|
|
}
|
|
|
|
return fReturn;
|
|
}
|
|
|
|
BOOL MyDeleteGroup(LPCTSTR szGroupName)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
TCHAR szFile[MAX_PATH];
|
|
SHFILEOPSTRUCT fos;
|
|
WIN32_FIND_DATA FindData;
|
|
HANDLE hFind;
|
|
BOOL bFindFile = TRUE;
|
|
BOOL fResult;
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
|
|
//we can't remove a directory that is not empty, so we need to empty this one
|
|
|
|
lstrcpy(szFile, szPath);
|
|
lstrcat(szFile, _T("\\*.*"));
|
|
|
|
ZeroMemory(&fos, sizeof(fos));
|
|
fos.hwnd = NULL;
|
|
fos.wFunc = FO_DELETE;
|
|
fos.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
|
|
|
|
hFind = FindFirstFile(szFile, &FindData);
|
|
if (INVALID_HANDLE_VALUE != hFind)
|
|
{
|
|
while (bFindFile)
|
|
{
|
|
if(*(FindData.cFileName) != _T('.'))
|
|
{
|
|
//copy the path and file name to our temp buffer
|
|
lstrcpy(szFile, szPath);
|
|
lstrcat(szFile, _T("\\"));
|
|
lstrcat(szFile, FindData.cFileName);
|
|
//add a second NULL because SHFileOperation is looking for this
|
|
lstrcat(szFile, _T("\0"));
|
|
|
|
//delete the file
|
|
fos.pFrom = szFile;
|
|
SHFileOperation(&fos);
|
|
}
|
|
//find the next file
|
|
bFindFile = FindNextFile(hFind, &FindData);
|
|
}
|
|
FindClose(hFind);
|
|
}
|
|
|
|
fResult = RemoveDirectory(szPath);
|
|
if (fResult)
|
|
{
|
|
SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, szPath, 0);
|
|
}
|
|
|
|
return(fResult);
|
|
}
|
|
|
|
void MyAddItem(LPCTSTR szGroupName, LPCTSTR szItemDesc, LPCTSTR szProgram, LPCTSTR szArgs, LPCTSTR szDir)
|
|
{
|
|
TCHAR szPath[_MAX_PATH];
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
if (!IsFileExist(szPath))
|
|
MyAddGroup(szGroupName);
|
|
|
|
lstrcat(szPath, _T("\\"));
|
|
lstrcat(szPath, szItemDesc);
|
|
lstrcat(szPath, _T(".lnk"));
|
|
|
|
MyCreateLink(szProgram, szArgs, szPath, szDir);
|
|
}
|
|
|
|
void MyDeleteItem(LPCTSTR szGroupName, LPCTSTR szAppName)
|
|
{
|
|
TCHAR szPath[_MAX_PATH];
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
lstrcat(szPath, _T("\\"));
|
|
lstrcat(szPath, szAppName);
|
|
lstrcat(szPath, _T(".lnk"));
|
|
|
|
MyDeleteLink(szPath);
|
|
|
|
if (MyIsGroupEmpty(szGroupName))
|
|
MyDeleteGroup(szGroupName);
|
|
}
|
|
|
|
// Use to delete files with extension other than ".lnk"
|
|
void MyDeleteItemEx(LPCTSTR szGroupName, LPCTSTR szAppName)
|
|
{
|
|
TCHAR szPath[_MAX_PATH];
|
|
|
|
MyGetGroupPath(szGroupName, szPath);
|
|
lstrcat(szPath, _T("\\"));
|
|
lstrcat(szPath, szAppName);
|
|
|
|
MyDeleteLink(szPath);
|
|
|
|
if (MyIsGroupEmpty(szGroupName))
|
|
MyDeleteGroup(szGroupName);
|
|
}
|
|
|
|
BOOL CreateISMLink()
|
|
{
|
|
// add items to the program group
|
|
CString csGroupName;
|
|
CString csNiceName;
|
|
CString csArgs;
|
|
CString csTemp;
|
|
CString csMmc;
|
|
|
|
DebugOutput(_T("Creating ISM link ..."));
|
|
|
|
// Get the program group name from the private data
|
|
GetIISProgramGroup(csGroupName, TRUE);
|
|
|
|
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
|
|
MyLoadString(IDS_MMC, csMmc);
|
|
MyLoadString(IDS_ITEMPATH_ISM, csArgs);
|
|
|
|
// Build the program group
|
|
csGroupName += csTemp;
|
|
|
|
MyLoadString(IDS_PROGITEM_ISM, csNiceName);
|
|
MyAddItem(csGroupName, csNiceName, csMmc, csArgs, NULL);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemoveISMLink()
|
|
{
|
|
// add items to the program group
|
|
CString csGroupName;
|
|
CString csNiceName;
|
|
CString csTemp;
|
|
|
|
DebugOutput(_T("Removing ISM link ..."));
|
|
|
|
// Get the program group name from the private data
|
|
GetIISProgramGroup(csGroupName, TRUE);
|
|
|
|
MyLoadString(IDS_PROGGROUP_MCIS_MAIL_AND_NEWS, csTemp);
|
|
|
|
// Build the program group
|
|
csGroupName += csTemp;
|
|
|
|
MyLoadString(IDS_PROGITEM_ISM, csNiceName);
|
|
MyDeleteItem(csGroupName, csNiceName);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
class CDwordQueue
|
|
{
|
|
private:
|
|
DWORD dwInstances;
|
|
DWORD dwDequeuePtr;
|
|
DWORD dwMaxInstances;
|
|
DWORD_PTR *rgdwInstanceIds;
|
|
|
|
public:
|
|
CDwordQueue()
|
|
{
|
|
dwInstances = 0;
|
|
dwMaxInstances = 0;
|
|
dwDequeuePtr = 0;
|
|
rgdwInstanceIds = NULL;
|
|
}
|
|
~CDwordQueue()
|
|
{
|
|
if (rgdwInstanceIds)
|
|
{
|
|
LocalFree(rgdwInstanceIds);
|
|
rgdwInstanceIds = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL QueueDword(DWORD_PTR dwValue);
|
|
BOOL DequeueDword(PDWORD_PTR pdwValue);
|
|
|
|
};
|
|
|
|
BOOL CDwordQueue::QueueDword(DWORD_PTR dwValue)
|
|
{
|
|
if (dwInstances == dwMaxInstances)
|
|
{
|
|
if (!dwMaxInstances)
|
|
dwMaxInstances = 1024;
|
|
else
|
|
dwMaxInstances <<= 1;
|
|
|
|
if (rgdwInstanceIds)
|
|
{
|
|
DWORD_PTR *pdwNew;
|
|
|
|
pdwNew = (PDWORD_PTR)LocalReAlloc(rgdwInstanceIds,
|
|
dwMaxInstances * sizeof(DWORD_PTR),
|
|
0);
|
|
if (!pdwNew)
|
|
return(FALSE);
|
|
|
|
rgdwInstanceIds = pdwNew;
|
|
}
|
|
else
|
|
{
|
|
rgdwInstanceIds = (PDWORD_PTR)LocalAlloc(0,
|
|
dwMaxInstances * sizeof(DWORD_PTR));
|
|
if (!rgdwInstanceIds)
|
|
return(FALSE);
|
|
}
|
|
}
|
|
rgdwInstanceIds[dwInstances++] = dwValue;
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL CDwordQueue::DequeueDword(PDWORD_PTR pdwValue)
|
|
{
|
|
if (dwDequeuePtr >= dwInstances)
|
|
return(FALSE);
|
|
*pdwValue = rgdwInstanceIds[dwDequeuePtr++];
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL UpdateServiceParameters(LPCTSTR szServiceName)
|
|
{
|
|
CString csKeyName;
|
|
CMDKey mKey;
|
|
CString csInstance;
|
|
CString csParameters;
|
|
CDwordQueue dwqQueue;
|
|
|
|
csKeyName = _T("LM/");
|
|
csKeyName += szServiceName;
|
|
|
|
mKey.OpenNode((LPCTSTR)csKeyName);
|
|
if ( (METADATA_HANDLE)mKey )
|
|
{
|
|
CMDKeyIter enumKey(mKey);
|
|
|
|
enumKey.Reset();
|
|
|
|
// Process all instances
|
|
while (enumKey.Next(&csInstance) == NO_ERROR)
|
|
{
|
|
if (dwqQueue.QueueDword(_ttol((LPCTSTR)csInstance)))
|
|
DebugOutput(_T("Read instance #%s"), (LPCTSTR)csInstance);
|
|
else
|
|
DebugOutput(_T("Error allocating buffer, skipping remaining instances"));
|
|
}
|
|
}
|
|
|
|
mKey.Close();
|
|
|
|
CMDKey mInstKey;
|
|
CMDKey mParamKey;
|
|
METADATA_RECORD mdRec;
|
|
DWORD_PTR i;
|
|
DWORD dwIndex = 0;
|
|
BYTE pBuffer[2048];
|
|
|
|
while (dwqQueue.DequeueDword(&i))
|
|
{
|
|
// Build "LM/*Svc/#"
|
|
csInstance.Format(_T("%s/%u"),
|
|
(LPCTSTR)csKeyName,
|
|
(DWORD)i);
|
|
|
|
csParameters = csInstance + _T("/Parameters");
|
|
|
|
DebugOutput(_T("Processing %s ..."), (LPCTSTR)csParameters);
|
|
|
|
dwIndex = 0;
|
|
while (1)
|
|
{
|
|
mParamKey.OpenNode(csParameters);
|
|
if ( (METADATA_HANDLE)mParamKey )
|
|
{
|
|
mdRec.dwMDIdentifier = 0;
|
|
mdRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
|
|
mdRec.dwMDUserType = 0;
|
|
mdRec.dwMDDataType = 0;
|
|
mdRec.dwMDDataLen = sizeof(pBuffer);
|
|
mdRec.pbMDData = pBuffer;
|
|
|
|
// Get the next value
|
|
if (!mParamKey.EnumData(dwIndex++, &mdRec))
|
|
{
|
|
mParamKey.Close();
|
|
break;
|
|
}
|
|
mParamKey.Close();
|
|
|
|
DebugOutput(_T("Read %s/%u"),
|
|
(LPCTSTR)csParameters,
|
|
mdRec.dwMDIdentifier);
|
|
|
|
// Migrate the value from the parameters level
|
|
// to instance level
|
|
mInstKey.OpenNode(csInstance);
|
|
if ( (METADATA_HANDLE)mInstKey )
|
|
{
|
|
DebugOutput(_T("Writing %s/%u"),
|
|
(LPCTSTR)csInstance,
|
|
mdRec.dwMDIdentifier);
|
|
mInstKey.SetData(&mdRec);
|
|
mInstKey.Close();
|
|
}
|
|
else
|
|
{
|
|
DebugOutput(_T("ERROR: Failed to open %s for writing"), csInstance);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DebugOutput(_T("Failed to open %s for enumeration"), csParameters);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Delete the parameters key
|
|
mInstKey.OpenNode(csInstance);
|
|
if ( (METADATA_HANDLE)mInstKey )
|
|
{
|
|
mInstKey.DeleteNode(_T("Parameters"));
|
|
mInstKey.Close();
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL rRemapKey(CString &csBaseName, DWORD dwBase, DWORD dwRegionSize, DWORD dwNewBase)
|
|
{
|
|
CString csPathName;
|
|
CMDKey mKey;
|
|
METADATA_RECORD mdRec;
|
|
DWORD dwIndex = 0;
|
|
DWORD_PTR dwId;
|
|
BYTE pBuffer[2048];
|
|
|
|
DebugOutput(_T("Remapping values under %s..."), (LPCTSTR)csBaseName);
|
|
|
|
mKey.OpenNode((LPCTSTR)csBaseName);
|
|
if (!(METADATA_HANDLE)mKey)
|
|
{
|
|
DebugOutput(_T("ERROR: Unable to open %s"), (LPCTSTR)csBaseName);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Use pre-order traversal to remap all the IDs
|
|
{
|
|
CDwordQueue dwqRemap;
|
|
|
|
while (1)
|
|
{
|
|
mdRec.dwMDIdentifier = 0;
|
|
mdRec.dwMDAttributes = METADATA_NO_ATTRIBUTES;
|
|
mdRec.dwMDUserType = 0;
|
|
mdRec.dwMDDataType = 0;
|
|
mdRec.dwMDDataLen = sizeof(pBuffer);
|
|
mdRec.pbMDData = pBuffer;
|
|
|
|
// Get the next value
|
|
if (!mKey.EnumData(dwIndex++, &mdRec))
|
|
break;
|
|
|
|
// See if this is a record that we will have to migrate
|
|
dwId = mdRec.dwMDIdentifier;
|
|
DebugOutput(_T("Remapping %u if necessary ..."), (DWORD)dwId);
|
|
if ((dwId >= dwBase) &&
|
|
((dwId - dwBase) < dwRegionSize))
|
|
{
|
|
DebugOutput(_T("Id %u scheduled for remapping"), (DWORD)dwId);
|
|
dwqRemap.QueueDword(dwId);
|
|
}
|
|
}
|
|
|
|
while (dwqRemap.DequeueDword(&dwId))
|
|
{
|
|
// Remap value
|
|
mdRec.dwMDIdentifier = (DWORD)dwId;
|
|
mdRec.dwMDAttributes = 0;
|
|
mdRec.dwMDUserType = 0;
|
|
mdRec.dwMDDataType = 0;
|
|
mdRec.dwMDDataLen = sizeof(pBuffer);
|
|
mdRec.pbMDData = pBuffer;
|
|
mKey.GetData(&mdRec);
|
|
|
|
mdRec.dwMDIdentifier = ((DWORD)dwId - dwBase) + dwNewBase;
|
|
DebugOutput(_T("Remapping from %u to %u"), (DWORD)dwId,
|
|
mdRec.dwMDIdentifier);
|
|
mKey.SetData(&mdRec);
|
|
|
|
// Delete the original data
|
|
mKey.DeleteData((DWORD)dwId, mdRec.dwMDDataType);
|
|
}
|
|
}
|
|
|
|
CMDKeyIter enumKey(mKey);
|
|
LPTSTR pName;
|
|
CDwordQueue dwqQueue;
|
|
|
|
enumKey.Reset();
|
|
while(enumKey.Next(&csPathName) == NO_ERROR)
|
|
{
|
|
pName = (LPTSTR)LocalAlloc(0, (csPathName.GetLength() + 1) * sizeof(TCHAR));
|
|
|
|
if (pName)
|
|
{
|
|
lstrcpy(pName, (LPCTSTR)csPathName);
|
|
dwqQueue.QueueDword((DWORD_PTR)pName);
|
|
}
|
|
}
|
|
mKey.Close();
|
|
|
|
while (dwqQueue.DequeueDword((PDWORD_PTR)&pName))
|
|
{
|
|
csPathName = _T("/");
|
|
csPathName += pName;
|
|
csPathName = csBaseName + csPathName;
|
|
|
|
// Traverse all subnodes of this tree
|
|
rRemapKey(csPathName, dwBase, dwRegionSize, dwNewBase);
|
|
|
|
LocalFree(pName);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL RemapServiceParameters(LPCTSTR szServiceName, DWORD dwBase, DWORD dwRegionSize, DWORD dwNewBase)
|
|
{
|
|
CString csKeyName;
|
|
CMDKey mKey;
|
|
|
|
csKeyName = _T("LM/");
|
|
csKeyName += szServiceName;
|
|
|
|
// Recursively walk the tree
|
|
rRemapKey(csKeyName, dwBase, dwRegionSize, dwNewBase);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void GetInetpubPathFromMD(CString& csPathInetpub)
|
|
{
|
|
TCHAR szw3root[] = _T("\\wwwroot");
|
|
TCHAR szPathInetpub[_MAX_PATH];
|
|
|
|
ZeroMemory( szPathInetpub, sizeof(szPathInetpub) );
|
|
|
|
CMDKey W3Key;
|
|
DWORD dwScratch;
|
|
DWORD dwType;
|
|
DWORD dwLength;
|
|
|
|
// Get W3Root path
|
|
W3Key.OpenNode(_T("LM/W3Svc/1/Root"));
|
|
if ( (METADATA_HANDLE)W3Key )
|
|
{
|
|
dwLength = _MAX_PATH;
|
|
|
|
if (W3Key.GetData(3001, &dwScratch, &dwScratch,
|
|
&dwType, &dwLength, (LPBYTE)szPathInetpub))
|
|
{
|
|
if (dwType == STRING_METADATA)
|
|
{
|
|
dwScratch = lstrlen(szw3root);
|
|
dwLength = lstrlen(szPathInetpub);
|
|
|
|
// If it ends with "\\wwwroot", then we copy the prefix into csPathInetpub
|
|
if ((dwLength > dwScratch) &&
|
|
!lstrcmpi(szPathInetpub + (dwLength - dwScratch), szw3root))
|
|
{
|
|
csPathInetpub.Empty();
|
|
lstrcpyn( csPathInetpub.GetBuffer(512), szPathInetpub, (dwLength - dwScratch + 1));
|
|
csPathInetpub.ReleaseBuffer();
|
|
}
|
|
|
|
// otherwise fall back to use the default...
|
|
}
|
|
}
|
|
W3Key.Close();
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
BOOL GetActionFromCheckboxStateOnly(LPCTSTR SubcomponentId, ACTION_TYPE *pAction)
|
|
{
|
|
DWORD State = 0;
|
|
DWORD OldState = 0;
|
|
|
|
*pAction = AT_DO_NOTHING;
|
|
|
|
// Get the check box state
|
|
State = gHelperRoutines.QuerySelectionState(
|
|
gHelperRoutines.OcManagerContext,
|
|
SubcomponentId,
|
|
OCSELSTATETYPE_CURRENT
|
|
);
|
|
if (GetLastError() != NO_ERROR)
|
|
{
|
|
DebugOutput(_T("Failed to get current state for <%s> (%u)"),
|
|
SubcomponentId, GetLastError());
|
|
State = 0;
|
|
}
|
|
|
|
// Check orignal state
|
|
OldState = gHelperRoutines.QuerySelectionState(
|
|
gHelperRoutines.OcManagerContext,
|
|
SubcomponentId,
|
|
OCSELSTATETYPE_ORIGINAL
|
|
);
|
|
if (GetLastError() != NO_ERROR)
|
|
{
|
|
DebugOutput(_T("Failed to get original state for <%s> (%u)"),
|
|
SubcomponentId, GetLastError());
|
|
OldState = 0;
|
|
}
|
|
|
|
if (State && !OldState)
|
|
{
|
|
// Change in state from OFF->ON = install docs
|
|
*pAction = AT_FRESH_INSTALL;
|
|
|
|
DebugOutput(_T("Installing subcomponent <%s>"), SubcomponentId);
|
|
}
|
|
else if (!State && OldState)
|
|
{
|
|
// Change in state from ON->OFF = uninstall docs
|
|
*pAction = AT_REMOVE;
|
|
|
|
DebugOutput(_T("Removing subcomponent <%s>"), SubcomponentId);
|
|
}
|
|
else if (State && OldState &&
|
|
(GetIMSSetupMode() == IIS_SETUPMODE_REINSTALL))
|
|
{
|
|
// Reinstall if that's the current mode
|
|
*pAction = AT_REINSTALL;
|
|
|
|
DebugOutput(_T("Reinstalling subcomponent <%s>"), SubcomponentId);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
enum DOMAIN_ROUTE_ACTION_TYPE
|
|
{
|
|
SMTP_NO_ACTION,
|
|
SMTP_DROP,
|
|
SMTP_SMARTHOST,
|
|
SMTP_SSL,
|
|
SMTP_ALIAS,
|
|
SMTP_DELIVER,
|
|
SMTP_DEFAULT,
|
|
LAST_SMTP_ACTION
|
|
};
|
|
|
|
const DWORD rgdwMapping[LAST_SMTP_ACTION] =
|
|
{
|
|
0x0, 0x1, 0x2, 0x4, 0x10, 0x20, 0x40
|
|
};
|
|
|
|
const DWORD dwEtrnFlag = 0x200;
|
|
|
|
#define SMTP_MD_ID(x) (0x9000 + (x))
|
|
#define _TAB _T('\t')
|
|
#define _NULL _T('\0')
|
|
#define _COMMA _T(',')
|
|
|
|
BOOL ReformatDomainRoutingEntries(LPCTSTR szServiceName)
|
|
{
|
|
CString csKeyName;
|
|
CString csDomainName;
|
|
CString csActionType;
|
|
CString csDomainRoute;
|
|
CMDKey mKey;
|
|
METADATA_RECORD mdRec;
|
|
TCHAR MultiSz[1024];
|
|
DWORD cbMultiSz = 1024;
|
|
LPTSTR Ptr;
|
|
|
|
csKeyName = _T("LM/");
|
|
csKeyName += szServiceName;
|
|
csKeyName += _T("/1");
|
|
|
|
// Open the node
|
|
mKey.OpenNode((LPCTSTR)csKeyName);
|
|
if (!(METADATA_HANDLE)mKey)
|
|
{
|
|
DebugOutput(_T("ERROR: Unable to open %s"), (LPCTSTR)csKeyName);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Get the domain routing MULTISZ value
|
|
mdRec.dwMDIdentifier = SMTP_MD_ID(56);
|
|
mdRec.dwMDAttributes = 0;
|
|
mdRec.dwMDUserType = 0;
|
|
mdRec.dwMDDataType = 0;
|
|
mdRec.dwMDDataLen = cbMultiSz;
|
|
mdRec.pbMDData = (LPBYTE)MultiSz;
|
|
if (!mKey.GetData(&mdRec))
|
|
{
|
|
DebugOutput(_T("ERROR: Unable to GetData on %u. We will not migrate Domain Routes."),
|
|
mdRec.dwMDIdentifier);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Close it so we can open a child later
|
|
mKey.Close();
|
|
|
|
DebugOutput(_T("Processing Domain routes ..."));
|
|
|
|
// This is the base name for all domain routes
|
|
csKeyName += _T("/Domain/");
|
|
Ptr = MultiSz;
|
|
while (Ptr && *Ptr)
|
|
{
|
|
do
|
|
{
|
|
TCHAR szDomainName[325];
|
|
TCHAR szActionType[MAX_PATH + 1];
|
|
TCHAR szValue[256];
|
|
int i, Action, NewAction;
|
|
BOOL UseEtrn;
|
|
|
|
szDomainName[0] = _NULL;
|
|
szValue[0] = _NULL;
|
|
szActionType[0] = _NULL;
|
|
|
|
// skip whitespace
|
|
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
|
|
Ptr++;
|
|
|
|
if(*Ptr == _NULL)
|
|
break;
|
|
|
|
//get the Action
|
|
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 255; Ptr++)
|
|
{
|
|
szValue[i++] = *Ptr;
|
|
}
|
|
|
|
//null terminate
|
|
szValue[i] = _NULL;
|
|
Action = _wtoi(szValue);
|
|
if( (Action == 0) || (Action >= (int) LAST_SMTP_ACTION) || (*Ptr == _NULL))
|
|
{
|
|
DebugOutput(_T("%d is an invalid action"), Action);
|
|
|
|
//unknown action type
|
|
break;
|
|
}
|
|
|
|
DebugOutput(_T("Action = %u"), Action);
|
|
|
|
//skip ,
|
|
Ptr++;
|
|
|
|
// skip whitespace
|
|
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
|
|
Ptr++;
|
|
|
|
//get the Domain
|
|
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 324; Ptr++)
|
|
{
|
|
szDomainName[i++] = *Ptr;
|
|
}
|
|
|
|
szDomainName[i] = _NULL;
|
|
csDomainName = szDomainName;
|
|
|
|
//check for bad data
|
|
if(szDomainName[0] == _NULL)
|
|
{
|
|
DebugOutput(_T("Found a NULL domain. Breaking out"));
|
|
break;
|
|
}
|
|
|
|
DebugOutput(_T("Domain = %s"), szDomainName);
|
|
|
|
//skip ,
|
|
Ptr++;
|
|
|
|
//get the Action
|
|
for (i = 0; Ptr != NULL && *Ptr != 0 && *Ptr != _COMMA && i < MAX_PATH; Ptr++)
|
|
{
|
|
szActionType[i++] = *Ptr;
|
|
}
|
|
|
|
szActionType[i] = _NULL;
|
|
csActionType = szActionType;
|
|
|
|
DebugOutput(_T("Action Type = %s"), szActionType);
|
|
|
|
//skip ,
|
|
Ptr++;
|
|
|
|
// skip whitespace
|
|
while( (*Ptr != _NULL) && (isspace (*Ptr) || (*Ptr == _TAB)))
|
|
Ptr++;
|
|
|
|
//get etrn
|
|
for (i = 0; *Ptr != 0 && *Ptr != _COMMA && i < 255; Ptr++)
|
|
{
|
|
szValue[i++] = *Ptr;
|
|
}
|
|
|
|
//null terminate
|
|
szValue[i] = _NULL;
|
|
UseEtrn = _wtoi(szValue);
|
|
|
|
//turn the number into a BOOL
|
|
UseEtrn = !!UseEtrn;
|
|
|
|
DebugOutput(_T("Use Etrn = %s"), UseEtrn?_T("TRUE"):_T("FALSE"));
|
|
|
|
// We don't deliver, so we coerce delivery to alias
|
|
if (Action == SMTP_DELIVER)
|
|
Action = SMTP_ALIAS;
|
|
|
|
// OK, we have come this far, so we can now write out the new
|
|
// domain routing entry
|
|
|
|
// First, remap the Action value, sinc eit had been changed.
|
|
NewAction = rgdwMapping[Action];
|
|
if (UseEtrn)
|
|
NewAction |= dwEtrnFlag;
|
|
|
|
// The Domain Name string that we get will become the new
|
|
// key name under smtpsvc/1/Domain/"Domain Name"
|
|
csDomainRoute = csKeyName + csDomainName;
|
|
DebugOutput(_T("Creating %s ..."), (LPCTSTR)csDomainName);
|
|
mKey.CreateNode(METADATA_MASTER_ROOT_HANDLE, (LPCTSTR)csDomainRoute);
|
|
if ( (METADATA_HANDLE)mKey )
|
|
{
|
|
// First set the route action DWORD
|
|
DebugOutput(_T("Creating route action = %08x"), NewAction);
|
|
mdRec.dwMDIdentifier = SMTP_MD_ID(82);
|
|
mdRec.dwMDAttributes = 1;
|
|
mdRec.dwMDUserType = 1;
|
|
mdRec.dwMDDataType = 1;
|
|
mdRec.dwMDDataLen = sizeof(DWORD);
|
|
mdRec.pbMDData = (LPBYTE)&NewAction;
|
|
mKey.SetData(&mdRec);
|
|
|
|
// Then set the route action type string
|
|
DebugOutput(_T("Creating route action type = %s"), (LPCTSTR)csActionType);
|
|
mdRec.dwMDIdentifier = SMTP_MD_ID(83);
|
|
mdRec.dwMDAttributes = 1;
|
|
mdRec.dwMDUserType = 1;
|
|
mdRec.dwMDDataType = 2;
|
|
mdRec.dwMDDataLen = (lstrlen(szActionType) + 1) * sizeof(TCHAR);
|
|
mdRec.pbMDData = (LPBYTE)szActionType;
|
|
mKey.SetData(&mdRec);
|
|
|
|
// Then set the KeyType
|
|
lstrcpy(szActionType, _T("IIsSmtpDomain"));
|
|
DebugOutput(_T("Creating Key type = %s"), szActionType);
|
|
mdRec.dwMDIdentifier = 1002;
|
|
mdRec.dwMDAttributes = 1;
|
|
mdRec.dwMDUserType = 1;
|
|
mdRec.dwMDDataType = 2;
|
|
mdRec.dwMDDataLen = (lstrlen(szActionType) + 1) * sizeof(TCHAR);
|
|
mdRec.pbMDData = (LPBYTE)szActionType;
|
|
mKey.SetData(&mdRec);
|
|
|
|
mKey.Close();
|
|
}
|
|
|
|
} while (0);
|
|
|
|
// We skip to the end of the current string and process the next one
|
|
// This makes sure we will not be in trouble when we break out in the
|
|
// middle of parsing
|
|
while (*Ptr++ != _NULL)
|
|
;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
// IIS SnapIn CLSID - {A841B6C4-7577-11d0-BB1F-00A0C922E79C}
|
|
//DEFINE_GUID(CLSID_IIS_SnapIn, 0xa841b6c4, 0x7577, 0x11d0, 0xbb, 0x1f, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x9c);
|
|
const WCHAR * wszIIS_SnapIn = _T("{A841B6C4-7577-11d0-BB1F-00A0C922E79C}");
|
|
|
|
BOOL
|
|
EnableSnapInExtension(
|
|
IN CString &csMMCDocFilePath,
|
|
IN LPCWSTR lpwszExtSnapInCLSID,
|
|
IN BOOL bEnable
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Enable/Disable snapin extension in IIS
|
|
NT5 - also enable our snapin under %systemroot%\system32\compmgmt.msc
|
|
|
|
Arguments:
|
|
|
|
csMMCDocFilePath - Path to iis.msc, normally %windir%\system32\inetsrv
|
|
ExtCLSID - CLSID for snapin extension
|
|
bEnable - TRUE enable, FALSE disable
|
|
|
|
Return Value:
|
|
|
|
TRUE - success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
// -------------------------------------------------------------------------------------
|
|
// $BUG(garypur) - removing the use of the IDocConfig interface since MMC support for it
|
|
// has been removed
|
|
// -------------------------------------------------------------------------------------
|
|
return TRUE;
|
|
|
|
/*
|
|
HRESULT hr = S_OK;
|
|
IDocConfig *pIDocConfig = NULL;
|
|
CString csMMCDocFile = csMMCDocFilePath;
|
|
VARIANT_BOOL boolVal = bEnable ? VARIANT_TRUE : VARIANT_FALSE;
|
|
BSTR bstrMMCDocFile;
|
|
BSTR bstrCLSID_IIS_SnapIn;
|
|
BSTR bstrCLSID_Ext_SnapIn;
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
DebugOutput(_T("Cannot CoInitialize()"));
|
|
return FALSE;
|
|
}
|
|
|
|
bstrMMCDocFile = ::SysAllocString((LPCWSTR) csMMCDocFile);
|
|
bstrCLSID_IIS_SnapIn = ::SysAllocString(wszIIS_SnapIn);
|
|
bstrCLSID_Ext_SnapIn = ::SysAllocString(lpwszExtSnapInCLSID);
|
|
|
|
//
|
|
// Get the IDocConfig interface pointer
|
|
//
|
|
hr = CoCreateInstance( (REFCLSID) CLSID_MMCDocConfig,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
(REFIID) IID_IDocConfig,
|
|
(void**) &pIDocConfig);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//
|
|
// Open iis.msc
|
|
//
|
|
hr = pIDocConfig->OpenFile( bstrMMCDocFile );
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//
|
|
// Enable the Snapin
|
|
//
|
|
hr = pIDocConfig->EnableSnapInExtension( bstrCLSID_IIS_SnapIn, bstrCLSID_Ext_SnapIn, boolVal );
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//
|
|
// Save the change
|
|
//
|
|
hr = pIDocConfig->SaveFile( bstrMMCDocFile );
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
//
|
|
// Close file
|
|
//
|
|
hr = pIDocConfig->CloseFile();
|
|
|
|
exit:
|
|
|
|
if (pIDocConfig)
|
|
{
|
|
pIDocConfig->Release();
|
|
pIDocConfig = NULL;
|
|
}
|
|
|
|
::SysFreeString(bstrMMCDocFile);
|
|
::SysFreeString(bstrCLSID_IIS_SnapIn);
|
|
::SysFreeString(bstrCLSID_Ext_SnapIn);
|
|
|
|
CoUninitialize();
|
|
|
|
return (S_OK == hr);
|
|
*/
|
|
}
|
|
|
|
|
|
const LPCTSTR g_cszMMCBasePath = _T("Software\\Microsoft\\MMC");
|
|
const LPCTSTR g_cszNodeTypes = _T("NodeTypes");
|
|
const LPCTSTR g_cszExtensions = _T("Extensions");
|
|
const LPCTSTR g_cszNameSpace = _T("NameSpace");
|
|
const LPCTSTR g_cszDynamicExt = _T("Dynamic Extensions");
|
|
const LPCTSTR g_cszServerAppsLoc = _T("System\\CurrentControlSet\\Control\\Server Applications");
|
|
|
|
BOOL
|
|
EnableCompMgmtExtension(
|
|
IN LPCWSTR lpwszExtSnapInCLSID,
|
|
IN LPCWSTR lpwszSnapInName,
|
|
IN BOOL bEnable
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Enable/Disable snapin extension in NT5 CompMgmt
|
|
|
|
Arguments:
|
|
|
|
ExtCLSID - CLSID for snapin extension
|
|
bEnable - TRUE enable, FALSE disable
|
|
|
|
Return Value:
|
|
|
|
TRUE - success, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
|
|
DebugOutput(_T("EnableCompMgmtExtension(): bEnable=%d"), bEnable);
|
|
|
|
CString strExtKey;
|
|
|
|
// set up registry values
|
|
CRegKey regMachine = HKEY_LOCAL_MACHINE;
|
|
|
|
if (bEnable)
|
|
{
|
|
{
|
|
//
|
|
// Register as a dynamic extension to computer management
|
|
//
|
|
strExtKey.Format(
|
|
_T("%s\\%s\\%s\\%s"),
|
|
g_cszMMCBasePath,
|
|
g_cszNodeTypes,
|
|
lstruuidNodetypeServerApps,
|
|
g_cszDynamicExt
|
|
);
|
|
|
|
CRegKey regMMCNodeTypes(strExtKey, regMachine);
|
|
if ((HKEY) regMMCNodeTypes)
|
|
{
|
|
regMMCNodeTypes.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
|
|
}
|
|
}
|
|
|
|
{
|
|
//
|
|
// Register as a namespace extension to computer management
|
|
//
|
|
strExtKey.Format(
|
|
_T("%s\\%s\\%s\\%s\\%s"),
|
|
g_cszMMCBasePath,
|
|
g_cszNodeTypes,
|
|
lstruuidNodetypeServerApps,
|
|
g_cszExtensions,
|
|
g_cszNameSpace
|
|
);
|
|
|
|
CRegKey regMMCNodeTypes(strExtKey, regMachine);
|
|
if ((HKEY) regMMCNodeTypes)
|
|
{
|
|
regMMCNodeTypes.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
|
|
}
|
|
}
|
|
|
|
//
|
|
// This key indicates that the service in question is available
|
|
// on the local machine
|
|
//
|
|
CRegKey regCompMgmt(g_cszServerAppsLoc, regMachine );
|
|
if ((HKEY) regCompMgmt)
|
|
{
|
|
regCompMgmt.SetValue( lpwszExtSnapInCLSID, lpwszSnapInName );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Disabling CompMgmt extension
|
|
//
|
|
{
|
|
//
|
|
// Unregister as a dynamic extension to computer management
|
|
//
|
|
strExtKey.Format(
|
|
_T("%s\\%s\\%s\\%s"),
|
|
g_cszMMCBasePath,
|
|
g_cszNodeTypes,
|
|
lstruuidNodetypeServerApps,
|
|
g_cszDynamicExt
|
|
);
|
|
|
|
CRegKey regMMCNodeTypes(strExtKey, regMachine);
|
|
if ((HKEY) regMMCNodeTypes)
|
|
{
|
|
regMMCNodeTypes.DeleteValue( lpwszExtSnapInCLSID );
|
|
}
|
|
}
|
|
|
|
{
|
|
//
|
|
// unregister as a namespace extension to computer management
|
|
//
|
|
strExtKey.Format(
|
|
_T("%s\\%s\\%s\\%s\\%s"),
|
|
g_cszMMCBasePath,
|
|
g_cszNodeTypes,
|
|
lstruuidNodetypeServerApps,
|
|
g_cszExtensions,
|
|
g_cszNameSpace
|
|
);
|
|
|
|
CRegKey regMMCNodeTypes(strExtKey, regMachine);
|
|
if ((HKEY) regMMCNodeTypes)
|
|
{
|
|
regMMCNodeTypes.DeleteValue( lpwszExtSnapInCLSID );
|
|
}
|
|
}
|
|
|
|
//
|
|
// This key indicates that the service in question is available
|
|
// on the local machine. Remove it
|
|
//
|
|
CRegKey regCompMgmt(g_cszServerAppsLoc, regMachine );
|
|
if ((HKEY) regCompMgmt)
|
|
{
|
|
regCompMgmt.DeleteValue( lpwszExtSnapInCLSID );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|