windows-nt/Source/XPSP1/NT/net/tapi/tregupr2/tregupr2.c

1952 lines
59 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************************************************************
Copyright (c) 1998-1999 Microsoft Corporation
Module Name: tregupr2.c
Abstract: Upgrades the telephony registry settings to the post NT5b2 format
Author: radus - 09/11/98
Notes: stolen from \Nt\Private\tapi\dev\apps\tapiupr\tapiupr.c
Rev History:
****************************************************************************/
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <stdlib.h>
// from the old version of loc_comn.h
#define MAXLEN_AREACODE 16
#define OLDFLAG_LOCATION_ALWAYSINCLUDEAREACODE 0x00000008
//
#include "tregupr2.h"
#include "debug.h"
#define BACKUP_OLD_KEYS
#define BACKUP_FILE_LOCATIONS _T("REGLOCS.OLD")
#define BACKUP_FILE_USER_LOCATIONS _T("REGULOCS.OLD")
#define BACKUP_FILE_CARDS _T("REGCARDS.OLD")
#define AREACODERULE_INCLUDEALLPREFIXES 0x00000001
#define AREACODERULE_DIALAREACODE 0x00000002
#define AREACODERULE_DIALNUMBERTODIAL 0x00000004
#define US_COUNTRY_CODE(x) ((x) == 1 || \
(x >= 100 && x < 200))
#define MAXLEN_NUMBER_LEN 12
#define MAXLEN_RULE 128
#define MAXLEN_ACCESS_NUMBER 128
#define MAXLEN_PIN 128
#define TEMPORARY_ID_FLAG 0x80000000
#define PRIVATE static
PRIVATE DWORD ConvertOneLocation( HKEY hLocation);
PRIVATE DWORD CreateAreaCodeRule( HKEY hParent,
int iRuleNumber,
LPCTSTR pszAreaCodeToCall,
LPCTSTR pszNumberToDial,
LPBYTE pbPrefixes,
DWORD dwPrefixesLength,
DWORD dwFlags
);
PRIVATE DWORD ConvertOneCard(HKEY hCard, DWORD);
PRIVATE DWORD ConvertPIN(HKEY hCard, DWORD);
PRIVATE BOOL IsTelephonyDigit(TCHAR );
PRIVATE DWORD SplitCallingCardRule(HKEY hCard, LPCTSTR pszRuleName, LPCTSTR pszAccessNumberName);
PRIVATE DWORD RegRenameKey( HKEY hParentKey,
LPCTSTR pszOldName,
LPCTSTR pszNewName);
PRIVATE DWORD RegCopyKeyRecursive(HKEY hSrcParentKey, LPCTSTR pszSrcName,
HKEY hDestParentKey, LPCTSTR pszDestName);
#ifdef BACKUP_OLD_KEYS
#ifdef WINNT
PRIVATE
BOOL
EnablePrivilege(
PTSTR PrivilegeName,
BOOL Enable,
BOOL *Old
);
#endif // WINNT
PRIVATE
BOOL
SaveKey(
HKEY hKey,
LPCTSTR pszFileName
);
#endif // BACKUP_OLD_KEYS
PRIVATE const TCHAR gszName[] = _T("Name");
PRIVATE const TCHAR gszID[] = _T("ID");
PRIVATE const TCHAR gszAreaCode[] = _T("AreaCode");
PRIVATE const TCHAR gszAreaCodeRules[] = _T("AreaCodeRules");
PRIVATE const TCHAR gszCountry[] = _T("Country");
PRIVATE const TCHAR gszFlags[] = _T("Flags");
PRIVATE const TCHAR gszDisableCallWaiting[] = _T("DisableCallWaiting");
PRIVATE const TCHAR gszTollList[] = _T("TollList");
PRIVATE const TCHAR gszNoPrefAC[] = _T("NoPrefAC");
PRIVATE const TCHAR gszPrefixes[] = _T("Prefixes");
PRIVATE const TCHAR gszRules[] = _T("Rules");
PRIVATE const TCHAR gszRule[] = _T("Rule");
PRIVATE const TCHAR gszAreaCodeToCall[] = _T("AreaCodeToCall");
PRIVATE const TCHAR gszNumberToDial[] = _T("NumberToDial");
PRIVATE const TCHAR gszCard[] = _T("Card");
PRIVATE const TCHAR gszCards[] = _T("Cards");
PRIVATE const TCHAR gszLocalRule[] = _T("LocalRule");
PRIVATE const TCHAR gszLDRule[] = _T("LDRule");
PRIVATE const TCHAR gszInternationalRule[] = _T("InternationalRule");
PRIVATE const TCHAR gszLocalAccessNumber[] = _T("LocalAccessNumber");
PRIVATE const TCHAR gszLDAccessNumber[] = _T("LDAccessNumber");
PRIVATE const TCHAR gszInternationalAccessNumber[] = _T("InternationalAccessNumber");
PRIVATE const TCHAR gszAccountNumber[] = _T("AccountNumber");
PRIVATE const WCHAR gwszPIN[] = L"PIN";
PRIVATE const TCHAR gszNumEntries[] = _T("NumEntries");
PRIVATE const TCHAR gszEmpty[] = _T("");
PRIVATE const TCHAR gszMultiEmpty[] = _T("\0");
PRIVATE const TCHAR gszLocations[] = _T("Locations");
PRIVATE const TCHAR gszLocation[] = _T("Location");
PRIVATE const TCHAR gszLocationsPath[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Locations");
PRIVATE const TCHAR gszCardsPath[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Telephony\\Cards");
PRIVATE const TCHAR gszUSLDSpecifier[] = _T("1");
PRIVATE const TCHAR gszLocationListVersion[] = _T("LocationListVersion");
PRIVATE const TCHAR gszCardListVersion[] = _T("CardListVersion");
PRIVATE const TCHAR gszKeyRenameHistory[] = _T("KeyRenameHistory");
#pragma check_stack ( off )
//***************************************************************************
//***************************************************************************
//***************************************************************************
//
// ConvertLocations - convert the telephony locations to the new format.
// see nt\private\tapi\dev\docs\dialrules.doc
//
DWORD ConvertLocations(void)
{
TCHAR Location[sizeof(gszLocation)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
TCHAR NewLocation[sizeof(gszLocation)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
DWORD dwError = ERROR_SUCCESS;
HKEY hLocations = NULL;
HKEY hLocation = NULL;
DWORD dwNumEntries;
DWORD dwCount;
DWORD dwRenameEntryCount;
DWORD dwCountPhase1;
DWORD dwLength;
DWORD dwType;
DWORD dwLocationID;
DWORD dwLocationIDTmp;
DWORD dwValue;
PDWORD pdwRenameList = NULL;
PDWORD pdwRenameEntry;
PDWORD pdwRenameEntryPhase1;
#ifdef BACKUP_OLD_KEYS
TCHAR szPath[MAX_PATH+1];
#endif
DBGOUT((9, "ConvertLocations - Enter"));
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
gszLocationsPath,
0,
KEY_READ | KEY_WRITE,
&hLocations
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Locations key not present, so there's nothing to convert"));
//Nothing to convert
return ERROR_SUCCESS;
}
EXIT_IF_DWERROR();
// Version check
if(!IsLocationListInOldFormat(hLocations))
{
//Nothing to convert
DBGOUT((1, "Locations key is already in the new format"));
RegCloseKey(hLocations);
return ERROR_SUCCESS;
}
#ifdef BACKUP_OLD_KEYS
// Try to save the old key
dwError = GetWindowsDirectory(szPath, MAX_PATH - 12); // a 8+3 name
if(dwError)
{
if(szPath[3] != _T('\0'))
lstrcat(szPath, _T("\\"));
lstrcat(szPath, BACKUP_FILE_LOCATIONS);
SaveKey(hLocations, szPath);
}
else
DBGOUT((1, "Cannot get windows directory (?!?)"));
dwError = ERROR_SUCCESS;
#endif
// Read number of entries
dwLength = sizeof(dwNumEntries);
dwError = RegQueryValueEx( hLocations,
gszNumEntries,
NULL,
&dwType,
(BYTE *)&dwNumEntries,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_DWORD)
{
dwError = ERROR_INVALID_DATA;
assert(FALSE);
}
// The value could be missing in an empty key
if(dwError != ERROR_SUCCESS)
dwNumEntries = 0;
// Alloc a rename list for the worst case (all key to be renamed using temporary IDs)
if(dwNumEntries>0)
{
pdwRenameList = (PDWORD)GlobalAlloc(GPTR, dwNumEntries*4*sizeof(DWORD) );
if(pdwRenameList==NULL)
{
DBGOUT((1, "Cannot allocate the Rename List"));
dwError = ERROR_OUTOFMEMORY;
goto forced_exit;
}
}
pdwRenameEntry = pdwRenameList;
dwRenameEntryCount = 0;
// Convert from end to the begining in order to avoid name conflicts during the key renames
for(dwCount = dwNumEntries-1; (LONG)dwCount>=0; dwCount--)
{
wsprintf(Location, _T("%s%d"), gszLocation, dwCount);
dwError = RegOpenKeyEx( hLocations,
Location,
0,
KEY_READ | KEY_WRITE,
&hLocation
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Cannot open old %s", Location));
// Try to recover - skip to the next entry
continue;
}
EXIT_IF_DWERROR();
// Read the ID for later usage
dwLength = sizeof(dwLocationID);
dwError = RegQueryValueEx( hLocation,
gszID,
NULL,
&dwType,
(LPBYTE)&dwLocationID,
&dwLength
);
if(dwError == ERROR_SUCCESS)
{
// Convert the location to the new format
dwError = ConvertOneLocation(hLocation);
if(dwError != ERROR_SUCCESS)
{
DBGOUT((1, "%s conversion failed with error %d. Trying to continue...", Location, dwError));
}
RegCloseKey(hLocation);
hLocation = NULL;
// Rename the key if it is necessary
if(dwLocationID != dwCount)
{
wsprintf(NewLocation, _T("%s%d"), gszLocation, dwLocationID);
// Check the destination for an old key still present. It may be possible to find one if
// the original TAPI version was TELEPHON.INI-based.
assert(!(dwLocationID & TEMPORARY_ID_FLAG));
dwLocationIDTmp = dwLocationID;
dwError = RegOpenKeyEx( hLocations,
NewLocation,
0,
KEY_READ,
&hLocation
);
if(dwError==ERROR_SUCCESS)
{
// use a temporary ID
dwLocationIDTmp |= TEMPORARY_ID_FLAG;
wsprintf(NewLocation, _T("%s%d"), gszLocation, dwLocationIDTmp);
}
if(hLocation)
{
RegCloseKey(hLocation);
hLocation = NULL;
}
dwError = RegRenameKey( hLocations,
Location,
NewLocation
);
EXIT_IF_DWERROR();
// trace the rename. It will be useful when we try to upgrade the HKEY_CURRENT_USER/../Locations key
*pdwRenameEntry++ = dwCount;
*pdwRenameEntry++ = dwLocationIDTmp;
dwRenameEntryCount++;
}
DBGOUT ((9, "Converted location %d (ID %d)", dwCount, dwLocationID));
}
}
dwError = ERROR_SUCCESS;
// Rewalk the list for renaming the keys with temporary IDs
pdwRenameEntryPhase1 = pdwRenameList;
dwCountPhase1 = dwRenameEntryCount;
for(dwCount=0; dwCount<dwCountPhase1; dwCount++)
{
pdwRenameEntryPhase1++;
dwLocationIDTmp = *pdwRenameEntryPhase1++;
if(dwLocationIDTmp & TEMPORARY_ID_FLAG)
{
wsprintf(Location, _T("%s%d"), gszLocation, dwLocationIDTmp);
dwLocationID = dwLocationIDTmp & ~TEMPORARY_ID_FLAG;
wsprintf(NewLocation, _T("%s%d"), gszLocation, dwLocationID);
dwError = RegRenameKey( hLocations,
Location,
NewLocation
);
EXIT_IF_DWERROR();
*pdwRenameEntry++ = dwLocationIDTmp;
*pdwRenameEntry++ = dwLocationID;
dwRenameEntryCount++;
DBGOUT ((9, "Renamed to permanent ID %d", dwLocationID));
}
}
// delete the DisableCallWaiting value
RegDeleteValue( hLocations,
gszDisableCallWaiting
);
// delete the NumEntries value. We don't need it any more
RegDeleteValue( hLocations,
gszNumEntries);
// add the rename history
dwError = RegSetValueEx( hLocations,
gszKeyRenameHistory,
0,
REG_BINARY,
(PBYTE)pdwRenameList,
dwRenameEntryCount*2*sizeof(DWORD)
);
EXIT_IF_DWERROR();
// add the versioning value
dwValue = TAPI_LOCATION_LIST_VERSION;
dwError = RegSetValueEx( hLocations,
gszLocationListVersion,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
EXIT_IF_DWERROR();
forced_exit:
if(hLocation)
RegCloseKey(hLocation);
if(hLocations)
RegCloseKey(hLocations);
if(pdwRenameList)
GlobalFree(pdwRenameList);
DBGOUT((9, "ConvertLocations - Exit %xh", dwError));
return dwError;
}
//***************************************************************************
//
// ConvertOneLocation - convert one location
// hLocation is the handle of the LocationX key
// Note The key rename according to location ID is executed in ConvertLocations
PRIVATE DWORD ConvertOneLocation( HKEY hLocation)
{
DWORD dwError = ERROR_SUCCESS;
LPTSTR pTollList = NULL;
LPBYTE pNoPrefAC = NULL;
TCHAR *pCrt;
TCHAR AreaCode[MAXLEN_AREACODE];
DWORD dwFlags;
DWORD dwCountryID;
DWORD dwType;
DWORD dwLength;
DWORD dwTollListLength;
DWORD dwDisp;
HKEY hAreaCodeRules = NULL;
int iRuleNumber;
DBGOUT((9, "ConvertOneLocation - Enter"));
assert(hLocation);
// Read the current location flags
dwLength = sizeof(dwFlags);
dwError = RegQueryValueEx( hLocation,
gszFlags,
NULL,
&dwType,
(BYTE *)&dwFlags,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_DWORD)
{
dwError=ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
//Read the current Area Code
dwLength = sizeof(AreaCode);
dwError = RegQueryValueEx( hLocation,
gszAreaCode,
NULL,
&dwType,
(BYTE *)AreaCode,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_SZ)
{
dwError=ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
//Read the current Country ID
dwLength = sizeof(dwCountryID);
dwError = RegQueryValueEx( hLocation,
gszCountry,
NULL,
&dwType,
(BYTE *)&dwCountryID,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_DWORD)
{
dwError=ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
// create the AreaCodeRules subkey
dwError = RegCreateKeyEx( hLocation,
gszAreaCodeRules,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hAreaCodeRules,
&dwDisp
);
if(dwError==ERROR_SUCCESS && dwDisp != REG_CREATED_NEW_KEY)
{
dwError=ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
iRuleNumber = 0;
// Create a rule for "Always Include Area Code" flag..
if(dwFlags & OLDFLAG_LOCATION_ALWAYSINCLUDEAREACODE)
{
dwError = CreateAreaCodeRule( hAreaCodeRules,
iRuleNumber++,
AreaCode,
gszEmpty,
(LPBYTE)gszMultiEmpty,
sizeof(gszMultiEmpty),
AREACODERULE_DIALAREACODE | AREACODERULE_INCLUDEALLPREFIXES
);
EXIT_IF_DWERROR();
// update the location flag
dwFlags &= ~OLDFLAG_LOCATION_ALWAYSINCLUDEAREACODE;
dwLength = sizeof(dwFlags);
dwError = RegSetValueEx( hLocation,
gszFlags,
0,
REG_DWORD,
(CONST BYTE *)&dwFlags,
dwLength
);
EXIT_IF_DWERROR();
}
// The TollList and NoPrefAC were valid only in countries with Country=1 (US, Canada)
// Ignore them if other country
if(US_COUNTRY_CODE(dwCountryID))
{
// Translate TollList
// Length...
dwError = RegQueryValueEx( hLocation,
gszTollList,
NULL,
NULL,
NULL,
&dwTollListLength);
if(dwError == ERROR_SUCCESS)
{
pTollList=GlobalAlloc(GPTR, dwTollListLength+sizeof(TCHAR)); // We'll convert in place to a
// REG_MULTI_SZ, so reserve an extra space for safety
dwError = pTollList!=NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
// ..and read
dwError = RegQueryValueEx( hLocation,
gszTollList,
NULL,
&dwType,
(BYTE *)pTollList,
&dwTollListLength
);
if(dwError == ERROR_SUCCESS && dwType != REG_SZ)
{
dwError = ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
// try to find one toll prefix
pCrt = pTollList;
//skip any unwanted commas
while(*pCrt==_T(','))
{
pCrt++;
dwTollListLength -= sizeof(TCHAR);
}
if(*pCrt)
{
TCHAR * pOut = pCrt;
// convert inplace to a REG_MULTI_SZ
while(*pCrt)
{
while(*pCrt && *pCrt!=_T(','))
{
pCrt++;
}
if(!*pCrt)
{
// incorrect string (does not end with a comma)
pCrt++;
*pCrt = _T('\0');
dwTollListLength+=sizeof(TCHAR);
}
else
*pCrt++ = _T('\0');
}
// Create one rule for all the prefixes
dwError = CreateAreaCodeRule( hAreaCodeRules,
iRuleNumber++,
AreaCode,
gszUSLDSpecifier,
(BYTE *)pOut,
dwTollListLength,
AREACODERULE_DIALAREACODE | AREACODERULE_DIALNUMBERTODIAL
);
EXIT_IF_DWERROR();
}
}
DBGOUT((9, "ConvertOneLocation - Success TollList"));
// Translate NoPrefAC
// Length...
dwError = RegQueryValueEx( hLocation,
gszNoPrefAC,
NULL,
NULL,
NULL,
&dwLength);
if(dwError== ERROR_SUCCESS && dwLength>0)
{
int iCount;
DWORD *pValue;
TCHAR AreaCodeToCall[MAXLEN_NUMBER_LEN];
pNoPrefAC=GlobalAlloc(GPTR, dwLength);
dwError = pNoPrefAC!=NULL ? ERROR_SUCCESS : ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
// ..and read
dwError = RegQueryValueEx( hLocation,
gszNoPrefAC,
NULL,
&dwType,
pNoPrefAC,
&dwLength
);
if(dwError == ERROR_SUCCESS && dwType != REG_BINARY)
{
dwError = ERROR_INVALID_DATA;
assert(FALSE);
}
EXIT_IF_DWERROR();
iCount = dwLength/4;
pValue = (DWORD *)pNoPrefAC;
while(iCount--)
{
// Create one rule for each area code
_itot(*pValue, AreaCodeToCall, 10);
dwError = CreateAreaCodeRule( hAreaCodeRules,
iRuleNumber++,
AreaCodeToCall,
gszEmpty,
(LPBYTE)gszMultiEmpty,
sizeof(gszMultiEmpty),
AREACODERULE_DIALAREACODE | AREACODERULE_INCLUDEALLPREFIXES
);
EXIT_IF_DWERROR();
pValue++;
}
}
DBGOUT((9, "ConvertOneLocation - Success NoPrefAC"));
}
dwError = ERROR_SUCCESS;
// delete the TollList Value
RegDeleteValue( hLocation,
gszTollList
);
// delete the NoPrefAC Value
RegDeleteValue( hLocation,
gszNoPrefAC
);
// delete the ID Value
RegDeleteValue( hLocation,
gszID
);
forced_exit:
if(hAreaCodeRules)
RegCloseKey(hAreaCodeRules);
if(pTollList)
GlobalFree(pTollList);
if(pNoPrefAC)
GlobalFree(pNoPrefAC);
DBGOUT((9, "ConvertOneLocation - Exit %xh", dwError));
return dwError;
}
//***************************************************************************
//
// CreateAreaCodeRule - creates an area code rule key
// hParent = handle of the AreaCodeRules key
// iRuleNumber = rule number
// pszAreaCodeToCall, pszNumberToDial & dwFlags = rule values
// pbPrefixes - prefixes
// dwPrefixesLength - length of the prefixes in bytes (including the NULL characters)
PRIVATE DWORD CreateAreaCodeRule( HKEY hParent,
int iRuleNumber,
LPCTSTR pszAreaCodeToCall,
LPCTSTR pszNumberToDial,
LPBYTE pbPrefixes,
DWORD dwPrefixesLength,
DWORD dwFlags
)
{
TCHAR szBuffer[MAXLEN_NUMBER_LEN + sizeof(gszRule)/sizeof(TCHAR)];
DWORD dwError = ERROR_SUCCESS;
DWORD dwDisp;
DWORD dwLength;
HKEY hRule = NULL;
DBGOUT((10, "CreateAreaCodeRule - Enter"));
assert(hParent);
assert(pszNumberToDial);
assert(pszAreaCodeToCall);
assert(pbPrefixes);
// Find the rule key name
wsprintf(szBuffer, _T("%s%d"), gszRule, iRuleNumber);
// Create the key
dwError = RegCreateKeyEx( hParent,
szBuffer,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
NULL,
&hRule,
&dwDisp
);
EXIT_IF_DWERROR();
assert(dwDisp==REG_CREATED_NEW_KEY);
// AreaCodeToCall value
dwLength = (_tcslen(pszAreaCodeToCall)+1)*sizeof(TCHAR);
dwError = RegSetValueEx( hRule,
gszAreaCodeToCall,
0,
REG_SZ,
(CONST BYTE *)pszAreaCodeToCall,
dwLength
);
EXIT_IF_DWERROR();
// NumberToDial value
dwLength = (_tcslen(pszNumberToDial)+1)*sizeof(TCHAR);
dwError = RegSetValueEx( hRule,
gszNumberToDial,
0,
REG_SZ,
(CONST BYTE *)pszNumberToDial,
dwLength
);
EXIT_IF_DWERROR();
// Flags value
dwLength = sizeof(dwFlags);
dwError = RegSetValueEx( hRule,
gszFlags,
0,
REG_DWORD,
(CONST BYTE *)&dwFlags,
dwLength
);
EXIT_IF_DWERROR();
// Prefixes value
dwError = RegSetValueEx( hRule,
gszPrefixes,
0,
REG_MULTI_SZ,
(CONST BYTE *)pbPrefixes,
dwPrefixesLength
);
EXIT_IF_DWERROR();
forced_exit:
if(hRule)
RegCloseKey(hRule);
DBGOUT((10, "CreateAreaCodeRule - Exit %xh", dwError));
return dwError;
}
//***************************************************************************
//***************************************************************************
//***************************************************************************
//
// ConvertUserLocations - convert the telephony locations stored in a per user way
// The parameter should be HKEY_CURRENT_USER
//
//
//
DWORD ConvertUserLocations(HKEY hUser)
{
TCHAR Location[sizeof(gszLocation)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
TCHAR NewLocation[sizeof(gszLocation)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
DWORD dwError = ERROR_SUCCESS;
HKEY hMachineLocations = NULL;
HKEY hLocations = NULL;
DWORD dwOldID;
DWORD dwNewID;
DWORD dwCount;
DWORD dwLength;
DWORD dwType;
DWORD dwValue;
PDWORD pdwRenameList = NULL;
PDWORD pdwRenameEntry;
#ifdef BACKUP_OLD_KEYS
TCHAR szPath[MAX_PATH+1];
#endif
DBGOUT((8, "ConvertUserLocations - Enter"));
assert(hUser);
dwError = RegOpenKeyEx( hUser,
gszLocationsPath,
0,
KEY_READ | KEY_WRITE,
&hLocations
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Locations key not present, so there's nothing to convert"));
//Nothing to convert
return ERROR_SUCCESS;
}
EXIT_IF_DWERROR();
#ifdef BACKUP_OLD_KEYS
// Try to save the old key
// We DON'T use different files for different users
dwError = GetWindowsDirectory(szPath, MAX_PATH - 12); // a 8+3 name
if(dwError)
{
if(szPath[3] != _T('\0'))
lstrcat(szPath, _T("\\"));
lstrcat(szPath, BACKUP_FILE_USER_LOCATIONS);
SaveKey(hLocations, szPath);
}
else
DBGOUT((1, "Cannot get windows directory (?!?)"));
dwError = ERROR_SUCCESS;
#endif
// Version check
if(!IsLocationListInOldFormat(hLocations))
{
//Nothing to convert
DBGOUT((1, "User Locations key is already in the new format"));
RegCloseKey(hLocations);
return ERROR_SUCCESS;
}
// Open the Machine Locations key
dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
gszLocationsPath,
0,
KEY_QUERY_VALUE,
&hMachineLocations
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Locations key not present, so there's nothing to convert in User Locations"));
//Nothing to convert
return ERROR_SUCCESS;
}
EXIT_IF_DWERROR();
// query info about the rename history value
dwError = RegQueryValueEx( hMachineLocations,
gszKeyRenameHistory,
NULL,
&dwType,
NULL,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType!=REG_BINARY)
{
// strange value
dwError = ERROR_INVALID_DATA;
}
if(dwError==ERROR_FILE_NOT_FOUND)
{
dwError = ERROR_SUCCESS;
dwLength = 0;
}
EXIT_IF_DWERROR();
if(dwLength>0)
{
pdwRenameList = (PDWORD)GlobalAlloc(GPTR, dwLength);
if(pdwRenameList == NULL)
{
DBGOUT((1, "Cannot allocate the Rename List"));
dwError = ERROR_OUTOFMEMORY;
goto forced_exit;
}
// Read the list
dwError = RegQueryValueEx( hMachineLocations,
gszKeyRenameHistory,
NULL,
NULL,
(PBYTE)pdwRenameList,
&dwLength);
EXIT_IF_DWERROR();
//
RegCloseKey(hMachineLocations);
hMachineLocations = NULL;
// convert dwLength to the number of entries
dwLength /= 2*sizeof(DWORD);
pdwRenameEntry = pdwRenameList;
for(dwCount = 0; dwCount<dwLength; dwCount++)
{
dwOldID = *pdwRenameEntry++;
dwNewID = *pdwRenameEntry++;
if(dwNewID != dwOldID)
{
wsprintf(Location, _T("%s%d"), gszLocation, dwOldID);
wsprintf(NewLocation, _T("%s%d"), gszLocation, dwNewID);
dwError = RegRenameKey( hLocations,
Location,
NewLocation );
if(dwError==ERROR_SUCCESS)
{
DBGOUT ((8, "Renamed user location number from %d to %d", dwOldID, dwNewID));
}
// ignore the errors - the key could be missing
}
}
}
// add the versioning value
dwValue = TAPI_LOCATION_LIST_VERSION;
dwError = RegSetValueEx( hLocations,
gszLocationListVersion,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
EXIT_IF_DWERROR();
forced_exit:
DBGOUT((8, "ConvertUserLocations - Exit %xh", dwError));
if(hMachineLocations)
RegCloseKey(hMachineLocations);
if(hLocations)
RegCloseKey(hLocations);
if(pdwRenameList)
GlobalFree(pdwRenameList);
return dwError;
}
//***************************************************************************
//***************************************************************************
//***************************************************************************
//
// ConvertCallingCards - convert the telephony calling cards to the new format
// The parameter should be HKEY_CURRENT_USER or the handle of HKU\.Default
//
// see nt\private\tapi\dev\docs\dialrules.doc
//
DWORD ConvertCallingCards(HKEY hUser)
{
TCHAR Card[sizeof(gszCard)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
TCHAR NewCard[sizeof(gszCard)/sizeof(TCHAR) + MAXLEN_NUMBER_LEN];
DWORD dwError = ERROR_SUCCESS;
HKEY hCards = NULL;
HKEY hCard = NULL;
DWORD dwNumCards;
DWORD dwCardID;
DWORD dwCardIDTmp;
DWORD dwCount;
DWORD dwLength;
DWORD dwType;
DWORD dwValue;
BOOL bCryptInitialized;
PDWORD pdwRenameList = NULL;
PDWORD pdwRenameEntry;
DWORD dwRenameEntryCount;
#ifdef BACKUP_OLD_KEYS
TCHAR szPath[MAX_PATH+1];
#endif
DBGOUT((8, "ConvertCallingCards - Enter"));
assert(hUser);
bCryptInitialized = FALSE;
// Open the key
dwError = RegOpenKeyEx( hUser,
gszCardsPath,
0,
KEY_READ | KEY_WRITE,
&hCards
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Cards key not present, so there's nothing to convert"));
//Nothing to convert
return ERROR_SUCCESS;
}
EXIT_IF_DWERROR();
// Version check
if(!IsCardListInOldFormat(hCards))
{
//Nothing to convert
DBGOUT((1, "Cards key is already in the new format"));
RegCloseKey(hCards);
return ERROR_SUCCESS;
}
#ifdef BACKUP_OLD_KEYS
// Try to save the old key
// We DON'T use different files for different users
dwError = GetWindowsDirectory(szPath, MAX_PATH - 12); // a 8+3 name
if(dwError)
{
if(szPath[3] != _T('\0'))
lstrcat(szPath, _T("\\"));
lstrcat(szPath, BACKUP_FILE_CARDS);
SaveKey(hCards, szPath);
}
else
DBGOUT((1, "Cannot get windows directory (?!?)"));
dwError = ERROR_SUCCESS;
#endif
// Read number of cards
dwLength = sizeof(dwNumCards);
dwError = RegQueryValueEx( hCards,
gszNumEntries,
NULL,
&dwType,
(BYTE *)&dwNumCards,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_DWORD)
{
dwError = ERROR_INVALID_DATA;
assert(FALSE);
}
// The value could be missing in an empty key
if(dwError != ERROR_SUCCESS)
dwNumCards = 0;
// Alloc storage for a list of card temp IDs
if(dwNumCards>0)
{
pdwRenameList = (PDWORD)GlobalAlloc(GPTR, dwNumCards*sizeof(DWORD) );
if(pdwRenameList==NULL)
{
DBGOUT((1, "Cannot allocate the temp IDs List"));
dwError = ERROR_OUTOFMEMORY;
goto forced_exit;
}
}
pdwRenameEntry = pdwRenameList;
dwRenameEntryCount = 0;
// Initialize the cryptographic part
dwError = TapiCryptInitialize();
bCryptInitialized = TRUE; // whatever the result was
if(dwError != ERROR_SUCCESS)
{
DBGOUT((8, "ConvertCallingCards - Cannot init Crypt %xh", dwError));
// Make it not fatal
dwError = ERROR_SUCCESS;
}
// Convert from end to the begining in order to avoid name conflicts during the key renames
for(dwCount = dwNumCards-1; (LONG)dwCount>=0; dwCount--)
{
wsprintf(Card, _T("%s%d"), gszCard, dwCount);
dwError = RegOpenKeyEx( hCards,
Card,
0,
KEY_READ | KEY_WRITE,
&hCard
);
if(dwError == ERROR_FILE_NOT_FOUND)
{
DBGOUT((1, "Cannot open old %s", Card));
// Try to recover - skip to the next entry
continue;
}
EXIT_IF_DWERROR();
// Read the ID for later usage
dwLength = sizeof(dwCardID);
dwError = RegQueryValueEx( hCard,
gszID,
NULL,
&dwType,
(LPBYTE)&dwCardID,
&dwLength
);
if(dwError == ERROR_SUCCESS)
{
// Convert the card to the new format
dwError = ConvertOneCard(hCard, dwCardID);
EXIT_IF_DWERROR();
RegCloseKey(hCard);
hCard = NULL;
// Rename the key if it is necessary
if(dwCardID != dwCount)
{
wsprintf(NewCard, _T("%s%d"), gszCard, dwCardID);
// Check the destination for an old key still present. It may be possible to find one if
// the original TAPI version was TELEPHON.INI-based.
assert(!(dwCardID & TEMPORARY_ID_FLAG));
dwCardIDTmp = dwCardID;
dwError = RegOpenKeyEx( hCards,
NewCard,
0,
KEY_READ,
&hCard
);
if(dwError==ERROR_SUCCESS)
{
// use a temporary ID
dwCardIDTmp |= TEMPORARY_ID_FLAG;
wsprintf(NewCard, _T("%s%d"), gszCard, dwCardIDTmp);
*pdwRenameEntry++ = dwCardIDTmp;
dwRenameEntryCount++;
}
if(hCard)
{
RegCloseKey(hCard);
hCard = NULL;
}
dwError = RegRenameKey( hCards,
Card,
NewCard
);
EXIT_IF_DWERROR();
}
DBGOUT ((8, "Converted card %d (ID %d)", dwCount, dwCardID));
}
}
dwError = ERROR_SUCCESS;
// Rewalk the list for renaming the keys with temporary IDs
pdwRenameEntry = pdwRenameList;
for(dwCount=0; dwCount<dwRenameEntryCount; dwCount++)
{
dwCardIDTmp = *pdwRenameEntry++;
wsprintf(Card, _T("%s%d"), gszCard, dwCardIDTmp);
dwCardID = dwCardIDTmp & ~TEMPORARY_ID_FLAG;
wsprintf(NewCard, _T("%s%d"), gszCard, dwCardID);
dwError = RegRenameKey( hCards,
Card,
NewCard
);
EXIT_IF_DWERROR();
DBGOUT ((8, "Renamed to permanent ID %d", dwCardID));
}
// delete the NumEntries value. We don't need it any more
RegDeleteValue( hCards,
gszNumEntries);
// add the versioning value
dwValue = TAPI_CARD_LIST_VERSION;
dwError = RegSetValueEx( hCards,
gszCardListVersion,
0,
REG_DWORD,
(PBYTE)&dwValue,
sizeof(dwValue)
);
EXIT_IF_DWERROR();
forced_exit:
if(hCard)
RegCloseKey(hCard);
if(hCards)
RegCloseKey(hCards);
if(bCryptInitialized)
TapiCryptUninitialize();
if(pdwRenameList)
GlobalFree(pdwRenameList);
DBGOUT((8, "ConvertCallingCards - Exit %xh", dwError));
return dwError;
}
//***************************************************************************
//
// ConvertOneCard - convert one calling card
// hCard is the handle of the CardX key
// Note The key rename according to card ID is executed in ConvertCallingCards
DWORD ConvertOneCard(HKEY hCard, DWORD dwCardID)
{
DWORD dwError = ERROR_SUCCESS;
DBGOUT((9, "ConvertOneCard - Enter"));
assert(hCard);
dwError = SplitCallingCardRule( hCard,
gszLocalRule,
gszLocalAccessNumber);
// ignore any error
dwError = SplitCallingCardRule( hCard,
gszLDRule,
gszLDAccessNumber);
// ignore any error
dwError = SplitCallingCardRule( hCard,
gszInternationalRule,
gszInternationalAccessNumber);
// ignore any error
dwError = RegSetValueEx( hCard,
gszAccountNumber,
0,
REG_SZ,
(BYTE *)gszEmpty,
sizeof(TCHAR)
);
// Converts the PIN number to a better encrypted form
dwError = ConvertPIN(hCard, dwCardID);
// delete the ID Value
RegDeleteValue( hCard,
gszID
);
//forced_exit:
DBGOUT((9, "ConvertOneCard - Exit %xh", dwError));
return dwError;
}
//***************************************************************************
//
// ConvertPIN - better encryption of the PIN number
// hCard is the handle of the CardX key
//
DWORD ConvertPIN(HKEY hCard, DWORD dwCardID)
{
WCHAR szOldPIN[MAXLEN_PIN+1];
PWSTR pszNewPIN = NULL;
DWORD dwError;
DWORD dwLength;
DWORD dwLength2;
DWORD dwLength3;
DWORD dwType;
// Read the old PIN with a UNICODE version of RegQuery..
dwLength = sizeof(szOldPIN);
dwError = RegQueryValueExW( hCard,
gwszPIN,
NULL,
&dwType,
(BYTE *)szOldPIN,
&dwLength
);
if(dwError==ERROR_SUCCESS)
{
if(*szOldPIN==L'\0')
{
// Nothing to do !
return ERROR_SUCCESS;
}
// Decrypts inplace
dwError = TapiDecrypt(szOldPIN, dwCardID, szOldPIN, &dwLength2);
if(dwError==ERROR_SUCCESS)
{
assert(dwLength2 == dwLength/sizeof(WCHAR));
// Find the space needed for the encrypted result
dwError = TapiEncrypt(szOldPIN, dwCardID, NULL, &dwLength2);
if(dwError == ERROR_SUCCESS)
{
// If the length is the same with the original, we have no conversion
if(dwLength2 > dwLength/sizeof(WCHAR))
{
pszNewPIN = (PWSTR)GlobalAlloc(GMEM_FIXED, dwLength2*sizeof(WCHAR));
if(pszNewPIN==NULL)
{
return ERROR_OUTOFMEMORY;
}
dwError = TapiEncrypt(szOldPIN, dwCardID, pszNewPIN, &dwLength3);
if(dwError == ERROR_SUCCESS)
{
assert(dwLength3<=dwLength2);
// Write the new PIN
dwError = RegSetValueExW( hCard,
gwszPIN,
0,
REG_SZ,
(BYTE *)pszNewPIN,
dwLength3*sizeof(WCHAR)
);
// TEST
/*
ZeroMemory(szOldPIN, sizeof(szOldPIN));
dwError = TapiDecrypt(pszNewPIN, dwCardID, szOldPIN, &dwLength3);
if(dwError==ERROR_SUCCESS)
DBGOUT((5, "TEST Decrypt Card %d - PIN # %S, Length=%d", dwCardID, szOldPIN, dwLength3));
else
DBGOUT((5, "TEST Decrypt Card %d - Error 0x%x", dwCardID, dwError));
*/
}
GlobalFree(pszNewPIN);
}
else
{
DBGOUT((5, "PIN for card %d not converted", dwCardID));
}
}
}
else
{
// Strange, shouldn't happen
assert(FALSE);
}
}
return dwError;
}
//***************************************************************************
//
// Version Check
BOOL IsLocationListInOldFormat(HKEY hLocations) // for both user & machine
{
return (ERROR_SUCCESS != RegQueryValueEx( hLocations,
gszLocationListVersion,
NULL,
NULL,
NULL,
NULL
));
}
BOOL IsCardListInOldFormat(HKEY hCards)
{
return (ERROR_SUCCESS != RegQueryValueEx( hCards,
gszCardListVersion,
NULL,
NULL,
NULL,
NULL
));
}
//***************************************************************************
//
// IsTelephonyDigit - test range 0123456789#*ABCD
PRIVATE BOOL IsTelephonyDigit(TCHAR c)
{
return _istdigit(c) || c==_T('*') || c==_T('#') || c==_T('A') || c==_T('B') || c==_T('C') || c==_T('D');
}
//***************************************************************************
//
// SplitCallingCardRule - tries to find the access numbers and updates the coresponding values
PRIVATE DWORD SplitCallingCardRule(HKEY hCard, LPCTSTR pszRuleName, LPCTSTR pszAccessNumberName)
{
TCHAR OldRule[MAXLEN_RULE];
TCHAR NewRule[MAXLEN_RULE];
TCHAR AccessNumber[MAXLEN_ACCESS_NUMBER];
TCHAR * pOld;
TCHAR * pNew;
TCHAR * pNr;
DWORD dwLength;
DWORD dwError = ERROR_SUCCESS;
DWORD dwType;
// read the local rule
dwLength = sizeof(OldRule);
dwError = RegQueryValueEx( hCard,
pszRuleName,
NULL,
&dwType,
(BYTE *)OldRule,
&dwLength
);
if(dwError==ERROR_SUCCESS && dwType != REG_SZ)
{
dwError = ERROR_INVALID_DATA;
assert(FALSE);
}
if(dwError==ERROR_SUCCESS)
{
// Parse the old rule
pOld = OldRule;
pNew = NewRule;
pNr = AccessNumber;
while(*pOld && IsTelephonyDigit(*pOld))
*pNr++ = *pOld++;
if(pNr!=AccessNumber)
*pNew++ = _T('J');
while(*pOld)
*pNew++ = *pOld++;
*pNew = _T('\0');
*pNr = _T('\0');
dwLength = (_tcslen(AccessNumber)+1)*sizeof(TCHAR);
dwError = RegSetValueEx( hCard,
pszAccessNumberName,
0,
REG_SZ,
(BYTE *)AccessNumber,
dwLength
);
EXIT_IF_DWERROR();
dwLength = (_tcslen(NewRule)+1)*sizeof(TCHAR);
dwError = RegSetValueEx( hCard,
pszRuleName,
0,
REG_SZ,
(BYTE *)NewRule,
dwLength
);
EXIT_IF_DWERROR();
}
forced_exit:
return dwError;
}
//***************************************************************************
//***************************************************************************
//***************************************************************************
// Helper functions for renaming the registry keys
PRIVATE DWORD RegRenameKey( HKEY hParentKey,
LPCTSTR pszOldName,
LPCTSTR pszNewName)
{
DWORD dwError;
assert(pszOldName);
assert(pszNewName);
DBGOUT((15, "RegRenameKey - Start, from %s to %s", pszOldName, pszNewName));
assert(hParentKey);
assert(_tcscmp(pszOldName, pszNewName)!=0);
dwError = RegCopyKeyRecursive( hParentKey,
pszOldName,
hParentKey,
pszNewName
);
EXIT_IF_DWERROR();
dwError = RegDeleteKeyRecursive(hParentKey,
pszOldName);
EXIT_IF_DWERROR();
forced_exit:
DBGOUT((15, "RegRenameKey - Exit %xh", dwError));
return dwError;
}
PRIVATE DWORD RegCopyKeyRecursive(HKEY hSrcParentKey, LPCTSTR pszSrcName,
HKEY hDestParentKey, LPCTSTR pszDestName)
{
HKEY hSrcKey = NULL;
HKEY hDestKey = NULL;
DWORD dwError = ERROR_SUCCESS;
DWORD dwDisp;
DWORD dwMaxSubkeyLength;
DWORD dwMaxValueNameLength;
DWORD dwMaxValueLength;
DWORD dwNumValues;
DWORD dwNumSubkeys;
DWORD dwIndex;
DWORD dwType;
DWORD dwValueLength;
DWORD dwValueNameLength;
DWORD dwSubkeyLength;
LPTSTR pszSubkey = NULL;
LPTSTR pszValueName = NULL;
LPBYTE pbValue = NULL;
assert(hSrcParentKey);
assert(hDestParentKey);
assert(pszSrcName);
assert(pszDestName);
// open source key
dwError = RegOpenKeyEx( hSrcParentKey,
pszSrcName,
0,
KEY_READ,
&hSrcKey
);
EXIT_IF_DWERROR();
// create destination key
dwError = RegCreateKeyEx( hDestParentKey,
pszDestName,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hDestKey,
&dwDisp
);
EXIT_IF_DWERROR();
assert(dwDisp==REG_CREATED_NEW_KEY);
// query some info about the source key in order to allocate memory
dwError = RegQueryInfoKey( hSrcKey,
NULL,
NULL,
NULL,
&dwNumSubkeys,
&dwMaxSubkeyLength,
NULL,
&dwNumValues,
&dwMaxValueNameLength,
&dwMaxValueLength,
NULL,
NULL
);
EXIT_IF_DWERROR();
pszSubkey = (LPTSTR)GlobalAlloc(GMEM_FIXED, (dwMaxSubkeyLength+1)*sizeof(TCHAR));
if(pszSubkey==NULL)
dwError = ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
pszValueName = (LPTSTR)GlobalAlloc(GMEM_FIXED, (dwMaxValueNameLength+1)*sizeof(TCHAR));
if(pszValueName==NULL)
dwError = ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
pbValue = (LPBYTE)GlobalAlloc(GMEM_FIXED, dwMaxValueLength);
if(pbValue==NULL)
dwError = ERROR_OUTOFMEMORY;
EXIT_IF_DWERROR();
// enumerate and copy the values
for(dwIndex=0; dwIndex<dwNumValues; dwIndex++)
{
// read one value
dwValueNameLength = dwMaxValueNameLength + 1;
dwValueLength = dwMaxValueLength;
dwError = RegEnumValue( hSrcKey,
dwIndex,
pszValueName,
&dwValueNameLength,
NULL,
&dwType,
pbValue,
&dwValueLength
);
EXIT_IF_DWERROR();
// write it
dwError = RegSetValueEx(hDestKey,
pszValueName,
0,
dwType,
pbValue,
dwValueLength
);
EXIT_IF_DWERROR();
}
// enumerate and copy the subkeys
for(dwIndex=0; dwIndex<dwNumSubkeys; dwIndex++)
{
// read a subkey
dwSubkeyLength = dwMaxSubkeyLength +1;
dwError = RegEnumKeyEx( hSrcKey,
dwIndex,
pszSubkey,
&dwSubkeyLength,
NULL,
NULL,
NULL,
NULL
);
EXIT_IF_DWERROR();
// copy it
dwError = RegCopyKeyRecursive( hSrcKey,
pszSubkey,
hDestKey,
pszSubkey
);
EXIT_IF_DWERROR();
}
forced_exit:
if(hSrcKey)
RegCloseKey(hSrcKey);
if(hDestKey)
RegCloseKey(hDestKey);
if(pszSubkey)
GlobalFree(pszSubkey);
if(pszValueName)
GlobalFree(pszValueName);
if(pbValue)
GlobalFree(pbValue);
return dwError;
}
DWORD RegDeleteKeyRecursive (HKEY hParentKey, LPCTSTR pszKeyName)
{
HKEY hKey = NULL;
DWORD dwError;
DWORD dwIndex;
DWORD dwSubKeyCount;
LPTSTR pszSubKeyName;
DWORD dwSubKeyNameLength; // in characters
DWORD dwSubKeyNameLengthBytes; // in bytes
DWORD dwMaxSubKeyLength;;
dwError = RegOpenKeyEx (hParentKey, pszKeyName, 0, KEY_READ | KEY_WRITE, &hKey);
if (dwError != ERROR_SUCCESS)
return dwError;
dwError = RegQueryInfoKey (
hKey, // key in question
NULL, NULL, // class
NULL, // reserved
&dwSubKeyCount, // number of subkeys
&dwMaxSubKeyLength, // maximum length of subkey name
NULL, // max class length
NULL, // number of values
NULL, // max value name len
NULL, // max value len
NULL, // security descriptor
NULL); // last write time
if (dwError != ERROR_SUCCESS) {
RegCloseKey (hKey);
return dwError;
}
if (dwSubKeyCount > 0) {
// at least one subkey
dwSubKeyNameLengthBytes = sizeof (TCHAR) * (dwMaxSubKeyLength + 1);
pszSubKeyName = (LPTSTR) GlobalAlloc (GMEM_FIXED, dwSubKeyNameLengthBytes);
if (pszSubKeyName) {
// delete from end to beginning, to avoid quadratic performance
// ignore deletion errors
for (dwIndex = dwSubKeyCount; dwIndex > 0; dwIndex--) {
dwSubKeyNameLength = dwMaxSubKeyLength + 1;
dwError = RegEnumKeyEx (hKey, dwIndex - 1, pszSubKeyName, &dwSubKeyNameLength, NULL, NULL, NULL, NULL);
if (dwError == ERROR_SUCCESS) {
RegDeleteKeyRecursive (hKey, pszSubKeyName);
}
}
// clean up any stragglers
for (;;) {
dwSubKeyNameLength = dwMaxSubKeyLength + 1;
dwError = RegEnumKeyEx (hKey, 0, pszSubKeyName, &dwSubKeyNameLength, NULL, NULL, NULL, NULL);
if (dwError == ERROR_SUCCESS)
RegDeleteKeyRecursive (hKey, pszSubKeyName);
else
break;
}
GlobalFree (pszSubKeyName);
}
}
RegCloseKey (hKey);
return RegDeleteKey (hParentKey, pszKeyName);
}
#ifdef BACKUP_OLD_KEYS
#ifdef WINNT
PRIVATE
BOOL
EnablePrivilege(
PTSTR PrivilegeName,
BOOL Enable,
BOOL *Old
)
{
HANDLE Token;
BOOL b;
TOKEN_PRIVILEGES NewPrivileges, OldPrivileges; // place for one priv
LUID Luid;
DWORD Length;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY ,&Token)) {
return(FALSE);
}
if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
CloseHandle(Token);
return(FALSE);
}
NewPrivileges.PrivilegeCount = 1;
NewPrivileges.Privileges[0].Luid = Luid;
NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
b = AdjustTokenPrivileges(
Token,
FALSE,
&NewPrivileges,
sizeof(OldPrivileges), // it has a place for one luid
&OldPrivileges,
&Length
);
CloseHandle(Token);
if(b)
{
if(OldPrivileges.PrivilegeCount==0)
*Old = Enable;
else
*Old = (OldPrivileges.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)
? TRUE : FALSE;
}
else
DBGOUT((1, "Cannot change SeBackupPrivilege - Error %d", GetLastError()));
return(b);
}
#endif // WINNT
PRIVATE
BOOL
SaveKey(
HKEY hKey,
LPCTSTR pszFileName
)
{
DWORD dwError;
#ifdef WINNT
BOOL bOldBackupPriv = FALSE;
#endif
// Delete the file if exists (ignore errors)
DeleteFile(pszFileName);
#ifdef WINNT
// Enable the BACKUP privilege (ignore errors)
EnablePrivilege(SE_BACKUP_NAME, TRUE, &bOldBackupPriv);
#endif
// Save the key
dwError = RegSaveKey( hKey,
pszFileName,
NULL
);
if(dwError==ERROR_SUCCESS)
DBGOUT((9, "Old Telephony key saved")) ;
else
DBGOUT((1, "Cannot save old Telephony key - Error %d", dwError));
#ifdef WINNT
// Restore the BACKUP privilege (ignore errors)
EnablePrivilege(SE_BACKUP_NAME, bOldBackupPriv, &bOldBackupPriv);
#endif
return (dwError == ERROR_SUCCESS);
}
#endif // BACKUP_OLD_KEYS