summaryrefslogtreecommitdiff
path: root/plugins/mir_core
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mir_core')
-rw-r--r--plugins/mir_core/commonheaders.cpp2
-rw-r--r--plugins/mir_core/commonheaders.h63
-rw-r--r--plugins/mir_core/langpack.cpp630
-rw-r--r--plugins/mir_core/lists.cpp278
-rw-r--r--plugins/mir_core/memory.cpp280
-rw-r--r--plugins/mir_core/mir_core.def5
-rw-r--r--plugins/mir_core/mir_core_10.vcxproj218
-rw-r--r--plugins/mir_core/mir_core_10.vcxproj.filters64
-rw-r--r--plugins/mir_core/miranda.cpp398
-rw-r--r--plugins/mir_core/miranda.h131
-rw-r--r--plugins/mir_core/modules.cpp644
-rw-r--r--plugins/mir_core/path.cpp210
-rw-r--r--plugins/mir_core/timezones.cpp224
-rw-r--r--plugins/mir_core/utf.cpp406
-rw-r--r--plugins/mir_core/utils.cpp150
15 files changed, 3703 insertions, 0 deletions
diff --git a/plugins/mir_core/commonheaders.cpp b/plugins/mir_core/commonheaders.cpp
new file mode 100644
index 0000000000..95b2201163
--- /dev/null
+++ b/plugins/mir_core/commonheaders.cpp
@@ -0,0 +1,2 @@
+#include "commonheaders.h"
+
diff --git a/plugins/mir_core/commonheaders.h b/plugins/mir_core/commonheaders.h
new file mode 100644
index 0000000000..2d04e12f4b
--- /dev/null
+++ b/plugins/mir_core/commonheaders.h
@@ -0,0 +1,63 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#define MIRANDA_VER 0x0A00
+
+#define WINVER 0x0700
+#define _WIN32_WINNT 0x0700
+#define _WIN32_IE 0x0601
+
+#define INCL_WINSOCK_API_TYPEDEFS 1
+
+#include "m_stdhdr.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <uxtheme.h>
+#include <commctrl.h>
+#include <vssym32.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <limits.h>
+#include <string.h>
+#include <locale.h>
+#include <direct.h>
+
+#include <win2k.h>
+
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_database.h>
+#include <newpluginapi.h>
+
+#include "miranda.h"
+
+#include <m_ssl.h>
+#include <m_xml.h>
diff --git a/plugins/mir_core/langpack.cpp b/plugins/mir_core/langpack.cpp
new file mode 100644
index 0000000000..d38dd6807d
--- /dev/null
+++ b/plugins/mir_core/langpack.cpp
@@ -0,0 +1,630 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+#include "commonheaders.h"
+
+#define LANGPACK_BUF_SIZE 4000
+
+static int CompareMuuids(const LangPackMuuid* p1, const LangPackMuuid* p2)
+{
+ return memcmp(&p1->muuid, &p2->muuid, sizeof(MUUID));
+}
+
+static LIST<LangPackMuuid> lMuuids(10, CompareMuuids);
+static LangPackMuuid* pCurrentMuuid = NULL;
+
+static BOOL bModuleInitialized = FALSE;
+
+struct LangPackEntry {
+ DWORD englishHash;
+ char *local;
+ wchar_t *wlocal;
+ LangPackMuuid* pMuuid;
+ LangPackEntry* pNext; // for langpack items with the same hash value
+};
+
+struct LangPackStruct {
+ TCHAR filename[MAX_PATH];
+ TCHAR filePath[MAX_PATH];
+ char language[64];
+ char lastModifiedUsing[64];
+ char authors[256];
+ char authorEmail[128];
+ LangPackEntry *entry;
+ int entryCount, entriesAlloced;
+ LCID localeID;
+ UINT defaultANSICp;
+} static langPack;
+
+static int IsEmpty(char *str)
+{
+ int i = 0;
+
+ while (str[i])
+ {
+ if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n')
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+static void ConvertBackslashes(char *str, UINT fileCp)
+{
+ char *pstr;
+ for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) {
+ if (*pstr == '\\') {
+ switch(pstr[1]) {
+ case 'n': *pstr = '\n'; break;
+ case 't': *pstr = '\t'; break;
+ case 'r': *pstr = '\r'; break;
+ default: *pstr = pstr[1]; break;
+ }
+ memmove(pstr+1, pstr+2, strlen(pstr+2) + 1);
+} } }
+
+#ifdef _DEBUG
+//#pragma optimize("gt", on)
+#endif
+
+// MurmurHash2
+MIR_CORE_DLL(unsigned int) mir_hash(const void * key, unsigned int len)
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char * data = (const unsigned char *)key;
+
+ while (len >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+static int SortLangPackHashesProc(LangPackEntry *arg1, LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+
+ return (arg1->pMuuid < arg2->pMuuid) ? -1 : 1;
+}
+
+static void swapBytes(void* p, size_t iSize)
+{
+ char *head = (char *)p; // here
+ char *tail = head + iSize - 1;
+
+ for (; tail > head; --tail, ++head) {
+ char temp = *head;
+ *head = *tail;
+ *tail = temp;
+ }
+}
+
+static bool EnterMuuid(const char* p, MUUID& result)
+{
+ if (*p++ != '{')
+ return false;
+
+ BYTE* d = (BYTE*)&result;
+
+ for (int nBytes = 0; *p && nBytes < 24; p++) {
+ if (*p == '-')
+ continue;
+
+ if (*p == '}')
+ break;
+
+ if ( !isxdigit(*p))
+ return false;
+
+ if ( !isxdigit(p[1]))
+ return false;
+
+ int c = 0;
+ if (sscanf(p, "%2x", &c) != 1)
+ return false;
+
+ *d++ = (BYTE)c;
+ nBytes++;
+ p++;
+ }
+
+ if (*p != '}')
+ return false;
+
+ swapBytes(&result.a, sizeof(result.a));
+ swapBytes(&result.b, sizeof(result.b));
+ swapBytes(&result.c, sizeof(result.c));
+ return true;
+}
+
+static void LoadLangPackFile(FILE* fp, char* line, UINT fileCp)
+{
+ while ( !feof(fp)) {
+ if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL)
+ break;
+
+ if (IsEmpty(line) || line[0] == ';' || line[0] == 0)
+ continue;
+
+ rtrim(line);
+
+ if (line[0] == '#') {
+ strlwr(line);
+
+ if ( !memcmp(line+1, "include", 7)) {
+ TCHAR tszFileName[ MAX_PATH ];
+ TCHAR* fileName = mir_a2t(ltrim(line+9));
+ mir_sntprintf(tszFileName, SIZEOF(tszFileName), _T("%s%s"), langPack.filePath, fileName);
+ mir_free(fileName);
+
+ FILE* p = _tfopen(tszFileName, _T("r"));
+ if (p) {
+ line[0] = 0;
+ fgets(line, SIZEOF(line), p);
+
+ UINT fileCp = CP_ACP;
+ if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf')
+ {
+ fileCp = CP_UTF8;
+ fseek(p, 3, SEEK_SET);
+ }
+ else
+ {
+ fileCp = langPack.defaultANSICp;
+ fseek(p, 0, SEEK_SET);
+ }
+
+ LoadLangPackFile(p, line, fileCp);
+ fclose(p);
+ }
+ }
+ else if ( !memcmp(line+1, "muuid", 5)) {
+ MUUID t;
+ if ( !EnterMuuid(line+7, t))
+ continue;
+
+ LangPackMuuid* pNew = (LangPackMuuid*)mir_alloc(sizeof(LangPackMuuid));
+ memcpy(&pNew->muuid, &t, sizeof(t));
+ pNew->pInfo = NULL;
+ lMuuids.insert(pNew);
+ pCurrentMuuid = pNew;
+ }
+
+ continue;
+ }
+
+ ConvertBackslashes(line, fileCp);
+
+ if (line[0] == '[' && line[ lstrlenA(line)-1 ] == ']') {
+ if (langPack.entryCount && langPack.entry[ langPack.entryCount-1].local == NULL)
+ langPack.entryCount--;
+
+ char* pszLine = line+1;
+ line[ lstrlenA(line)-1 ] = '\0';
+ if (++langPack.entryCount > langPack.entriesAlloced) {
+ langPack.entriesAlloced += 128;
+ langPack.entry = (LangPackEntry*)mir_realloc(langPack.entry, sizeof(LangPackEntry)*langPack.entriesAlloced);
+ }
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ E->englishHash = mir_hashstr(pszLine);
+ E->local = NULL;
+ E->wlocal = NULL;
+ E->pMuuid = pCurrentMuuid;
+ E->pNext = NULL;
+ continue;
+ }
+
+ if ( !langPack.entryCount)
+ continue;
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ if (E->local == NULL) {
+ E->local = mir_strdup(line);
+ if (fileCp == CP_UTF8)
+ Utf8DecodeCP(E->local, langPack.defaultANSICp, NULL);
+
+ int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0);
+ E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t));
+ MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal, iNeeded);
+ }
+ else {
+ size_t iOldLenA = strlen(E->local);
+ E->local = (char*)mir_realloc(E->local, iOldLenA + strlen(line) + 2);
+ strcat(E->local, "\n");
+ strcat(E->local, line);
+
+ if (fileCp == CP_UTF8)
+ Utf8DecodeCP(E->local + iOldLenA + 1, langPack.defaultANSICp, NULL);
+
+ int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0);
+ size_t iOldLen = wcslen(E->wlocal);
+ E->wlocal = (wchar_t*)mir_realloc(E->wlocal, (sizeof(wchar_t) * (iOldLen + iNeeded + 2)));
+ wcscat(E->wlocal, L"\n");
+ MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal + iOldLen + 1, iNeeded);
+ }
+ }
+}
+
+MIR_CORE_DLL(int) LoadLangPack(const TCHAR *szLangPack)
+{
+ int startOfLine=0;
+ USHORT langID;
+
+ lstrcpy(langPack.filename, szLangPack);
+ lstrcpy(langPack.filePath, szLangPack);
+ TCHAR* p = _tcsrchr(langPack.filePath, '\\');
+ if (p)
+ p[1] = 0;
+
+ FILE *fp = _tfopen(szLangPack, _T("rt"));
+ if (fp == NULL)
+ return 1;
+
+ char line[ LANGPACK_BUF_SIZE ] = "";
+ fgets(line, SIZEOF(line), fp);
+
+ UINT fileCp = CP_ACP;
+ size_t lineLen = strlen(line);
+ if (lineLen >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf')
+ {
+ fileCp = CP_UTF8;
+ memmove(line, line + 3, lineLen - 2);
+ }
+
+ lrtrim(line);
+ if (lstrcmpA(line, "Miranda Language Pack Version 1")) {
+ fclose(fp);
+ return 2;
+ }
+
+ //headers
+ while ( !feof(fp)) {
+ startOfLine = ftell(fp);
+ if (fgets(line, SIZEOF(line), fp) == NULL)
+ break;
+
+ lrtrim(line);
+ if (IsEmpty(line) || line[0] == ';' || line[0] == 0)
+ continue;
+
+ if (line[0] == '[' || line[0] == '#')
+ break;
+
+ char* pszColon = strchr(line, ':');
+ if (pszColon == NULL) {
+ fclose(fp);
+ return 3;
+ }
+
+ *pszColon++ = 0;
+ if ( !lstrcmpA(line, "Language")) {mir_snprintf(langPack.language, sizeof(langPack.language), "%s", pszColon); lrtrim(langPack.language);}
+ else if ( !lstrcmpA(line, "Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing, sizeof(langPack.lastModifiedUsing), "%s", pszColon); lrtrim(langPack.lastModifiedUsing);}
+ else if ( !lstrcmpA(line, "Authors")) {mir_snprintf(langPack.authors, sizeof(langPack.authors), "%s", pszColon); lrtrim(langPack.authors);}
+ else if ( !lstrcmpA(line, "Author-email")) {mir_snprintf(langPack.authorEmail, sizeof(langPack.authorEmail), "%s", pszColon); lrtrim(langPack.authorEmail);}
+ else if ( !lstrcmpA(line, "Locale")) {
+ char szBuf[20], *stopped;
+
+ lrtrim(pszColon + 1);
+ langID = (USHORT)strtol(pszColon, &stopped, 16);
+ langPack.localeID = MAKELCID(langID, 0);
+ GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10);
+ szBuf[5] = 0; // codepages have max. 5 digits
+ langPack.defaultANSICp = atoi(szBuf);
+ if (fileCp == CP_ACP)
+ fileCp = langPack.defaultANSICp;
+ }
+ }
+
+ //body
+ fseek(fp, startOfLine, SEEK_SET);
+ langPack.entriesAlloced = 0;
+
+ LoadLangPackFile(fp, line, fileCp);
+ fclose(fp);
+ pCurrentMuuid = NULL;
+
+ qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int SortLangPackHashesProc2(LangPackEntry *arg1, LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+ return 0;
+}
+
+static char *LangPackTranslateString(LangPackMuuid* pUuid, const char *szEnglish, const int W)
+{
+ if (langPack.entryCount == 0 || szEnglish == NULL)
+ return (char*)szEnglish;
+
+ LangPackEntry key, *entry;
+ key.englishHash = W ? mir_hashstrW((WCHAR*)szEnglish) : mir_hashstr(szEnglish);
+ entry = (LangPackEntry*)bsearch(&key, langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc2);
+ if (entry == NULL)
+ return (char*)szEnglish;
+
+ // try to find the exact match, otherwise the first entry will be returned
+ if (pUuid) {
+ for (LangPackEntry* p = entry->pNext; p != NULL; p = p->pNext) {
+ if (p->pMuuid == pUuid) {
+ entry = p;
+ break;
+ } } }
+
+ return W ? (char *)entry->wlocal : entry->local;
+}
+
+MIR_CORE_DLL(int) LangPackGetDefaultCodePage()
+{
+ return langPack.defaultANSICp;
+}
+
+MIR_CORE_DLL(int) LangPackGetDefaultLocale()
+{
+ return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID;
+}
+
+MIR_CORE_DLL(TCHAR*) LangPackPcharToTchar(const char* pszStr)
+{
+ if (pszStr == NULL)
+ return NULL;
+
+ { int len = (int)strlen(pszStr);
+ TCHAR* result = (TCHAR*)alloca((len+1)*sizeof(TCHAR));
+ MultiByteToWideChar(LangPackGetDefaultCodePage(), 0, pszStr, -1, result, len);
+ result[len] = 0;
+ return mir_wstrdup(TranslateW(result));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(char*) TranslateA_LP(const char* str, int hLangpack)
+{
+ return (char*)LangPackTranslateString(LangPackLookupUuid(hLangpack), str, FALSE);
+}
+
+MIR_CORE_DLL(WCHAR*) TranslateW_LP(const WCHAR* str, int hLangpack)
+{
+ return (WCHAR*)LangPackTranslateString(LangPackLookupUuid(hLangpack), (LPCSTR)str, TRUE);
+}
+
+MIR_CORE_DLL(void) TranslateMenu_LP(HMENU hMenu, int hLangpack)
+{
+ LangPackMuuid* uuid = LangPackLookupUuid(hLangpack);
+
+ MENUITEMINFO mii;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ for (int i = GetMenuItemCount(hMenu)-1; i >= 0; i--) {
+ TCHAR str[256];
+ mii.fMask = MIIM_TYPE|MIIM_SUBMENU;
+ mii.dwTypeData = (TCHAR*)str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+
+ if (mii.cch && mii.dwTypeData) {
+ TCHAR* result = (TCHAR*)LangPackTranslateString(uuid, (const char*)mii.dwTypeData, TRUE);
+ if (result != mii.dwTypeData) {
+ mii.dwTypeData = result;
+ mii.fMask = MIIM_TYPE;
+ SetMenuItemInfo(hMenu, i, TRUE, &mii);
+ } }
+
+ if (mii.hSubMenu != NULL) TranslateMenu_LP(mii.hSubMenu, hLangpack);
+ }
+}
+
+static void TranslateWindow(LangPackMuuid* pUuid, HWND hwnd)
+{
+ TCHAR title[2048];
+ GetWindowText(hwnd, title, SIZEOF(title));
+
+ TCHAR* result = (TCHAR*)LangPackTranslateString(pUuid, (const char*)title, TRUE);
+ if (result != title)
+ SetWindowText(hwnd, result);
+}
+
+struct LANGPACKTRANSLATEDIALOG
+{
+ HWND hwndDlg;
+ int hLangpack;
+};
+
+static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd, LPARAM lParam)
+{
+ int hLangpack = (int)lParam;
+ TCHAR szClass[32];
+ int id = GetDlgCtrlID(hwnd);
+
+ LangPackMuuid* uuid = LangPackLookupUuid(hLangpack);
+
+ GetClassName(hwnd, szClass, SIZEOF(szClass));
+ if ( !lstrcmpi(szClass, _T("static")) || !lstrcmpi(szClass, _T("hyperlink")) || !lstrcmpi(szClass, _T("button")) || !lstrcmpi(szClass, _T("MButtonClass")) || !lstrcmpi(szClass, _T("MHeaderbarCtrl")))
+ TranslateWindow(uuid, hwnd);
+ else if ( !lstrcmpi(szClass, _T("edit"))) {
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY)
+ TranslateWindow(uuid, hwnd);
+ }
+ return TRUE;
+}
+
+MIR_CORE_DLL(void) TranslateDialog_LP(HWND hDlg, int hLangpack)
+{
+ TranslateWindow(LangPackLookupUuid(hLangpack), hDlg);
+ EnumChildWindows(hDlg, TranslateDialogEnumProc, hLangpack);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(LangPackMuuid*) LangPackLookupUuid(WPARAM wParam)
+{
+ int idx = (wParam >> 16) & 0xFFFF;
+ return (idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[ idx-1 ] : NULL;
+}
+
+MIR_CORE_DLL(int) LangPackMarkPluginLoaded(PLUGININFOEX* pInfo)
+{
+ LangPackMuuid tmp; tmp.muuid = pInfo->uuid;
+ int idx = lMuuids.getIndex(&tmp);
+ if (idx == -1)
+ return 0;
+
+ lMuuids[ idx ]->pInfo = pInfo;
+ return (idx+1) << 16;
+}
+
+MIR_CORE_DLL(void) LangPackDropUnusedItems(void)
+{
+ if (langPack.entryCount == 0)
+ return;
+
+ LangPackEntry *s = langPack.entry+1, *d = s, *pLast = langPack.entry;
+ DWORD dwSavedHash = langPack.entry->englishHash;
+ bool bSortNeeded = false;
+
+ for (int i=1; i < langPack.entryCount; i++, s++) {
+ if (s->pMuuid != NULL && s->pMuuid->pInfo == NULL)
+ s->pMuuid = NULL;
+
+ if (s->englishHash != dwSavedHash) {
+ pLast = d;
+ if (s != d)
+ *d++ = *s;
+ else
+ d++;
+ dwSavedHash = s->englishHash;
+ }
+ else {
+ bSortNeeded = true;
+ LangPackEntry* p = (LangPackEntry*)mir_alloc(sizeof(LangPackEntry));
+ *p = *s;
+ pLast->pNext = p; pLast = p;
+ }
+ }
+
+ if (bSortNeeded) {
+ langPack.entryCount = (int)(d - langPack.entry);
+ qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int LoadLangPackModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ ZeroMemory(&langPack, sizeof(langPack));
+
+ TCHAR szSearch[MAX_PATH];
+ PathToAbsoluteT(_T("langpack_*.txt"), szSearch, NULL);
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearch, &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ PathToAbsoluteT(fd.cFileName, szSearch, NULL);
+ FindClose(hFind);
+ LoadLangPack(szSearch);
+ }
+ return 0;
+}
+
+void UnloadLangPackModule()
+{
+ if ( !bModuleInitialized) return;
+
+ int i;
+ for (i=0; i < lMuuids.getCount(); i++)
+ mir_free(lMuuids[i]);
+ lMuuids.destroy();
+
+ LangPackEntry* p = langPack.entry;
+ for (i=0; i < langPack.entryCount; i++, p++) {
+ if (p->pNext != NULL) {
+ for (LangPackEntry* p1 = p->pNext; p1 != NULL;) {
+ LangPackEntry* p2 = p1; p1 = p1->pNext;
+ mir_free(p2->local);
+ mir_free(p2->wlocal);
+ mir_free(p2);
+ } }
+
+ mir_free(p->local);
+ mir_free(p->wlocal);
+ }
+
+ if (langPack.entryCount) {
+ mir_free(langPack.entry);
+ langPack.entry=0;
+ langPack.entryCount=0;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(void) ReloadLangpack(TCHAR *pszStr)
+{
+ if (pszStr == NULL)
+ pszStr = langPack.filename;
+
+ UnloadLangPackModule();
+ LoadLangPack(pszStr);
+ LangPackDropUnusedItems();
+}
diff --git a/plugins/mir_core/lists.cpp b/plugins/mir_core/lists.cpp
new file mode 100644
index 0000000000..e4996fc156
--- /dev/null
+++ b/plugins/mir_core/lists.cpp
@@ -0,0 +1,278 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#include "commonheaders.h"
+
+/* a simple sorted list implementation */
+
+MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment)
+{
+ SortedList* result = (SortedList*)mir_calloc(sizeof(SortedList));
+ if (result == NULL)
+ return(NULL);
+
+ result->increment = p_increment;
+ result->limit = p_limit;
+ return(result);
+}
+
+MIR_CORE_DLL(void) List_Destroy(SortedList* p_list)
+{
+ if (p_list == NULL)
+ return;
+
+ if (p_list->items != NULL) {
+ mir_free(p_list->items);
+ p_list->items = NULL;
+ }
+
+ p_list->realCount = p_list->limit = 0;
+}
+
+MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value)
+{
+ int index;
+
+ if ( !List_GetIndex(p_list, p_value, &index))
+ return(NULL);
+
+ return(p_list->items[ index ]);
+}
+
+#ifdef _DEBUG
+#pragma optimize("gt", on)
+#endif
+
+MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index)
+{
+ if (p_value == NULL)
+ {
+ *p_index = -1;
+ return 0;
+ }
+
+ switch ((INT_PTR)p_list->sortFunc)
+ {
+ case 0:
+ break;
+
+ case HandleKeySort:
+#ifdef _WIN64
+ {
+ const unsigned __int64 val = *(unsigned __int64 *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+#endif
+
+ case NumericKeySort:
+ {
+ const unsigned val = *(unsigned *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned vali = *(unsigned *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ case PtrKeySort:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ const void* vali = p_list->items[i];
+ if (vali == p_value)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < p_value)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ default:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ int result = p_list->sortFunc(p_list->items[i], p_value);
+ if (result == 0)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (result < 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value)
+{
+ if (p_value == NULL)
+ return -1;
+
+ int i;
+ for (i=0; i < p_list->realCount; i++)
+ if (p_list->items[i] == p_value)
+ return i;
+
+ return -1;
+}
+
+#ifdef _DEBUG
+#pragma optimize("", on)
+#endif
+
+MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index)
+{
+ if (p_value == NULL || p_index > p_list->realCount)
+ return 0;
+
+ if (p_list->realCount == p_list->limit)
+ {
+ p_list->items = (void**)mir_realloc(p_list->items, sizeof(void*)*(p_list->realCount + p_list->increment));
+ p_list->limit += p_list->increment;
+ }
+
+ if (p_index < p_list->realCount)
+ memmove(p_list->items+p_index+1, p_list->items+p_index, sizeof(void*)*(p_list->realCount-p_index));
+
+ p_list->realCount++;
+
+ p_list->items[ p_index ] = p_value;
+ return 1;
+}
+
+MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p)
+{
+ if (p == NULL)
+ return -1;
+
+ int idx = list->realCount;
+ List_GetIndex(list, p, &idx);
+ return List_Insert(list, p, idx);
+}
+
+MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index)
+{
+ if (index < 0 || index > p_list->realCount)
+ return(0);
+
+ p_list->realCount--;
+ if (p_list->realCount > index)
+ {
+ memmove(p_list->items+index, p_list->items+index+1, sizeof(void*)*(p_list->realCount-index));
+ p_list->items[ p_list->realCount ] = NULL;
+ }
+
+ return 1;
+}
+
+MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p)
+{
+ int idx = -1;
+ if (List_GetIndex(list, p, &idx))
+ List_Remove(list, idx);
+
+ return idx;
+}
+
+MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize)
+{
+ d->increment = s->increment;
+ d->limit = s->limit;
+ d->realCount = s->realCount;
+ d->items = (void**)mir_alloc( sizeof(void*) * d->realCount);
+ memcpy(d->items, s->items, sizeof(void*) * d->realCount);
+}
+
+MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize)
+{
+ int i;
+
+ d->increment = s->increment;
+ d->sortFunc = s->sortFunc;
+
+ for (i = 0; i < s->realCount; i++) {
+ void* item = new char[ itemSize ];
+ memcpy(item, s->items[i], itemSize);
+ List_Insert(d, item, i);
+} }
diff --git a/plugins/mir_core/memory.cpp b/plugins/mir_core/memory.cpp
new file mode 100644
index 0000000000..25b4d880c2
--- /dev/null
+++ b/plugins/mir_core/memory.cpp
@@ -0,0 +1,280 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#include "commonheaders.h"
+
+#define BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock(void* blk)
+{
+ int result = FALSE;
+ char* p = (char*)blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *(DWORD*)p;
+ b = (DWORD*)&p[ sizeof(DWORD) ];
+ e = (DWORD*)&p[ sizeof(DWORD)*2 + size ];
+
+ if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED)
+ {
+ if (*b == BLOCK_FREED && *e == BLOCK_FREED)
+ OutputDebugStringA("memory block is already deleted\n");
+ else
+ OutputDebugStringA("memory block is corrupted\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ OutputDebugStringA("access violation during checking memory block\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(void*) mir_alloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+ {
+ char* p = (char*)malloc(size + sizeof(DWORD)*3);
+ if (p == NULL) {
+ OutputDebugStringA("memory overflow\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *(DWORD*)p = (DWORD)size;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof(DWORD)*2;
+} }
+
+/******************************************************************************/
+
+MIR_CORE_DLL(void*) mir_calloc(size_t size)
+{
+ void* p = mir_alloc(size);
+ if (p != NULL)
+ memset(p, 0, size);
+ return p;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(void*) mir_realloc(void* ptr, size_t size)
+{
+ char* p;
+
+ if (ptr != NULL) {
+ if ( !CheckBlock(ptr))
+ return NULL;
+ p = (char*)ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = (char*)realloc(p, size + sizeof(DWORD)*3);
+ if (p == NULL) {
+ OutputDebugStringA("memory overflow\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *(DWORD*)p = (DWORD)size;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof(DWORD)*2;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(void) mir_free(void* ptr)
+{
+ char* p;
+ DWORD size;
+
+ if (ptr == NULL)
+ return;
+ if ( !CheckBlock(ptr))
+ return;
+
+ p = (char*)ptr - sizeof(DWORD)*2;
+ size = *(DWORD*)p;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free(p);
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_strdup(const char* str)
+{
+ if (str != NULL) {
+ char* p = (char*)mir_alloc(strlen(str)+1);
+ if (p)
+ strcpy(p, str);
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_strndup(const char* str, size_t len)
+{
+ if (str != NULL && len != 0) {
+ char* p = (char*)mir_alloc(len + 1);
+ if ( !p) {
+ memcpy(p, str, len);
+ p[ len ] = 0;
+ }
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(WCHAR*) mir_wstrdup(const WCHAR* str)
+{
+ if (str != NULL) {
+ WCHAR* p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(wcslen(str)+1));
+ if (p)
+ wcscpy(p, str);
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va)
+{
+ int len;
+
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va)
+{
+ int len;
+
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage)
+{
+ if (src == NULL)
+ return NULL;
+
+ int cbLen = MultiByteToWideChar(codepage, 0, src, -1, NULL, 0);
+ wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1));
+ if (result == NULL)
+ return NULL;
+
+ MultiByteToWideChar(codepage, 0, src, -1, result, cbLen);
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src)
+{
+ return mir_a2u_cp(src, LangPackGetDefaultCodePage());
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage)
+{
+ if (src == NULL)
+ return NULL;
+
+ int cbLen = WideCharToMultiByte(codepage, 0, src, -1, NULL, 0, NULL, NULL);
+ char* result = (char*)mir_alloc(cbLen+1);
+ if (result == NULL)
+ return NULL;
+
+ WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, NULL, NULL);
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src)
+{
+ return mir_u2a_cp(src, LangPackGetDefaultCodePage());
+}
diff --git a/plugins/mir_core/mir_core.def b/plugins/mir_core/mir_core.def
new file mode 100644
index 0000000000..78e8323ff8
--- /dev/null
+++ b/plugins/mir_core/mir_core.def
@@ -0,0 +1,5 @@
+LIBRARY mir_core
+
+EXPORTS
+ CallContactService @1
+ CallProtoService @2
diff --git a/plugins/mir_core/mir_core_10.vcxproj b/plugins/mir_core/mir_core_10.vcxproj
new file mode 100644
index 0000000000..ba1b174e58
--- /dev/null
+++ b/plugins/mir_core/mir_core_10.vcxproj
@@ -0,0 +1,218 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\include\m_core.h" />
+ <ClInclude Include="..\..\include\m_system.h" />
+ <ClInclude Include="commonheaders.h" />
+ <ClInclude Include="forkthread.h" />
+ <ClInclude Include="miranda.h" />
+ <ClInclude Include="modules.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="commonheaders.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="langpack.cpp" />
+ <ClCompile Include="lists.cpp" />
+ <ClCompile Include="memory.cpp" />
+ <ClCompile Include="miranda.cpp" />
+ <ClCompile Include="modules.cpp" />
+ <ClCompile Include="path.cpp" />
+ <ClCompile Include="timezones.cpp" />
+ <ClCompile Include="utf.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>mir_core</ProjectName>
+ <ProjectGuid>{D9EFEA4B-B817-4DE1-BD62-68A5DB8F5F60}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>
+ </ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/mir_core/mir_core_10.vcxproj.filters b/plugins/mir_core/mir_core_10.vcxproj.filters
new file mode 100644
index 0000000000..30facd3a4c
--- /dev/null
+++ b/plugins/mir_core/mir_core_10.vcxproj.filters
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{bf74d1c9-acd8-4fba-837d-734f024521c9}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{a578a180-0eb9-4c3e-b4ae-0eaefa01d207}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="commonheaders.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="memory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="miranda.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="modules.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lists.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="langpack.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utf.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="path.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="timezones.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="commonheaders.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="modules.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="forkthread.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\m_core.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="miranda.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\m_system.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/mir_core/miranda.cpp b/plugins/mir_core/miranda.cpp
new file mode 100644
index 0000000000..1e714089d1
--- /dev/null
+++ b/plugins/mir_core/miranda.cpp
@@ -0,0 +1,398 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/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.
+
+*/
+
+#include "commonheaders.h"
+
+HWND hAPCWindow = NULL;
+
+int InitPathUtils(void);
+void RecalculateTime(void);
+
+HANDLE hStackMutex, hThreadQueueEmpty;
+int hLangpack = 0;
+HINSTANCE hInst = 0;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// exception handling
+
+static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*)
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
+
+MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter()
+{
+ return pMirandaExceptFilter;
+}
+
+MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter)
+{
+ pfnExceptionFilter oldOne = pMirandaExceptFilter;
+ if (pMirandaExceptFilter != 0)
+ pMirandaExceptFilter = pMirandaExceptFilter;
+ return oldOne;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread support functions
+
+struct THREAD_WAIT_ENTRY
+{
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+ void* pObject;
+ PVOID addr;
+};
+
+static LIST<THREAD_WAIT_ENTRY> threads(10, NumericKeySortT);
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ pThreadFuncEx threadcodeex;
+ void *arg, *owner;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthread - starts a new thread
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH, 0, (LPARAM)callercode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ callercode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthread( void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r, stacksize, &fa);
+ if ((UINT_PTR)-1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthreadex - starts a new thread with the extended info and returns the thread id
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa = (struct FORK_ARG *)arg;
+ pThreadFuncEx threadcode = fa->threadcodeex;
+ pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex;
+ void *cookie = fa->arg;
+ void *owner = fa->owner;
+ unsigned long rc = 0;
+
+ CallService(MS_SYSTEM_THREAD_PUSH, (WPARAM)fa->owner, (LPARAM)threadcode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ if (owner)
+ rc = threadcodeex(owner, cookie);
+ else
+ rc = threadcode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP, 0, 0);
+ return rc;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void* owner,
+ void *arg,
+ unsigned *thraddr)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa = { 0 };
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.owner = owner;
+ fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr);
+ if (rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// APC and mutex functions
+
+static void __stdcall DummyAPCFunc(ULONG_PTR)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if (rc == WAIT_OBJECT_0 + 1) {
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (IsDialogMessage(msg.hwnd, &msg)) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ else if (rc == WAIT_OBJECT_0) { // got object
+ return 1;
+ }
+ else if (rc == WAIT_ABANDONED_0 || rc == WAIT_FAILED)
+ return 0;
+ }
+}
+
+static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
+{
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName));
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ mir_free(p);
+ }
+
+ threads.destroy();
+
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty);
+ }
+}
+
+MIR_CORE_DLL(void) KillObjectThreads(void* owner)
+{
+ if (owner == NULL)
+ return;
+
+ WaitForSingleObject(hStackMutex, INFINITE);
+
+ HANDLE* threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE));
+ int threadCount = 0;
+
+ for (int j = threads.getCount(); j--;) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner)
+ threadPool[ threadCount++ ] = p->hThread;
+ }
+ ReleaseMutex(hStackMutex);
+
+ // is there anything to kill?
+ if (threadCount > 0) {
+ if ( WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) {
+ // forcibly kill all remaining threads after 5 secs
+ WaitForSingleObject(hStackMutex, INFINITE);
+ for (int j = threads.getCount()-1; j >= 0; j--) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner) {
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ }
+}
+
+MIR_CORE_DLL(void) UnwindThreadWait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ int j;
+ for (j=0; j < threads.getCount(); j++)
+ QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer(NULL, 0, 5000, KillAllThreads);
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+MIR_CORE_DLL(void*) GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD_PTR dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread");
+ if (NtQueryInformationThread == NULL)
+ return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if ( !DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
+ CloseHandle(hDupHandle);
+
+ if (ntStatus != ERROR_SUCCESS) return 0;
+ return (void*)dwStartAddress;
+}
+
+MIR_CORE_DLL(INT_PTR) UnwindThreadPush(WPARAM wParam, LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ p->dwThreadId = GetCurrentThreadId();
+ p->pObject = (void*)wParam;
+ p->hOwner = GetInstByAddress((void*)lParam);
+ p->addr = (void*)lParam;
+ threads.insert(p);
+
+ ReleaseMutex(hStackMutex);
+ }
+ return 0;
+}
+
+MIR_CORE_DLL(INT_PTR) UnwindThreadPop(WPARAM, LPARAM)
+{
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ DWORD dwThreadId = GetCurrentThreadId();
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->dwThreadId == dwThreadId) {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+
+ if ( !threads.getCount()) {
+ threads.destroy();
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ }
+
+ ReleaseMutex(hStackMutex);
+ return 0;
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ return 1;
+}
+
+static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_NULL) SleepEx(0, TRUE);
+ if (msg == WM_TIMECHANGE) RecalculateTime();
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// module init
+
+static void LoadSystemModule(void)
+{
+ INITCOMMONCONTROLSEX icce = {0};
+ icce.dwSize = sizeof(icce);
+ icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+
+ if ( IsWinVerXPPlus()) {
+ 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);
+ hStackMutex = CreateMutex(NULL, FALSE, NULL);
+
+ InitPathUtils();
+ LoadLangPackModule();
+ InitialiseModularEngine();
+ InitTimeZones();
+}
+
+static void UnloadSystemModule(void)
+{
+ DestroyModularEngine();
+ UnloadLangPackModule();
+ UninitTimeZones();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// entry point
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH) {
+ hInst = hinstDLL;
+ LoadSystemModule();
+ }
+ else if(fdwReason == DLL_PROCESS_DETACH)
+ UnloadSystemModule();
+ return TRUE;
+}
diff --git a/plugins/mir_core/miranda.h b/plugins/mir_core/miranda.h
new file mode 100644
index 0000000000..3b639ac4aa
--- /dev/null
+++ b/plugins/mir_core/miranda.h
@@ -0,0 +1,131 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#define NEWSTR_ALLOCA(A) (A == NULL)?NULL:strcpy((char*)alloca(strlen(A)+1), A)
+#define NEWTSTR_ALLOCA(A) (A == NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1)* sizeof(TCHAR)), A)
+
+struct LangPackMuuid
+{
+ MUUID muuid;
+ PLUGININFOEX* pInfo;
+};
+
+MIR_CORE_DLL(int) LangPackMarkPluginLoaded(PLUGININFOEX* pInfo);
+
+MIR_CORE_DLL(LangPackMuuid*) LangPackLookupUuid(WPARAM wParam);
+
+int LoadLangPackModule(void);
+void UnloadLangPackModule(void);
+
+int InitialiseModularEngine(void);
+void DestroyModularEngine(void);
+
+void InitTimeZones(void);
+void UninitTimeZones(void);
+
+int InitPathUtils(void);
+
+extern HINSTANCE hInst;
+
+/**** modules.cpp **********************************************************************/
+
+struct THookSubscriber
+{
+ HINSTANCE hOwner;
+ int type;
+ union {
+ struct {
+ union {
+ MIRANDAHOOK pfnHook;
+ MIRANDAHOOKPARAM pfnHookParam;
+ MIRANDAHOOKOBJ pfnHookObj;
+ MIRANDAHOOKOBJPARAM pfnHookObjParam;
+ };
+ void* object;
+ LPARAM lParam;
+ };
+ struct {
+ HWND hwnd;
+ UINT message;
+ };
+ };
+};
+
+struct THook
+{
+ char name[ MAXMODULELABELLENGTH ];
+ int id;
+ int subscriberCount;
+ THookSubscriber* subscriber;
+ MIRANDAHOOK pfnHook;
+ CRITICAL_SECTION csHook;
+};
+
+/**** langpack.cpp *********************************************************************/
+
+char* LangPackTranslateString(struct LangPackMuuid* pUuid, const char *szEnglish, const int W);
+TCHAR* LangPackTranslateStringT(int hLangpack, const TCHAR* tszEnglish);
+
+/**** options.cpp **********************************************************************/
+
+HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name);
+
+/**** utils.cpp ************************************************************************/
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key);
+WORD GetHotkeyValue(INT_PTR idHotkey);
+
+HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId);
+
+class StrConvUT
+{
+private:
+ wchar_t* m_body;
+
+public:
+ StrConvUT(const char* pSrc) :
+ m_body(mir_a2u(pSrc)) {}
+
+ ~StrConvUT() { mir_free(m_body); }
+ operator const wchar_t* () const { return m_body; }
+};
+
+class StrConvAT
+{
+private:
+ char* m_body;
+
+public:
+ StrConvAT(const wchar_t* pSrc) :
+ m_body(mir_u2a(pSrc)) {}
+
+ ~StrConvAT() { mir_free(m_body); }
+ operator const char* () const { return m_body; }
+ operator const wchar_t* () const { return (wchar_t*)m_body; } // type cast to fake the interface definition
+ operator const LPARAM () const { return (LPARAM)m_body; }
+};
+
+#define StrConvT(x) StrConvUT(x)
+#define StrConvTu(x) x
+#define StrConvA(x) StrConvAT(x)
+#define StrConvU(x) x
diff --git a/plugins/mir_core/modules.cpp b/plugins/mir_core/modules.cpp
new file mode 100644
index 0000000000..6a9aa54bcb
--- /dev/null
+++ b/plugins/mir_core/modules.cpp
@@ -0,0 +1,644 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#include "commonheaders.h"
+#include <m_plugins.h>
+
+// list of hooks
+
+static int compareHooks(const THook* p1, const THook* p2)
+{
+ return strcmp(p1->name, p2->name);
+}
+
+static LIST<THook> hooks(50, compareHooks);
+
+struct THookToMainThreadItem
+{
+ THook* hook;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+};
+
+// list of services
+
+struct TService
+{
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ union {
+ MIRANDASERVICE pfnService;
+ MIRANDASERVICEPARAM pfnServiceParam;
+ MIRANDASERVICEOBJ pfnServiceObj;
+ MIRANDASERVICEOBJPARAM pfnServiceObjParam;
+ };
+ int flags;
+ LPARAM lParam;
+ void* object;
+ char name[1];
+};
+
+LIST<TService> services(100, NumericKeySortT);
+
+typedef struct
+{
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+}
+ TServiceToMainThreadItem;
+
+// other static variables
+static BOOL bServiceMode = FALSE;
+static CRITICAL_SECTION csHooks, csServices;
+static DWORD mainThreadId;
+static int hookId = 1;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+static THook *pLastHook = NULL;
+
+///////////////////////////////////////////////////////////////////////////////
+// HOOKS
+
+MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name)
+{
+ THook* ret;
+ int idx;
+
+ if (name == NULL)
+ return NULL;
+
+ EnterCriticalSection(&csHooks);
+ if ((idx = hooks.getIndex((THook*)name)) != -1) {
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ ret = (THook*)mir_alloc(sizeof(THook));
+ strncpy(ret->name, name, sizeof(ret->name)); ret->name[ MAXMODULELABELLENGTH-1 ] = 0;
+ ret->id = hookId++;
+ ret->subscriberCount = 0;
+ ret->subscriber = NULL;
+ ret->pfnHook = NULL;
+ InitializeCriticalSection(&ret->csHook);
+ hooks.insert(ret);
+
+ LeaveCriticalSection(&csHooks);
+ return (HANDLE)ret;
+}
+
+MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent)
+{
+ EnterCriticalSection(&csHooks);
+ if (pLastHook == (THook*)hEvent)
+ pLastHook = NULL;
+
+ int idx;
+ if ((idx = hooks.getIndex((THook*)hEvent)) == -1) {
+ LeaveCriticalSection(&csHooks);
+ return 1;
+ }
+
+ THook* p = hooks[idx];
+ if (p->subscriberCount) {
+ mir_free(p->subscriber);
+ p->subscriber = NULL;
+ p->subscriberCount = 0;
+ }
+ hooks.remove(idx);
+ DeleteCriticalSection(&p->csHook);
+ mir_free(p);
+
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ THook* p = (THook*)hEvent;
+
+ EnterCriticalSection(&csHooks);
+ if (hooks.getIndex(p) != -1)
+ p->pfnHook = pfnHook;
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam, LPARAM lParam)
+{
+ int returnVal = 0;
+ THook* p = (THook*)hEvent;
+ if (p == NULL)
+ return -1;
+
+ EnterCriticalSection(&p->csHook);
+ for (int i = 0; i < p->subscriberCount; i++) {
+ THookSubscriber* s = &p->subscriber[i];
+ if (s->hOwner != hInst)
+ continue;
+
+ switch (s->type) {
+ case 1: returnVal = s->pfnHook(wParam, lParam); break;
+ case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break;
+ case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break;
+ case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break;
+ case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break;
+ default: continue;
+ }
+ if (returnVal)
+ break;
+ }
+
+ if (p->subscriberCount == 0 && p->pfnHook != 0)
+ returnVal = p->pfnHook(wParam, lParam);
+
+ LeaveCriticalSection(&p->csHook);
+ return returnVal;
+}
+
+MIR_CORE_DLL(int) CallHookSubscribers(HANDLE hEvent, WPARAM wParam, LPARAM lParam)
+{
+ int returnVal = 0;
+ THook* p = (THook*)hEvent;
+ if (p == NULL)
+ return -1;
+
+ EnterCriticalSection(&p->csHook);
+
+ // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for (int i = 0; i < p->subscriberCount; i++) {
+ THookSubscriber* s = &p->subscriber[i];
+ switch (s->type) {
+ case 1: returnVal = s->pfnHook(wParam, lParam); break;
+ case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break;
+ case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break;
+ case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break;
+ case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break;
+ default: continue;
+ }
+ if (returnVal)
+ break;
+ }
+
+ // check for no hooks and call the default hook if any
+ if (p->subscriberCount == 0 && p->pfnHook != 0)
+ returnVal = p->pfnHook(wParam, lParam);
+
+ LeaveCriticalSection(&p->csHook);
+ return returnVal;
+}
+
+static int checkHook(HANDLE hHook)
+{
+ if (hHook == NULL)
+ return -1;
+
+ EnterCriticalSection(&csHooks);
+ if (pLastHook != hHook || !pLastHook) {
+ if (hooks.getIndex((THook*)hHook) == -1) {
+ LeaveCriticalSection(&csHooks);
+ return -1;
+ }
+ pLastHook = (THook*)hHook;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam)
+{
+ THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam;
+
+ if (checkHook(item->hook) == -1)
+ item->result = -1;
+ else
+ item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if ( GetCurrentThreadId() != mainThreadId) {
+ THookToMainThreadItem item;
+
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ item.hook = (THook*)hEvent;
+ item.wParam = wParam;
+ item.lParam = lParam;
+
+ QueueUserAPC(HookToMainAPCFunc, hMainThread, (ULONG_PTR)&item);
+ PostMessage(hAPCWindow, WM_NULL, 0, 0); // let it process APC even if we're in a common dialog
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return (checkHook(hEvent) == -1) ? -1 : CallHookSubscribers(hEvent, wParam, lParam);
+}
+
+static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam)
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ if ((idx = hooks.getIndex((THook*)name)) == -1) {
+ #ifdef _DEBUG
+ OutputDebugStringA("Attempt to hook: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
+ p->subscriber[ p->subscriberCount ].type = type;
+ p->subscriber[ p->subscriberCount ].pfnHook = hookProc;
+ p->subscriber[ p->subscriberCount ].object = object;
+ p->subscriber[ p->subscriberCount ].lParam = lParam;
+ p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress(hookProc);
+ p->subscriberCount++;
+
+ ret = (HANDLE)((p->id << 16) | p->subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+MIR_CORE_DLL(HANDLE) HookEvent(const char* name, MIRANDAHOOK hookProc)
+{
+ return HookEventInt(1, name, hookProc, 0, 0);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventParam(const char* name, MIRANDAHOOKPARAM hookProc, LPARAM lParam)
+{
+ return HookEventInt(2, name, (MIRANDAHOOK)hookProc, 0, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventObj(const char* name, MIRANDAHOOKOBJ hookProc, void* object)
+{
+ return HookEventInt(3, name, (MIRANDAHOOK)hookProc, object, 0);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventObjParam(const char* name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam)
+{
+ return HookEventInt(4, name, (MIRANDAHOOK)hookProc, object, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventMessage(const char* name, HWND hwnd, UINT message)
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection(&csHooks);
+ if ((idx = hooks.getIndex((THook*)name)) == -1) {
+ #ifdef _DEBUG
+ MessageBoxA(NULL, "Attempt to hook non-existant event", name, MB_OK);
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
+ p->subscriber[ p->subscriberCount ].type = 5;
+ p->subscriber[ p->subscriberCount ].hwnd = hwnd;
+ p->subscriber[ p->subscriberCount ].message = message;
+ p->subscriberCount++;
+
+ ret = (HANDLE)((p->id << 16) | p->subscriberCount);
+ LeaveCriticalSection(&csHooks);
+ return ret;
+}
+
+MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook)
+{
+ int i;
+ THook* p = NULL;
+
+ int hookId = (int)hHook >> 16;
+ int subscriberId = ((int)hHook & 0xFFFF) - 1;
+
+ if (hHook == NULL) return 0;
+
+ EnterCriticalSection(&csHooks);
+ for (i = 0; i < hooks.getCount(); i++) {
+ if (hooks[i]->id == hookId) {
+ p = hooks[i];
+ break;
+ } }
+
+ if (p == NULL) {
+ LeaveCriticalSection(&csHooks);
+ return 1;
+ }
+
+ if (subscriberId >= p->subscriberCount || subscriberId < 0) {
+ LeaveCriticalSection(&csHooks);
+ return 1;
+ }
+
+ p->subscriber[subscriberId].type = 0;
+ p->subscriber[subscriberId].pfnHook = NULL;
+ p->subscriber[subscriberId].hOwner = NULL;
+ while (p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0)
+ p->subscriberCount--;
+ if (p->subscriberCount == 0) {
+ if (p->subscriber) mir_free(p->subscriber);
+ p->subscriber = NULL;
+ }
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst)
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for (i = hooks.getCount()-1; i >= 0; i--) {
+ if (hooks[i]->subscriberCount == 0)
+ continue;
+
+ for (j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ if (hooks[i]->subscriber[j].hOwner == hInst) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
+ if (hooks[i]->subscriberCount == 0)
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject)
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for (i = hooks.getCount()-1; i >= 0; i--) {
+ if (hooks[i]->subscriberCount == 0)
+ continue;
+
+ for (j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ if (hooks[i]->subscriber[j].object == pObject) {
+ UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
+ if (hooks[i]->subscriberCount == 0)
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+/////////////////////SERVICES
+
+static __inline TService* FindServiceByName(const char *name)
+{
+ unsigned hash = mir_hashstr(name);
+ return services.find((TService*)&hash);
+}
+
+static HANDLE CreateServiceInt(int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam)
+{
+ if (name == NULL)
+ return NULL;
+
+ TService tmp;
+ tmp.nameHash = mir_hashstr(name);
+
+ EnterCriticalSection(&csServices);
+
+ if (services.getIndex(&tmp) != -1) {
+ LeaveCriticalSection(&csServices);
+ return NULL;
+ }
+
+ TService* p = (TService*)mir_alloc(sizeof(*p) + strlen(name));
+ strcpy(p->name, name);
+ p->nameHash = tmp.nameHash;
+ p->pfnService = serviceProc;
+ p->hOwner = GetInstByAddress(serviceProc);
+ p->flags = type;
+ p->lParam = lParam;
+ p->object = object;
+ services.insert(p);
+
+ LeaveCriticalSection(&csServices);
+ return (HANDLE)tmp.nameHash;
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc)
+{
+ return CreateServiceInt(0, name, serviceProc, 0, 0);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam)
+{
+ return CreateServiceInt(1, name, (MIRANDASERVICE)serviceProc, 0, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object)
+{
+ return CreateServiceInt(2, name, (MIRANDASERVICE)serviceProc, object, 0);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam)
+{
+ return CreateServiceInt(3, name, (MIRANDASERVICE)serviceProc, object, lParam);
+}
+
+MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService)
+{
+ int idx;
+
+ EnterCriticalSection(&csServices);
+ if ((idx = services.getIndex((TService*)&hService)) != -1) {
+ mir_free(services[idx]);
+ services.remove(idx);
+ }
+
+ LeaveCriticalSection(&csServices);
+ return 0;
+}
+
+MIR_CORE_DLL(int) ServiceExists(const char *name)
+{
+ if (name == NULL)
+ return FALSE;
+
+ EnterCriticalSection(&csServices);
+ int ret = FindServiceByName(name) != NULL;
+ LeaveCriticalSection(&csServices);
+ return ret;
+}
+
+MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ #ifdef _DEBUG
+ if (name == NULL) {
+ MessageBoxA(0, "Someone tried to CallService(NULL, ..) see stack trace for details", "", 0);
+ DebugBreak();
+ return CALLSERVICE_NOTFOUND;
+ }
+ #else
+ if (name == NULL) return CALLSERVICE_NOTFOUND;
+ #endif
+
+ EnterCriticalSection(&csServices);
+ TService *pService = FindServiceByName(name);
+ if (pService == NULL) {
+ LeaveCriticalSection(&csServices);
+ #ifdef _DEBUG
+ OutputDebugStringA("Missing service called: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+
+ return CALLSERVICE_NOTFOUND;
+ }
+
+ MIRANDASERVICE pfnService = pService->pfnService;
+ int flags = pService->flags;
+ LPARAM fnParam = pService->lParam;
+ void* object = pService->object;
+ LeaveCriticalSection(&csServices);
+ switch(flags) {
+ case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam, lParam, fnParam);
+ case 2: return ((MIRANDASERVICEOBJ)pfnService)(object, wParam, lParam);
+ case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object, wParam, lParam, fnParam);
+ default: return pfnService(wParam, lParam);
+} }
+
+static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if (name == NULL) return CALLSERVICE_NOTFOUND;
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() != mainThreadId) {
+ TServiceToMainThreadItem item;
+ item.wParam = wParam;
+ item.lParam = lParam;
+ item.name = name;
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (ULONG_PTR) &item);
+ PostMessage(hAPCWindow, WM_NULL, 0, 0); // let this get processed in its own time
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return CallService(name, wParam, lParam);
+}
+
+MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg)
+{
+ extern HWND hAPCWindow;
+ int r = QueueUserAPC((void (__stdcall *)(ULONG_PTR))func, hMainThread, (ULONG_PTR)arg);
+ PostMessage(hAPCWindow, WM_NULL, 0, 0);
+ return r;
+}
+
+MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst)
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for (i = services.getCount()-1; i >= 0; i--) {
+ if (services[i]->hOwner == hInst) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(services[i]->hOwner, szModuleName, sizeof(szModuleName));
+ DestroyServiceFunction((HANDLE)services[i]->nameHash);
+ } }
+
+ LeaveCriticalSection(&csServices);
+}
+
+MIR_CORE_DLL(void) KillObjectServices(void* pObject)
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for (i = services.getCount()-1; i >= 0; i--)
+ if (services[i]->object == pObject)
+ DestroyServiceFunction((HANDLE)services[i]->nameHash);
+
+ LeaveCriticalSection(&csServices);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int InitialiseModularEngine(void)
+{
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId = GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return 0;
+}
+
+void DestroyModularEngine(void)
+{
+ EnterCriticalSection(&csHooks);
+ for (int i=0; i < hooks.getCount(); i++) {
+ THook* p = hooks[i];
+ if (p->subscriberCount)
+ mir_free(p->subscriber);
+ DeleteCriticalSection(&p->csHook);
+ mir_free(p);
+ }
+ hooks.destroy();
+ LeaveCriticalSection(&csHooks);
+ DeleteCriticalSection(&csHooks);
+
+ EnterCriticalSection(&csServices);
+ for (int j=0; j < services.getCount(); j++)
+ mir_free(services[j]);
+
+ services.destroy();
+ LeaveCriticalSection(&csServices);
+ DeleteCriticalSection(&csServices);
+ CloseHandle(hMainThread);
+}
diff --git a/plugins/mir_core/path.cpp b/plugins/mir_core/path.cpp
new file mode 100644
index 0000000000..fada3dcd18
--- /dev/null
+++ b/plugins/mir_core/path.cpp
@@ -0,0 +1,210 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+#include "commonheaders.h"
+
+static char szMirandaPath[MAX_PATH];
+static char szMirandaPathLower[MAX_PATH];
+static TCHAR szMirandaPathW[MAX_PATH];
+static TCHAR szMirandaPathWLower[MAX_PATH];
+
+static int pathIsAbsolute(const char *path)
+{
+ if (strlen(path) <= 2)
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut)
+{
+ if ( !pSrc || !strlen(pSrc) || strlen(pSrc)>MAX_PATH) return 0;
+ if ( !pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return (int)strlen(pOut);
+ }
+
+ char szTmp[MAX_PATH];
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPathLower)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPathLower));
+ return (int)strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return (int)strlen(pOut);
+ }
+}
+
+MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, char* base)
+{
+ if ( !pSrc || !strlen(pSrc) || strlen(pSrc) > MAX_PATH)
+ return 0;
+
+ if (base == NULL)
+ base = szMirandaPath;
+
+ char buf[MAX_PATH];
+ if (pSrc[0] < ' ')
+ return mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ else if (pathIsAbsolute(pSrc))
+ return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL);
+ else if (pSrc[0] != '\\')
+ mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc);
+ else
+ mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc+1);
+
+ return GetFullPathNameA(buf, MAX_PATH, pOut, NULL);
+}
+
+MIR_CORE_DLL(void) CreatePathToFile(char* szFilePath)
+{
+ char* pszLastBackslash = strrchr(szFilePath, '\\');
+ if (pszLastBackslash == NULL)
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree(szFilePath);
+ *pszLastBackslash = '\\';
+}
+
+MIR_CORE_DLL(int) CreateDirectoryTree(const char *szDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynA(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributesA(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return 0;
+
+ pszLastBackslash = strrchr(szTestDir, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree(szTestDir);
+ *pszLastBackslash = '\\';
+ return (CreateDirectoryA(szTestDir, NULL) == 0) ? GetLastError() : 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int pathIsAbsoluteW(const TCHAR *path)
+{
+ if (lstrlen(path) <= 2)
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+MIR_CORE_DLL(int) PathToRelativeW(const WCHAR *pSrc, WCHAR *pOut)
+{
+ if ( !pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+
+ if ( !pathIsAbsoluteW(pSrc))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else {
+ TCHAR szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ _tcslwr(szTmp);
+ if (_tcsstr(szTmp, szMirandaPathWLower))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc+lstrlen(szMirandaPathWLower));
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ }
+ return lstrlen(pOut);
+}
+
+MIR_CORE_DLL(int) PathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base)
+{
+ if ( !pSrc || !wcslen(pSrc) || wcslen(pSrc) > MAX_PATH)
+ return 0;
+
+ if (base == NULL)
+ base = szMirandaPathW;
+
+ TCHAR buf[MAX_PATH];
+ if (pSrc[0] < ' ')
+ return mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else if (pathIsAbsoluteW(pSrc))
+ return GetFullPathName(pSrc, MAX_PATH, pOut, NULL);
+ else if (pSrc[0] != '\\')
+ mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc);
+ else
+ mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc+1);
+
+ return GetFullPathName(buf, MAX_PATH, pOut, NULL);
+}
+
+MIR_CORE_DLL(void) CreatePathToFileW(WCHAR* wszFilePath)
+{
+ WCHAR* pszLastBackslash = wcsrchr(wszFilePath, '\\');
+ if (pszLastBackslash == NULL)
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW(wszFilePath);
+ *pszLastBackslash = '\\';
+}
+
+MIR_CORE_DLL(int) CreateDirectoryTreeW(const WCHAR* szDir)
+{
+ DWORD dwAttributes;
+ WCHAR* pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynW(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributesW(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return 0;
+
+ pszLastBackslash = wcsrchr(szTestDir, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW(szTestDir);
+ *pszLastBackslash = '\\';
+ return (CreateDirectoryW(szTestDir, NULL) == 0) ? GetLastError() : 0;
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(hInst, szMirandaPath, SIZEOF(szMirandaPath));
+ p = strrchr(szMirandaPath, '\\');
+ if (p)
+ p[1] = 0;
+ mir_snprintf(szMirandaPathLower, MAX_PATH, "%s", szMirandaPath);
+ _strlwr(szMirandaPathLower);
+
+ GetModuleFileName(hInst, szMirandaPathW, SIZEOF(szMirandaPathW));
+ TCHAR *tp = _tcsrchr(szMirandaPathW, '\\');
+ if (tp)
+ tp[1] = 0;
+ mir_sntprintf(szMirandaPathWLower, SIZEOF(szMirandaPathWLower), _T("%s"), szMirandaPathW);
+ _tcslwr(szMirandaPathWLower);
+ return 0;
+}
diff --git a/plugins/mir_core/timezones.cpp b/plugins/mir_core/timezones.cpp
new file mode 100644
index 0000000000..24340cd3d8
--- /dev/null
+++ b/plugins/mir_core/timezones.cpp
@@ -0,0 +1,224 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda ICQ/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 "commonheaders.h"
+
+#include <m_timezones.h>
+
+typedef DWORD (WINAPI *pfnGetDynamicTimeZoneInformation_t)(DYNAMIC_TIME_ZONE_INFORMATION *pdtzi);
+static pfnGetDynamicTimeZoneInformation_t pfnGetDynamicTimeZoneInformation;
+
+typedef HRESULT (WINAPI *pfnSHLoadIndirectString_t)(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved);
+static pfnSHLoadIndirectString_t pfnSHLoadIndirectString;
+
+typedef LANGID (WINAPI *pfnGetUserDefaultUILanguage_t)(void);
+static pfnGetUserDefaultUILanguage_t pfnGetUserDefaultUILanguage;
+
+typedef LANGID (WINAPI *pfnGetSystemDefaultUILanguage_t)(void);
+static pfnGetSystemDefaultUILanguage_t pfnGetSystemDefaultUILanguage;
+
+typedef LPARAM (WINAPI *pfnSendMessageW_t)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+static pfnSendMessageW_t pfnSendMessageW;
+
+typedef struct _REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+} REG_TZI_FORMAT;
+
+#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; }
+};
+
+typedef struct
+{
+ DWORD timestamp; // last time updated
+ MIM_TIMEZONE myTZ; // set to my own timezone
+} TZ_INT_INFO;
+
+static TZ_INT_INFO myInfo;
+bool muiInstalled;
+
+static OBJLIST<MIM_TIMEZONE> g_timezones(55, NumericKeySortT);
+static LIST<MIM_TIMEZONE> g_timezonesBias(55, MIM_TIMEZONE::compareBias);
+
+void FormatTime (const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest);
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft);
+time_t FileTimeToUnixTime(LPFILETIME pft);
+
+#define fnSystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime
+
+void GetLocalizedString(HKEY hSubKey, const TCHAR *szName, wchar_t *szBuf, DWORD cbLen)
+{
+ szBuf[0] = 0;
+ if (muiInstalled)
+ {
+ TCHAR tszTempBuf[MIM_TZ_NAMELEN], tszName[30];
+ mir_sntprintf(tszName, SIZEOF(tszName), _T("MUI_%s"), szName);
+ DWORD dwLength = cbLen * sizeof(TCHAR);
+ if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, tszName, NULL, NULL, (unsigned char *)tszTempBuf, &dwLength))
+ {
+ tszTempBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+ if (pfnSHLoadIndirectString)
+ pfnSHLoadIndirectString(StrConvU(tszTempBuf), szBuf, cbLen, NULL);
+ }
+ }
+ if (szBuf[0] == 0)
+ {
+ 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);
+ _tcscpy(myInfo.myTZ.tszName, myTzKey);
+ 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 ( !wcscmp(tz.tzi.StandardName, myInfo.myTZ.tzi.StandardName) ||
+ !wcscmp(tz.tzi.DaylightName, myInfo.myTZ.tzi.DaylightName))
+ {
+ _tcscpy(myInfo.myTZ.tszName, tz.tszName);
+ found = true;
+ }
+ }
+ }
+}
+
+void InitTimeZones(void)
+{
+ REG_TZI_FORMAT tzi;
+ HKEY hKey;
+
+ const TCHAR *tszKey = IsWinVerNT() ?
+ _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones") :
+ _T("SOFTWARE\\Microsoft\\Windows\\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 (IsWinVer2000Plus())
+ {
+ pfnSHLoadIndirectString = (pfnSHLoadIndirectString_t)GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHLoadIndirectString");
+ pfnGetSystemDefaultUILanguage = (pfnGetSystemDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetSystemDefaultUILanguage");
+ pfnGetUserDefaultUILanguage = (pfnGetUserDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetUserDefaultUILanguage");
+ muiInstalled = pfnSHLoadIndirectString && pfnGetSystemDefaultUILanguage() != pfnGetUserDefaultUILanguage();
+ }
+
+ pfnSendMessageW = (pfnSendMessageW_t)GetProcAddress(GetModuleHandle(_T("user32")), "SendMessageW");
+
+ 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;
+
+ _tcscpy(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();
+}
+
+void UninitTimeZones(void)
+{
+ g_timezonesBias.destroy();
+ g_timezones.destroy();
+}
diff --git a/plugins/mir_core/utf.cpp b/plugins/mir_core/utf.cpp
new file mode 100644
index 0000000000..5ec6042758
--- /dev/null
+++ b/plugins/mir_core/utf.cpp
@@ -0,0 +1,406 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+ Copyright 2000 Alexandre Julliard of Wine project
+ (UTF-8 conversion routines)
+
+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.
+*/
+
+#include "commonheaders.h"
+
+/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
+static const char utf8_length[128] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */
+ 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */
+};
+
+/* first byte mask depending on UTF-8 sequence length */
+static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
+
+/* minimum Unicode value depending on UTF-8 sequence length */
+static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
+
+/* get the next char value taking surrogates into account */
+static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen)
+{
+ if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */
+ if (src[0] > 0xdbff || /* invalid high surrogate */
+ srclen <= 1 || /* missing low surrogate */
+ src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */
+ return 0;
+ return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff);
+ }
+ return src[0];
+}
+
+/* query necessary dst length for src string */
+static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen)
+{
+ int len;
+ unsigned int val;
+
+ for (len = 0; srclen; srclen--, src++) {
+ if (*src < 0x80) { /* 0x00-0x7f: 1 byte */
+ len++;
+ continue;
+ }
+ if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */
+ len += 2;
+ continue;
+ }
+ if ( !(val = getSurrogateValue(src, srclen)))
+ return -2;
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ len += 3;
+ else { /* 0x10000-0x10ffff: 4 bytes */
+ len += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return len;
+}
+
+MIR_CORE_DLL(int) Ucs2toUtf8Len(const wchar_t *src)
+{
+ if (src == 0)
+ return 0;
+
+ return Ucs2toUtf8Len(src, (int)wcslen(src));
+}
+
+/* wide char to UTF-8 string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen)
+{
+ int len;
+
+ for (len = dstlen; srclen; srclen--, src++)
+ {
+ WCHAR ch = *src;
+ unsigned int val;
+
+ if (ch < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ if ( !len--) return -1; /* overflow */
+ *dst++ = ch;
+ continue;
+ }
+
+ if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ if ((len -= 2) < 0) return -1; /* overflow */
+ dst[1] = 0x80 | (ch & 0x3f);
+ ch >>= 6;
+ dst[0] = 0xc0 | ch;
+ dst += 2;
+ continue;
+ }
+
+ if ( !(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ {
+ if ((len -= 3) < 0) return -1; /* overflow */
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xe0 | val;
+ dst += 3;
+ }
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ if ((len -= 4) < 0) return -1; /* overflow */
+ dst[3] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xf0 | val;
+ dst += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return dstlen - len;
+}
+
+/* helper for the various utf8 mbstowcs functions */
+static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend)
+{
+ unsigned int len = utf8_length[ch-0x80];
+ unsigned int res = ch & utf8_mask[len];
+ const char *end = *str + len;
+
+ if (end > strend) return ~0;
+ switch(len)
+ {
+ case 3:
+ if ((ch = end[-3] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 2:
+ if ((ch = end[-2] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 1:
+ if ((ch = end[-1] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ if (res < utf8_minval[len]) break;
+ return res;
+ }
+ return ~0;
+}
+
+/* query necessary dst length for src string */
+static inline int Utf8toUcs2Len(const char *src, int srclen)
+{
+ int ret = 0;
+ unsigned int res;
+ const char *srcend = src + srclen;
+
+ while (src < srcend)
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ ret++;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff)
+ {
+ if (res > 0xffff) ret++;
+ ret++;
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ return ret;
+}
+
+/* UTF-8 to wide char string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen)
+{
+ unsigned int res;
+ const char *srcend = src + srclen;
+ wchar_t *dstend = dst + dstlen;
+
+ while ((dst < dstend) && (src < srcend))
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ *dst++ = ch;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff)
+ {
+ *dst++ = res;
+ }
+ else if (res <= 0x10ffff) /* we need surrogates */
+ {
+ if (dst == dstend - 1) return -1; /* overflow */
+ res -= 0x10000;
+ *dst++ = 0xd800 | (res >> 10);
+ *dst++ = 0xdc00 | (res & 0x3ff);
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ if (src < srcend) return -1; /* overflow */
+ return dstlen - (dstend - dst);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+MIR_CORE_DLL(char*) Utf8DecodeCP(char* str, int codepage, wchar_t** ucs2)
+{
+ int len;
+ bool needs_free = false;
+ wchar_t* tempBuf = NULL;
+ if (ucs2)
+ *ucs2 = NULL;
+
+ if (str == NULL)
+ return NULL;
+
+ len = (int)strlen(str);
+
+ if (len < 2) {
+ if (ucs2 != NULL) {
+ *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(codepage, 0, str, len, tempBuf, len);
+ tempBuf[len] = 0;
+ }
+ return str;
+ }
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0)
+ return NULL;
+
+ if (ucs2 == NULL) {
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = NULL;
+ needs_free = true;
+ }
+ }
+
+ if (tempBuf == NULL) {
+ tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL)
+ return NULL;
+ }
+
+ Utf8toUcs2(str, len, tempBuf, destlen);
+ tempBuf[destlen] = 0;
+ WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL);
+
+ if (ucs2)
+ *ucs2 = tempBuf;
+ else if (needs_free)
+ mir_free(tempBuf);
+
+ return str;
+}
+
+MIR_CORE_DLL(char*) Utf8Decode(char* str, wchar_t** ucs2)
+{
+ return Utf8DecodeCP(str, LangPackGetDefaultCodePage(), ucs2);
+}
+
+MIR_CORE_DLL(wchar_t*) Utf8DecodeW(const char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ int len = (int)strlen(str);
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0) return NULL;
+
+ wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (ucs2 == NULL) return NULL;
+
+ if (Utf8toUcs2(str, len, ucs2, destlen) >= 0)
+ {
+ ucs2[destlen] = 0;
+ return ucs2;
+ }
+
+ mir_free(ucs2);
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+MIR_CORE_DLL(char*) Utf8EncodeCP(const char* src, int codepage)
+{
+ int len;
+ bool needs_free = false;
+ char* result = NULL;
+ wchar_t* tempBuf;
+
+ if (src == NULL)
+ return NULL;
+
+ len = (int)strlen(src);
+
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL) return NULL;
+ needs_free = true;
+ }
+
+ len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1);
+
+ int destlen = Ucs2toUtf8Len(tempBuf, len);
+ if (destlen >= 0)
+ {
+ result = (char*)mir_alloc(destlen + 1);
+ if (result)
+ {
+ Ucs2toUtf8(tempBuf, len, result, destlen);
+ result[destlen] = 0;
+ }
+ }
+
+ if (needs_free)
+ mir_free(tempBuf);
+
+ return result;
+}
+
+MIR_CORE_DLL(char*) Utf8Encode(const char* src)
+{
+ return Utf8EncodeCP(src, LangPackGetDefaultCodePage());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+MIR_CORE_DLL(char*) Utf8EncodeW(const wchar_t* src)
+{
+ if (src == NULL)
+ return NULL;
+
+ int len = (int)wcslen(src);
+
+ int destlen = Ucs2toUtf8Len(src, len);
+ if (destlen < 0) return NULL;
+
+ char* result = (char*)mir_alloc(destlen + 1);
+ if (result == NULL)
+ return NULL;
+
+ Ucs2toUtf8(src, len, result, destlen);
+ result[destlen] = 0;
+
+ return result;
+}
diff --git a/plugins/mir_core/utils.cpp b/plugins/mir_core/utils.cpp
new file mode 100644
index 0000000000..f0fcdcfa07
--- /dev/null
+++ b/plugins/mir_core/utils.cpp
@@ -0,0 +1,150 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/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.
+*/
+
+#include "commonheaders.h"
+
+MIR_CORE_DLL(char*) rtrim(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = strchr(str, 0);
+ while (--p >= str) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+MIR_CORE_DLL(WCHAR*) wrtrim(WCHAR *str)
+{
+ if (str == NULL)
+ return NULL;
+
+ WCHAR* p = _tcschr(str, 0);
+ while (--p >= str) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+MIR_CORE_DLL(char*) ltrim(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = str;
+ for (;;) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ memmove(str, p, strlen(p) + 1);
+ return str;
+ }
+ }
+}
+
+MIR_CORE_DLL(char*) ltrimp(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = str;
+ for (;;) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ return p;
+ }
+ }
+}
+
+MIR_CORE_DLL(int) wildcmp(char * name, char * mask)
+{
+ char * last='\0';
+ for (;; mask++, name++) {
+ if (*mask != '?' && *mask != *name) break;
+ if (*name == '\0') return ((BOOL)!*mask);
+ }
+ if (*mask != '*') return FALSE;
+ for (;; mask++, name++){
+ while (*mask == '*') {
+ last = mask++;
+ if (*mask == '\0') return ((BOOL)!*mask); /* true */
+ }
+ if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */
+ if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int sttComparePlugins(const HINSTANCE__* p1, const HINSTANCE__* p2)
+{
+ if (p1 == p2)
+ return 0;
+
+ return (p1 < p2) ? -1 : 1;
+}
+
+static LIST<HINSTANCE__> pluginListAddr(10, sttComparePlugins);
+
+MIR_CORE_DLL(void) RegisterModule(HINSTANCE hInst)
+{
+ pluginListAddr.insert(hInst);
+}
+
+MIR_CORE_DLL(void) UnregisterModule(HINSTANCE hInst)
+{
+ pluginListAddr.remove(hInst);
+}
+
+MIR_CORE_DLL(HINSTANCE) GetInstByAddress(void* codePtr)
+{
+ if (pluginListAddr.getCount() == 0)
+ return NULL;
+
+ int idx;
+ List_GetIndex((SortedList*)&pluginListAddr, &codePtr, &idx);
+ if (idx > 0)
+ idx--;
+
+ HINSTANCE result = pluginListAddr[idx];
+ if (result < hInst && codePtr > hInst)
+ result = hInst;
+ else if (idx == 0 && codePtr < (void*)result)
+ result = NULL;
+
+ return result;
+}