/*++ Copyright (c) 2001 Microsoft Corporation Module Name: fxocUpgrade.cpp Abstract: Implementation of the Upgrade process Author: Iv Garber (IvG) Mar, 2001 Revision History: --*/ #include "faxocm.h" #pragma hdrstop #include #include // For SHCopyKey DWORD g_LastUniqueLineId = 0; // // EnumDevicesType is used to call prv_StoreDevices() callback function during the Enumeration of // Devices in the Registry. // typedef enum prv_EnumDevicesType { edt_None = 0x00, edt_PFWDevices = 0x02, // Enumerate W2K Fax Devices edt_Inbox = 0x04 // Find List of Inbox Folders for W2K Fax }; // // Local Static Variable, to store data between OS Manager calls // static struct prv_Data { DWORD dwFaxInstalledPriorUpgrade; // bit-wise combination of fxState_UpgradeApp_e values to define // which fax clients were installed on the machine prior to upgrade // // data for PFW // TCHAR tszCommonCPDir[MAX_PATH]; // Folder for Common Cover Pages LPTSTR *plptstrInboxFolders; // Array of different Inbox Folders DWORD dwInboxFoldersCount; // number of Inbox Folders in the plptstrInboxFolders array } prv_Data = { FXSTATE_NONE, // no fax client applications is installed by default {0}, // tszCommonCPDir NULL, // plptstrInboxFolders 0 // dwInboxFoldersCount }; // // Internal assisting functions // BOOL prv_StoreDevices(HKEY hKey, LPWSTR lpwstrKeyName, DWORD dwIndex, LPVOID lpContext); static DWORD prv_MoveCoverPages(LPTSTR lptstrSourceDir, LPTSTR lptstrDestDir, LPTSTR lptstrPrefix); static DWORD prv_GetPFWCommonCPDir(void); static DWORD prv_GetSBSServerCPDir(LPTSTR lptstrCPDir) {return NO_ERROR; }; static DWORD prv_SaveArchives(void); DWORD fxocUpg_WhichFaxWasUninstalled( DWORD dwFaxAppList ) /*++ Routine name : fxocUpg_WhichFaxWasUninstalled Routine description: Set flags regarding fax applications installed before upgrade. Called from SaveUnattendedData() if the corresponding data is found in the Answer File. Author: Iv Garber (IvG), May, 2001 Arguments: FaxApp [in] - the combination of the applications that were installed before the upgrade Return Value: Standard Win32 error code --*/ { DWORD dwReturn = NO_ERROR; DBG_ENTER(_T("fxocUpg_WhichFaxWasUninstalled"), dwReturn); prv_Data.dwFaxInstalledPriorUpgrade = dwFaxAppList; return dwReturn; } DWORD fxocUpg_GetUpgradeApp(void) /*++ Routine name : fxocUpg_GetUpgradeApp Routine description: Return type of the upgrade, which indicates which fax applications were installed before the upgrade. Author: Iv Garber (IvG), May, 2001 Return Value: The type of the upgrade --*/ { DBG_ENTER(_T("fxocUpg_GetUpgradeApp"), prv_Data.dwFaxInstalledPriorUpgrade); return prv_Data.dwFaxInstalledPriorUpgrade; } DWORD fxocUpg_Init(void) /*++ Routine name : fxocUpg_Init Routine description: checks which Fax applications are installed on the machine, and set global flags in prv_Data. Author: Iv Garber (IvG), May, 2001 Return Value: DWORD - failure or success --*/ { DWORD dwReturn = NO_ERROR; bool bInstalled = false; DBG_ENTER(_T("fxocUpg_Init"), dwReturn); // // Clear the SBS 5.0 Server flag // prv_Data.dwFaxInstalledPriorUpgrade = FXSTATE_NONE; // // Check presence of the SBS 5.0 Server // dwReturn = WasSBS2000FaxServerInstalled(&bInstalled); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("CheckInstalledFax() failed, ec=%ld."), dwReturn); } if (bInstalled) { prv_Data.dwFaxInstalledPriorUpgrade |= FXSTATE_SBS5_SERVER; } return dwReturn; } DWORD fxocUpg_SaveSettings(void) /*++ Routine name : fxocUpg_SaveSettings Routine description: Save settings of SBS 5.0 Server to allow smooth migration to the Windows XP Fax. Device Settings should be stored BEFORE handling of the Registry ( which deletes the Devices key ) and BEFORE the Service Start ( which creates new devices and uses settings that are stored here ). Author: Iv Garber (IvG), May, 2001 Return Value: DWORD - failure or success --*/ { DWORD dwReturn = NO_ERROR; DWORD dwEnumType = edt_None; DBG_ENTER(_T("fxocUpg_SaveSettings"), dwReturn); // // Handle Upgrade from W2K/PFW Fax // if (fxState_IsUpgrade() == FXSTATE_UPGRADE_TYPE_W2K) { // // Save its Common CP Dir. This should be done BEFORE Copy/Delete Files of Windows XPFax. // dwReturn = prv_GetPFWCommonCPDir(); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("prv_GetPFWCommonCPDir() failed, ec=%ld."), dwReturn); } // // Store Device Settings of PFW -- if SBS 5.0 Server is not present on the machine. // Also, find Inbox Folders List of the PFW Devices. // HKEY hKey = OpenRegistryKey(HKEY_LOCAL_MACHINE, REGKEY_SOFTWARE, FALSE, KEY_READ); if (!hKey) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to open Registry for Fax, ec = %ld."), dwReturn); return dwReturn; } if (prv_Data.dwFaxInstalledPriorUpgrade & FXSTATE_SBS5_SERVER) { // // Devices already enumerated, through SBS 5.0 Server // Enumerate only Inbox Folders // dwEnumType = edt_Inbox; } else { // // Full Enumeration for PFW Devices : Devices Settings + Inbox Folders // dwEnumType = edt_PFWDevices | edt_Inbox; } dwReturn = EnumerateRegistryKeys(hKey, REGKEY_DEVICES, FALSE, prv_StoreDevices, &dwEnumType); VERBOSE(DBG_MSG, _T("For PFW, enumerated %ld devices."), dwReturn); RegCloseKey(hKey); // // prv_StoreDevices stored list of PFW's Inbox Folders in prv_Data. // Now save the Inbox Folders List and SentItems Folder // dwReturn = prv_SaveArchives(); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("prv_SaveArchives() failed, ec=%ld."), dwReturn); } dwReturn = NO_ERROR; } return dwReturn; } BOOL prv_StoreDevices(HKEY hDeviceKey, LPWSTR lpwstrKeyName, DWORD dwIndex, LPVOID lpContextData ) /*++ Routine name : prv_StoreDevices Routine description: Callback function used in enumeration of devices in the registry. Stores device's data in the Registry, under Setup/Original Setup Data. Creates List of Inbox Folders ( used for PFW ) and saves it in the prv_Data. Used when upgrading from PFW/SBS 5.0 Server to Windows XP Fax. Author: Iv Garber (IvG), Mar, 2001 Arguments: hKey [in] - current key lpwstrKeyName [in] - name of the current key, if exists dwIndex [in] - count of all the subkeys for the given key / index of the current key lpContextData [in] - NULL, not used Return Value: TRUE if success, FALSE otherwise. --*/ { HKEY hSetupKey = NULL; DWORD dwReturn = NO_ERROR; DWORD dwNumber = 0; TCHAR tszNewKeyName[MAX_PATH] = {0}; LPTSTR lptstrString = NULL; DWORD *pdwEnumType = NULL; DBG_ENTER(_T("prv_StoreDevices")); if (lpwstrKeyName == NULL) { // // This is the SubKey we started at ( i.e. Devices ) // // If InboxFolders should be stored, then allocate // enough memory for prv_Data.plptstrInboxFolders. // dwIndex contains TOTAL number of subkeys ( Devices ). // pdwEnumType = (DWORD *)lpContextData; if ( (*pdwEnumType & edt_Inbox) == edt_Inbox ) { prv_Data.plptstrInboxFolders = (LPTSTR *)MemAlloc(sizeof(LPTSTR) * dwIndex); if (prv_Data.plptstrInboxFolders) { ZeroMemory(prv_Data.plptstrInboxFolders, sizeof(LPTSTR) * dwIndex); } else { // // Not enough memory // VERBOSE(DBG_WARNING, _T("Not enough memory to store the Inbox Folders.")); } } return TRUE; } // // The per Device section // // // Store Device's Inbox Folder // if (prv_Data.plptstrInboxFolders) { // // we are here only when lpContextData contains edt_InboxFolders // and the memory allocation succeded. // // // Open Routing SubKey // hSetupKey = OpenRegistryKey(hDeviceKey, REGKEY_PFW_ROUTING, FALSE, KEY_READ); if (!hSetupKey) { // // Failed to open Routing Subkey // dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to open 'Registry' Key for Device #ld, ec = %ld."), dwIndex, dwReturn); goto ContinueStoreDevice; } // // Take 'Store Directory' Value // lptstrString = GetRegistryString(hSetupKey, REGVAL_PFW_INBOXDIR, EMPTY_STRING); if ((!lptstrString) || (_tcslen(lptstrString) == 0)) { // // Failed to take the value // dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to get StoreDirectory value for Device #ld, ec = %ld."), dwIndex, dwReturn); goto ContinueStoreDevice; } // // Check if it is already present // DWORD dwI; for ( dwI = 0 ; dwI < prv_Data.dwInboxFoldersCount ; dwI++ ) { if (prv_Data.plptstrInboxFolders[dwI]) { if (_tcscmp(prv_Data.plptstrInboxFolders[dwI], lptstrString) == 0) { // // String found // goto ContinueStoreDevice; } } } // // String was NOT found between all already registered string, so add it // prv_Data.plptstrInboxFolders[dwI] = LPTSTR(MemAlloc(sizeof(TCHAR) * (_tcslen(lptstrString) + 1))); if (prv_Data.plptstrInboxFolders[dwI]) { // // copy string & update the counter // _tcscpy(prv_Data.plptstrInboxFolders[dwI], lptstrString); prv_Data.dwInboxFoldersCount++; } else { // // Not enough memory // VERBOSE(DBG_WARNING, _T("Not enough memory to store the Inbox Folders.")); } ContinueStoreDevice: if (hSetupKey) { RegCloseKey(hSetupKey); hSetupKey = NULL; } MemFree(lptstrString); lptstrString = NULL; } // // Check whether to store Device's Data and how // pdwEnumType = (DWORD *)lpContextData; if ((*pdwEnumType & edt_PFWDevices) == edt_PFWDevices) { // // Store PFW Devices Data // lptstrString = REGVAL_PERMANENT_LINEID; } else { // // no need to save any Device Data // return TRUE; } // // Take Device's Permanent Line Id // dwReturn = GetRegistryDwordEx(hDeviceKey, lptstrString, &dwNumber); if (dwReturn != ERROR_SUCCESS) { // // Cannot find TAPI Permanent LineId --> This is invalid Device Registry // return TRUE; } VERBOSE(DBG_MSG, _T("Current Tapi Line Id = %ld"), dwNumber); // // Create a SubKey Name from it // _sntprintf( tszNewKeyName, ARR_SIZE(tszNewKeyName) -1, TEXT("%s\\%010d"), REGKEY_FAX_SETUP_ORIG, dwNumber); hSetupKey = OpenRegistryKey(HKEY_LOCAL_MACHINE, tszNewKeyName, TRUE, 0); if (!hSetupKey) { // // Failed to create registry key // dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to create a SubKey for the Original Setup Data of the Device, ec = %ld."), dwReturn); // // Continue to the next device // return TRUE; } // // Set the Flags for the newly created key // dwNumber = GetRegistryDword(hDeviceKey, REGVAL_FLAGS); SetRegistryDword(hSetupKey, REGVAL_FLAGS, dwNumber); VERBOSE(DBG_MSG, _T("Flags are : %ld"), dwNumber); // // Set the Rings for the newly created key // dwNumber = GetRegistryDword(hDeviceKey, REGVAL_RINGS); SetRegistryDword(hSetupKey, REGVAL_RINGS, dwNumber); VERBOSE(DBG_MSG, _T("Rings are : %ld"), dwNumber); // // Set the TSID for the newly created key // lptstrString = GetRegistryString(hDeviceKey, REGVAL_ROUTING_TSID, REGVAL_DEFAULT_TSID); SetRegistryString(hSetupKey, REGVAL_ROUTING_TSID, lptstrString); VERBOSE(DBG_MSG, _T("TSID is : %s"), lptstrString); MemFree(lptstrString); // // Set the CSID for the newly created key // lptstrString = GetRegistryString(hDeviceKey, REGVAL_ROUTING_CSID, REGVAL_DEFAULT_CSID); SetRegistryString(hSetupKey, REGVAL_ROUTING_CSID, lptstrString); VERBOSE(DBG_MSG, _T("CSID is : %s"), lptstrString); MemFree(lptstrString); RegCloseKey(hSetupKey); return TRUE; } DWORD fxocUpg_RestoreSettings(void) /*++ Routine name : fxocUpg_RestoreSettings Routine description: Restore settings that were stored at the SaveSettings(). Author: Iv Garber (IvG), Feb, 2001 Return Value: DWORD - failure or success --*/ { DWORD dwReturn = NO_ERROR; HANDLE hPrinter = NULL; DBG_ENTER(_T("fxocUpg_RestoreSettings"), dwReturn); return dwReturn; } DWORD fxocUpg_MoveFiles(void) /*++ Routine name : fxocUpg_MoveFiles Routine description: Move files from the folders that should be deleted. Should be called BEFORE directories delete. Author: Iv Garber (IvG), Feb, 2001 Return Value: DWORD - failure or success --*/ { DWORD dwReturn = NO_ERROR; TCHAR tszDestination[MAX_PATH] = {0}; LPTSTR lptstrCPDir = NULL; DBG_ENTER(_T("fxocUpg_MoveFiles"), dwReturn); if ( (fxState_IsUpgrade() != FXSTATE_UPGRADE_TYPE_W2K) && !(prv_Data.dwFaxInstalledPriorUpgrade & FXSTATE_SBS5_SERVER) ) { // // This is not PFW / SBS 5.0 Server upgrade. Do nothing // VERBOSE(DBG_MSG, _T("No need to Move any Files from any Folders.")); return dwReturn; } // // Find Destination Folder : COMMON APP DATA + ServiceCPDir from the Registry // if (!GetServerCpDir(NULL, tszDestination, MAX_PATH)) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("GetServerCPDir() failed, ec=%ld."), dwReturn); return dwReturn; } if (fxState_IsUpgrade() == FXSTATE_UPGRADE_TYPE_W2K) { // // PFW Server CP Dir is stored at SaveSettings() in prv_Data.lptstrPFWCommonCPDir // dwReturn = prv_MoveCoverPages(prv_Data.tszCommonCPDir, tszDestination, CP_PREFIX_W2K); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("prv_MoveCoverPages() for Win2K failed, ec = %ld"), dwReturn); } } if (prv_Data.dwFaxInstalledPriorUpgrade & FXSTATE_SBS5_SERVER) { // // Get SBS Server CP Dir // dwReturn = prv_GetSBSServerCPDir(lptstrCPDir); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("prv_GetSBSServerCPDir() failed, ec=%ld"), dwReturn); return dwReturn; } // // Move Cover Pages // dwReturn = prv_MoveCoverPages(lptstrCPDir, tszDestination, CP_PREFIX_SBS); if (dwReturn != NO_ERROR) { VERBOSE(DBG_WARNING, _T("prv_MoveCoverPages() for SBS failed, ec = %ld"), dwReturn); } MemFree(lptstrCPDir); } return dwReturn; } static DWORD prv_MoveCoverPages( LPTSTR lptstrSourceDir, LPTSTR lptstrDestDir, LPTSTR lptstrPrefix ) /*++ Routine name : prv_MoveCoverPages Routine description: Move all the Cover Pages from Source folder to Destination folder and add a prefix to all the Cover Page names. Author: Iv Garber (IvG), Mar, 2001 Arguments: lptstrSourceDir [IN] - Source Directory where Cover Pages are reside before the upgrade lptstrDestDir [IN] - where the Cover Pages should reside after the upgrade lptstrPrefix [IN] - prefix that should be added to the Cover Page file names Return Value: Success or Failure Error Code. --*/ { DWORD dwReturn = ERROR_SUCCESS; TCHAR szSearch[MAX_PATH] = {0}; HANDLE hFind = NULL; WIN32_FIND_DATA FindFileData = {0}; TCHAR szFrom[MAX_PATH] = {0}; TCHAR szTo[MAX_PATH] = {0}; DBG_ENTER(_T("prv_MoveCoverPages"), dwReturn); if ((!lptstrSourceDir) || (_tcslen(lptstrSourceDir) == 0)) { // // we do not know from where to take Cover Pages // dwReturn = ERROR_INVALID_PARAMETER; VERBOSE(DBG_WARNING, _T("SourceDir is NULL. Cannot move Cover Pages. Exiting...")); return dwReturn; } if ((!lptstrDestDir) || (_tcslen(lptstrDestDir) == 0)) { // // we do not know where to put the Cover Pages // dwReturn = ERROR_INVALID_PARAMETER; VERBOSE(DBG_WARNING, _T("DestDir is NULL. Cannot move Cover Pages. Exiting...")); return dwReturn; } // // Find all Cover Page files in the given Source Directory // _sntprintf( szSearch, ARR_SIZE(szSearch) -1, _T("%s\\*.cov"), lptstrSourceDir); hFind = FindFirstFile(szSearch, &FindFileData); if (INVALID_HANDLE_VALUE == hFind) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("FindFirstFile() on %s folder for Cover Pages is failed, ec = %ld"), lptstrSourceDir, dwReturn); return dwReturn; } // // Go for each Cover Page // do { // // This is full current Cover Page file name // _sntprintf(szFrom, ARR_SIZE(szFrom) -1, _T("%s\\%s"), lptstrSourceDir, FindFileData.cFileName); // // This is full new Cover Page file name // _sntprintf(szTo, ARR_SIZE(szTo) -1, _T("%s\\%s_%s"), lptstrDestDir, lptstrPrefix, FindFileData.cFileName); // // Move the file // if (!MoveFile(szFrom, szTo)) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("MoveFile() for %s Cover Page failed, ec=%ld"), szFrom, dwReturn); } } while(FindNextFile(hFind, &FindFileData)); VERBOSE(DBG_MSG, _T("last call to FindNextFile() returns %ld."), GetLastError()); // // Close Handle // FindClose(hFind); return dwReturn; } static DWORD prv_GetPFWCommonCPDir( ) /*++ Routine name : prv_GetPFWCommonCPDir Routine description: Return Folder for Common Cover Pages used for PFW. This Folder is equal to : CSIDL_COMMON_DOCUMENTS + Localized Dir This Localized Dir name we can take from the Resource of Win2K's FaxOcm.Dll. So, this function should be called BEFORE Copy/Delete Files of Install that will remove old FaxOcm.Dll. Currently it is called at SaveSettings(), which IS called before CopyFiles. Author: Iv Garber (IvG), Mar, 2001 Return Value: static DWORD -- failure or success --*/ { DWORD dwReturn = NO_ERROR; HMODULE hModule = NULL; TCHAR tszName[MAX_PATH] = {0}; DBG_ENTER(_T("prv_GetPFWCommonCPDir"), dwReturn); // // find full path to FaxOcm.Dll // if (!GetSpecialPath(CSIDL_SYSTEM, tszName, ARR_SIZE(tszName))) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("GetSpecialPath(CSIDL_SYSTEM) failed, ec = %ld"), dwReturn); return dwReturn; } if ((_tcslen(tszName) + _tcslen(FAXOCM_NAME) + 1 ) >= ARR_SIZE(tszName)) // 1 for '\' { // // not enough place // dwReturn = ERROR_OUTOFMEMORY; VERBOSE(DBG_WARNING, _T("FaxOcm.Dll path is too long, ec = %ld"), dwReturn); return dwReturn; } _tcscat(tszName, _T("\\")); _tcscat(tszName, FAXOCM_NAME); VERBOSE(DBG_MSG, _T("Full Name of FaxOcm is %s"), tszName); hModule = LoadLibraryEx(tszName, NULL, LOAD_LIBRARY_AS_DATAFILE); if (!hModule) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("LoadLibrary(%s) failed, ec = %ld."), tszName, dwReturn); return dwReturn; } dwReturn = LoadString(hModule, CPDIR_RESOURCE_ID, tszName, MAX_PATH); if (dwReturn == 0) { // // Resource string is not found // dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("LoadString() failed, ec = %ld."), dwReturn); goto Exit; } VERBOSE(DBG_MSG, _T("FaxOcm returned '%s'"), tszName); // // Take the Base part of the Folder name // if (!GetSpecialPath(CSIDL_COMMON_DOCUMENTS, prv_Data.tszCommonCPDir,ARR_SIZE(prv_Data.tszCommonCPDir))) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("GetSpecialPath(CSIDL_COMMON_DOCUMENTS) failed, ec = %ld"), dwReturn); prv_Data.tszCommonCPDir[0] = _T('\0'); goto Exit; } // // Combine the full Folder name // if ((_tcslen(tszName) + _tcslen(prv_Data.tszCommonCPDir) + 1) >= ARR_SIZE(prv_Data.tszCommonCPDir)) // 1 for '\' { // // not enough place // dwReturn = ERROR_OUTOFMEMORY; VERBOSE(DBG_WARNING, _T("Full path to the Common CP dir for PFW is too long, ec = %ld"), dwReturn); goto Exit; } _tcscat(prv_Data.tszCommonCPDir,_T("\\")); _tcscat(prv_Data.tszCommonCPDir, tszName); VERBOSE(DBG_MSG, _T("Full path for Common PFW Cover Pages is '%s'"), prv_Data.tszCommonCPDir); Exit: if (hModule) { FreeLibrary(hModule); } return dwReturn; } static DWORD prv_SaveArchives( ) /*++ Routine name : prv_SaveArchives Routine description: Store PFW SentItems & Inbox Archive Folder. SentItems is taken from Registry : under Fax/Archive Directory. Inbox Folders List is created by prv_StoreDevices(), that should be called before and that fills prv_Data.plptstrInboxFolder with an array of Inbox Folders. This function transforms the data in prv_Data.plptstrInboxFolders into the required format, and stores in the Registry. Frees the prv_Data.plptstrInboxFolders. Author: Iv Garber (IvG), Mar, 2001 Return Value: static DWORD -- failure or success --*/ { DWORD dwReturn = NO_ERROR; DWORD dwListLen = 0; DWORD dwI = 0; HKEY hFromKey = NULL; HKEY hToKey = NULL; LPTSTR lptstrFolder = NULL; LPTSTR lptstrCursor = NULL; DBG_ENTER(_T("prv_SaveArchives"), dwReturn); // // Open Registry Key to read the ArchiveDirectory value // hFromKey = OpenRegistryKey(HKEY_LOCAL_MACHINE, REGKEY_SOFTWARE, FALSE, KEY_READ); if (!hFromKey) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to open Registry for Fax, ec = %ld."), dwReturn); goto Exit; } // // Open Registry Key to write the Archive values // hToKey = OpenRegistryKey(HKEY_LOCAL_MACHINE, REGKEY_FAX_SETUP, FALSE, KEY_SET_VALUE); if (!hToKey) { dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to open Registry for Fax/Setup, ec = %ld."), dwReturn); goto Exit; } // // Read & Write Outgoing Archive Folder // lptstrFolder = GetRegistryString(hFromKey, REGVAL_PFW_OUTBOXDIR, EMPTY_STRING); VERBOSE(DBG_MSG, _T("Outgoing Archive Folder is : %s"), lptstrFolder); SetRegistryString(hToKey, REGVAL_W2K_SENT_ITEMS, lptstrFolder); MemFree(lptstrFolder); lptstrFolder = NULL; // // Create valid REG_MULTI_SZ string from List of Inbox Folders // if (!prv_Data.plptstrInboxFolders || prv_Data.dwInboxFoldersCount == 0) { // // no Inbox Folders found // goto Exit; } // // Calculate the length of the string // for ( dwI = 0 ; dwI < prv_Data.dwInboxFoldersCount ; dwI++ ) { dwListLen += _tcslen(prv_Data.plptstrInboxFolders[dwI]) + 1; } // // Allocate that string // lptstrFolder = LPTSTR(MemAlloc((dwListLen + 1) * sizeof(TCHAR))); if (!lptstrFolder) { // // Not enough memory // VERBOSE(DBG_WARNING, _T("Not enough memory to store the Inbox Folders.")); goto Exit; } ZeroMemory(lptstrFolder, ((dwListLen + 1) * sizeof(TCHAR))); lptstrCursor = lptstrFolder; // // Fill with the Inbox Folders // for ( dwI = 0 ; dwI < prv_Data.dwInboxFoldersCount ; dwI++ ) { if (prv_Data.plptstrInboxFolders[dwI]) { _tcscpy(lptstrCursor, prv_Data.plptstrInboxFolders[dwI]); lptstrCursor += _tcslen(prv_Data.plptstrInboxFolders[dwI]) + 1; MemFree(prv_Data.plptstrInboxFolders[dwI]); } } MemFree(prv_Data.plptstrInboxFolders); prv_Data.plptstrInboxFolders = NULL; prv_Data.dwInboxFoldersCount = 0; // // Additional NULL at the end // *lptstrCursor = _T('\0'); if (!SetRegistryStringMultiSz(hToKey, REGVAL_W2K_INBOX, lptstrFolder, ((dwListLen + 1) * sizeof(TCHAR)))) { // // Failed to store Inbox Folders // dwReturn = GetLastError(); VERBOSE(DBG_WARNING, _T("Failed to SetRegistryStringMultiSz() for W2K_Inbox, ec = %ld."), dwReturn); } Exit: if (hFromKey) { RegCloseKey(hFromKey); } if (hToKey) { RegCloseKey(hToKey); } MemFree(lptstrFolder); if (prv_Data.plptstrInboxFolders) { for ( dwI = 0 ; dwI < prv_Data.dwInboxFoldersCount ; dwI++ ) { MemFree(prv_Data.plptstrInboxFolders[dwI]); } MemFree(prv_Data.plptstrInboxFolders); prv_Data.plptstrInboxFolders = NULL; } prv_Data.dwInboxFoldersCount = 0; return dwReturn; } /*++ Routine description: Copy a content of one registry key into another, using shlwapi.dll Arguments: hkeyDest [in] - handle for destination registry key lpszDestSubKeyName [in] - name of destination subkey hkeySrc [in] - handle for source registry key lpszSrcSubKeyName [in] - name of source subkey Return Value: Win32 Error code Note: If you already have an open handle to the source\dest, you can provide them are hKeySrc/hKeyDest, and set the approriate name to "". --*/ DWORD CopyRegistrySubkeys2( HKEY hKeyDest, LPCTSTR lpszDestSubKeyName, HKEY hKeySrc, LPCTSTR lpszSrcSubKeyName ) { DWORD ec = ERROR_SUCCESS; HKEY hKeyDestReal = NULL; // Create destination Key hKeyDestReal = OpenRegistryKey( hKeyDest, lpszDestSubKeyName, TRUE, // create KEY_WRITE); if (!hKeyDestReal) { ec = GetLastError(); goto exit; } // // copy subkeys recursively // ec = SHCopyKey(hKeySrc, lpszSrcSubKeyName, hKeyDestReal, 0); if (ERROR_SUCCESS != ec) { goto exit; } exit: if (NULL != hKeyDestReal) { RegCloseKey(hKeyDestReal); } return ec; } // FaxCopyRegSubkeys /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupDevice // // Purpose: // This functions handles the adaptation of a device // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// BOOL FixupDevice(HKEY hKey, LPWSTR lpwstrKeyName, DWORD dwIndex, LPVOID lpContext) { WCHAR wszDeviceId[32] = {0}; DWORD dwRet = ERROR_SUCCESS; BOOL bRet = TRUE; DWORD dwDeviceId = 0; HKEY hDevices = NULL; HKEY hDevice = NULL; DBG_ENTER(_T("FixupDevice"),dwRet); if (lpwstrKeyName==NULL) { goto exit; } if (wcscmp(lpwstrKeyName,REGKEY_UNASSOC_EXTENSION_DATA)==0) { VERBOSE(DBG_MSG, _T("No migration for UnassociatedExtensionData")); goto exit; } VERBOSE(DBG_MSG, _T("Migrating the %s device"),lpwstrKeyName); // convert the key name from Hex to Decimal dwDeviceId = wcstol(lpwstrKeyName,NULL,16); if (dwDeviceId==0) { VERBOSE(SETUP_ERR, _T("converting the device ID to decimal failed")); bRet = FALSE; goto exit; } if (dwDeviceId>g_LastUniqueLineId) { g_LastUniqueLineId = dwDeviceId; } if (wsprintf(wszDeviceId,L"%010d",dwDeviceId)==0) { VERBOSE(SETUP_ERR, _T("wsprintf failed")); bRet = FALSE; goto exit; } // create the new device key hDevices = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_FAX_DEVICES,TRUE,KEY_WRITE); if (hDevices==NULL) { VERBOSE(SETUP_ERR, _T("OpenRegistryKey REGKEY_FAX_DEVICES failed (ec=%ld)"),GetLastError()); bRet = FALSE; goto exit; } // create a key under HKLM\Sw\Ms\Fax\Devices\wszDeviceId hDevice = OpenRegistryKey(hDevices,wszDeviceId,TRUE,KEY_WRITE); if (hDevice==NULL) { VERBOSE(SETUP_ERR, _T("OpenRegistryKey %s failed (ec=%ld)"),wszDeviceId,GetLastError()); bRet = FALSE; goto exit; } // set the 'Permanent Lineid' REG_DWORD if (!SetRegistryDword(hDevice,REGVAL_PERMANENT_LINEID,dwDeviceId)) { VERBOSE(SETUP_ERR, _T("SetRegistryDword REGVAL_PERMANENT_LINEID failed (ec=%ld)"),GetLastError()); bRet = FALSE; goto exit; } // create an entry under the service GUID for the device. // and copy the rest of the setting to the new location dwRet = CopyRegistrySubkeys2(hDevice, REGKEY_FAXSVC_DEVICE_GUID ,hKey,_T("")); if (dwRet!=ERROR_SUCCESS) { VERBOSE(DBG_WARNING, _T("CopyRegistrySubkeys() failed, ec = %ld."), dwRet); goto exit; } exit: if (hDevices) { RegCloseKey(hDevices); } if (hDevice) { RegCloseKey(hDevice); } return bRet; } /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupDevicesNode // // Purpose: // This functions handles the adaptation of the devices // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // Each device is copied but the structure in the registry in // a little different. specifically, the device data is kept // under a GUID. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// DWORD FixupDevicesNode() { HKEY hFax = NULL; DWORD dwRet = ERROR_SUCCESS; DBG_ENTER(_T("FixupDevicesNode"),dwRet); // enumerate all the devices, and for each, move its key under its GUID dwRet = EnumerateRegistryKeys( HKEY_LOCAL_MACHINE, REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_DEVICES, FALSE, FixupDevice, NULL); VERBOSE(DBG_MSG, _T("For SBS 5.0 Server, enumerated %ld devices."), dwRet); // write the LastUniqueLineId to HKLM\Sw\Ms\Fax. hFax = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_FAXSERVER,TRUE,KEY_WRITE); if (hFax==NULL) { dwRet = GetLastError(); VERBOSE(SETUP_ERR, _T("OpenRegistryKey REGKEY_FAXSERVER failed (ec=%ld)"),dwRet); return dwRet; } if (!SetRegistryDword(hFax,REGVAL_LAST_UNIQUE_LINE_ID,g_LastUniqueLineId+1)) { dwRet = GetLastError(); VERBOSE(SETUP_ERR, _T("SetRegistryDword REGVAL_LAST_UNIQUE_LINE_ID failed (ec=%ld)"),dwRet); return dwRet; } return ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupDeviceProvider // // Purpose: // This functions handles the adaptation of a device provider // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // The 'Microsoft Modem Device Provider' is not copied. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// BOOL FixupDeviceProvider(HKEY hKey, LPWSTR lpwstrKeyName, DWORD dwIndex, LPVOID lpContext) { DWORD dwRet = ERROR_SUCCESS; BOOL bRet = TRUE; HKEY hDeviceProviders = NULL; DBG_ENTER(_T("FixupDeviceProvider"),dwRet); if (lpwstrKeyName==NULL) { goto exit; } if (wcscmp(lpwstrKeyName,REGKEY_MODEM_PROVIDER)==0) { VERBOSE(DBG_MSG, _T("No migration for the Microsoft Modem Device Provider")); goto exit; } VERBOSE(DBG_MSG, _T("Migrating the %s Device provider"),lpwstrKeyName); // create a key under HKLM\Sw\Ms\Fax\Device Providers hDeviceProviders = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_DEVICE_PROVIDER_KEY,TRUE,KEY_WRITE); if (hDeviceProviders==NULL) { VERBOSE(SETUP_ERR, _T("OpenRegistryKey REGKEY_DEVICE_PROVIDER_KEY failed (ec=%ld)"),GetLastError()); bRet = FALSE; goto exit; } // create a key under HKLM\Sw\Ms\Fax\Device Providers\name dwRet = CopyRegistrySubkeys2(hDeviceProviders,lpwstrKeyName,hKey,_T("")); if (dwRet!=ERROR_SUCCESS) { VERBOSE(DBG_WARNING, _T("CopyRegistrySubkeys() failed, ec = %ld."), dwRet); goto exit; } exit: if (hDeviceProviders) { RegCloseKey(hDeviceProviders); } return bRet; } /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupDeviceProvidersNode // // Purpose: // This functions handles the adaptation of the device providers // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // The 'Microsoft Modem Device Provider' is not copied and as for // other FSPs, the key under which they are registered is changed // to hold the GUID of the FSP. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// DWORD FixupDeviceProvidersNode() { DWORD dwRet = ERROR_SUCCESS; DBG_ENTER(_T("FixupDeviceProvidersNode"),dwRet); // enumerate the rest of the FSPs, and for each, move its key under its GUID dwRet = EnumerateRegistryKeys( HKEY_LOCAL_MACHINE, REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_DEVICE_PROVIDERS, FALSE, FixupDeviceProvider, NULL); VERBOSE(DBG_MSG, _T("For SBS 5.0 Server, enumerated %ld device providers."), dwRet); return ERROR_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupRoutingExtension // // Purpose: // This functions handles the adaptation of a routing extension // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // The 'Microsoft Routing Extension' is not copied and as for // other Routing extensions, they're copied as is. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// BOOL FixupRoutingExtension(HKEY hKey, LPWSTR lpwstrKeyName, DWORD dwIndex, LPVOID lpContext) { DWORD dwRet = ERROR_SUCCESS; BOOL bRet = TRUE; HKEY hRoutingExtensions = NULL; DBG_ENTER(_T("FixupRoutingExtension"),dwRet); if (lpwstrKeyName==NULL) { goto exit; } if (wcscmp(lpwstrKeyName,REGKEY_ROUTING_EXTENSION)==0) { VERBOSE(DBG_MSG, _T("No migration for the Microsoft Routing Extension")); goto exit; } VERBOSE(DBG_MSG, _T("Migrating the %s Routing extension"),lpwstrKeyName); // create a key under HKLM\Sw\Ms\Fax\Routing Extensions hRoutingExtensions = OpenRegistryKey(HKEY_LOCAL_MACHINE,REGKEY_ROUTING_EXTENSION_KEY,TRUE,KEY_WRITE); if (hRoutingExtensions==NULL) { VERBOSE(SETUP_ERR, _T("OpenRegistryKey REGKEY_ROUTING_EXTENSIONS failed (ec=%ld)"),GetLastError()); bRet = FALSE; goto exit; } // create a key under HKLM\Sw\Ms\Fax\Routing Extensions\name dwRet = CopyRegistrySubkeys2(hRoutingExtensions,lpwstrKeyName,hKey,_T("")); if (dwRet!=ERROR_SUCCESS) { VERBOSE(DBG_WARNING, _T("CopyRegistrySubkeys() failed, ec = %ld."), dwRet); goto exit; } exit: if (hRoutingExtensions) { RegCloseKey(hRoutingExtensions); } return bRet; } /////////////////////////////////////////////////////////////////////////////////////// // Function: // FixupRoutingExtensionsNode // // Purpose: // This functions handles the adaptation of the routing extension // in the registry from the format used in SBS2000 to the format // used by Server 2003 fax. // The 'Microsoft Routing Extension' is not copied to the destination. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 18-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// DWORD FixupRoutingExtensionsNode() { DWORD dwRet = ERROR_SUCCESS; DBG_ENTER(_T("FixupRoutingExtensionsNode"),dwRet); // enumerate the rest of the Routing Extension, and for each decide whether to copy or not. dwRet = EnumerateRegistryKeys( HKEY_LOCAL_MACHINE, REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_ROUTING_EXTENSIONS, FALSE, FixupRoutingExtension, NULL); VERBOSE(DBG_MSG, _T("For SBS 5.0 Server, enumerated %ld routing extensions."), dwRet); return ERROR_SUCCESS; } struct REG_KEY_PAIR { LPCTSTR lpctstrSourceKey; LPCTSTR lpctstrDestinationKey; } g_RegKeyPairs[] = { { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_ACTIVITY_LOG_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_ACTIVITY_LOG_CONFIG }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_DEVICES _T("\\") REGKEY_UNASSOC_EXTENSION_DATA, REGKEY_FAXSERVER _T("\\") REGKEY_DEVICES _T("\\") REGKEY_UNASSOC_EXTENSION_DATA }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_LOGGING, REGKEY_FAXSERVER _T("\\") REGKEY_LOGGING }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_ARCHIVE_INBOX_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_ARCHIVE_INBOX_CONFIG }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_OUTBOUND_ROUTING, REGKEY_FAXSERVER _T("\\") REGKEY_OUTBOUND_ROUTING }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_RECEIPTS_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_RECEIPTS_CONFIG }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_SECURITY_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_SECURITY_CONFIG }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_ARCHIVE_SENTITEMS_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_ARCHIVE_SENTITEMS_CONFIG }, { REGKEY_SBS2000_FAX_BACKUP _T("\\") REGKEY_TAPIDEVICES_CONFIG, REGKEY_FAXSERVER _T("\\") REGKEY_TAPIDEVICES_CONFIG } }; const INT iCopyKeys = sizeof(g_RegKeyPairs)/sizeof(g_RegKeyPairs[0]); LPCTSTR lpctstrValuesToCopy[] = { REGVAL_BRANDING, REGVAL_DIRTYDAYS, REGVAL_RETRIES, REGVAL_RETRYDELAY, REGVAL_SERVERCP, REGVAL_STARTCHEAP, REGVAL_STOPCHEAP, REGVAL_USE_DEVICE_TSID }; const INT iCopyValues = sizeof(lpctstrValuesToCopy)/sizeof(lpctstrValuesToCopy[0]); /////////////////////////////////////////////////////////////////////////////////////// // Function: // fxocUpg_MoveRegistry // // Purpose: // When a machine running SBS2000 server was upgraded to Windows Server 2003 // we migrate the existing registry from SBS to the fax service. // For most registry entries, the existing format is still compatible with // the format used by SBS2000 so we just 'move' the registry around from // one place to the other. // This function is responsible for moving the following subkeys under Fax: // ActivityLogging // Device Providers\ // Devices\UnassociatedExtensionData // Logging // Inbox // Outbound Routing // Receipts // Routing Extensions\ // Security // SentItems // TAPIDevices // // After moving the registry, some fixup to the registry takes place in order // to make modifications from the format used in SBS2000 to the one used // in Server 2003 Fax. // // Params: // None // // Return Value: // NO_ERROR - in case of success // Win32 Error code otherwise // // Author: // Mooly Beery (MoolyB) 17-Dec-2001 /////////////////////////////////////////////////////////////////////////////////////// DWORD fxocUpg_MoveRegistry(void) { INT iCount = 0; DWORD dwRet = NO_ERROR; HKEY hDotNetFax = NULL; HKEY hSbsFax = NULL; DBG_ENTER(_T("fxocUpg_MoveRegistry"),dwRet); if ( !(prv_Data.dwFaxInstalledPriorUpgrade & FXSTATE_SBS5_SERVER) ) { VERBOSE(DBG_MSG, _T("SBS2000 was not installed, nothing to migrate")); goto exit; } // Share the printer (unless printer sharing rule was specified in unattended file) if (IsFaxShared() && !fxUnatnd_IsPrinterRuleDefined()) { VERBOSE(DBG_MSG, _T("SBS2000 was installed, sharing printer")); fxocPrnt_SetFaxPrinterShared(TRUE); } // first, we copy all the above mentioned registry from HKLM\\Sw\\Ms\\SharedFax to HKLM\\Sw\\Ms\\Fax for (iCount=0; iCount