|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
timezone.c
Abstract:
This module is responsible for managing the mapping of timezones from windows 9x to windows Nt. Because of the fact that the timezone strings are different between the several different platforms (Win9x Win98 WinNt) and because it is important to end users that there timezone setting accurately reflect there geographic location, a somewhat complex method of mapping timezones is needed.
Author:
Marc R. Whitten (marcw) 09-Jul-1998
Revision History:
marcw 18-Aug-1998 Added timezone enum, support for retaining fixed matches.
--*/
#include "pch.h"
#define DBG_TIMEZONE "TimeZone"
#define S_FIRSTBOOT TEXT("!!!First Boot!!!")
TCHAR g_TimeZoneMap[20] = TEXT(""); TCHAR g_CurrentTimeZone[MAX_TIMEZONE] = TEXT(""); BOOL g_TimeZoneMapped = FALSE;
//
// Variable used by tztest tool.
//
HANDLE g_TzTestHiveSftInf = NULL;
BOOL pBuildNtTimeZoneData ( VOID )
/*++
Routine Description:
pBuildNtTimeZone data reads the timezone information that is stored in hivesft.inf and organizes it into memdb. This data is used to look up display names of timezone indices.
Arguments:
None.
Return Value:
TRUE if the function completes successfully, FALSE otherwise.
--*/
{ HINF inf = INVALID_HANDLE_VALUE; INFSTRUCT is = INITINFSTRUCT_POOLHANDLE; BOOL rSuccess = FALSE; PTSTR key = NULL; PTSTR value = NULL; PTSTR desc = NULL; PTSTR index = NULL; BOOL timeZonesFound = FALSE; TCHAR paddedIndex[20]; PTSTR p = NULL; UINT i = 0; UINT count = 0;
if (!g_TzTestHiveSftInf) { //
// First, Read data from hivesft.inf.
//
inf = InfOpenInfInAllSources (S_HIVESFT_INF); } else {
inf = g_TzTestHiveSftInf; }
if (inf == INVALID_HANDLE_VALUE) { LOG ((LOG_ERROR, "Cannot load hivesoft.inf. Unable to build timezone information." )); return FALSE; }
if (InfFindFirstLine (inf, S_ADDREG, NULL, &is)) {
do {
//
// Cycle through all of the lines looking for timezone information.
//
key = InfGetStringField (&is, 2);
if (key && IsPatternMatch (TEXT("*Time Zones*"), key)) {
//
// Remember that we have found the first timezone entry.
//
timeZonesFound = TRUE;
//
// Now, get value. We care about "display" and "index"
//
value = InfGetStringField (&is, 3);
if (!value) { continue; }
if (StringIMatch (value, S_DISPLAY)) {
//
// display string found.
//
desc = InfGetStringField (&is, 5);
} else if (StringIMatch (value, S_INDEX)) {
//
// index value found.
//
index = InfGetStringField (&is, 5); }
if (index && desc) {
//
// Make sure the index is 0 padded.
//
count = 3 - TcharCount (index); p = paddedIndex; for (i=0; i<count; i++) { *p = TEXT('0'); p = _tcsinc (p); } StringCopy (p, index);
//
// we have all the information we need. Save this entry into memdb.
//
MemDbSetValueEx (MEMDB_CATEGORY_NT_TIMEZONES, paddedIndex, desc, NULL, 0, NULL); index = NULL; desc = NULL;
}
} else {
//
// Keep memory usage low.
//
InfResetInfStruct (&is);
if (key) { if (timeZonesFound) { //
// We have gathered all of the timezone information from hivesft.inf
// we can abort our loop at this point.
//
break; } } }
} while (InfFindNextLine(&is));
} ELSE_DEBUGMSG ((DBG_ERROR, "[%s] not found in hivesft.inf!",S_ADDREG));
//
// Clean up resources
//
InfCleanUpInfStruct (&is); InfCloseInfFile (inf);
return TRUE;
}
BOOL pBuild9xTimeZoneData ( VOID )
/*++
Routine Description:
pBuild9xTimeZone Data is responsible for reading the time zone information that is stored in win95upg.inf and organizing it into memdb. The timezone enumeration routines then use this data in order to find all Nt timezones that can map to a particular 9x timezone.
Arguments:
None.
Return Value:
TRUE if the data is successfully stored in memdb, FALSE otherwise.
--*/
{
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE; PTSTR desc = NULL; PTSTR index = NULL; UINT count = 0; PTSTR p = NULL;
//
// Now, read in information about win9x registry mappings.
//
if (InfFindFirstLine (g_Win95UpgInf, S_TIMEZONEMAPPINGS, NULL, &is)) {
do {
//
// Get the display name and matching index(es) for this timezone.
//
desc = InfGetStringField (&is,0); index = InfGetStringField (&is,1);
//
// Enumerate the indices and save them into memdb.
//
count = 0; while (index) {
p = _tcschr (index, TEXT(',')); if (p) {
*p = 0; }
MemDbSetValueEx ( MEMDB_CATEGORY_9X_TIMEZONES, desc, MEMDB_FIELD_INDEX, index, 0, NULL );
count++;
if (p) { index = _tcsinc(p); } else { //
// Save away the count of possible nt timezones for this 9x timezone.
//
MemDbSetValueEx ( MEMDB_CATEGORY_9X_TIMEZONES, desc, MEMDB_FIELD_COUNT, NULL, count, NULL );
index = NULL; } }
} while (InfFindNextLine (&is));
}
//
// Clean up resources.
//
InfCleanUpInfStruct (&is);
return TRUE; }
BOOL pGetCurrentTimeZone ( VOID )
/*++
Routine Description:
pGetCurrentTimeZone retrieves the user's timezone from the windows 9x registry. The enumeration routines use this timezone in order to enumerate the possible matching timezones in the INF.
Arguments:
None.
Return Value:
TRUE if the function successfully retrieves the user's password, FALSE otherwise.
--*/
{ BOOL rSuccess = TRUE; PCTSTR displayName = NULL; REGTREE_ENUM eTree; PCTSTR valueName = NULL; PCTSTR value = NULL; PCTSTR curTimeZone = NULL; HKEY hKey = NULL;
//
// Get the current timezone name, and set the valuename to the correct string.
//
hKey = OpenRegKeyStr (S_TIMEZONEINFORMATION);
if (!hKey) {
LOG ((LOG_ERROR, "Unable to open %s key.", S_TIMEZONEINFORMATION)); return FALSE; }
if ((curTimeZone = GetRegValueString (hKey, S_STANDARDNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
//
// standard time. We need to look under the "STD" value to match this.
//
valueName = S_STD;
} else if ((curTimeZone = GetRegValueString (hKey, S_DAYLIGHTNAME)) && !StringIMatch (curTimeZone, S_FIRSTBOOT)) {
//
// Daylight Savings Time. We need to look under the "DLT" value to match this.
//
valueName = S_DLT;
} else {
CloseRegKey (hKey); hKey = OpenRegKeyStr (TEXT("HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Time Zones")); if (hKey) {
if (curTimeZone = GetRegValueString (hKey, TEXT(""))) { valueName = S_STD; }
}
if (!valueName) {
//
// No timezone found!
//
DEBUGMSG((DBG_WHOOPS,"Unable to get Timezone name..User will have to enter timezone in GUI mode.")); return FALSE; } } __try {
//
// Now we have to search through the timezones key and find the key that has a value equal to
// the current timezone name. A big pain.
//
if (EnumFirstRegKeyInTree (&eTree, S_TIMEZONES)) { do {
//
// For each subkey, we must look for the string in valueName and
// see if it matches.
//
value = GetRegValueString (eTree.CurrentKey->KeyHandle, valueName); if (value) {
if (StringIMatch (value, curTimeZone)) {
//
// We found the key we were looking for and we can finally
// gather the data we need.
//
displayName = GetRegValueString (eTree.CurrentKey->KeyHandle, S_DISPLAY); if (!displayName) { DEBUGMSG((DBG_WHOOPS,"Error! Timezone key found, but no Display value!")); AbortRegKeyTreeEnum (&eTree); rSuccess = FALSE; __leave; }
//
// Save away the current Timezone and leave the loop. We are done.
//
StringCopy (g_CurrentTimeZone, displayName); AbortRegKeyTreeEnum (&eTree); break; } MemFree (g_hHeap, 0, value); value = NULL;
}
} while (EnumNextRegKeyInTree (&eTree)); }
} __finally {
if (curTimeZone) { MemFree (g_hHeap, 0, curTimeZone); }
if (value) { MemFree (g_hHeap, 0, value); }
if (displayName) { MemFree (g_hHeap, 0, displayName); }
CloseRegKey (hKey); }
return rSuccess; }
BOOL pInitTimeZoneData ( VOID )
/*++
Routine Description:
pInitTimeZoneData is responsible for performing all of the initialization necessary to use the time zone enumeration routines.
Arguments:
None.
Return Value:
TRUE if initialization completes successfully, FALSE otherwise.
--*/
{ BOOL rSuccess = TRUE;
//
// First, fill memdb with timezone
// information regarding winnt and win9x
// (from hivesft.inf and win95upg.inf)
//
if (!pBuildNtTimeZoneData ()) {
LOG ((LOG_ERROR, "Unable to gather nt timezone information.")); rSuccess = FALSE; }
if (!pBuild9xTimeZoneData ()) {
LOG ((LOG_ERROR, "Unable to gather 9x timezone information.")); rSuccess = FALSE; }
//
// Next, get the user's timezone.
//
if (!pGetCurrentTimeZone ()) { LOG ((LOG_ERROR, "Failure trying to retrieve timezone information.")); rSuccess = FALSE; }
return rSuccess;
}
BOOL pEnumFirstNtTimeZone ( OUT PTIMEZONE_ENUM EnumPtr ) { BOOL rSuccess = FALSE; PTSTR p;
EnumPtr -> MapCount = 0; if (MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) { do { EnumPtr -> MapCount++; } while (MemDbEnumNextValue (&(EnumPtr -> Enum))); } else { return FALSE; }
MemDbEnumFirstValue (&(EnumPtr -> Enum), MEMDB_CATEGORY_NT_TIMEZONES"\\*", MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY);
p = _tcschr (EnumPtr->Enum.szName,TEXT('\\')); if (!p) { return FALSE; }
*p = 0; EnumPtr -> MapIndex = EnumPtr -> Enum.szName; StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
return TRUE; }
BOOL pEnumNextNtTimeZone ( OUT PTIMEZONE_ENUM EnumPtr ) {
PTSTR p;
if (!MemDbEnumNextValue(&EnumPtr -> Enum)) { return FALSE; }
p = _tcschr (EnumPtr->Enum.szName,TEXT('\\')); if (!p) { return FALSE; }
*p = 0; EnumPtr -> MapIndex = EnumPtr -> Enum.szName; StringCopy (EnumPtr -> NtTimeZone, _tcsinc(p));
return TRUE;
}
BOOL EnumFirstTimeZone ( OUT PTIMEZONE_ENUM EnumPtr, IN DWORD Flags )
/*++
Routine Description:
EnumFirstTimeZone/EnumNextTimeZone enumerate the Nt timezones that can match the user's current Windows 9x time zone. In most cases, there will be only one, but, in some cases, there can be several.
Arguments:
EnumPtr - A pointer to a valid timezone enumeration structure. This variable holds the necessary state between timezone enumeration calls.
Return Value:
TRUE if there are any timezones to enumerate, FALSE otherwise.
--*/
{ BOOL rSuccess = FALSE; TCHAR key[MEMDB_MAX]; static BOOL firstTime = TRUE;
if (firstTime) { if (!pInitTimeZoneData ()) { LOG ((LOG_ERROR, "Error initializing timezone data.")); return FALSE; }
firstTime = FALSE; }
MYASSERT (EnumPtr);
EnumPtr -> CurTimeZone = g_CurrentTimeZone; EnumPtr -> Flags = Flags;
if (Flags & TZFLAG_ENUM_ALL) { return pEnumFirstNtTimeZone (EnumPtr); }
if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
//
// We have a force mapping, so mapcount is 1.
//
EnumPtr -> MapCount = 1; } else {
//
// Get count of matches.
//
MemDbBuildKey (key, MEMDB_CATEGORY_9X_TIMEZONES, EnumPtr -> CurTimeZone, MEMDB_FIELD_COUNT, NULL);
if (!MemDbGetValue (key, &(EnumPtr -> MapCount))) {
DEBUGMSG (( DBG_WARNING, "EnumFirstTimeZone: Could not retrieve count of nt timezone matches from memdb for %s.", EnumPtr -> CurTimeZone ));
return FALSE; } }
DEBUGMSG ((DBG_TIMEZONE, "%d Nt time zones match the win9x timezone %s.", EnumPtr -> MapCount, EnumPtr -> CurTimeZone));
if ((Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) {
//
// Use the previously forced mapping.
//
EnumPtr -> MapIndex = g_TimeZoneMap;
} else {
//
// Now, enumerate the matching map indexes in memdb.
//
rSuccess = MemDbGetValueEx ( &(EnumPtr -> Enum), MEMDB_CATEGORY_9X_TIMEZONES, EnumPtr -> CurTimeZone, MEMDB_FIELD_INDEX );
if (!rSuccess) { return FALSE; }
EnumPtr -> MapIndex = EnumPtr -> Enum.szName;
}
//
// Get the NT display string for this map index.
//
rSuccess = MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
return rSuccess; }
BOOL EnumNextTimeZone ( IN OUT PTIMEZONE_ENUM EnumPtr )
{
if (EnumPtr -> Flags & TZFLAG_ENUM_ALL) { return pEnumNextNtTimeZone (EnumPtr); }
if ((EnumPtr -> Flags & TZFLAG_USE_FORCED_MAPPINGS) && g_TimeZoneMapped) { return FALSE; }
if (!MemDbEnumNextValue (&(EnumPtr->Enum))) { return FALSE; }
EnumPtr->MapIndex = EnumPtr->Enum.szName;
return MemDbGetEndpointValueEx (MEMDB_CATEGORY_NT_TIMEZONES, EnumPtr->MapIndex, NULL, EnumPtr->NtTimeZone);
}
BOOL ForceTimeZoneMap ( IN PCTSTR NtTimeZone )
/*++
Routine Description:
ForceTimeZoneMap forces the mapping of a particular 9x timezone to a particular Nt timezone. This function is used in cases where there are multiple nt timezones that could map to a particular 9x timezone.
Arguments:
NtTimeZone - String containing the timezone to force mapping to.
Return Value:
TRUE if the function successfully updated the timezone mapping, FALSE otherwise.
--*/
{ TIMEZONE_ENUM e; //
// Find index that matches this timezone.
//
if (EnumFirstTimeZone (&e, TZFLAG_ENUM_ALL)) {
do {
if (StringIMatch (NtTimeZone, e.NtTimeZone)) {
//
// this is the index we need.
//
StringCopy (g_TimeZoneMap, e.MapIndex); g_TimeZoneMapped = TRUE;
break;
}
} while (EnumNextTimeZone (&e)); }
return TRUE; }
|