[evolution-data-server] [win32] Get system timezone location by querying the registry



commit 933e0cd0f00da19bbe6bd135e4781c69b0233c71
Author: Fridrich Strba <fridrich strba bluewin ch>
Date:   Sat Mar 20 23:36:34 2010 +0100

    [win32] Get system timezone location by querying the registry

 calendar/libecal/e-cal-system-timezone.c |  292 ++++++++++++++++++++++++++++++
 1 files changed, 292 insertions(+), 0 deletions(-)
---
diff --git a/calendar/libecal/e-cal-system-timezone.c b/calendar/libecal/e-cal-system-timezone.c
index 2a13622..9abb388 100644
--- a/calendar/libecal/e-cal-system-timezone.c
+++ b/calendar/libecal/e-cal-system-timezone.c
@@ -23,6 +23,8 @@
 #include <string.h>
 #include "e-cal-system-timezone.h"
 
+#ifndef G_OS_WIN32
+
 #ifdef HAVE_SOLARIS
 #define SYSTEM_ZONEINFODIR "/usr/share/lib/zoneinfo/tab"
 #else
@@ -429,6 +431,282 @@ system_timezone_find (void)
 	return NULL;
 }
 
+#else /* G_OS_WIN32 */
+#include <windows.h>
+#include <stdio.h>
+
+struct timezone_map_entry
+{
+	const gchar *windows_string;
+	const gchar *olson_string;
+};
+
+static gchar* 
+windows_timezone_string_to_olson(const gchar* windows_tz)
+{
+	/* source: http://www.chronos-st.org/Windows-to-Olson.txt */
+	static const struct timezone_map_entry timezone_map[] = {
+		{ "Afghanistan", "Asia/Kabul" },
+		{ "Afghanistan Standard Time", "Asia/Kabul" },
+		{ "Alaskan", "America/Anchorage" },
+		{ "Alaskan Standard Time", "America/Anchorage" },
+		{ "Arab", "Asia/Riyadh" },
+		{ "Arab Standard Time", "Asia/Riyadh" },
+		{ "Arabian", "Asia/Muscat" },
+		{ "Arabian Standard Time", "Asia/Muscat" },
+		{ "Arabic Standard Time", "Asia/Baghdad" },
+		{ "Atlantic", "America/Halifax" },
+		{ "Atlantic Standard Time", "America/Halifax" },
+		{ "AUS Central", "Australia/Darwin" },
+		{ "AUS Central Standard Time", "Australia/Darwin" },
+		{ "AUS Eastern", "Australia/Sydney" },
+		{ "AUS Eastern Standard Time", "Australia/Sydney" },
+		{ "Azerbaijan Standard Time", "Asia/Baku" },
+		{ "Azores", "Atlantic/Azores" },
+		{ "Azores Standard Time", "Atlantic/Azores" },
+		{ "Bangkok", "Asia/Bangkok" },
+		{ "Bangkok Standard Time", "Asia/Bangkok" },
+		{ "Beijing", "Asia/Shanghai" },
+		{ "Canada Central", "America/Regina" },
+		{ "Canada Central Standard Time", "America/Regina" },
+		{ "Cape Verde Standard Time", "Atlantic/Cape_Verde" },
+		{ "Caucasus", "Asia/Yerevan" },
+		{ "Caucasus Standard Time", "Asia/Yerevan" },
+		{ "Cen. Australia", "Australia/Adelaide" },
+		{ "Cen. Australia Standard Time", "Australia/Adelaide" },
+		{ "Central", "America/Chicago" },
+		{ "Central America Standard Time", "America/Regina" },
+		{ "Central Asia", "Asia/Dhaka" },
+		{ "Central Asia Standard Time", "Asia/Dhaka" },
+		{ "Central Brazilian Standard Time", "America/Manaus" },
+		{ "Central Europe", "Europe/Prague" },
+		{ "Central Europe Standard Time", "Europe/Prague" },
+		{ "Central European", "Europe/Belgrade" },
+		{ "Central European Standard Time", "Europe/Belgrade" },
+		{ "Central Pacific", "Pacific/Guadalcanal" },
+		{ "Central Pacific Standard Time", "Pacific/Guadalcanal" },
+		{ "Central Standard Time", "America/Chicago" },
+		{ "Central Standard Time (Mexico)", "America/Mexico_City" },
+		{ "China", "Asia/Shanghai" },
+		{ "China Standard Time", "Asia/Shanghai" },
+		{ "Dateline", "GMT-1200" },
+		{ "Dateline Standard Time", "GMT-1200" },
+		{ "E. Africa", "Africa/Nairobi" },
+		{ "E. Africa Standard Time", "Africa/Nairobi" },
+		{ "E. Australia", "Australia/Brisbane" },
+		{ "E. Australia Standard Time", "Australia/Brisbane" },
+		{ "E. Europe", "Europe/Minsk" },
+		{ "E. Europe Standard Time", "Europe/Minsk" },
+		{ "E. South America", "America/Sao_Paulo" },
+		{ "E. South America Standard Time", "America/Sao_Paulo" },
+		{ "Eastern", "America/New_York" },
+		{ "Eastern Standard Time", "America/New_York" },
+		{ "Egypt", "Africa/Cairo" },
+		{ "Egypt Standard Time", "Africa/Cairo" },
+		{ "Ekaterinburg", "Asia/Yekaterinburg" },
+		{ "Ekaterinburg Standard Time", "Asia/Yekaterinburg" },
+		{ "Fiji", "Pacific/Fiji" },
+		{ "Fiji Standard Time", "Pacific/Fiji" },
+		{ "FLE", "Europe/Helsinki" },
+		{ "FLE Standard Time", "Europe/Helsinki" },
+		{ "Georgian Standard Time", "Asia/Tbilisi" },
+		{ "GFT", "Europe/Athens" },
+		{ "GFT Standard Time", "Europe/Athens" },
+		{ "GMT", "Europe/London" },
+		{ "GMT Standard Time", "Europe/London" },
+		{ "GMT Standard Time", "GMT" },
+		{ "Greenland Standard Time", "America/Godthab" },
+		{ "Greenwich", "GMT" },
+		{ "Greenwich Standard Time", "GMT" },
+		{ "GTB", "Europe/Athens" },
+		{ "GTB Standard Time", "Europe/Athens" },
+		{ "Hawaiian", "Pacific/Honolulu" },
+		{ "Hawaiian Standard Time", "Pacific/Honolulu" },
+		{ "India", "Asia/Calcutta" },
+		{ "India Standard Time", "Asia/Calcutta" },
+		{ "Iran", "Asia/Tehran" },
+		{ "Iran Standard Time", "Asia/Tehran" },
+		{ "Israel", "Asia/Jerusalem" },
+		{ "Israel Standard Time", "Asia/Jerusalem" },
+		{ "Jordan Standard Time", "Asia/Amman" },
+		{ "Korea", "Asia/Seoul" },
+		{ "Korea Standard Time", "Asia/Seoul" },
+		{ "Mexico", "America/Mexico_City" },
+		{ "Mexico Standard Time", "America/Mexico_City" },
+		{ "Mexico Standard Time 2", "America/Chihuahua" },
+		{ "Mid-Atlantic", "Atlantic/South_Georgia" },
+		{ "Mid-Atlantic Standard Time", "Atlantic/South_Georgia" },
+		{ "Middle East Standard Time", "Asia/Beirut" },
+		{ "Mountain", "America/Denver" },
+		{ "Mountain Standard Time", "America/Denver" },
+		{ "Mountain Standard Time (Mexico)", "America/Chihuahua" },
+		{ "Myanmar Standard Time", "Asia/Rangoon" },
+		{ "N. Central Asia Standard Time", "Asia/Novosibirsk" },
+		{ "Namibia Standard Time", "Africa/Windhoek" },
+		{ "Nepal Standard Time", "Asia/Katmandu" },
+		{ "New Zealand", "Pacific/Auckland" },
+		{ "New Zealand Standard Time", "Pacific/Auckland" },
+		{ "Newfoundland", "America/St_Johns" },
+		{ "Newfoundland Standard Time", "America/St_Johns" },
+		{ "North Asia East Standard Time", "Asia/Ulaanbaatar" },
+		{ "North Asia Standard Time", "Asia/Krasnoyarsk" },
+		{ "Pacific", "America/Los_Angeles" },
+		{ "Pacific SA", "America/Santiago" },
+		{ "Pacific SA Standard Time", "America/Santiago" },
+		{ "Pacific Standard Time", "America/Los_Angeles" },
+		{ "Pacific Standard Time (Mexico)", "America/Tijuana" },
+		{ "Prague Bratislava", "Europe/Prague" },
+		{ "Romance", "Europe/Paris" },
+		{ "Romance Standard Time", "Europe/Paris" },
+		{ "Russian", "Europe/Moscow" },
+		{ "Russian Standard Time", "Europe/Moscow" },
+		{ "SA Eastern", "America/Buenos_Aires" },
+		{ "SA Eastern Standard Time", "America/Buenos_Aires" },
+		{ "SA Pacific", "America/Bogota" },
+		{ "SA Pacific Standard Time", "America/Bogota" },
+		{ "SA Western", "America/Caracas" },
+		{ "SA Western Standard Time", "America/Caracas" },
+		{ "Samoa", "Pacific/Apia" },
+		{ "Samoa Standard Time", "Pacific/Apia" },
+		{ "Saudi Arabia", "Asia/Riyadh" },
+		{ "Saudi Arabia Standard Time", "Asia/Riyadh" },
+		{ "SE Asia", "Asia/Bangkok" },
+		{ "SE Asia Standard Time", "Asia/Bangkok" },
+		{ "Singapore", "Asia/Singapore" },
+		{ "Singapore Standard Time", "Asia/Singapore" },
+		{ "South Africa", "Africa/Harare" },
+		{ "South Africa Standard Time", "Africa/Harare" },
+		{ "Sri Lanka", "Asia/Colombo" },
+		{ "Sri Lanka Standard Time", "Asia/Colombo" },
+		{ "Sydney Standard Time", "Australia/Sydney" },
+		{ "Taipei", "Asia/Taipei" },
+		{ "Taipei Standard Time", "Asia/Taipei" },
+		{ "Tasmania", "Australia/Hobart" },
+		{ "Tasmania Standard Time", "Australia/Hobart" },
+		{ "Tasmania Standard Time", "Australia/Hobart" },
+		{ "Tokyo", "Asia/Tokyo" },
+		{ "Tokyo Standard Time", "Asia/Tokyo" },
+		{ "Tonga Standard Time", "Pacific/Tongatapu" },
+		{ "US Eastern", "America/Indianapolis" },
+		{ "US Eastern Standard Time", "America/Indianapolis" },
+		{ "US Mountain", "America/Phoenix" },
+		{ "US Mountain Standard Time", "America/Phoenix" },
+		{ "Vladivostok", "Asia/Vladivostok" },
+		{ "Vladivostok Standard Time", "Asia/Vladivostok" },
+		{ "W. Australia", "Australia/Perth" },
+		{ "W. Australia Standard Time", "Australia/Perth" },
+		{ "W. Central Africa Standard Time", "Africa/Luanda" },
+	   	{ "W. Europe", "Europe/Berlin" },
+		{ "W. Europe Standard Time", "Europe/Berlin" },
+		{ "Warsaw", "Europe/Warsaw" },
+		{ "West Asia", "Asia/Karachi" },
+		{ "West Asia Standard Time", "Asia/Karachi" },
+		{ "West Pacific", "Pacific/Guam" },
+		{ "West Pacific Standard Time", "Pacific/Guam" },
+		{ "Western Brazilian Standard Time", "America/Rio_Branco" },
+		{ "Yakutsk", "Asia/Yakutsk" },
+		{ "Yakutsk Standard Time", "Asia/Yakutsk" },
+		{ 0, 0 } // end marker
+	};
+
+	int i;
+
+	for (i=0; timezone_map[i].windows_string && windows_tz; i++) {
+		int res = strcmp( timezone_map[i].windows_string, windows_tz);
+		if (res > 0)
+			return NULL;
+		if (res == 0) {
+			return g_strdup(timezone_map[i].olson_string);
+		}
+	}
+	
+	return NULL;
+}
+
+#define MAX_VALUE_NAME 4096
+
+static gchar *
+system_timezone_win32_query_registry (void)
+{
+	DWORD type;
+	DWORD size;
+	LONG res;
+	DWORD i;
+
+	static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
+	static HKEY reg_subkey = (HKEY) INVALID_HANDLE_VALUE;
+	gchar timeZone[MAX_VALUE_NAME] = "";
+	gchar timeZoneStd[MAX_VALUE_NAME] = "";
+	gchar subKey[MAX_VALUE_NAME] = "";
+
+	res = RegOpenKeyExA (HKEY_LOCAL_MACHINE,
+		"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", 0, KEY_READ, &reg_key);
+	if (res != ERROR_SUCCESS) {
+		g_debug("Could not find system timezone! (1)\n");
+		return NULL;
+	}
+
+	/* On Windows Vista, Windows Server 2008 and later, the Windows timezone name is the value of 'TimeZoneKeyName' */
+
+	size = MAX_VALUE_NAME;
+	res = RegQueryValueExA (reg_key, "TimeZoneKeyName", 0, &type, (LPBYTE) timeZone, &size);
+
+	if (type == REG_SZ && res == ERROR_SUCCESS) {
+		RegCloseKey (reg_key);
+		g_debug ("Windows Timezone String (1): %s\n", timeZone);
+		return g_strdup (timeZone);
+	}
+
+	/* On older Windows, we must first find the value of 'StandardName' */
+
+	res = RegQueryValueExA (reg_key, "StandardName", 0, &type, (LPBYTE) timeZone, &size);
+
+	if (type != REG_SZ || res != ERROR_SUCCESS) {
+		RegCloseKey (reg_key);
+		g_debug ("Could not find system timezone! (2)\n");
+		return NULL;
+	}
+
+	RegCloseKey (reg_key);
+
+	/* Windows NT and its family */
+	res = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+		"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
+		0, KEY_READ, &reg_key);
+	if (res != ERROR_SUCCESS) {
+		g_debug ("Could not find the timezone! (3)\n");
+		return NULL;
+	}
+
+	for (i=0, res = ERROR_SUCCESS; res != ERROR_NO_MORE_ITEMS; i++) {
+		size = MAX_VALUE_NAME;
+		res = RegEnumKeyEx (reg_key, i, subKey, &size, NULL, NULL, NULL, NULL);
+		if (res == ERROR_SUCCESS) {
+			res = RegOpenKeyExA (reg_key, subKey, 0, KEY_READ, &reg_subkey);
+			if (res != ERROR_SUCCESS)
+				continue;
+			size = MAX_VALUE_NAME;
+			res = RegQueryValueExA (reg_subkey, "Std", 0, &type,
+				(LPBYTE) timeZoneStd, &size);
+			RegCloseKey (reg_subkey);
+			if (type != REG_SZ || res != ERROR_SUCCESS) {
+				continue;
+			}
+			if (g_strcmp0 (timeZone,timeZoneStd) == 0) {
+				RegCloseKey (reg_key);
+				g_debug ("Windows Timezone String (2): %s\n", subKey);
+				return g_strdup (subKey);
+			}
+		}
+	}
+
+	g_debug ("Could not find system timezone! (3)\n");
+	RegCloseKey (reg_key);
+	return NULL;
+}
+
+#endif /* G_OS_WIN32 */
+
 /**
  * e_cal_system_timezone_get_location:
  *
@@ -440,5 +718,19 @@ system_timezone_find (void)
 gchar *
 e_cal_system_timezone_get_location (void)
 {
+#ifndef G_OS_WIN32
 	return system_timezone_find ();
+#else
+	gchar *windows_timezone_string = NULL;
+	gchar *olson_timezone_string = NULL;
+	
+	if (!(windows_timezone_string = system_timezone_win32_query_registry ()))
+		return NULL;
+	olson_timezone_string = windows_timezone_string_to_olson (windows_timezone_string);
+	g_free (windows_timezone_string);
+	if (!olson_timezone_string)
+		return NULL;
+	g_debug("Olson Timezone String: %s\n", olson_timezone_string);
+	return olson_timezone_string;
+#endif
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]