summaryrefslogtreecommitdiff
path: root/src/mir_core
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2015-06-19 18:18:13 +0000
committerGeorge Hazan <george.hazan@gmail.com>2015-06-19 18:18:13 +0000
commitbf37d6655a27cc3ea5af5412c9717596c9d1c30f (patch)
tree9a537b8cd5cd85b27b5a296f77a972a0ae0c3863 /src/mir_core
parentd55f17dea8734cfb458fd8fcbac684d141b181af (diff)
timezone api migrated to mir_core
git-svn-id: http://svn.miranda-ng.org/main/trunk@14266 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/mir_core')
-rw-r--r--src/mir_core/src/mir_core.def16
-rw-r--r--src/mir_core/src/mir_core64.def16
-rw-r--r--src/mir_core/src/miranda.cpp14
-rw-r--r--src/mir_core/src/stdafx.h2
-rw-r--r--src/mir_core/src/timezones.cpp587
5 files changed, 625 insertions, 10 deletions
diff --git a/src/mir_core/src/mir_core.def b/src/mir_core/src/mir_core.def
index f693d41233..70ee0c1c1d 100644
--- a/src/mir_core/src/mir_core.def
+++ b/src/mir_core/src/mir_core.def
@@ -953,3 +953,19 @@ Utils_AssertInsideScreen @1110
Utils_RestoreWindowPosition @1111
Utils_SaveWindowPosition @1112
mir_getLP @1113
+TimeZone_CreateByContact @1114
+TimeZone_CreateByName @1115
+TimeZone_GetDescription @1116
+TimeZone_GetInfo @1117
+TimeZone_GetName @1118
+TimeZone_GetTimeZoneTime @1119
+TimeZone_PrepareList @1120
+TimeZone_PrintDateTime @1121
+TimeZone_PrintTimeStamp @1122
+TimeZone_SelectListItem @1123
+TimeZone_StoreByContact @1124
+TimeZone_StoreListResult @1125
+TimeZone_ToLocal @1126
+TimeZone_ToString @1127
+TimeZone_ToStringW @1128
+TimeZone_UtcToLocal @1129
diff --git a/src/mir_core/src/mir_core64.def b/src/mir_core/src/mir_core64.def
index eadbef2572..cc345a6ca8 100644
--- a/src/mir_core/src/mir_core64.def
+++ b/src/mir_core/src/mir_core64.def
@@ -953,3 +953,19 @@ Utils_AssertInsideScreen @1110
Utils_RestoreWindowPosition @1111
Utils_SaveWindowPosition @1112
mir_getLP @1113
+TimeZone_CreateByContact @1114
+TimeZone_CreateByName @1115
+TimeZone_GetDescription @1116
+TimeZone_GetInfo @1117
+TimeZone_GetName @1118
+TimeZone_GetTimeZoneTime @1119
+TimeZone_PrepareList @1120
+TimeZone_PrintDateTime @1121
+TimeZone_PrintTimeStamp @1122
+TimeZone_SelectListItem @1123
+TimeZone_StoreByContact @1124
+TimeZone_StoreListResult @1125
+TimeZone_ToLocal @1126
+TimeZone_ToString @1127
+TimeZone_ToStringW @1128
+TimeZone_UtcToLocal @1129
diff --git a/src/mir_core/src/miranda.cpp b/src/mir_core/src/miranda.cpp
index 53091dc2c9..fa99d1d8db 100644
--- a/src/mir_core/src/miranda.cpp
+++ b/src/mir_core/src/miranda.cpp
@@ -28,7 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
HWND hAPCWindow = NULL;
int InitPathUtils(void);
-void (*RecalculateTime)(void);
+void RecalculateTime(void);
void CheckLogs();
void InitLogs();
@@ -36,6 +36,7 @@ void UninitLogs();
void InitWinver();
void InitMetaContacts();
+void InitTimeZones();
int hLangpack = 0;
HINSTANCE hInst = 0;
@@ -57,7 +58,7 @@ static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
if (msg == WM_TIMER)
CheckLogs();
- if (msg == WM_TIMECHANGE && RecalculateTime)
+ if (msg == WM_TIMECHANGE)
RecalculateTime();
return DefWindowProc(hwnd, msg, wParam, lParam);
@@ -73,7 +74,6 @@ static void LoadCoreModule(void)
hAPCWindow = CreateWindowEx(0, _T("ComboLBox"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW);
DestroyWindow(hAPCWindow);
- hAPCWindow = NULL;
hAPCWindow = CreateWindowEx(0, _T("STATIC"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc);
@@ -81,16 +81,10 @@ static void LoadCoreModule(void)
hStackMutex = CreateMutex(NULL, FALSE, NULL);
hThreadQueueEmpty = CreateEvent(NULL, TRUE, TRUE, NULL);
- #ifdef _WIN64
- HMODULE mirInst = GetModuleHandleA("miranda64.exe");
- #else
- HMODULE mirInst = GetModuleHandleA("miranda32.exe");
- #endif
- RecalculateTime = (void (*)()) GetProcAddress(mirInst, "RecalculateTime");
-
InitWinver();
InitPathUtils();
InitLogs();
+ InitTimeZones();
InitialiseModularEngine();
InitMetaContacts();
}
diff --git a/src/mir_core/src/stdafx.h b/src/mir_core/src/stdafx.h
index 359230ab17..eb5f1ac352 100644
--- a/src/mir_core/src/stdafx.h
+++ b/src/mir_core/src/stdafx.h
@@ -57,6 +57,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <m_skin.h>
#include <m_icolib.h>
#include <m_netlib.h>
+#include <m_timezones.h>
+#include <m_protocols.h>
#include "miranda.h"
diff --git a/src/mir_core/src/timezones.cpp b/src/mir_core/src/timezones.cpp
new file mode 100644
index 0000000000..b9510f2a71
--- /dev/null
+++ b/src/mir_core/src/timezones.cpp
@@ -0,0 +1,587 @@
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (ñ) 2012-15 Miranda NG project (http://miranda-ng.org),
+Copyright (c) 2000-12 Miranda IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include "stdafx.h"
+
+typedef DWORD (WINAPI *pfnGetDynamicTimeZoneInformation_t)(DYNAMIC_TIME_ZONE_INFORMATION *pdtzi);
+static pfnGetDynamicTimeZoneInformation_t pfnGetDynamicTimeZoneInformation;
+
+struct REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+};
+
+#define MIM_TZ_DISPLAYLEN 128
+
+struct MIM_TIMEZONE
+{
+ unsigned hash;
+ int offset;
+
+ TCHAR tszName[MIM_TZ_NAMELEN]; // windows name for the time zone
+ wchar_t szDisplay[MIM_TZ_DISPLAYLEN]; // more descriptive display name (that's what usually appears in dialogs)
+ // every hour should be sufficient.
+ TIME_ZONE_INFORMATION tzi;
+
+ static int compareBias(const MIM_TIMEZONE* p1, const MIM_TIMEZONE* p2)
+ { return p2->tzi.Bias - p1->tzi.Bias;
+ }
+};
+
+struct TZ_INT_INFO
+{
+ DWORD timestamp; // last time updated
+ MIM_TIMEZONE myTZ; // set to my own timezone
+};
+
+static TZ_INT_INFO myInfo;
+
+static OBJLIST<MIM_TIMEZONE> g_timezones(55, NumericKeySortT);
+static LIST<MIM_TIMEZONE> g_timezonesBias(55, MIM_TIMEZONE::compareBias);
+
+// KB167296
+void UnixTimeToFileTime(mir_time ts, LPFILETIME pft)
+{
+ unsigned __int64 ll = UInt32x32To64(ts, 10000000) + 116444736000000000i64;
+ pft->dwLowDateTime = (DWORD)ll;
+ pft->dwHighDateTime = ll >> 32;
+}
+
+mir_time FileTimeToUnixTime(LPFILETIME pft)
+{
+ unsigned __int64 ll = (unsigned __int64)pft->dwHighDateTime << 32 | pft->dwLowDateTime;
+ ll -= 116444736000000000i64;
+ return (mir_time)(ll / 10000000);
+}
+
+void FormatTime(const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, size_t cbDest)
+{
+ if (szDest == NULL || cbDest == 0) return;
+
+ CMString tszTemp;
+
+ for (const TCHAR* pFormat = szFormat; *pFormat; ++pFormat) {
+ DWORD fmt = 0;
+ bool date = false, iso = false;
+ switch (*pFormat) {
+ case 't':
+ fmt = TIME_NOSECONDS;
+ date = false;
+ break;
+
+ case 's':
+ fmt = 0;
+ date = false;
+ break;
+
+ case 'm':
+ fmt = TIME_NOMINUTESORSECONDS;
+ date = false;
+ break;
+
+ case 'd':
+ fmt = DATE_SHORTDATE;
+ date = true;
+ break;
+
+ case 'D':
+ fmt = DATE_LONGDATE;
+ date = true;
+ break;
+
+ case 'I':
+ iso = true;
+ break;
+
+ default:
+ tszTemp.AppendChar(*pFormat);
+ continue;
+ }
+
+ TCHAR dateTimeStr[64];
+ if (iso)
+ tszTemp.AppendFormat(_T("%d-%02d-%02dT%02d:%02d:%02dZ"), st->wYear, st->wMonth, st->wDay, st->wHour, st->wMinute, st->wSecond);
+ else if (date) {
+ GetDateFormat(LOCALE_USER_DEFAULT, fmt, st, NULL, dateTimeStr, SIZEOF(dateTimeStr));
+ tszTemp.Append(dateTimeStr);
+ }
+ else {
+ GetTimeFormat(LOCALE_USER_DEFAULT, fmt, st, NULL, dateTimeStr, SIZEOF(dateTimeStr));
+ tszTemp.Append(dateTimeStr);
+ }
+ }
+
+ _tcsncpy_s(szDest, cbDest, tszTemp, _TRUNCATE);
+}
+
+#define fnSystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime
+
+MIR_CORE_DLL(int) TimeZone_GetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st)
+{
+ if (st == NULL) return 1;
+
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == UTC_TIME_HANDLE)
+ GetSystemTime(st);
+ else if (tz && tz != &myInfo.myTZ) {
+ SYSTEMTIME sto;
+ GetSystemTime(&sto);
+ return !fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &sto, st);
+ }
+ else
+ GetLocalTime(st);
+
+ return 0;
+}
+
+MIR_CORE_DLL(LPCTSTR) TimeZone_GetName(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL)
+ return myInfo.myTZ.tszName;
+ else if (tz == UTC_TIME_HANDLE)
+ return _T("UTC");
+
+ return tz->tszName;
+}
+
+MIR_CORE_DLL(LPCTSTR) TimeZone_GetDescription(LPCTSTR TZname)
+{
+ for (int i = 0; i < g_timezonesBias.getCount(); i++) {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+
+ if (!mir_tstrcmp(tz->tszName, TZname))
+ return tz->szDisplay;
+ }
+ return _T("");
+}
+
+static void CalcTsOffset(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+ GetSystemTime(&st);
+
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ mir_time ts1 = FileTimeToUnixTime(&ft);
+
+ if (!fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &st, &stl))
+ return;
+
+ SystemTimeToFileTime(&stl, &ft);
+ mir_time ts2 = FileTimeToUnixTime(&ft);
+
+ tz->offset = ts2 - ts1;
+}
+
+static bool IsSameTime(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+
+ if (tz == &myInfo.myTZ)
+ return true;
+
+ TimeZone_GetTimeZoneTime(tz, &stl);
+ TimeZone_GetTimeZoneTime(NULL, &st);
+
+ return st.wHour == stl.wHour && st.wMinute == stl.wMinute;
+}
+
+MIR_CORE_DLL(HANDLE) TimeZone_CreateByName(LPCTSTR tszName, DWORD dwFlags)
+{
+ if (tszName == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (mir_tstrcmp(myInfo.myTZ.tszName, tszName) == 0)
+ return (dwFlags & TZF_DIFONLY) ? NULL : &myInfo.myTZ;
+
+ MIM_TIMEZONE tzsearch;
+ tzsearch.hash = mir_hashstrT(tszName);
+
+ MIM_TIMEZONE *tz = g_timezones.find(&tzsearch);
+ if (tz == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (dwFlags & TZF_DIFONLY)
+ return IsSameTime(tz) ? NULL : tz;
+
+ return tz;
+}
+
+MIR_CORE_DLL(HANDLE) TimeZone_CreateByContact(MCONTACT hContact, LPCSTR szModule, DWORD dwFlags)
+{
+ if (hContact == NULL && szModule == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (szModule == NULL) szModule = "UserInfo";
+
+ DBVARIANT dbv;
+ if (!db_get_ts(hContact, szModule, "TzName", &dbv)) {
+ HANDLE res = TimeZone_CreateByName(dbv.ptszVal, dwFlags);
+ db_free(&dbv);
+ if (res) return res;
+ }
+
+ signed char timezone = (signed char)db_get_b(hContact, szModule, "Timezone", -1);
+ if (timezone == -1) {
+ char *szProto = GetContactProto(hContact);
+ if (!db_get_ts(hContact, szProto, "TzName", &dbv)) {
+ HANDLE res = TimeZone_CreateByName(dbv.ptszVal, dwFlags);
+ db_free(&dbv);
+ if (res) return res;
+ }
+ timezone = (signed char)db_get_b(hContact, szProto, "Timezone", -1);
+ }
+
+ if (timezone != -1) {
+ MIM_TIMEZONE tzsearch;
+ tzsearch.tzi.Bias = timezone * 30;
+ if (myInfo.myTZ.tzi.Bias == tzsearch.tzi.Bias) {
+ if (dwFlags & TZF_DIFONLY) return NULL;
+ return &myInfo.myTZ;
+ }
+
+ int i = g_timezonesBias.getIndex(&tzsearch);
+ while (i >= 0 && g_timezonesBias[i]->tzi.Bias == tzsearch.tzi.Bias) --i;
+
+ int delta = LONG_MAX;
+ for (int j = ++i; j < g_timezonesBias.getCount() && g_timezonesBias[j]->tzi.Bias == tzsearch.tzi.Bias; ++j) {
+ int delta1 = abs(g_timezonesBias[j]->tzi.DaylightDate.wMonth - myInfo.myTZ.tzi.DaylightDate.wMonth);
+ if (delta1 <= delta) {
+ delta = delta1;
+ i = j;
+ }
+ }
+
+ if (i >= 0) {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+ return ((dwFlags & TZF_DIFONLY) && IsSameTime(tz)) ? NULL : tz;
+ }
+ }
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+}
+
+MIR_CORE_DLL(void) TimeZone_StoreByContact(MCONTACT hContact, LPCSTR szModule, HANDLE hTZ)
+{
+ if (szModule == NULL) szModule = "UserInfo";
+
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz) {
+ db_set_ts(hContact, szModule, "TzName", tz->tszName);
+ db_set_b(hContact, szModule, "Timezone", (char)((tz->tzi.Bias + tz->tzi.StandardBias) / 30));
+ }
+ else {
+ db_unset(hContact, szModule, "TzName");
+ db_unset(hContact, szModule, "Timezone");
+ }
+}
+
+MIR_CORE_DLL(int) TimeZone_PrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ SYSTEMTIME st;
+ if (TimeZone_GetTimeZoneTime(tz, &st))
+ return 1;
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+ return 0;
+}
+
+MIR_CORE_DLL(int) TimeZone_PrintTimeStamp(HANDLE hTZ, mir_time ts, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ if (tz == NULL)
+ tz = &myInfo.myTZ;
+
+ FILETIME ft;
+ if (tz == UTC_TIME_HANDLE)
+ UnixTimeToFileTime(ts, &ft);
+ else {
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ UnixTimeToFileTime(ts + tz->offset, &ft);
+ }
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+ return 0;
+}
+
+MIR_CORE_DLL(LPTIME_ZONE_INFORMATION) TimeZone_GetInfo(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ return tz ? &tz->tzi : &myInfo.myTZ.tzi;
+}
+
+MIR_CORE_DLL(mir_time) TimeZone_UtcToLocal(HANDLE hTZ, mir_time ts)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL)
+ tz = &myInfo.myTZ;
+
+ if (tz == UTC_TIME_HANDLE)
+ return ts;
+
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ return ts + tz->offset;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct ListMessages
+{
+ UINT addStr, getSel, setSel, getData, setData;
+};
+
+static const ListMessages lbMessages = { LB_ADDSTRING, LB_GETCURSEL, LB_SETCURSEL, LB_GETITEMDATA, LB_SETITEMDATA };
+static const ListMessages cbMessages = { CB_ADDSTRING, CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_SETITEMDATA };
+
+static const ListMessages* GetListMessages(HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL)
+ return NULL;
+
+ if (!(dwFlags & (TZF_PLF_CB | TZF_PLF_LB))) {
+ TCHAR tszClassName[128];
+ GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
+ if (!mir_tstrcmpi(tszClassName, _T("COMBOBOX")))
+ dwFlags |= TZF_PLF_CB;
+ else if (!mir_tstrcmpi(tszClassName, _T("LISTBOX")))
+ dwFlags |= TZF_PLF_LB;
+ }
+ if (dwFlags & TZF_PLF_CB)
+ return &cbMessages;
+ else if (dwFlags & TZF_PLF_LB)
+ return &lbMessages;
+ else
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(int) TimeZone_SelectListItem(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags)
+{
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL)
+ return -1;
+
+ if (szModule == NULL) szModule = "UserInfo";
+
+ int iSelection = 0;
+ ptrT tszName(db_get_tsa(hContact, szModule, "TzName"));
+ if (tszName != NULL) {
+ unsigned hash = mir_hashstrT(tszName);
+ for (int i = 0; i < g_timezonesBias.getCount(); i++) {
+ if (hash == g_timezonesBias[i]->hash) {
+ iSelection = i + 1;
+ break;
+ }
+ }
+ }
+ else {
+ signed char cBias = db_get_b(hContact, szModule, "Timezone", -100);
+ if (cBias != -100) {
+ int iBias = cBias * 30;
+ for (int i = 0; i < g_timezonesBias.getCount(); i++) {
+ if (iBias == g_timezonesBias[i]->tzi.Bias) {
+ iSelection = i + 1;
+ break;
+ }
+ }
+ }
+ }
+
+ SendMessage(hWnd, lstMsg->setSel, iSelection, 0);
+ return iSelection;
+}
+
+MIR_CORE_DLL(int) TimeZone_PrepareList(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags)
+{
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL)
+ return 0;
+
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)TranslateT("<unspecified>"));
+
+ for (int i = 0; i < g_timezonesBias.getCount(); i++) {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)tz->szDisplay);
+ SendMessage(hWnd, lstMsg->setData, i + 1, (LPARAM)tz);
+ }
+
+ return TimeZone_SelectListItem(hContact, szModule, hWnd, dwFlags);
+}
+
+MIR_CORE_DLL(void) TimeZone_StoreListResult(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags)
+{
+ if (szModule == NULL) szModule = "UserInfo";
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg) {
+ LRESULT offset = SendMessage(hWnd, lstMsg->getSel, 0, 0);
+ if (offset > 0) {
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)SendMessage(hWnd, lstMsg->getData, offset, 0);
+ if ((INT_PTR)tz != CB_ERR && tz != NULL)
+ TimeZone_StoreByContact(hContact, szModule, tz);
+ }
+ else TimeZone_StoreByContact(hContact, szModule, NULL);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(DWORD) TimeZone_ToLocal(DWORD timeVal)
+{
+ return TimeZone_UtcToLocal(NULL, (mir_time)timeVal);
+}
+
+MIR_CORE_DLL(char*) TimeZone_ToString(mir_time timeVal, const char *szFormat, char *szDest, size_t cchDest)
+{
+ TCHAR *szTemp = (TCHAR*)alloca(cchDest*sizeof(TCHAR));
+ TimeZone_PrintTimeStamp(NULL, timeVal, _A2T(szFormat), szTemp, cchDest, 0);
+ WideCharToMultiByte(CP_ACP, 0, szTemp, -1, szDest, (int)cchDest, NULL, NULL);
+ return szDest;
+}
+
+MIR_CORE_DLL(wchar_t*) TimeZone_ToStringW(mir_time timeVal, const wchar_t *wszFormat, wchar_t *wszDest, size_t cchDest)
+{
+ TimeZone_PrintTimeStamp(NULL, timeVal, wszFormat, wszDest, cchDest, 0);
+ return wszDest;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GetLocalizedString(HKEY hSubKey, const TCHAR *szName, wchar_t *szBuf, DWORD cbLen)
+{
+ DWORD dwLength = cbLen * sizeof(wchar_t);
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBuf, &dwLength);
+ szBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+}
+
+void RecalculateTime(void)
+{
+ GetTimeZoneInformation(&myInfo.myTZ.tzi);
+ myInfo.timestamp = time(NULL);
+ myInfo.myTZ.offset = INT_MIN;
+
+ bool found = false;
+ DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+
+ if (pfnGetDynamicTimeZoneInformation && pfnGetDynamicTimeZoneInformation(&dtzi) != TIME_ZONE_ID_INVALID) {
+ TCHAR *myTzKey = mir_u2t(dtzi.TimeZoneKeyName);
+ _tcsncpy_s(myInfo.myTZ.tszName, myTzKey, _TRUNCATE);
+ mir_free(myTzKey);
+ found = true;
+ }
+
+ for (int i = 0; i < g_timezones.getCount(); i++) {
+ MIM_TIMEZONE &tz = g_timezones[i];
+ if (tz.offset != INT_MIN)
+ tz.offset = INT_MIN;
+
+ if (!found) {
+ if (!mir_wstrcmp(tz.tzi.StandardName, myInfo.myTZ.tzi.StandardName) || !mir_wstrcmp(tz.tzi.DaylightName, myInfo.myTZ.tzi.DaylightName)) {
+ _tcsncpy_s(myInfo.myTZ.tszName, tz.tszName, _TRUNCATE);
+ found = true;
+ }
+ }
+ }
+}
+
+void InitTimeZones(void)
+{
+ REG_TZI_FORMAT tzi;
+ HKEY hKey;
+
+ const TCHAR *tszKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
+
+ /*
+ * use GetDynamicTimeZoneInformation() on Vista+ - this will return a structure with
+ * the registry key name, so finding our own time zone later will be MUCH easier for
+ * localized systems or systems with a MUI pack installed
+ */
+ if (IsWinVerVistaPlus())
+ pfnGetDynamicTimeZoneInformation = (pfnGetDynamicTimeZoneInformation_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetDynamicTimeZoneInformation");
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszKey, 0, KEY_ENUMERATE_SUB_KEYS, &hKey)) {
+ DWORD dwIndex = 0;
+ HKEY hSubKey;
+ TCHAR tszName[MIM_TZ_NAMELEN];
+
+ DWORD dwSize = SIZEOF(tszName);
+ while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hKey, dwIndex++, tszName, &dwSize, NULL, NULL, 0, NULL)) {
+ if (ERROR_SUCCESS == RegOpenKeyEx(hKey, tszName, 0, KEY_QUERY_VALUE, &hSubKey)) {
+ dwSize = sizeof(tszName);
+
+ DWORD dwLength = sizeof(tzi);
+ if (ERROR_SUCCESS != RegQueryValueEx(hSubKey, _T("TZI"), NULL, NULL, (unsigned char *)&tzi, &dwLength))
+ continue;
+
+ MIM_TIMEZONE *tz = new MIM_TIMEZONE;
+
+ tz->tzi.Bias = tzi.Bias;
+ tz->tzi.StandardDate = tzi.StandardDate;
+ tz->tzi.StandardBias = tzi.StandardBias;
+ tz->tzi.DaylightDate = tzi.DaylightDate;
+ tz->tzi.DaylightBias = tzi.DaylightBias;
+
+ mir_tstrcpy(tz->tszName, tszName);
+ tz->hash = mir_hashstrT(tszName);
+ tz->offset = INT_MIN;
+
+ GetLocalizedString(hSubKey, _T("Display"), tz->szDisplay, SIZEOF(tz->szDisplay));
+ GetLocalizedString(hSubKey, _T("Std"), tz->tzi.StandardName, SIZEOF(tz->tzi.StandardName));
+ GetLocalizedString(hSubKey, _T("Dlt"), tz->tzi.DaylightName, SIZEOF(tz->tzi.DaylightName));
+
+ g_timezones.insert(tz);
+ g_timezonesBias.insert(tz);
+
+ RegCloseKey(hSubKey);
+ }
+ dwSize = SIZEOF(tszName);
+ }
+ RegCloseKey(hKey);
+ }
+
+ RecalculateTime();
+}