From 144d05b638162094aabb5153483439589e103ed4 Mon Sep 17 00:00:00 2001 From: kreol13 Date: Thu, 21 Apr 2011 12:56:41 +0000 Subject: initial commit git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@3 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- svc_timezone_old.cpp | 645 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 645 insertions(+) create mode 100644 svc_timezone_old.cpp (limited to 'svc_timezone_old.cpp') diff --git a/svc_timezone_old.cpp b/svc_timezone_old.cpp new file mode 100644 index 0000000..e4961a2 --- /dev/null +++ b/svc_timezone_old.cpp @@ -0,0 +1,645 @@ +/* +UserinfoEx plugin for Miranda IM + +Copyright: + 2006-2010 DeathAxe, Yasnovidyashii, Merlin, K. Romanov, Kreol + +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. + +=============================================================================== + +File name : $HeadURL: https://userinfoex.googlecode.com/svn/trunk/svc_timezone_old.cpp $ +Revision : $Revision: 194 $ +Last change on : $Date: 2010-09-20 15:57:18 +0400 (Пн, 20 сен 2010) $ +Last change by : $Author: ing.u.horn $ + +=============================================================================== +*/ +#include "commonheaders.h" +#include "m_icq.h" +#include "svc_timezone_old.h" + +#define TZREG "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones" +#define TZREG_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones" + +/************************************************************************************************** + * struct CTimeZone + **************************************************************************************************/ + +/** + * This is the default constructure, which resets + * all attributes to NULL. + **/ +CTimeZone::CTimeZone() +{ + ZeroMemory(this, sizeof(*this)); +} + +/** + * The default construcor's task ist to clear out + * all pieces of the used memory. + **/ +CTimeZone::~CTimeZone() +{ + MIR_FREE(ptszName); + MIR_FREE(ptszDisplay); +} + +/** + * This method can be used to basically convert a Windows + * timezone to the format, known by miranda. + * + * @warning This operation does not work vice versa in + * all cases, as there are sometimes more then + * one Windows timezones with the same Bias. + **/ +BYTE CTimeZone::ToMirandaTimezone() const +{ + return (BYTE) (Bias / 30); +} + +/** + * This operator translates the content of this object to + * a TIME_ZONE_INFORMATION structure as it is required by + * several windows functions. + **/ +CTimeZone::operator TIME_ZONE_INFORMATION() const +{ + TIME_ZONE_INFORMATION tzi; + + tzi.Bias = Bias; + tzi.DaylightBias = DaylightBias; + tzi.StandardBias = StandardBias; + + memcpy(&tzi.DaylightDate, &DaylightDate, sizeof(DaylightDate)); + memcpy(&tzi.StandardDate, &StandardDate, sizeof(DaylightDate)); + return tzi; +} + +/*********************************************************************************************************** + * class CTzBias + ***********************************************************************************************************/ + +class CTzBias : public LIST +{ + static INT sortFunc(const CTimeZone *tz1, const CTimeZone *tz2) + { + INT result = tz2->Bias - tz1->Bias; + // DO NOT USE mir_tcsicmp here as it does only return TRUE or FALSE!!! + // lstrcmpi takes care of umlauts e.g. ,,.... + return (result || !tz1->ptszDisplay || !tz2->ptszDisplay) ? result : lstrcmpi(tz1->ptszDisplay, tz2->ptszDisplay); + } +public: + CTzBias() : LIST(50, (FTSortFunc) CTzBias::sortFunc) + { + } + + ~CTzBias() + { + // delete the list, items delete by CTzMgr + this->destroy(); + } +}; +/*********************************************************************************************************** + * class CTzMgr + ***********************************************************************************************************/ + +/** + * This class is a deriviant of miranda's SortedList and holds all timezones + * known by Windows. By default there is no API to list timezones, so we + * need to get the information directly from the registry. In order to avoid + * heavy reading operations from registry, this class has the task to cache + * all required information for much faster access. + **/ +class CTzMgr : public LIST +{ + CTzBias _bias; + + static INT sortFunc(const CTimeZone *tz1, const CTimeZone *tz2) + { + // DO NOT USE mir_tcsicmp here as it does only return TRUE or FALSE!!! + return _tcsicmp(tz1->ptszName, tz2->ptszName); + } + + /** + * This method clears the TzTzMgr's data. + **/ + VOID destroy() + { + INT i; + + // delete data + for (i = 0 ; i < count; i++) + { + delete (*this)[i]; + } + // delete the list + LIST::destroy(); + // delete the _bias list ???? + //_bias.destroy(); + + } + +public: + + const CTzBias& Bias; + + CTzMgr() + :LIST(50, (FTSortFunc) CTzMgr::sortFunc), + _bias(), Bias(_bias) + { + } + + /** + * This is the default destructor of the class. + * + * @param none + * + * @return nothing + **/ + ~CTzMgr() + { + destroy(); + } + + /** + * This method loads all information about timezones from windows' registry. + **/ + INT Init() + { + INT result; + HKEY hKeyRoot, + hKeyTz; + DWORD i, + cbData; + TCHAR szName[MAX_PATH], + szDisplay[MAX_PATH]; + CTimeZone *pTimeZone; + + result = RegOpenKey(HKEY_LOCAL_MACHINE, _T(TZREG), &hKeyRoot); + if (result != ERROR_SUCCESS) + { + result = RegOpenKey(HKEY_LOCAL_MACHINE, _T(TZREG_9X), &hKeyRoot); + } + if (result == ERROR_SUCCESS) + { + // clear out old list + this->destroy(); _bias.destroy(); + for (i = 0; ERROR_SUCCESS == RegEnumKey(hKeyRoot, i, szName, SIZEOF(szName)); i++) + { + result = RegOpenKey(hKeyRoot, szName, &hKeyTz); + if (result == ERROR_SUCCESS) + { + pTimeZone = new CTimeZone(); + if (pTimeZone) + { + cbData = sizeof(szDisplay); + result |= RegQueryValueEx(hKeyTz, _T("Display"), 0, 0, (LPBYTE)szDisplay, &cbData); + + cbData = sizeof(REG_TZI_FORMAT); + result |= RegQueryValueEx(hKeyTz, _T("TZI"), 0, 0, (LPBYTE)pTimeZone, &cbData); + + cbData = sizeof(DWORD); + if (RegQueryValueEx(hKeyTz, _T("Index"), 0, 0, (LPBYTE)(UINT_PTR)pTimeZone->dwIndex, &cbData) != ERROR_SUCCESS) + { + pTimeZone->dwIndex = TZINDEX_UNSPECIFIED; + } + if (result == ERROR_SUCCESS) + { + pTimeZone->ptszName = mir_tcsdup(szName); + pTimeZone->ptszDisplay = mir_tcsdup(szDisplay); + result = (insert(pTimeZone) == ERROR_SUCCESS); + } + if (result != ERROR_SUCCESS) + { + delete pTimeZone; + } + else + { + _bias.insert(pTimeZone); + } + } + RegCloseKey(hKeyTz); + } + } + RegCloseKey(hKeyRoot); + } + return result; + } + + /** + * This method is used to find a certain list entry according to + * a key, providing information about the entry to look for. + * + * @param result - Pointer to a pointer, retrieving the CTimeZone + * object, matching the criteria provided by key + * @param key - Pointer to a CTimeZone structure, providing + * information about the item to look for. + * The Bias member and/or pszDisplay member must + * be valid. + * @retval -1 : item not found + * @retval 0...count : index of the found item + **/ + INT find(CTimeZone** pTimezone, CTimeZone* pKey) const + { + INT nItemIndex = -1; + + if (pKey && pKey->ptszName) + { + nItemIndex = getIndex(pKey); + if (pTimezone) + { + *pTimezone = (nItemIndex == -1) ? NULL : items[nItemIndex]; + } + } + return nItemIndex; + } + + INT find(CTimeZone** pTimezone, LPTSTR ptszName) const + { + CTimeZone key; + INT nItemIndex; + + key.ptszName = ptszName; + nItemIndex = find(pTimezone, &key); + key.ptszName = NULL; // prevents ptszName from being deleted by the destructor. + return nItemIndex; + } + + /** + * This method is used to find a certain list entry according to + * a given dwTzIndex, providing information about the entry to look for. + * + * @param result - Pointer to a pointer, retrieving the CTimeZone + * object, matching the criteria provided by key + * @param dwTzIndex - Timezone index as read from Windows Registry + * @retval -1 : item not found + * @retval 0...count : index of the found item + **/ + INT find(CTimeZone** result, DWORD dwTzIndex) const + { + INT nItemIndex = -1; + CTimeZone *ptz = NULL; + + if (dwTzIndex != TZINDEX_UNSPECIFIED) + { + for (nItemIndex = 0; nItemIndex < count; nItemIndex++) + { + ptz = items[nItemIndex]; + if (ptz && (ptz->dwIndex == dwTzIndex)) + break; + } + } + if (result) + { + *result = ptz; + } + return ((nItemIndex == count) ? -1 : nItemIndex); + } + +}; +// global timezone TzMgr object +static CTzMgr TzMgr; + +/*********************************************************************************************************** + * public Service functions + ***********************************************************************************************************/ + +/** + * This method trys to find some default windows timezone idices for a given + * miranda timezone. + * + * @param MirTz - this is a miranda timezone with values between -24 and 24. + * + * @return This method returns a @TZ_MAP struct of a windows timezone, which is maps + * the @MirTz value,name or {-1,NULL} if no windows timezone index exists. + **/ +static TZ_MAP MirTZ2WinTZ(const CHAR MirTz) +{ + /** + * This is an item of an array of timezones, which are known by both Miranda-IM + * and Windows. It is used to map an ICQ timezone against a Windows timezone + * for retrieving information about daylight saving time and more. + **/ + static const TZ_MAP TzMap[] = { + { 0, _T("Dateline Standard Time")}, // GMT-12:00 Eniwetok; Kwajalein + {-1, _T("")}, // GMT-11:30 + { 1, _T("Samoa Standard Time")}, // GMT-11:00 Midway Island; Samoa + {-1, _T("")}, // GMT-10:30 + { 2, _T("Hawaiian Standard Time")}, // GMT-10:00 Hawaii + {-1, _T("")}, // GMT-9:30 + { 3, _T("Alaskan Standard Time")}, // GMT-9:00 Alaska + {-1, _T("")}, // GMT-8:30 + { 4, _T("Pacific Standard Time")}, // GMT-8:00 Pacific Time; Tijuana + {-1, _T("")}, // GMT-7:30 + {15, _T("US Mountain Standard Time")}, // GMT-7:00 Arizona; Mountain Time + {-1, _T("")}, // GMT-6:30 + {33, _T("Central America Standard Time")}, // GMT-6:00 Central Time; Central America; Saskatchewan + {-1, _T("")}, // GMT-5:30 + {45, _T("SA Pacific Standard Time")}, // GMT-5:00 Eastern Time; Bogota; Lima; Quito + {-1, _T("")}, // GMT-4:30 + {56, _T("Pacific SA Standard Time")}, // GMT-4:00 Atlantic Time; Santiago; Caracas; La Paz + {60, _T("Newfoundland Standard Time")}, // GMT-3:30 Newfoundland + {70, _T("SA Eastern Standard Time")}, // GMT-3:00 Greenland; Buenos Aires; Georgetown + {-1, _T("")}, // GMT-2:30 + {75, _T("Mid-Atlantic Standard Time")}, // GMT-2:00 Mid-Atlantic + {-1, _T("")}, // GMT-1:30 + {80, _T("Azores Standard Time")}, // GMT-1:00 Cape Verde Islands; Azores + {-1, _T("")}, // GMT-0:30 + {85, _T("GMT Standard Time")}, // GMT+0:00 London; Dublin; Edinburgh; Lisbon; Casablanca + {-1, _T("")}, // GMT+0:30 + {105, _T("Romance Standard Time")}, // GMT+1:00 Central European Time; West Central Africa; Warsaw + {-1, _T("")}, // GMT+1:30 + {140, _T("South Africa Standard Time")}, // GMT+2:00 Jerusalem; Helsinki; Harare; Cairo; Bucharest; Athens + {-1, _T("")}, // GMT+2:30 + {145, _T("Russian Standard Time")}, // GMT+3:00 Moscow; St. Petersburg; Nairobi; Kuwait; Baghdad + {160, _T("Iran Standard Time")}, // GMT+3:30 Tehran + {165, _T("Arabian Standard Time")}, // GMT+4:00 Baku; Tbilisi; Yerevan; Abu Dhabi; Muscat + {175, _T("Afghanistan Standard Time")}, // GMT+4:30 Kabul + {185, _T("West Asia Standard Time")}, // GMT+5:00 Calcutta; Chennai; Mumbai; New Delhi; Ekaterinburg + {200, _T("Sri Lanka Standard Time")}, // GMT+5:30 Sri Jayawardenepura + {201, _T("N. Central Asia Standard Time")}, // GMT+6:00 Astana; Dhaka; Almaty; Novosibirsk + {203, _T("Myanmar Standard Time")}, // GMT+6:30 Rangoon + {207, _T("North Asia Standard Time")}, // GMT+7:00 Bankok; Hanoi; Jakarta; Krasnoyarsk + {-1, _T("")}, // GMT+7:30 + {210, _T("China Standard Time")}, // GMT+8:00 Perth; Taipei; Singapore; Hong Kong; Beijing + {-1, _T("")}, // GMT+8:30 + {235, _T("Tokyo Standard Time")}, // GMT+9:00 Tokyo; Osaka; Seoul; Sapporo; Yakutsk + {245, _T("AUS Central Standard Time")}, // GMT+9:30 Darwin; Adelaide + {270, _T("Vladivostok Standard Time")}, // GMT+10:00 East Australia; Guam; Vladivostok + {-1, _T("")}, // GMT+10:30 + {280, _T("Central Pacific Standard Time")}, // GMT+11:00 Magadan; Solomon Is.; New Caledonia + {-1, _T("")}, // GMT+11:30 + {290, _T("New Zealand Standard Time")}, // GMT+12:00 Auckland; Wellington; Fiji; Kamchatka; Marshall Is. + {-1, _T("")} + }; + return (MirTz >= -24 && MirTz <= 24) ? TzMap[24 - MirTz] : TzMap[49] ; +} + +/** + * This function reads out the Timezone, associated with the given contact + * + * @param hContact - HANDLE of the contact to retrieve the timezone for. + * @param pszProto - contact's protocol + * + * @retval NULL - No timezone exists. + * @retval CTimeZone* - Pointer to the timezone. + **/ +CTimeZone* GetContactTimeZone(HANDLE hContact, LPCSTR pszProto) +{ + LPTSTR ptszName; + CTimeZone* pTimeZone = NULL; + + // read windows timezone from database (include meta subcontacts) + ptszName = DB::Setting::GetTStringEx(hContact, USERINFO, pszProto, SET_CONTACT_TIMEZONENAME); + if (!ptszName || FAILED(TzMgr.find(&pTimeZone, ptszName))) + { + DBVARIANT dbv; + TZ_MAP MirTZ; + + // try to get miranda's timezone index value + if (!myGlobals.TzIndexExist || DB::Setting::GetAsIsEx(hContact, USERINFO, pszProto, SET_CONTACT_TIMEZONEINDEX, &dbv) || FAILED(TzMgr.find(&pTimeZone,dbv.dVal))) + { + // maybe a failure lets us read a string, so clear it out + DB::Variant::Free(&dbv); + + // try to get miranda's timezone value + if (DB::Setting::GetAsIsEx(hContact, USERINFO, pszProto, SET_CONTACT_TIMEZONE, &dbv) || (dbv.type != DBVT_BYTE)) + { + // maybe a failure lets us read a string, so clear it out + DB::Variant::Free(&dbv); + } + else + { + MirTZ = MirTZ2WinTZ(dbv.cVal); + if (*MirTZ.Name != 0) + { + TzMgr.find(&pTimeZone, MirTZ.Name); + } + } + } + } + MIR_FREE(ptszName); + return pTimeZone; +} + +/** + * + * + **/ +CTimeZone* GetContactTimeZone(HANDLE hContact) +{ + return GetContactTimeZone(hContact, DB::Contact::Proto(hContact)); +} + +/** + * This method trys to find the contact's windows timezone. + * + * @warning Make sure you convert @e dwIndex to CHAR if the function returns 1 in order to get + * the correct miranda timezone! + * + * @param hContact - the HANDLE of the contact to read timezone information for + * @param szProto - contact's protocol + * @param pTimeZone - Pointer to the pointer of a CTimeZone structure, + * which retrieves information about contact's timezone. + * + * @retval CTRLF_... flag - The index for a windows timezone was found for the contact. + * @retval 0 - There is no index, but if the contact's 'timezone' setting is valid, + * @e dwIndex retrieved its value. If not, dwIndex is -100 (unspecified). + **/ +WORD GetContactTimeZoneCtrl(HANDLE hContact, LPCSTR pszProto, CTimeZone** pTimeZone) +{ + WORD flags; + DBVARIANT dbv; + CTimeZone* pTz = NULL; + + // try to read windows' timezone name from database + flags = DB::Setting::GetCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_TIMEZONENAME, &dbv, DBVT_TCHAR); + if (flags == 0 || FAILED(TzMgr.find(&pTz, dbv.ptszVal))) + { + DB::Variant::Free(&dbv); + + // try to get miranda's timezone index value + if (myGlobals.TzIndexExist) + { + flags = DB::Setting::GetAsIsCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_TIMEZONEINDEX, &dbv); + if (flags && FAILED(TzMgr.find(&pTz, dbv.dVal))) + { + flags = 0; + } + } + if (flags == 0) + { + // try to get miranda's timezone value + flags = DB::Setting::GetAsIsCtrl(hContact, USERINFO, USERINFO, pszProto, SET_CONTACT_TIMEZONE, &dbv); + if (flags != 0) + { + TZ_MAP MirTZ; + MirTZ = MirTZ2WinTZ(dbv.cVal); + if ((*MirTZ.Name == 0) || FAILED(TzMgr.find(&pTz, MirTZ.Name))) + { + flags = 0; + } + } + } + } + if (pTimeZone && flags != 0) + { + *pTimeZone = pTz; + } + DB::Variant::Free(&dbv); + return flags; +} + +/** + * This function returns the display name for the contact's timezone + * + * @param hContact - handle of the contact + * + * @return String containing display name. + **/ +LPCTSTR GetContactTimeZoneDisplayName(HANDLE hContact) +{ + CTimeZone *pTimeZone; + + pTimeZone = GetContactTimeZone(hContact); + return (pTimeZone) ? pTimeZone->ptszDisplay : NULL; +} + +/** + * + * + **/ +INT_PTR EnumTimeZones(PEnumNamesProc enumProc, LPARAM lParam) +{ + INT_PTR i, c, r = 0; + CTimeZone *pTz; + + for (i = 0, c = TzMgr.Bias.getCount(); i < c; i++) + { + pTz = TzMgr.Bias[i]; + if (pTz) + { + r = enumProc(pTz, i, lParam); + if (r) break; + } + } + return r; +} + +/** + * + * + **/ +static BOOL SvcTimezoneSyncWithWindowsProc(LPCSTR pszProto, INT bias) +{ + INT tz = (INT) ((CHAR)DB::Setting::GetByte(pszProto, SET_CONTACT_TIMEZONE, (BYTE)-100)); + if (tz * 30 != bias) + { + DB::Setting::WriteByte(pszProto, SET_CONTACT_TIMEZONE, (BYTE)(bias / 30)); + return TRUE; + } + return FALSE; +} + +/** + * + * + **/ +VOID SvcTimezoneSyncWithWindows() +{ + PROTOACCOUNT **pAcc; + INT i, nAccCount; + TIME_ZONE_INFORMATION tzi; + + ZeroMemory(&tzi, sizeof(tzi)); + GetTimeZoneInformation(&tzi); + + if (MIRSUCCEEDED(ProtoEnumAccounts(&nAccCount, &pAcc))) + { + for (i = 0; i < nAccCount; i++) + { + // update local timezone as database setting + if (IsProtoAccountEnabled(pAcc[i]) && SvcTimezoneSyncWithWindowsProc(pAcc[i]->szModuleName, tzi.Bias)) + { + // update my contact information on icq server + CallProtoService(pAcc[i]->szModuleName, PS_CHANGEINFOEX, CIXT_LOCATION, NULL); + } + } + } +} + +/*********************************************************************************************************** + * services use old UIEX timezone + ***********************************************************************************************************/ + +/** + * This service function provides a TIME_ZONE_INFORMATION structure + * for the desired contact, in case the contact's timezone can be determined. + * + * @param wParam - HANDLE of the contact, to retrieve timezone information from. + * @param lParam - pointer to a TIME_ZONE_INFORMATION to fill. + * + * @retval 0 - success + * @retval 1 - failure + **/ +INT_PTR GetContactTimeZoneInformation_old(WPARAM wParam,LPARAM lParam) +{ + CTimeZone *pTimeZone; + TIME_ZONE_INFORMATION* pTimeZoneInformation = (TIME_ZONE_INFORMATION*)lParam; + + pTimeZone = GetContactTimeZone((HANDLE)wParam); + if (pTimeZone && pTimeZoneInformation) + { + (*pTimeZoneInformation) = *pTimeZone; + } + return (pTimeZone == NULL) || (pTimeZoneInformation == NULL); +} + +/** + * This function returns the contact's local time. + * + * @param wParam - HANDLE of the contact, to retrieve timezone information from. + * @param lParam - pointer to a systemtime structure + * + * @return TRUE or FALSE + **/ +INT_PTR GetContactLocalTime_old(WPARAM wParam, LPARAM lParam) +{ + MTime now; + LPSYSTEMTIME pSystemTime = (LPSYSTEMTIME)lParam; + + now.GetLocalTime((HANDLE)wParam); + *pSystemTime = now.SystemTime(); + return 0; +} + +/*********************************************************************************************************** + * initialization + ***********************************************************************************************************/ + +/** + * This function initially loads the module uppon startup. + **/ +VOID SvcTimezoneLoadModule_old() +{ + TzMgr.Init(); + myCreateServiceFunction(MS_USERINFO_TIMEZONEINFO, GetContactTimeZoneInformation); + myCreateServiceFunction(MS_USERINFO_LOCALTIME, GetContactLocalTime); + if (DB::Setting::GetByte(SET_OPT_AUTOTIMEZONE, TRUE)) + { + SvcTimezoneSyncWithWindows(); + } +} -- cgit v1.2.3