From b69809d6331b17865cc657cfd2ad48ed7464a6f2 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 11 Jan 2018 20:31:51 +0300 Subject: mdbx-plugin: fix names for clarity (minor, but renaming). # Conflicts: # plugins/Dbx_mdbx/src/libmdbx --- .gitmodules | 2 +- plugins/Dbx_mdb/dbx_lmdb.vcxproj | 49 ---- plugins/Dbx_mdb/dbx_lmdb.vcxproj.filters | 4 - plugins/Dbx_mdb/res/dbx_mdb.rc | 177 ------------ plugins/Dbx_mdb/res/logo.ico | Bin 5430 -> 0 bytes plugins/Dbx_mdb/res/pass.ico | Bin 1150 -> 0 bytes plugins/Dbx_mdb/res/version.rc | 55 ---- plugins/Dbx_mdb/src/dbcontacts.cpp | 247 ----------------- plugins/Dbx_mdb/src/dbcrypt.cpp | 226 ---------------- plugins/Dbx_mdb/src/dbevents.cpp | 428 ------------------------------ plugins/Dbx_mdb/src/dbintf.cpp | 279 ------------------- plugins/Dbx_mdb/src/dbintf.h | 268 ------------------- plugins/Dbx_mdb/src/dbmodulechain.cpp | 72 ----- plugins/Dbx_mdb/src/dbsettings.cpp | 398 --------------------------- plugins/Dbx_mdb/src/dbutils.cpp | 47 ---- plugins/Dbx_mdb/src/init.cpp | 133 ---------- plugins/Dbx_mdb/src/libmdbx | 1 - plugins/Dbx_mdb/src/resource.h | 35 --- plugins/Dbx_mdb/src/stdafx.cxx | 18 -- plugins/Dbx_mdb/src/stdafx.h | 169 ------------ plugins/Dbx_mdb/src/ui.cpp | 202 -------------- plugins/Dbx_mdb/src/ui.h | 187 ------------- plugins/Dbx_mdb/src/version.h | 13 - plugins/Dbx_mdbx/dbx_mdbx.vcxproj | 51 ++++ plugins/Dbx_mdbx/dbx_mdbx.vcxproj.filters | 4 + plugins/Dbx_mdbx/res/dbx_mdbx.rc | 177 ++++++++++++ plugins/Dbx_mdbx/res/logo.ico | Bin 0 -> 5430 bytes plugins/Dbx_mdbx/res/pass.ico | Bin 0 -> 1150 bytes plugins/Dbx_mdbx/res/version.rc | 55 ++++ plugins/Dbx_mdbx/src/dbcontacts.cpp | 247 +++++++++++++++++ plugins/Dbx_mdbx/src/dbcrypt.cpp | 226 ++++++++++++++++ plugins/Dbx_mdbx/src/dbevents.cpp | 428 ++++++++++++++++++++++++++++++ plugins/Dbx_mdbx/src/dbintf.cpp | 279 +++++++++++++++++++ plugins/Dbx_mdbx/src/dbintf.h | 268 +++++++++++++++++++ plugins/Dbx_mdbx/src/dbmodulechain.cpp | 72 +++++ plugins/Dbx_mdbx/src/dbsettings.cpp | 398 +++++++++++++++++++++++++++ plugins/Dbx_mdbx/src/dbutils.cpp | 47 ++++ plugins/Dbx_mdbx/src/init.cpp | 133 ++++++++++ plugins/Dbx_mdbx/src/libmdbx | 1 + plugins/Dbx_mdbx/src/resource.h | 35 +++ plugins/Dbx_mdbx/src/stdafx.cxx | 18 ++ plugins/Dbx_mdbx/src/stdafx.h | 169 ++++++++++++ plugins/Dbx_mdbx/src/ui.cpp | 202 ++++++++++++++ plugins/Dbx_mdbx/src/ui.h | 187 +++++++++++++ plugins/Dbx_mdbx/src/version.h | 13 + 45 files changed, 3011 insertions(+), 3009 deletions(-) delete mode 100644 plugins/Dbx_mdb/dbx_lmdb.vcxproj delete mode 100644 plugins/Dbx_mdb/dbx_lmdb.vcxproj.filters delete mode 100644 plugins/Dbx_mdb/res/dbx_mdb.rc delete mode 100644 plugins/Dbx_mdb/res/logo.ico delete mode 100644 plugins/Dbx_mdb/res/pass.ico delete mode 100644 plugins/Dbx_mdb/res/version.rc delete mode 100644 plugins/Dbx_mdb/src/dbcontacts.cpp delete mode 100644 plugins/Dbx_mdb/src/dbcrypt.cpp delete mode 100644 plugins/Dbx_mdb/src/dbevents.cpp delete mode 100644 plugins/Dbx_mdb/src/dbintf.cpp delete mode 100644 plugins/Dbx_mdb/src/dbintf.h delete mode 100644 plugins/Dbx_mdb/src/dbmodulechain.cpp delete mode 100644 plugins/Dbx_mdb/src/dbsettings.cpp delete mode 100644 plugins/Dbx_mdb/src/dbutils.cpp delete mode 100644 plugins/Dbx_mdb/src/init.cpp delete mode 160000 plugins/Dbx_mdb/src/libmdbx delete mode 100644 plugins/Dbx_mdb/src/resource.h delete mode 100644 plugins/Dbx_mdb/src/stdafx.cxx delete mode 100644 plugins/Dbx_mdb/src/stdafx.h delete mode 100644 plugins/Dbx_mdb/src/ui.cpp delete mode 100644 plugins/Dbx_mdb/src/ui.h delete mode 100644 plugins/Dbx_mdb/src/version.h create mode 100644 plugins/Dbx_mdbx/dbx_mdbx.vcxproj create mode 100644 plugins/Dbx_mdbx/dbx_mdbx.vcxproj.filters create mode 100644 plugins/Dbx_mdbx/res/dbx_mdbx.rc create mode 100644 plugins/Dbx_mdbx/res/logo.ico create mode 100644 plugins/Dbx_mdbx/res/pass.ico create mode 100644 plugins/Dbx_mdbx/res/version.rc create mode 100644 plugins/Dbx_mdbx/src/dbcontacts.cpp create mode 100644 plugins/Dbx_mdbx/src/dbcrypt.cpp create mode 100644 plugins/Dbx_mdbx/src/dbevents.cpp create mode 100644 plugins/Dbx_mdbx/src/dbintf.cpp create mode 100644 plugins/Dbx_mdbx/src/dbintf.h create mode 100644 plugins/Dbx_mdbx/src/dbmodulechain.cpp create mode 100644 plugins/Dbx_mdbx/src/dbsettings.cpp create mode 100644 plugins/Dbx_mdbx/src/dbutils.cpp create mode 100644 plugins/Dbx_mdbx/src/init.cpp create mode 160000 plugins/Dbx_mdbx/src/libmdbx create mode 100644 plugins/Dbx_mdbx/src/resource.h create mode 100644 plugins/Dbx_mdbx/src/stdafx.cxx create mode 100644 plugins/Dbx_mdbx/src/stdafx.h create mode 100644 plugins/Dbx_mdbx/src/ui.cpp create mode 100644 plugins/Dbx_mdbx/src/ui.h create mode 100644 plugins/Dbx_mdbx/src/version.h diff --git a/.gitmodules b/.gitmodules index fff2a59f2a..feab0cc1e2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "plugins/Dbx_mdb/src/libmdbx"] - path = plugins/Dbx_mdb/src/libmdbx + path = plugins/Dbx_mdbx/src/libmdbx url = https://github.com/leo-yuriev/libmdbx.git branch = master diff --git a/plugins/Dbx_mdb/dbx_lmdb.vcxproj b/plugins/Dbx_mdb/dbx_lmdb.vcxproj deleted file mode 100644 index a4016eb5b6..0000000000 --- a/plugins/Dbx_mdb/dbx_lmdb.vcxproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - Dbx_mdbx - {E0ACDEA0-0AC9-4431-8CA3-6B0CCACB2E18} - - - - - - - NotUsing - - - NotUsing - - - NotUsing - - - NotUsing - - - - - Sync - MDB_DEBUG=5;%(PreprocessorDefinitions) - MDB_VL32;%(PreprocessorDefinitions) - - - \ No newline at end of file diff --git a/plugins/Dbx_mdb/dbx_lmdb.vcxproj.filters b/plugins/Dbx_mdb/dbx_lmdb.vcxproj.filters deleted file mode 100644 index de5ad9f66c..0000000000 --- a/plugins/Dbx_mdb/dbx_lmdb.vcxproj.filters +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/plugins/Dbx_mdb/res/dbx_mdb.rc b/plugins/Dbx_mdb/res/dbx_mdb.rc deleted file mode 100644 index 03c0486fe6..0000000000 --- a/plugins/Dbx_mdb/res/dbx_mdb.rc +++ /dev/null @@ -1,177 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "..\src\resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Английский (США) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_SELECT_CRYPTOPROVIDER DIALOGEX 0, 0, 229, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Select crypto provider" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,113,55,50,14 - PUSHBUTTON "Cancel",IDCANCEL,172,55,50,14 - COMBOBOX IDC_SELECTCRYPT_COMBO,16,12,199,30,CBS_DROPDOWNLIST | CBS_SORT | WS_TABSTOP - LTEXT "",IDC_CRYPTOPROVIDER_DESCR,17,29,197,14,NOT WS_GROUP - CONTROL "Total encryption (Recommended only for paranoid users)",IDC_CHECK_TOTALCRYPT, - "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,14,45,89,24 -END - -IDD_LOGIN DIALOGEX 0, 0, 190, 86 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW -CAPTION "Login to Miranda NG" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,190,26 - CTEXT "",IDC_LANG,158,34,13,13,SS_CENTERIMAGE | NOT WS_GROUP - EDITTEXT IDC_USERPASS,21,34,128,14,ES_PASSWORD | ES_AUTOHSCROLL | WS_GROUP - DEFPUSHBUTTON "OK",IDOK,36,64,50,14 - PUSHBUTTON "Cancel",IDCANCEL,102,64,50,14 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,55,190,1 -END - -IDD_NEWPASS DIALOGEX 0, 0, 190, 102 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW -CAPTION "New password" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Please enter your new password",IDC_HEADERBAR, - "MHeaderbarCtrl",0x0,0,0,190,26 - CTEXT "",IDC_LANG,158,34,13,13,SS_CENTERIMAGE | NOT WS_GROUP - EDITTEXT IDC_USERPASS1,21,34,128,14,ES_PASSWORD | ES_AUTOHSCROLL - EDITTEXT IDC_USERPASS2,21,54,128,14,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "OK",IDOK,36,84,50,14 - PUSHBUTTON "Cancel",IDCANCEL,100,84,50,14 - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,77,190,1 -END - -IDD_CHANGEPASS DIALOGEX 0, 0, 190, 148 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOOLWINDOW -CAPTION "Enter password" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "Change password",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,190,26 - CTEXT "",IDC_LANG,158,42,13,13,SS_CENTERIMAGE | NOT WS_GROUP - EDITTEXT IDC_OLDPASS,21,42,128,14,ES_PASSWORD | ES_AUTOHSCROLL - EDITTEXT IDC_USERPASS1,21,77,128,14,ES_PASSWORD | ES_AUTOHSCROLL - EDITTEXT IDC_USERPASS2,21,98,128,14,ES_PASSWORD | ES_AUTOHSCROLL - DEFPUSHBUTTON "Change",IDOK,11,127,50,14 - PUSHBUTTON "Remove",IDREMOVE,69,127,50,14 - PUSHBUTTON "Cancel",IDCANCEL,126,127,50,14 - LTEXT "New password",IDC_STATIC,11,66,163,10,0,WS_EX_TRANSPARENT - CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,119,190,1 - LTEXT "Old password",IDC_STATIC,11,31,140,10,0,WS_EX_TRANSPARENT -END - -IDD_OPTIONS DIALOGEX 0, 0, 318, 176 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "Database encryption mode",IDC_STATIC,6,22,305,125 - CONTROL "Standard",IDC_STANDARD,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,12,38,292,12 - CONTROL "Total",IDC_TOTAL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,12,95,292,12 - LTEXT "Only critical data are encrypted (passwords, security tokens, etc). All other settings and history remains unencrypted. Fast and effective, suitable for the most cases",IDC_STATIC,22,54,284,37 - LTEXT "All string settings and all events in histories are encrypted. It also makes Miranda much slower and creates a risk of losing everything you've stored in a profile in case of losing password. Recommended only for paranoid users",IDC_STATIC,22,110,284,33 - PUSHBUTTON "Set password",IDC_USERPASS,200,153,111,17 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICONPASS ICON "pass.ico" -IDI_LOGO ICON "logo.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_SELECT_CRYPTOPROVIDER, DIALOG - BEGIN - END - - IDD_LOGIN, DIALOG - BEGIN - END - - IDD_CHANGEPASS, DIALOG - BEGIN - END - - IDD_OPTIONS, DIALOG - BEGIN - END -END -#endif // APSTUDIO_INVOKED - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "..\\src\\resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include \0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Английский (США) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/Dbx_mdb/res/logo.ico b/plugins/Dbx_mdb/res/logo.ico deleted file mode 100644 index f49bbe83d6..0000000000 Binary files a/plugins/Dbx_mdb/res/logo.ico and /dev/null differ diff --git a/plugins/Dbx_mdb/res/pass.ico b/plugins/Dbx_mdb/res/pass.ico deleted file mode 100644 index dc47a6ed4f..0000000000 Binary files a/plugins/Dbx_mdb/res/pass.ico and /dev/null differ diff --git a/plugins/Dbx_mdb/res/version.rc b/plugins/Dbx_mdb/res/version.rc deleted file mode 100644 index fdeb14668c..0000000000 --- a/plugins/Dbx_mdb/res/version.rc +++ /dev/null @@ -1,55 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#ifdef APSTUDIO_INVOKED -#error this file is not editable by Microsoft Visual C++ -#endif //APSTUDIO_INVOKED - -#include "..\src\version.h" - -#define APSTUDIO_READONLY_SYMBOLS -#include "afxres.h" -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -VS_VERSION_INFO VERSIONINFO - FILEVERSION __FILEVERSION_STRING - PRODUCTVERSION __FILEVERSION_STRING - FILEFLAGSMASK 0x17L -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x4L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "000004b0" - BEGIN - VALUE "Author", __AUTHOR - VALUE "FileDescription", __DESCRIPTION - VALUE "FileVersion", __VERSION_STRING - VALUE "InternalName", __PLUGIN_NAME - VALUE "LegalCopyright", __COPYRIGHT - VALUE "OriginalFilename", __FILENAME - VALUE "ProductName", __PLUGIN_NAME - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0, 1200 - END -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/Dbx_mdb/src/dbcontacts.cpp b/plugins/Dbx_mdb/src/dbcontacts.cpp deleted file mode 100644 index 04acc73c19..0000000000 --- a/plugins/Dbx_mdb/src/dbcontacts.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -STDMETHODIMP_(LONG) CDbxMdb::GetContactCount(void) -{ - return m_contactCount; -} - -STDMETHODIMP_(LONG) CDbxMdb::GetContactSize(void) -{ - return sizeof(DBCachedContact); -} - -STDMETHODIMP_(LONG) CDbxMdb::DeleteContact(MCONTACT contactID) -{ - if (contactID == 0) // global contact cannot be removed - return 1; - - NotifyEventHooks(hContactDeletedEvent, contactID, 0); - { - OBJLIST events(50); - GatherContactHistory(contactID, events); - while (events.getCount()) { - DeleteEvent(contactID, events[0].eventId); - events.remove(0); - } - } - { - MDBX_val key, data; - DBSettingKey keyS = { contactID, 0, 0 }; - - txn_ptr txn(m_pMdbEnv); - cursor_ptr cursor(txn, m_dbSettings); - - key.iov_len = sizeof(keyS); key.iov_base = &keyS; - - for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { - const DBSettingKey *pKey = (const DBSettingKey*)key.iov_base; - if (pKey->hContact != contactID) - break; - mdbx_cursor_del(cursor, 0); - } - - txn.commit(); - } - - MDBX_val key = { &contactID, sizeof(MCONTACT) }; - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_del(trnlck, m_dbContacts, &key, nullptr), 1); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - - InterlockedDecrement(&m_contactCount); - - return 0; -} - -STDMETHODIMP_(MCONTACT) CDbxMdb::AddContact() -{ - MCONTACT dwContactId = InterlockedIncrement(&m_maxContactId); - - DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); - - MDBX_val key = { &dwContactId, sizeof(MCONTACT) }; - MDBX_val data = { &cc->dbc, sizeof(cc->dbc) }; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &key, &data, 0), 0); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - - InterlockedIncrement(&m_contactCount); - NotifyEventHooks(hContactAddedEvent, dwContactId, 0); - return dwContactId; -} - -STDMETHODIMP_(BOOL) CDbxMdb::IsDbContact(MCONTACT contactID) -{ - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - return (cc != NULL); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDbxMdb::GatherContactHistory(MCONTACT hContact, LIST &list) -{ - DBEventSortingKey keyVal = { 0, 0, hContact }; - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - - txn_ptr_ro trnlck(m_txn); - cursor_ptr_ro cursor(m_curEventsSort); - - for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { - const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; - if (pKey->hContact != hContact) - return; - - list.insert(new EventItem(pKey->ts, pKey->hEvent)); - } -} - -BOOL CDbxMdb::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) -{ - LIST list(1000); - GatherContactHistory(ccSub->contactID, list); - - for (int i = 0; i < list.getCount(); i++) { - EventItem *EI = list[i]; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - DBEventSortingKey insVal = { EI->eventId, EI->ts, ccMeta->contactID }; - MDBX_val key = { &insVal, sizeof(insVal) }, data = { (void*)"", 1 }; - mdbx_put(trnlck, m_dbEventsSort, &key, &data, 0); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - ccMeta->dbc.dwEventCount++; - delete EI; - } - - MDBX_val keyc = { &ccMeta->contactID, sizeof(MCONTACT) }, datac = { &ccMeta->dbc, sizeof(ccMeta->dbc) }; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &keyc, &datac, 0), 1); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -BOOL CDbxMdb::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) -{ - LIST list(1000); - GatherContactHistory(ccSub->contactID, list); - - for (int i = 0; i < list.getCount(); i++) { - EventItem *EI = list[i]; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - DBEventSortingKey insVal = { EI->eventId, EI->ts, ccMeta->contactID }; - MDBX_val key = { &insVal, sizeof(insVal) }, data = { (void*)"", 1 }; - mdbx_del(trnlck, m_dbEventsSort, &key, &data); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - ccMeta->dbc.dwEventCount--; - delete EI; - } - - MDBX_val keyc = { &ccMeta->contactID, sizeof(MCONTACT) }, datac = { &ccMeta->dbc, sizeof(ccMeta->dbc) }; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &keyc, &datac, 0), 1); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void DBCachedContact::Advance(MEVENT id, DBEvent &dbe) -{ - dbc.dwEventCount++; - - if (dbe.flags & (DBEF_READ | DBEF_SENT)) - return; - - if (dbe.timestamp < dbc.tsFirstUnread || dbc.tsFirstUnread == 0) { - dbc.tsFirstUnread = dbe.timestamp; - dbc.evFirstUnread = id; - } -} - -void DBCachedContact::Snapshot() -{ - tmp_dbc = dbc; -} - -void DBCachedContact::Revert() -{ - dbc = tmp_dbc; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// initial cycle to fill the contacts' cache - -void CDbxMdb::FillContacts() -{ - LIST arContacts(m_contactCount); - - txn_ptr_ro trnlck(m_txn); - cursor_ptr_ro cursor(m_curContacts); - - MDBX_val key, data; - while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { - DBCachedContact *cc = m_cache->AddContactToCache(*(MCONTACT*)key.iov_base); - cc->dbc = *(DBContact*)data.iov_base; - - CheckProto(cc, ""); - - DBVARIANT dbv; dbv.type = DBVT_DWORD; - cc->nSubs = (0 != GetContactSetting(cc->contactID, META_PROTO, "NumContacts", &dbv)) ? -1 : dbv.dVal; - if (cc->nSubs != -1) { - cc->pSubs = (MCONTACT*)mir_alloc(cc->nSubs * sizeof(MCONTACT)); - for (int k = 0; k < cc->nSubs; k++) { - char setting[100]; - mir_snprintf(setting, _countof(setting), "Handle%d", k); - cc->pSubs[k] = (0 != GetContactSetting(cc->contactID, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; - } - } - cc->nDefault = (0 != GetContactSetting(cc->contactID, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; - cc->parentID = (0 != GetContactSetting(cc->contactID, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; - } -} diff --git a/plugins/Dbx_mdb/src/dbcrypt.cpp b/plugins/Dbx_mdb/src/dbcrypt.cpp deleted file mode 100644 index e704420128..0000000000 --- a/plugins/Dbx_mdb/src/dbcrypt.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// - -char DBKey_Crypto_Provider[] = "Provider"; -char DBKey_Crypto_Key[] = "Key"; -char DBKey_Crypto_IsEncrypted[] = "EncryptedDB"; - -CRYPTO_PROVIDER* CDbxMdb::SelectProvider() -{ - CRYPTO_PROVIDER **ppProvs, *pProv; - int iNumProvs; - Crypto_EnumProviders(&iNumProvs, &ppProvs); - - if (iNumProvs == 0) - return nullptr; - - bool bTotalCrypt = false; - - if (iNumProvs > 1) { - CSelectCryptoDialog dlg(ppProvs, iNumProvs); - dlg.DoModal(); - pProv = dlg.GetSelected(); - bTotalCrypt = dlg.TotalSelected(); - } - else pProv = ppProvs[0]; - - for (;; Remap()) { - txn_ptr txn(m_pMdbEnv); - - MDBX_val key = { DBKey_Crypto_Provider, sizeof(DBKey_Crypto_Provider) }, value = { pProv->pszName, mir_strlen(pProv->pszName) + 1 }; - MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), nullptr); - - key.iov_len = sizeof(DBKey_Crypto_IsEncrypted); key.iov_base = DBKey_Crypto_IsEncrypted; value.iov_len = sizeof(bool); value.iov_base = &bTotalCrypt; - MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), nullptr); - - if (txn.commit() == MDBX_SUCCESS) - break; - } - - return pProv; -} - -int CDbxMdb::InitCrypt() -{ - CRYPTO_PROVIDER *pProvider; - - txn_ptr_ro txn(m_txn); - - MDBX_val key = { DBKey_Crypto_Provider, sizeof(DBKey_Crypto_Provider) }, value; - if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS) { - pProvider = Crypto_GetProvider((const char*)value.iov_base); - if (pProvider == nullptr) - pProvider = SelectProvider(); - } - else pProvider = SelectProvider(); - - if (pProvider == nullptr) - return 1; - - if ((m_crypto = pProvider->pFactory()) == nullptr) - return 3; - - key.iov_len = sizeof(DBKey_Crypto_Key); key.iov_base = DBKey_Crypto_Key; - if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS && (value.iov_len == m_crypto->getKeyLength())) { - if (!m_crypto->setKey((const BYTE*)value.iov_base, value.iov_len)) { - DlgChangePassParam param = { this }; - CEnterPasswordDialog dlg(¶m); - while (true) { - if (-128 != dlg.DoModal()) - return 4; - m_crypto->setPassword(pass_ptrA(mir_utf8encodeW(param.newPass))); - if (m_crypto->setKey((const BYTE*)value.iov_base, value.iov_len)) { - m_bUsesPassword = true; - SecureZeroMemory(¶m, sizeof(param)); - break; - } - param.wrongPass++; - } - } - } - else { - if (!m_crypto->generateKey()) - return 6; - StoreKey(); - } - - key.iov_len = sizeof(DBKey_Crypto_IsEncrypted); key.iov_base = DBKey_Crypto_IsEncrypted; - - if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS) - m_bEncrypted = *(const bool*)value.iov_base; - else - m_bEncrypted = false; - - InitDialogs(); - return 0; -} - -void CDbxMdb::StoreKey() -{ - size_t iKeyLength = m_crypto->getKeyLength(); - BYTE *pKey = (BYTE*)_alloca(iKeyLength); - m_crypto->getKey(pKey, iKeyLength); - - for (;; Remap()) { - txn_ptr txn(m_pMdbEnv); - MDBX_val key = { DBKey_Crypto_Key, sizeof(DBKey_Crypto_Key) }, value = { pKey, iKeyLength }; - mdbx_put(txn, m_dbCrypto, &key, &value, 0); - if (txn.commit() == MDBX_SUCCESS) - break; - } - SecureZeroMemory(pKey, iKeyLength); -} - -void CDbxMdb::SetPassword(const wchar_t *ptszPassword) -{ - if (ptszPassword == NULL || *ptszPassword == 0) { - m_bUsesPassword = false; - m_crypto->setPassword(NULL); - } - else { - m_bUsesPassword = true; - m_crypto->setPassword(pass_ptrA(mir_utf8encodeW(ptszPassword))); - } - UpdateMenuItem(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CDbxMdb::EnableEncryption(bool bEncrypted) -{ - if (m_bEncrypted == bEncrypted) - return 0; - - { - txn_ptr_ro txnro(m_txn); - - MDBX_stat st; - mdbx_dbi_stat(txnro, m_dbEvents, &st, sizeof(st)); - - std::vector lstEvents; - lstEvents.reserve(st.ms_entries); - - { - cursor_ptr_ro cursor(m_curEvents); - MDBX_val key, data; - while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { - const MEVENT hDbEvent = *(const MEVENT*)key.iov_base; - lstEvents.push_back(hDbEvent); - } - } - for (auto it = lstEvents.begin(); it != lstEvents.end(); ++it) { - MEVENT &hDbEvent = *it; - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - mdbx_get(txnro, m_dbEvents, &key, &data); - - const DBEvent *dbEvent = (const DBEvent*)data.iov_base; - const BYTE *pBlob = (BYTE*)(dbEvent + 1); - - if (((dbEvent->flags & DBEF_ENCRYPTED) != 0) != bEncrypted) { - mir_ptr pNewBlob; - size_t nNewBlob; - uint32_t dwNewFlags; - - if (dbEvent->flags & DBEF_ENCRYPTED) { - pNewBlob = (BYTE*)m_crypto->decodeBuffer(pBlob, dbEvent->cbBlob, &nNewBlob); - dwNewFlags = dbEvent->flags & (~DBEF_ENCRYPTED); - } - else { - pNewBlob = m_crypto->encodeBuffer(pBlob, dbEvent->cbBlob, &nNewBlob); - dwNewFlags = dbEvent->flags | DBEF_ENCRYPTED; - } - - for (;; Remap()) { - txn_ptr txn(m_pMdbEnv); - data.iov_len = sizeof(DBEvent) + nNewBlob; - MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), 1); - - DBEvent *pNewDBEvent = (DBEvent *)data.iov_base; - *pNewDBEvent = *dbEvent; - pNewDBEvent->cbBlob = (uint16_t)nNewBlob; - pNewDBEvent->flags = dwNewFlags; - memcpy(pNewDBEvent + 1, pNewBlob, nNewBlob); - - - if (txn.commit() == MDBX_SUCCESS) - break; - } - } - } - } - - for (;; Remap()) { - txn_ptr txn(m_pMdbEnv); - MDBX_val key = { DBKey_Crypto_IsEncrypted, sizeof(DBKey_Crypto_IsEncrypted) }, value = { &bEncrypted, sizeof(bool) }; - MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), 1); - if (txn.commit() == MDBX_SUCCESS) - break; - } - - m_bEncrypted = bEncrypted; - return 0; -} diff --git a/plugins/Dbx_mdb/src/dbevents.cpp b/plugins/Dbx_mdb/src/dbevents.cpp deleted file mode 100644 index 75ba92e95b..0000000000 --- a/plugins/Dbx_mdb/src/dbevents.cpp +++ /dev/null @@ -1,428 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -STDMETHODIMP_(LONG) CDbxMdb::GetEventCount(MCONTACT contactID) -{ - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - return (cc == NULL) ? 0 : cc->dbc.dwEventCount; -} - -STDMETHODIMP_(MEVENT) CDbxMdb::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) -{ - if (dbei == NULL) return 0; - if (dbei->timestamp == 0) return 0; - - DBEvent dbe; - dbe.contactID = contactID; // store native or subcontact's id - dbe.iModuleId = GetModuleID(dbei->szModule); - - MCONTACT contactNotifyID = contactID; - DBCachedContact *cc, *ccSub = NULL; - if ((cc = m_cache->GetCachedContact(contactID)) == NULL) - return 0; - - if (cc->IsSub()) { - ccSub = cc; - if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) - return 0; - - // set default sub to the event's source - if (!(dbei->flags & DBEF_SENT)) - db_mc_setDefault(cc->contactID, contactID, false); - contactID = cc->contactID; // and add an event to a metahistory - if (db_mc_isEnabled()) - contactNotifyID = contactID; - } - - if (m_safetyMode) - if (NotifyEventHooks(hEventFilterAddedEvent, contactNotifyID, (LPARAM)dbei)) - return NULL; - - dbe.timestamp = dbei->timestamp; - dbe.flags = dbei->flags; - dbe.wEventType = dbei->eventType; - dbe.cbBlob = dbei->cbBlob; - BYTE *pBlob = dbei->pBlob; - - mir_ptr pCryptBlob; - if (m_bEncrypted) { - size_t len; - BYTE *pResult = m_crypto->encodeBuffer(pBlob, dbe.cbBlob, &len); - if (pResult != NULL) { - pCryptBlob = pBlob = pResult; - dbe.cbBlob = (uint16_t)len; - dbe.flags |= DBEF_ENCRYPTED; - } - } - - - MEVENT dwEventId = InterlockedIncrement(&m_dwMaxEventId); - - const auto Snapshot = [&]() { cc->Snapshot(); if (ccSub) ccSub->Snapshot(); }; - const auto Revert = [&]() { cc->Revert(); if (ccSub) ccSub->Revert(); }; - - for (Snapshot();; Revert(), Remap()) { - txn_ptr txn(m_pMdbEnv); - - MDBX_val key = { &dwEventId, sizeof(MEVENT) }, data = { NULL, sizeof(DBEvent) + dbe.cbBlob }; - MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), 0); - - DBEvent *pNewEvent = (DBEvent*)data.iov_base; - *pNewEvent = dbe; - memcpy(pNewEvent + 1, pBlob, dbe.cbBlob); - - // add a sorting key - DBEventSortingKey key2 = { contactID, dwEventId, dbe.timestamp }; - key.iov_len = sizeof(key2); key.iov_base = &key2; - data.iov_len = 1; data.iov_base = (char*)(""); - MDBX_CHECK(mdbx_put(txn, m_dbEventsSort, &key, &data, 0), 0); - - cc->Advance(dwEventId, dbe); - MDBX_val keyc = { &contactID, sizeof(MCONTACT) }, datac = { &cc->dbc, sizeof(DBContact) }; - MDBX_CHECK(mdbx_put(txn, m_dbContacts, &keyc, &datac, 0), 0); - - // insert an event into a sub's history too - if (ccSub != NULL) { - key2.hContact = ccSub->contactID; - MDBX_CHECK(mdbx_put(txn, m_dbEventsSort, &key, &data, 0), 0); - - ccSub->Advance(dwEventId, dbe); - datac.iov_base = &ccSub->dbc; - keyc.iov_base = &ccSub->contactID; - MDBX_CHECK(mdbx_put(txn, m_dbContacts, &keyc, &datac, 0), 0); - } - - if (txn.commit() == MDBX_SUCCESS) - break; - } - - // Notify only in safe mode or on really new events - if (m_safetyMode) - NotifyEventHooks(hEventAddedEvent, contactNotifyID, dwEventId); - - return dwEventId; -} - -STDMETHODIMP_(BOOL) CDbxMdb::DeleteEvent(MCONTACT contactID, MEVENT hDbEvent) -{ - DBCachedContact *cc = m_cache->GetCachedContact(contactID), *cc2 = nullptr; - if (cc == NULL || cc->dbc.dwEventCount == 0) - return 1; - - DBEvent dbe; - { - txn_ptr_ro txn(m_txn); - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return 1; - dbe = *(DBEvent*)data.iov_base; - } - - if (contactID != dbe.contactID) { - cc2 = m_cache->GetCachedContact(dbe.contactID); - } - - const auto Snapshot = [&]() { cc->Snapshot(); if (cc2) cc2->Snapshot(); }; - const auto Revert = [&]() { cc->Revert(); if (cc2) cc2->Revert(); }; - - for (Snapshot();; Revert(), Remap()) { - DBEventSortingKey key2 = { contactID, hDbEvent, dbe.timestamp }; - - txn_ptr txn(m_pMdbEnv); - MDBX_val key = { &key2, sizeof(key2) }, data; - - MDBX_CHECK(mdbx_del(txn, m_dbEventsSort, &key, &data), 1) - - { - key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; - cc->dbc.dwEventCount--; - if (cc->dbc.evFirstUnread == hDbEvent) - FindNextUnread(txn, cc, key2); - - data.iov_len = sizeof(DBContact); data.iov_base = &cc->dbc; - MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), 1); - } - - if (cc2) { - key2.hContact = dbe.contactID; - MDBX_CHECK(mdbx_del(txn, m_dbEventsSort, &key, &data), 1); - - key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; - cc2->dbc.dwEventCount--; - if (cc2->dbc.evFirstUnread == hDbEvent) - FindNextUnread(txn, cc2, key2); - - data.iov_len = sizeof(DBContact); data.iov_base = &cc2->dbc; - MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), 1); - - } - - // remove a event - key.iov_len = sizeof(MEVENT); key.iov_base = &hDbEvent; - MDBX_CHECK(mdbx_del(txn, m_dbEvents, &key, &data), 1); - - if (txn.commit() == MDBX_SUCCESS) - break; - } - - NotifyEventHooks(hEventDeletedEvent, contactID, hDbEvent); - - return 0; -} - -STDMETHODIMP_(LONG) CDbxMdb::GetBlobSize(MEVENT hDbEvent) -{ - txn_ptr_ro txn(m_txn); - - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return -1; - return ((const DBEvent*)data.iov_base)->cbBlob; -} - -STDMETHODIMP_(BOOL) CDbxMdb::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei) -{ - if (dbei == NULL) return 1; - if (dbei->cbBlob > 0 && dbei->pBlob == NULL) { - dbei->cbBlob = 0; - return 1; - } - - txn_ptr_ro txn(m_txn); - - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return 1; - - const DBEvent *dbe = (const DBEvent*)data.iov_base; - - dbei->szModule = GetModuleName(dbe->iModuleId); - dbei->timestamp = dbe->timestamp; - dbei->flags = dbe->flags; - dbei->eventType = dbe->wEventType; - size_t bytesToCopy = min(dbei->cbBlob, dbe->cbBlob); - dbei->cbBlob = dbe->cbBlob; - if (bytesToCopy && dbei->pBlob) { - BYTE *pSrc = (BYTE*)data.iov_base + sizeof(DBEvent); - if (dbe->flags & DBEF_ENCRYPTED) { - dbei->flags &= ~DBEF_ENCRYPTED; - size_t len; - BYTE* pBlob = (BYTE*)m_crypto->decodeBuffer(pSrc, dbe->cbBlob, &len); - if (pBlob == NULL) - return 1; - - memcpy(dbei->pBlob, pBlob, bytesToCopy); - if (bytesToCopy > len) - memset(dbei->pBlob + len, 0, bytesToCopy - len); - mir_free(pBlob); - } - else memcpy(dbei->pBlob, pSrc, bytesToCopy); - } - return 0; -} - -void CDbxMdb::FindNextUnread(const txn_ptr &txn, DBCachedContact *cc, DBEventSortingKey &key2) -{ - cursor_ptr cursor(txn, m_dbEventsSort); - - MDBX_val key = { &key2, sizeof(key2) }, data; - - for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { - const DBEvent *dbe = (const DBEvent*)data.iov_base; - if (dbe->contactID != cc->contactID) - break; - if (!dbe->markedRead()) { - cc->dbc.evFirstUnread = key2.hEvent; - cc->dbc.tsFirstUnread = key2.ts; - return; - } - } - - cc->dbc.evFirstUnread = cc->dbc.tsFirstUnread = 0; -} - -STDMETHODIMP_(BOOL) CDbxMdb::MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) -{ - if (hDbEvent == 0) return -1; - - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - if (cc == NULL) - return -1; - - uint32_t wRetVal = -1; - - for (cc->Snapshot();; cc->Revert(), Remap()) { - txn_ptr txn(m_pMdbEnv); - - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - MDBX_CHECK(mdbx_get(txn, m_dbEvents, &key, &data), -1); - - const DBEvent *cdbe = (const DBEvent*)data.iov_base; - - if (cdbe->markedRead()) - return cdbe->flags; - - DBEventSortingKey keyVal = { contactID, hDbEvent, cdbe->timestamp }; - - MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), -1); - - DBEvent *pNewEvent = (DBEvent*)data.iov_base; - *pNewEvent = *cdbe; - - wRetVal = (pNewEvent->flags |= DBEF_READ); - - FindNextUnread(txn, cc, keyVal); - key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; - data.iov_base = &cc->dbc; data.iov_len = sizeof(cc->dbc); - MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), -1); - - if (txn.commit() == MDBX_SUCCESS) - break; - } - - NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); - return wRetVal; -} - -STDMETHODIMP_(MCONTACT) CDbxMdb::GetEventContact(MEVENT hDbEvent) -{ - if (hDbEvent == 0) - return INVALID_CONTACT_ID; - - txn_ptr_ro txn(m_txn); - - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return INVALID_CONTACT_ID; - - return ((const DBEvent*)data.iov_base)->contactID; -} - -thread_local uint64_t t_tsLast = 0; -thread_local MEVENT t_evLast = 0; - -STDMETHODIMP_(MEVENT) CDbxMdb::FindFirstEvent(MCONTACT contactID) -{ - DBEventSortingKey keyVal = { contactID, 0, 0 }; - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - - txn_ptr_ro txn(m_txn); - - cursor_ptr_ro cursor(m_curEventsSort); - if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE) != MDBX_SUCCESS) - return t_evLast = 0; - - const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; - t_tsLast = pKey->ts; - return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; -} - -STDMETHODIMP_(MEVENT) CDbxMdb::FindFirstUnreadEvent(MCONTACT contactID) -{ - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - return (cc == NULL) ? 0 : cc->dbc.evFirstUnread; -} - -STDMETHODIMP_(MEVENT) CDbxMdb::FindLastEvent(MCONTACT contactID) -{ - DBEventSortingKey keyVal = { contactID, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - - txn_ptr_ro txn(m_txn); - cursor_ptr_ro cursor(m_curEventsSort); - - if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE) != MDBX_SUCCESS) { - if (mdbx_cursor_get(cursor, &key, &data, MDBX_LAST) != MDBX_SUCCESS) - return t_evLast = 0; - } - else { - if (mdbx_cursor_get(cursor, &key, &data, MDBX_PREV) != MDBX_SUCCESS) - return t_evLast = 0; - } - - const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; - t_tsLast = pKey->ts; - return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; -} - -STDMETHODIMP_(MEVENT) CDbxMdb::FindNextEvent(MCONTACT contactID, MEVENT hDbEvent) -{ - if (hDbEvent == 0) - return t_evLast = 0; - - txn_ptr_ro txn(m_txn); - - if (t_evLast != hDbEvent) { - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return 0; - t_tsLast = ((DBEvent*)data.iov_base)->timestamp; - } - - DBEventSortingKey keyVal = { contactID, hDbEvent, t_tsLast }; - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - - cursor_ptr_ro cursor(m_curEventsSort); - if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET) != MDBX_SUCCESS) - return t_evLast = 0; - - if (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) != MDBX_SUCCESS) - return t_evLast = 0; - - const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; - t_tsLast = pKey->ts; - return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; -} - -STDMETHODIMP_(MEVENT) CDbxMdb::FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) -{ - if (hDbEvent == 0) - return t_evLast = 0; - - MDBX_val data; - - txn_ptr_ro txn(m_txn); - - if (t_evLast != hDbEvent) { - MDBX_val key = { &hDbEvent, sizeof(MEVENT) }; - if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) - return 0; - t_tsLast = ((DBEvent*)data.iov_base)->timestamp; - } - - DBEventSortingKey keyVal = { contactID, hDbEvent, t_tsLast }; - MDBX_val key = { &keyVal, sizeof(keyVal) }; - - cursor_ptr_ro cursor(m_curEventsSort); - if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET) != MDBX_SUCCESS) - return t_evLast = 0; - - if (mdbx_cursor_get(cursor, &key, &data, MDBX_PREV) != MDBX_SUCCESS) - return t_evLast = 0; - - const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; - t_tsLast = pKey->ts; - return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; -} diff --git a/plugins/Dbx_mdb/src/dbintf.cpp b/plugins/Dbx_mdb/src/dbintf.cpp deleted file mode 100644 index b0b2b6e1bf..0000000000 --- a/plugins/Dbx_mdb/src/dbintf.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -CDbxMdb::CDbxMdb(const TCHAR *tszFileName, int iMode) : - m_safetyMode(true), - m_bReadOnly((iMode & DBMODE_READONLY) != 0), - m_bShared((iMode & DBMODE_SHARED) != 0), - m_maxContactId(0) -{ - m_tszProfileName = mir_wstrdup(tszFileName); - InitDbInstance(this); - - mdbx_env_create(&m_pMdbEnv); - mdbx_env_set_maxdbs(m_pMdbEnv, 10); - mdbx_env_set_userctx(m_pMdbEnv, this); - // mdbx_env_set_assert(m_pMdbEnv, LMDBX_FailAssert); -} - -CDbxMdb::~CDbxMdb() -{ - mdbx_env_close(m_pMdbEnv); - - DestroyServiceFunction(hService); - UnhookEvent(hHook); - - if (m_crypto) - m_crypto->destroy(); - - DestroyHookableEvent(hContactDeletedEvent); - DestroyHookableEvent(hContactAddedEvent); - DestroyHookableEvent(hSettingChangeEvent); - DestroyHookableEvent(hEventMarkedRead); - - DestroyHookableEvent(hEventAddedEvent); - DestroyHookableEvent(hEventDeletedEvent); - DestroyHookableEvent(hEventFilterAddedEvent); - - DestroyDbInstance(this); - mir_free(m_tszProfileName); -} - -int CDbxMdb::Load(bool bSkipInit) -{ - if (Map() != MDBX_SUCCESS) - return EGROKPRF_CANTREAD; - - if (!bSkipInit) { - txn_ptr trnlck(m_pMdbEnv); - - unsigned int defFlags = MDBX_CREATE; - - mdbx_dbi_open(trnlck, "global", defFlags | MDBX_INTEGERKEY, &m_dbGlobal); - mdbx_dbi_open(trnlck, "crypto", defFlags, &m_dbCrypto); - mdbx_dbi_open(trnlck, "contacts", defFlags | MDBX_INTEGERKEY, &m_dbContacts); - mdbx_dbi_open(trnlck, "modules", defFlags | MDBX_INTEGERKEY, &m_dbModules); - mdbx_dbi_open(trnlck, "events", defFlags | MDBX_INTEGERKEY, &m_dbEvents); - - mdbx_dbi_open_ex(trnlck, "eventsrt", defFlags, &m_dbEventsSort, DBEventSortingKey::Compare, nullptr); - mdbx_dbi_open_ex(trnlck, "settings", defFlags, &m_dbSettings, DBSettingKey::Compare, nullptr); - { - uint32_t keyVal = 1; - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - if (mdbx_get(trnlck, m_dbGlobal, &key, &data) == MDBX_SUCCESS) { - const DBHeader *hdr = (const DBHeader*)data.iov_base; - if (hdr->dwSignature != DBHEADER_SIGNATURE) - return EGROKPRF_DAMAGED; - if (hdr->dwVersion != DBHEADER_VERSION) - return EGROKPRF_OBSOLETE; - - m_header = *hdr; - } - else { - m_header.dwSignature = DBHEADER_SIGNATURE; - m_header.dwVersion = DBHEADER_VERSION; - data.iov_base = &m_header; data.iov_len = sizeof(m_header); - mdbx_put(trnlck, m_dbGlobal, &key, &data, 0); - } - trnlck.commit(); - } - { - MDBX_val key, val; - - mdbx_txn_begin(m_pMdbEnv, nullptr, MDBX_RDONLY, &m_txn); - - mdbx_cursor_open(m_txn, m_dbEvents, &m_curEvents); - if (mdbx_cursor_get(m_curEvents, &key, &val, MDBX_LAST) == MDBX_SUCCESS) - m_dwMaxEventId = *(MEVENT*)key.iov_base; - - mdbx_cursor_open(m_txn, m_dbEventsSort, &m_curEventsSort); - mdbx_cursor_open(m_txn, m_dbSettings, &m_curSettings); - mdbx_cursor_open(m_txn, m_dbModules, &m_curModules); - - mdbx_cursor_open(m_txn, m_dbContacts, &m_curContacts); - if (mdbx_cursor_get(m_curContacts, &key, &val, MDBX_LAST) == MDBX_SUCCESS) - m_maxContactId = *(MCONTACT*)key.iov_base; - - MDBX_stat st; - mdbx_dbi_stat(m_txn, m_dbContacts, &st, sizeof(st)); - m_contactCount = st.ms_entries; - - mdbx_txn_reset(m_txn); - } - - - if (InitModules()) return EGROKPRF_DAMAGED; - if (InitCrypt()) return EGROKPRF_DAMAGED; - - // everything is ok, go on - if (!m_bReadOnly) { - // retrieve the event handles - hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED); - hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED); - hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED); - hEventMarkedRead = CreateHookableEvent(ME_DB_EVENT_MARKED_READ); - - hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED); - hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED); - hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD); - } - - FillContacts(); - } - - return EGROKPRF_NOERROR; -} - -int CDbxMdb::Create(void) -{ - return (Map() == MDBX_SUCCESS) ? 0 : EGROKPRF_CANTREAD; -} - -size_t iDefHeaderOffset = 0; -BYTE bDefHeader[] = { 0 }; - -int CDbxMdb::Check(void) -{ - FILE *pFile = _wfopen(m_tszProfileName, L"rb"); - if (pFile == nullptr) - return EGROKPRF_CANTREAD; - - fseek(pFile, (LONG)iDefHeaderOffset, SEEK_SET); - BYTE buf[_countof(bDefHeader)]; - size_t cbRead = fread(buf, 1, _countof(buf), pFile); - fclose(pFile); - if (cbRead != _countof(buf)) - return EGROKPRF_DAMAGED; - - return (memcmp(buf, bDefHeader, _countof(bDefHeader))) ? EGROKPRF_UNKHEADER : 0; -} - -int CDbxMdb::PrepareCheck(int*) -{ - InitModules(); - return InitCrypt(); -} - -STDMETHODIMP_(void) CDbxMdb::SetCacheSafetyMode(BOOL bIsSet) -{ - m_safetyMode = bIsSet != 0; -} - -int CDbxMdb::Map() -{ - unsigned int mode = MDBX_NOSUBDIR | MDBX_MAPASYNC | MDBX_WRITEMAP | MDBX_NOSYNC; - if (m_bReadOnly) - mode |= MDBX_RDONLY; - mdbx_env_open(m_pMdbEnv, _T2A(m_tszProfileName), mode, 0664); - mdbx_env_set_mapsize(m_pMdbEnv, 0x1000000); - return MDBX_SUCCESS; -} - -bool CDbxMdb::Remap() -{ - MDBX_envinfo ei; - mdbx_env_info(m_pMdbEnv, &ei, sizeof(ei)); - return mdbx_env_set_geometry(m_pMdbEnv, -1, -1, ei.mi_mapsize + 0x100000, 0x100000, -1, -1) == MDBX_SUCCESS; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static DWORD DatabaseCorrupted = 0; -static const TCHAR *msg = NULL; -static DWORD dwErr = 0; -static wchar_t tszPanic[] = LPGENW("Miranda has detected corruption in your database. This corruption may be fixed by DbChecker plugin. Please download it from https://miranda-ng.org/p/DbChecker/. Miranda will now shut down."); - -EXTERN_C void __cdecl dbpanic(void *) -{ - if (msg) { - if (dwErr == ERROR_DISK_FULL) - msg = TranslateT("Disk is full. Miranda will now shut down."); - - TCHAR err[256]; - mir_snwprintf(err, msg, TranslateT("Database failure. Miranda will now shut down."), dwErr); - - MessageBox(0, err, TranslateT("Database Error"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); - } - else MessageBox(0, TranslateW(tszPanic), TranslateT("Database Panic"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); - TerminateProcess(GetCurrentProcess(), 255); -} - - -EXTERN_C void LMDBX_FailAssert(MDBX_env *env, const char *text) -{ - ((CDbxMdb*)mdbx_env_get_userctx(env))->DatabaseCorruption(_A2T(text)); -} - -EXTERN_C void LMDBX_Log(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - Netlib_Log(0, CMStringA().FormatV(fmt, args)); - va_end(args); -} - -void CDbxMdb::DatabaseCorruption(const TCHAR *text) -{ - int kill = 0; - - if (DatabaseCorrupted == 0) { - DatabaseCorrupted++; - kill++; - msg = text; - dwErr = GetLastError(); - } - else { - /* db is already corrupted, someone else is dealing with it, wait here - so that we don't do any more damage */ - Sleep(INFINITE); - return; - } - - if (kill) { - _beginthread(dbpanic, 0, NULL); - Sleep(INFINITE); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// MIDatabaseChecker - -typedef int (CDbxMdb::*CheckWorker)(int); - -int CDbxMdb::Start(DBCHeckCallback *callback) -{ - cb = callback; - return ERROR_SUCCESS; -} - -int CDbxMdb::CheckDb(int, int) -{ - return ERROR_OUT_OF_PAPER; -} - -void CDbxMdb::Destroy() -{ - delete this; -} diff --git a/plugins/Dbx_mdb/src/dbintf.h b/plugins/Dbx_mdb/src/dbintf.h deleted file mode 100644 index 9c9b88fcf9..0000000000 --- a/plugins/Dbx_mdb/src/dbintf.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 OWN_CACHED_CONTACT - -#include - -#pragma warning (disable: 4200) - -#define DBMODE_SHARED 0x0001 -#define DBMODE_READONLY 0x0002 - -#define DBVT_ENCRYPTED 250 -#define DBVT_UNENCRYPTED 251 - -#define MARKED_READ (DBEF_READ | DBEF_SENT) - -#include - -#define DBHEADER_VERSION MAKELONG(1, 4) - -#define DBHEADER_SIGNATURE 0x40DECADEu -struct DBHeader -{ - uint32_t dwSignature; - uint32_t dwVersion; // database format version -}; - -struct DBContact -{ - uint32_t dwEventCount; // number of events in the chain for this contact - MEVENT evFirstUnread; - uint64_t tsFirstUnread; -}; - -struct DBEvent -{ - MCONTACT contactID; // a contact this event belongs to - uint32_t iModuleId; // offset to a DBModuleName struct of the name of - uint64_t timestamp; // seconds since 00:00:00 01/01/1970 - uint32_t flags; // see m_database.h, db/event/add - uint16_t wEventType; // module-defined event type - uint16_t cbBlob; // number of bytes in the blob - - bool __forceinline markedRead() const - { - return (flags & MARKED_READ) != 0; - } -}; - -struct DBEventSortingKey -{ - MCONTACT hContact; - MEVENT hEvent; - uint64_t ts; - - static int Compare(const MDBX_val* a, const MDBX_val* b); -}; - -struct DBSettingKey -{ - MCONTACT hContact; - uint32_t dwModuleId; - char szSettingName[1]; - - static int Compare(const MDBX_val*, const MDBX_val*); -}; - -struct DBSettingValue -{ - BYTE type; - union - { - BYTE bVal; - WORD wVal; - DWORD dwVal; - char szVal[]; - - struct - { - size_t nLength; - BYTE bVal[]; - } blob; - }; -}; - -#include - -struct DBCachedContact : public DBCachedContactBase -{ - void Advance(MEVENT id, DBEvent &dbe); - void Snapshot(); - void Revert(); - DBContact dbc, tmp_dbc; -}; - -struct EventItem -{ - __forceinline EventItem(int _ts, MEVENT _id) : - ts(_ts), eventId(_id) - {} - - uint64_t ts; - MEVENT eventId; -}; - -struct CDbxMdb : public MDatabaseCommon, public MIDatabaseChecker, public MZeroedObject -{ - friend class LMDBEventCursor; - - CDbxMdb(const TCHAR *tszFileName, int mode); - virtual ~CDbxMdb(); - - int Load(bool bSkipInit); - int Create(void); - int Check(void); - - void DatabaseCorruption(const TCHAR *ptszText); - - void StoreKey(void); - void SetPassword(const wchar_t *ptszPassword); - void UpdateMenuItem(void); - - int PrepareCheck(int*); - - __forceinline LPSTR GetMenuTitle() const { return m_bUsesPassword ? (char*)LPGEN("Change/remove password") : (char*)LPGEN("Set password"); } - - __forceinline bool isEncrypted() const { return m_bEncrypted; } - __forceinline bool usesPassword() const { return m_bUsesPassword; } - int EnableEncryption(bool bEnable); -public: - STDMETHODIMP_(BOOL) IsRelational(void) { return TRUE; } - STDMETHODIMP_(void) SetCacheSafetyMode(BOOL); - - STDMETHODIMP_(LONG) GetContactCount(void); - STDMETHODIMP_(LONG) DeleteContact(MCONTACT contactID); - STDMETHODIMP_(MCONTACT) AddContact(void); - STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID); - STDMETHODIMP_(LONG) GetContactSize(void); - - STDMETHODIMP_(LONG) GetEventCount(MCONTACT contactID); - STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, DBEVENTINFO *dbe); - STDMETHODIMP_(BOOL) DeleteEvent(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(LONG) GetBlobSize(MEVENT hDbEvent); - STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe); - STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent); - STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID); - STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent); - STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent); - - STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam); - - STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); - STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws); - STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting); - STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param); - - STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); - STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); - -protected: - STDMETHODIMP_(BOOL) Start(DBCHeckCallback *callback); - STDMETHODIMP_(BOOL) CheckDb(int phase, int firstTime); - STDMETHODIMP_(VOID) Destroy(); - -protected: - - void FillContacts(void); - - int Map(); - bool Remap(); - -protected: - TCHAR* m_tszProfileName; - bool m_safetyMode, m_bReadOnly, m_bShared, m_bEncrypted, m_bUsesPassword; - - //////////////////////////////////////////////////////////////////////////// - // database stuff -public: - MICryptoEngine *m_crypto; - -protected: - MDBX_env *m_pMdbEnv; - CMDBX_txn_ro m_txn; - - MDBX_dbi m_dbGlobal; - DBHeader m_header; - - HANDLE hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent, hEventMarkedRead; - - //////////////////////////////////////////////////////////////////////////// - // settings - - MDBX_dbi m_dbSettings; - MDBX_cursor *m_curSettings; - - HANDLE hService, hHook; - - //////////////////////////////////////////////////////////////////////////// - // contacts - - MDBX_dbi m_dbContacts; - MDBX_cursor *m_curContacts; - - uint32_t m_contactCount; - MCONTACT m_maxContactId; - - void GatherContactHistory(MCONTACT hContact, LIST &items); - - //////////////////////////////////////////////////////////////////////////// - // events - - MDBX_dbi m_dbEvents, m_dbEventsSort; - MDBX_cursor *m_curEvents, *m_curEventsSort; - MEVENT m_dwMaxEventId; - - HANDLE hEventAddedEvent, hEventDeletedEvent, hEventFilterAddedEvent; - - void FindNextUnread(const txn_ptr &_txn, DBCachedContact *cc, DBEventSortingKey &key2); - - //////////////////////////////////////////////////////////////////////////// - // modules - - MDBX_dbi m_dbModules; - MDBX_cursor *m_curModules; - - std::map m_Modules; - - int InitModules(); - - uint32_t GetModuleID(const char *szName); - char* GetModuleName(uint32_t dwId); - - DBCHeckCallback *cb; - - //////////////////////////////////////////////////////////////////////////// - // encryption - - MDBX_dbi m_dbCrypto; - - int InitCrypt(void); - CRYPTO_PROVIDER* SelectProvider(); - - void InitDialogs(); -}; \ No newline at end of file diff --git a/plugins/Dbx_mdb/src/dbmodulechain.cpp b/plugins/Dbx_mdb/src/dbmodulechain.cpp deleted file mode 100644 index dc59798eb3..0000000000 --- a/plugins/Dbx_mdb/src/dbmodulechain.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -int CDbxMdb::InitModules() -{ - txn_ptr_ro trnlck(m_txn); - cursor_ptr_ro cursor(m_curModules); - - MDBX_val key, data; - while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { - uint32_t iMod = *(uint32_t*)key.iov_base; - const char *szMod = (const char*)data.iov_base; - m_Modules[iMod] = szMod; - } - return 0; -} - -// will create the offset if it needs to -uint32_t CDbxMdb::GetModuleID(const char *szName) -{ - uint32_t iHash = mir_hashstr(szName); - if (m_Modules.find(iHash) == m_Modules.end()) { - MDBX_val key = { &iHash, sizeof(iHash) }, data = { (void*)szName, strlen(szName) + 1 }; - - for (;; Remap()) { - txn_ptr txn(m_pMdbEnv); - MDBX_CHECK(mdbx_put(txn, m_dbModules, &key, &data, 0), -1); - if (txn.commit() == MDBX_SUCCESS) - break; - } - m_Modules[iHash] = szName; - } - - return iHash; -} - -char* CDbxMdb::GetModuleName(uint32_t dwId) -{ - auto it = m_Modules.find(dwId); - return it != m_Modules.end() ? const_cast(it->second.c_str()) : nullptr; -} - -STDMETHODIMP_(BOOL) CDbxMdb::EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam) -{ - for (auto it = m_Modules.begin(); it != m_Modules.end(); ++it) - if (int ret = pFunc(it->second.c_str(), pParam)) - return ret; - - return 0; -} diff --git a/plugins/Dbx_mdb/src/dbsettings.cpp b/plugins/Dbx_mdb/src/dbsettings.cpp deleted file mode 100644 index 0337dce06c..0000000000 --- a/plugins/Dbx_mdb/src/dbsettings.cpp +++ /dev/null @@ -1,398 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -#define VLT(n) ((n == DBVT_UTF8 || n == DBVT_ENCRYPTED)?DBVT_ASCIIZ:n) - -static bool ValidLookupName(LPCSTR szModule, LPCSTR szSetting) -{ - if (!strcmp(szModule, META_PROTO)) - return strcmp(szSetting, "IsSubcontact") && strcmp(szSetting, "ParentMetaID"); - - if (!strcmp(szModule, "Ignore")) - return false; - - return true; -} - -int CDbxMdb::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic) -{ - if (szSetting == NULL || szModule == NULL) - return 1; - - size_t settingNameLen = strlen(szSetting); - size_t moduleNameLen = strlen(szModule); - -LBL_Seek: - char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); - - DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); - if (pCachedValue != NULL) { - if (pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8) { - int cbOrigLen = dbv->cchVal; - char *cbOrigPtr = dbv->pszVal; - memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); - if (isStatic) { - int cbLen = 0; - if (pCachedValue->pszVal != NULL) - cbLen = (int)strlen(pCachedValue->pszVal); - - cbOrigLen--; - dbv->pszVal = cbOrigPtr; - if (cbLen < cbOrigLen) - cbOrigLen = cbLen; - memcpy(dbv->pszVal, pCachedValue->pszVal, cbOrigLen); - dbv->pszVal[cbOrigLen] = 0; - dbv->cchVal = cbLen; - } - else { - dbv->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal) + 1); - strcpy(dbv->pszVal, pCachedValue->pszVal); - } - } - else memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); - - return (pCachedValue->type == DBVT_DELETED) ? 1 : 0; - } - - // never look db for the resident variable - if (szCachedSettingName[-1] != 0) - return 1; - - DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; - - txn_ptr_ro trnlck(m_txn); - - DBSettingKey *keyVal = (DBSettingKey *)_alloca(sizeof(DBSettingKey) + settingNameLen); - keyVal->hContact = contactID; - keyVal->dwModuleId = GetModuleID(szModule); - memcpy(&keyVal->szSettingName, szSetting, settingNameLen + 1); - - - MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }, data; - if (mdbx_get(trnlck, m_dbSettings, &key, &data) != MDBX_SUCCESS) { - // try to get the missing mc setting from the active sub - if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { - if (contactID = db_mc_getDefault(contactID)) { - if (szModule = GetContactProto(contactID)) { - moduleNameLen = strlen(szModule); - goto LBL_Seek; - } - } - } - return 1; - } - - const BYTE *pBlob = (const BYTE*)data.iov_base; - if (isStatic && (pBlob[0] & DBVTF_VARIABLELENGTH) && VLT(dbv->type) != VLT(pBlob[0])) - return 1; - - int varLen; - BYTE iType = dbv->type = pBlob[0]; pBlob++; - switch (iType) { - case DBVT_DELETED: /* this setting is deleted */ - dbv->type = DBVT_DELETED; - return 2; - - case DBVT_BYTE: dbv->bVal = *pBlob; break; - case DBVT_WORD: dbv->wVal = *(WORD*)pBlob; break; - case DBVT_DWORD: dbv->dVal = *(DWORD*)pBlob; break; - - case DBVT_UTF8: - case DBVT_ASCIIZ: - varLen = *(WORD*)pBlob; - pBlob += 2; - if (isStatic) { - dbv->cchVal--; - if (varLen < dbv->cchVal) - dbv->cchVal = varLen; - memcpy(dbv->pszVal, pBlob, dbv->cchVal); // decode - dbv->pszVal[dbv->cchVal] = 0; - dbv->cchVal = varLen; - } - else { - dbv->pszVal = (char*)mir_alloc(1 + varLen); - memcpy(dbv->pszVal, pBlob, varLen); - dbv->pszVal[varLen] = 0; - } - break; - - case DBVT_BLOB: - varLen = *(WORD*)pBlob; - pBlob += 2; - if (isStatic) { - if (varLen < dbv->cpbVal) - dbv->cpbVal = varLen; - memcpy(dbv->pbVal, pBlob, dbv->cpbVal); - } - else { - dbv->pbVal = (BYTE *)mir_alloc(varLen); - memcpy(dbv->pbVal, pBlob, varLen); - } - dbv->cpbVal = varLen; - break; - - case DBVT_ENCRYPTED: - if (m_crypto == NULL) - return 1; - - varLen = *(WORD*)pBlob; - pBlob += 2; - - size_t realLen; - ptrA decoded(m_crypto->decodeString(pBlob, varLen, &realLen)); - if (decoded == NULL) - return 1; - - varLen = (WORD)realLen; - dbv->type = DBVT_UTF8; - if (isStatic) { - dbv->cchVal--; - if (varLen < dbv->cchVal) - dbv->cchVal = varLen; - memcpy(dbv->pszVal, decoded, dbv->cchVal); - dbv->pszVal[dbv->cchVal] = 0; - dbv->cchVal = varLen; - } - else { - dbv->pszVal = (char*)mir_alloc(1 + varLen); - memcpy(dbv->pszVal, decoded, varLen); - dbv->pszVal[varLen] = 0; - } - break; - } - - /**** add to cache **********************/ - if (iType != DBVT_BLOB && iType != DBVT_ENCRYPTED) { - pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); - if (pCachedValue != NULL) - m_cache->SetCachedVariant(dbv, pCachedValue); - } - - return 0; -} - -STDMETHODIMP_(BOOL) CDbxMdb::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) -{ - if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly) - return 1; - - // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name - size_t settingNameLen = strlen(dbcws->szSetting); - size_t moduleNameLen = strlen(dbcws->szModule); - - // used for notifications - DBCONTACTWRITESETTING dbcwNotif = *dbcws; - if (dbcwNotif.value.type == DBVT_WCHAR) { - if (dbcwNotif.value.pszVal != NULL) { - T2Utf val(dbcwNotif.value.pwszVal); - if (val == NULL) - return 1; - - dbcwNotif.value.pszVal = NEWSTR_ALLOCA(val); - dbcwNotif.value.type = DBVT_UTF8; - } - else return 1; - } - - if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL) - return 1; - - DBCONTACTWRITESETTING dbcwWork = dbcwNotif; - - mir_ptr pEncoded(NULL); - bool bIsEncrypted = false; - switch (dbcwWork.value.type) { - case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD: - break; - - case DBVT_ASCIIZ: case DBVT_UTF8: - bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting); -LBL_WriteString: - if (dbcwWork.value.pszVal == NULL) - return 1; - dbcwWork.value.cchVal = (WORD)strlen(dbcwWork.value.pszVal); - if (bIsEncrypted) { - size_t len; - BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); - if (pResult != NULL) { - pEncoded = dbcwWork.value.pbVal = pResult; - dbcwWork.value.cpbVal = (WORD)len; - dbcwWork.value.type = DBVT_ENCRYPTED; - } - } - break; - - case DBVT_UNENCRYPTED: - dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8; - goto LBL_WriteString; - - case DBVT_BLOB: case DBVT_ENCRYPTED: - if (dbcwWork.value.pbVal == NULL) - return 1; - break; - default: - return 1; - } - - char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); - - // we don't cache blobs and passwords - if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) { - DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); - if (pCachedValue != NULL) { - bool bIsIdentical = false; - if (pCachedValue->type == dbcwWork.value.type) { - switch (dbcwWork.value.type) { - case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal; break; - case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal; break; - case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal; break; - case DBVT_UTF8: - case DBVT_ASCIIZ: bIsIdentical = strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break; - } - if (bIsIdentical) - return 0; - } - m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); - } - if (szCachedSettingName[-1] != 0) { - NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork); - return 0; - } - } - else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); - - DBSettingKey *keyVal = (DBSettingKey *)_alloca(sizeof(DBSettingKey) + settingNameLen); - keyVal->hContact = contactID; - keyVal->dwModuleId = GetModuleID(dbcws->szModule); - memcpy(&keyVal->szSettingName, dbcws->szSetting, settingNameLen + 1); - - - MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }, data; - - switch (dbcwWork.value.type) { - case DBVT_BYTE: data.iov_len = 2; break; - case DBVT_WORD: data.iov_len = 3; break; - case DBVT_DWORD: data.iov_len = 5; break; - - case DBVT_ASCIIZ: - case DBVT_UTF8: - data.iov_len = 3 + dbcwWork.value.cchVal; break; - - case DBVT_BLOB: - case DBVT_ENCRYPTED: - data.iov_len = 3 + dbcwWork.value.cpbVal; break; - } - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_put(trnlck, m_dbSettings, &key, &data, MDBX_RESERVE), 1); - - BYTE *pBlob = (BYTE*)data.iov_base; - *pBlob++ = dbcwWork.value.type; - switch (dbcwWork.value.type) { - case DBVT_BYTE: *pBlob = dbcwWork.value.bVal; break; - case DBVT_WORD: *(WORD*)pBlob = dbcwWork.value.wVal; break; - case DBVT_DWORD: *(DWORD*)pBlob = dbcwWork.value.dVal; break; - - case DBVT_ASCIIZ: - case DBVT_UTF8: - data.iov_len = *(WORD*)pBlob = dbcwWork.value.cchVal; - pBlob += 2; - memcpy(pBlob, dbcwWork.value.pszVal, dbcwWork.value.cchVal); - break; - - case DBVT_BLOB: - case DBVT_ENCRYPTED: - data.iov_len = *(WORD*)pBlob = dbcwWork.value.cpbVal; - pBlob += 2; - memcpy(pBlob, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); - } - - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - - // notify - NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); - return 0; -} - -STDMETHODIMP_(BOOL) CDbxMdb::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) -{ - if (!szModule || !szSetting) - return 1; - - size_t settingNameLen = strlen(szSetting); - size_t moduleNameLen = strlen(szModule); - - char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); - - if (szCachedSettingName[-1] == 0) // it's not a resident variable - { - DBSettingKey *keyVal = (DBSettingKey*)_alloca(sizeof(DBSettingKey) + settingNameLen); - keyVal->hContact = contactID; - keyVal->dwModuleId = GetModuleID(szModule); - memcpy(&keyVal->szSettingName, szSetting, settingNameLen + 1); - - MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }; - - for (;; Remap()) { - txn_ptr trnlck(m_pMdbEnv); - MDBX_CHECK(mdbx_del(trnlck, m_dbSettings, &key, nullptr), 1); - if (trnlck.commit() == MDBX_SUCCESS) - break; - } - } - - m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); - - // notify - DBCONTACTWRITESETTING dbcws = { 0 }; - dbcws.szModule = szModule; - dbcws.szSetting = szSetting; - dbcws.value.type = DBVT_DELETED; - NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcws); - return 0; -} - -STDMETHODIMP_(BOOL) CDbxMdb::EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) -{ - int result = -1; - - DBSettingKey keyVal = { hContact, GetModuleID(szModule), 0 }; - txn_ptr_ro txn(m_txn); - cursor_ptr_ro cursor(m_curSettings); - - MDBX_val key = { &keyVal, sizeof(keyVal) }, data; - - for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { - const DBSettingKey *pKey = (const DBSettingKey*)key.iov_base; - if (pKey->hContact != hContact || pKey->dwModuleId != keyVal.dwModuleId) - break; - result = pfnEnumProc(pKey->szSettingName, param); - } - - return result; -} diff --git a/plugins/Dbx_mdb/src/dbutils.cpp b/plugins/Dbx_mdb/src/dbutils.cpp deleted file mode 100644 index 147b43ef30..0000000000 --- a/plugins/Dbx_mdb/src/dbutils.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -#define CMP_UINT(x, y) { if ((x) != (y)) return (x) < (y) ? -1 : 1; } - -int DBEventSortingKey::Compare(const MDBX_val *ax, const MDBX_val *bx) -{ - const DBEventSortingKey *a = (DBEventSortingKey *)ax->iov_base; - const DBEventSortingKey *b = (DBEventSortingKey *)bx->iov_base; - - CMP_UINT(a->hContact, b->hContact); - CMP_UINT(a->ts, b->ts); - CMP_UINT(a->hEvent, b->hEvent); - return 0; -} - -int DBSettingKey::Compare(const MDBX_val *ax, const MDBX_val *bx) -{ - const DBSettingKey *a = (DBSettingKey *)ax->iov_base; - const DBSettingKey *b = (DBSettingKey *)bx->iov_base; - - CMP_UINT(a->hContact, b->hContact); - CMP_UINT(a->dwModuleId, b->dwModuleId); - return strcmp(a->szSettingName, b->szSettingName); -} diff --git a/plugins/Dbx_mdb/src/init.cpp b/plugins/Dbx_mdb/src/init.cpp deleted file mode 100644 index 3af9855292..0000000000 --- a/plugins/Dbx_mdb/src/init.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -int hLangpack; - -static PLUGININFOEX pluginInfo = -{ - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE | STATIC_PLUGIN, - // {7C3D0A33-2646-4001-9107-F35EA299D292} - { 0x7c3d0a33, 0x2646, 0x4001, { 0x91, 0x7, 0xf3, 0x5e, 0xa2, 0x99, 0xd2, 0x92 } } -}; - -HINSTANCE g_hInst = NULL; - -LIST g_Dbs(1, HandleKeySortT); - -///////////////////////////////////////////////////////////////////////////////////////// - -// returns 0 if the profile is created, EMKPRF* -static int makeDatabase(const TCHAR *profile) -{ - std::unique_ptr db(new CDbxMdb(profile, 0)); - return db->Create(); -} - -// returns 0 if the given profile has a valid header -static int grokHeader(const TCHAR *profile) -{ - std::unique_ptr db(new CDbxMdb(profile, DBMODE_SHARED | DBMODE_READONLY)); - return db->Check(); -} - -// returns 0 if all the APIs are injected otherwise, 1 -static MIDatabase* LoadDatabase(const TCHAR *profile, BOOL bReadOnly) -{ - // set the memory, lists & UTF8 manager - mir_getLP(&pluginInfo); - - std::unique_ptr db(new CDbxMdb(profile, (bReadOnly) ? DBMODE_READONLY : 0)); - if (db->Load(false) != ERROR_SUCCESS) - return NULL; - - g_Dbs.insert(db.get()); - return db.release(); -} - -static int UnloadDatabase(MIDatabase *db) -{ - g_Dbs.remove((CDbxMdb*)db); - delete (CDbxMdb*)db; - return 0; -} - -MIDatabaseChecker* CheckDb(const TCHAR *profile, int *error) -{ - std::unique_ptr db(new CDbxMdb(profile, DBMODE_READONLY)); - if (db->Load(true) != ERROR_SUCCESS) { - *error = ERROR_ACCESS_DENIED; - return NULL; - } - - if (db->PrepareCheck(error)) - return NULL; - - return db.release(); -} - -static DATABASELINK dblink = -{ - sizeof(DATABASELINK), - "dbx_mdbx", - L"LMDBx database driver", - makeDatabase, - grokHeader, - LoadDatabase, - UnloadDatabase, - CheckDb -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD) -{ - return &pluginInfo; -} - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_DATABASE, MIID_LAST }; - -extern "C" __declspec(dllexport) int Load(void) -{ - RegisterDatabasePlugin(&dblink); - return 0; -} - -extern "C" __declspec(dllexport) int Unload(void) -{ - return 0; -} - -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD, LPVOID) -{ - g_hInst = hInstDLL; - return TRUE; -} diff --git a/plugins/Dbx_mdb/src/libmdbx b/plugins/Dbx_mdb/src/libmdbx deleted file mode 160000 index 24a8bdec49..0000000000 --- a/plugins/Dbx_mdb/src/libmdbx +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 24a8bdec49ee360bf0412631ff8931de91e109fc diff --git a/plugins/Dbx_mdb/src/resource.h b/plugins/Dbx_mdb/src/resource.h deleted file mode 100644 index 21f82d6f05..0000000000 --- a/plugins/Dbx_mdb/src/resource.h +++ /dev/null @@ -1,35 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Включаемый файл, созданный в Microsoft Visual C++. -// Используется d:\Others\SVN\MirandaNG\trunk\plugins\Dbx_mdb\res\dbx_mdb.rc -// -#define IDREMOVE 3 -#define IDI_ICONPASS 100 -#define IDI_LOGO 101 -#define IDD_LOGIN 102 -#define IDD_NEWPASS 103 -#define IDD_CHANGEPASS 104 -#define IDD_OPTIONS 105 -#define IDD_SELECT_CRYPTOPROVIDER 106 -#define IDC_HEADERBAR 1001 -#define IDC_LANG 1002 -#define IDC_USERPASS 1003 -#define IDC_USERPASS1 1004 -#define IDC_USERPASS2 1005 -#define IDC_OLDPASS 1006 -#define IDC_STANDARD 1007 -#define IDC_TOTAL 1008 -#define IDC_SELECTCRYPT_COMBO 1010 -#define IDC_CRYPTOPROVIDER_DESCR 1011 -#define IDC_CHECK1 1012 -#define IDC_CHECK_TOTALCRYPT 1012 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1013 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/plugins/Dbx_mdb/src/stdafx.cxx b/plugins/Dbx_mdb/src/stdafx.cxx deleted file mode 100644 index e579779bcc..0000000000 --- a/plugins/Dbx_mdb/src/stdafx.cxx +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright (C) 2012-18 Miranda NG team (https://miranda-ng.org) - -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 version 2 -of the License. - -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, see . -*/ - -#include "stdafx.h" \ No newline at end of file diff --git a/plugins/Dbx_mdb/src/stdafx.h b/plugins/Dbx_mdb/src/stdafx.h deleted file mode 100644 index c6a4edc01e..0000000000 --- a/plugins/Dbx_mdb/src/stdafx.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libmdbx/mdbx.h" - -#ifndef thread_local -# define thread_local __declspec(thread) -#endif - - -class txn_ptr -{ - MDBX_txn *m_txn; -public: - __forceinline txn_ptr(MDBX_env *pEnv) - { - mdbx_txn_begin(pEnv, NULL, 0, &m_txn); - } - - __forceinline ~txn_ptr() - { - if (m_txn) - mdbx_txn_abort(m_txn); - } - - __forceinline operator MDBX_txn*() const { return m_txn; } - - __forceinline int commit() - { - MDBX_txn *tmp = m_txn; - m_txn = nullptr; - return mdbx_txn_commit(tmp); - } - - __forceinline void abort() - { - mdbx_txn_abort(m_txn); - m_txn = NULL; - } -}; - -struct CMDBX_txn_ro -{ - MDBX_txn *m_txn; - bool bIsActive; - mir_cs cs; - - __forceinline CMDBX_txn_ro() : m_txn(nullptr), bIsActive(false) {} - - __forceinline operator MDBX_txn* () { return m_txn; } - __forceinline MDBX_txn** operator &() { return &m_txn; } -}; - -class txn_ptr_ro -{ - CMDBX_txn_ro &m_txn; - bool bNeedReset; - mir_cslock lock; -public: - __forceinline txn_ptr_ro(CMDBX_txn_ro &txn) : m_txn(txn), bNeedReset(!txn.bIsActive), lock(m_txn.cs) - { - if (bNeedReset) - { - mdbx_txn_renew(m_txn); - m_txn.bIsActive = true; - } - } - __forceinline ~txn_ptr_ro() - { - if (bNeedReset) - { - mdbx_txn_reset(m_txn); - m_txn.bIsActive = false; - } - } - __forceinline operator MDBX_txn*() const { return m_txn; } -}; - -class cursor_ptr -{ - MDBX_cursor *m_cursor; - -public: - __forceinline cursor_ptr(MDBX_txn *_txn, MDBX_dbi _dbi) - { - if (mdbx_cursor_open(_txn, _dbi, &m_cursor) != MDBX_SUCCESS) - m_cursor = NULL; - } - - __forceinline ~cursor_ptr() - { - if (m_cursor) - mdbx_cursor_close(m_cursor); - } - - __forceinline operator MDBX_cursor*() const { return m_cursor; } -}; - -class cursor_ptr_ro -{ - MDBX_cursor *m_cursor; -public: - __forceinline cursor_ptr_ro(MDBX_cursor *cursor) : m_cursor(cursor) - { - mdbx_cursor_renew(mdbx_cursor_txn(m_cursor), m_cursor); - } - __forceinline operator MDBX_cursor*() const { return m_cursor; } -}; - -#define MDBX_CHECK(A,B) \ - switch (A) { \ - case MDBX_SUCCESS: break; \ - case MDBX_MAP_FULL: continue; \ - default: return (B); } - - - - -#include "dbintf.h" -#include "resource.h" -#include "version.h" - -extern HINSTANCE g_hInst; -extern LIST g_Dbs; - -#include "ui.h" diff --git a/plugins/Dbx_mdb/src/ui.cpp b/plugins/Dbx_mdb/src/ui.cpp deleted file mode 100644 index 6067a0d3d2..0000000000 --- a/plugins/Dbx_mdb/src/ui.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) -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 "stdafx.h" - -static HGENMENU hSetPwdMenu; - -static UINT oldLangID; -void LanguageChanged(HWND hwndDlg) -{ - UINT_PTR LangID = (UINT_PTR)GetKeyboardLayout(0); - char Lang[3] = { 0 }; - if (LangID != oldLangID) { - oldLangID = LangID; - GetLocaleInfoA(MAKELCID((LangID & 0xffffffff), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, Lang, 2); - Lang[0] = toupper(Lang[0]); - Lang[1] = tolower(Lang[1]); - SetDlgItemTextA(hwndDlg, IDC_LANG, Lang); - } -} - - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool CheckOldPassword(HWND hwndDlg, CDbxMdb *db) -{ - if (db->usesPassword()) - { - TCHAR buf[100]; - GetDlgItemText(hwndDlg, IDC_OLDPASS, buf, _countof(buf)); - pass_ptrA oldPass(mir_utf8encodeW(buf)); - if (!db->m_crypto->checkPassword(oldPass)) - { - SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Wrong old password entered!")); - return false; - } - } - return true; -} - -static INT_PTR CALLBACK sttChangePassword(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - DlgChangePassParam *param = (DlgChangePassParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - TCHAR buf[100]; - - switch (uMsg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_SETICON, ICON_SMALL, (LPARAM)IcoLib_GetIconByHandle(iconList[0].hIcolib, true)); - - param = (DlgChangePassParam*)lParam; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); - - oldLangID = 0; - SetTimer(hwndDlg, 1, 200, NULL); - LanguageChanged(hwndDlg); - return TRUE; - - case WM_CTLCOLORSTATIC: - if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_LANG)) { - SetTextColor((HDC)wParam, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetSysColorBrush(COLOR_HIGHLIGHT); - } - return FALSE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hwndDlg, IDCANCEL); - break; - - case IDREMOVE: - if (!CheckOldPassword(hwndDlg, param->db)) { - LBL_Error: - SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_NCPAINT, 0, 0); - SetDlgItemTextA(hwndDlg, IDC_USERPASS1, ""); - SetDlgItemTextA(hwndDlg, IDC_USERPASS2, ""); - } - else { - // param->db->WriteSignature(dbSignatureU); - param->db->SetPassword(nullptr); - param->db->StoreKey(); - EndDialog(hwndDlg, IDREMOVE); - } - break; - - case IDOK: - TCHAR buf2[100]; - GetDlgItemText(hwndDlg, IDC_USERPASS1, buf2, _countof(buf2)); - if (wcslen(buf2) < 3) { - SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Password is too short!")); - goto LBL_Error; - } - - GetDlgItemText(hwndDlg, IDC_USERPASS2, buf, _countof(buf)); - if (wcscmp(buf2, buf)) { - SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Passwords do not match!")); - goto LBL_Error; - } - - if (!CheckOldPassword(hwndDlg, param->db)) - goto LBL_Error; - - // param->db->WriteSignature(dbSignatureE); - param->db->SetPassword(buf2); - param->db->StoreKey(); - SecureZeroMemory(buf2, sizeof(buf2)); - EndDialog(hwndDlg, IDOK); - } - break; - - case WM_TIMER: - LanguageChanged(hwndDlg); - return FALSE; - - case WM_DESTROY: - KillTimer(hwndDlg, 1); - IcoLib_ReleaseIcon((HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0)); - } - - return FALSE; -} - -static INT_PTR ChangePassword(void* obj, WPARAM, LPARAM) -{ - CDbxMdb *db = (CDbxMdb*)obj; - DlgChangePassParam param = { db }; - DialogBoxParam(g_hInst, MAKEINTRESOURCE(db->usesPassword() ? IDD_CHANGEPASS : IDD_NEWPASS), 0, sttChangePassword, (LPARAM)¶m); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - - -static int OnOptionsInit(PVOID obj, WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = { sizeof(odp) }; - odp.position = -790000000; - odp.flags = ODPF_BOLDGROUPS; - odp.szTitle.a = LPGEN("Database"); - odp.pDialog = new COptionsDialog((CDbxMdb*)obj); - Options_AddPage(wParam, &odp); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDbxMdb::UpdateMenuItem() -{ - Menu_ModifyItem(hSetPwdMenu, _A2T(GetMenuTitle()), iconList[1].hIcolib); -} - -static int OnModulesLoaded(PVOID obj, WPARAM, LPARAM) -{ - CDbxMdb *db = (CDbxMdb*)obj; - - Icon_Register(g_hInst, LPGEN("Database"), iconList, _countof(iconList), "lmdb"); - - HookEventObj(ME_OPT_INITIALISE, OnOptionsInit, db); - - CMenuItem mi; - - // main menu item - mi.root = Menu_CreateRoot(MO_MAIN, LPGENW("Database"), 500000000, iconList[0].hIcolib); - Menu_ConfigureItem(mi.root, MCI_OPT_UID, "F7C5567C-D1EE-484B-B4F6-24677A5AAAEF"); - - SET_UID(mi, 0x50321866, 0xba1, 0x46dd, 0xb3, 0xa6, 0xc3, 0xcc, 0x55, 0xf2, 0x42, 0x9e); - mi.hIcolibItem = iconList[1].hIcolib; - mi.name.a = db->GetMenuTitle(); - mi.pszService = MS_DB_CHANGEPASSWORD; - hSetPwdMenu = Menu_AddMainMenuItem(&mi); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDbxMdb::InitDialogs() -{ - hService = CreateServiceFunctionObj(MS_DB_CHANGEPASSWORD, ChangePassword, this); - hHook = HookEventObj(ME_SYSTEM_MODULESLOADED, OnModulesLoaded, this); -} diff --git a/plugins/Dbx_mdb/src/ui.h b/plugins/Dbx_mdb/src/ui.h deleted file mode 100644 index b20a43d623..0000000000 --- a/plugins/Dbx_mdb/src/ui.h +++ /dev/null @@ -1,187 +0,0 @@ -static IconItem iconList[] = -{ - { LPGEN("Logo"), "logo", IDI_LOGO }, - { LPGEN("Password"), "password", IDI_ICONPASS } -}; - -#define MS_DB_CHANGEPASSWORD "DB/UI/ChangePassword" - -class COptionsDialog : public CDlgBase -{ - CCtrlCheck m_chkStandart; - CCtrlCheck m_chkTotal; - CCtrlButton m_btnChangePass; - CDbxMdb *m_db; - - void OnInitDialog() - { - m_chkStandart.SetState(!m_db->isEncrypted()); - m_chkTotal.SetState(m_db->isEncrypted()); - m_btnChangePass.SetTextA(Translate(m_db->GetMenuTitle())); - } - - void OnApply() - { - m_db->EnableEncryption(m_chkTotal.GetState() != 0); - m_chkStandart.SetState(!m_db->isEncrypted()); - m_chkTotal.SetState(m_db->isEncrypted()); - } - - void ChangePass(CCtrlButton*) - { - CallService(MS_DB_CHANGEPASSWORD, 0, 0); - } - -public: - COptionsDialog(CDbxMdb *db) : - CDlgBase(g_hInst, IDD_OPTIONS), - m_chkStandart(this, IDC_STANDARD), - m_chkTotal(this, IDC_TOTAL), - m_btnChangePass(this, IDC_USERPASS), - m_db(db) - { - m_btnChangePass.OnClick = Callback(this, &COptionsDialog::ChangePass); - } -}; - -class CSelectCryptoDialog : public CDlgBase -{ - CCtrlCombo m_combo; - CCtrlData m_descr; - CCtrlCheck m_chkTotalCrypt; - CRYPTO_PROVIDER **m_provs; - size_t m_provscount; - CRYPTO_PROVIDER *m_selected; - bool m_bTotalEncryption; - - void OnInitDialog() - { - for (size_t i = 0; i < m_provscount; i++) - { - CRYPTO_PROVIDER *prov = m_provs[i]; - m_combo.AddStringA(prov->pszName, i); - } - m_combo.SetCurSel(0); - m_descr.SetText(m_provs[0]->ptszDescr); - } - - void OnClose() - { - m_selected = m_provs[ m_combo.GetItemData(m_combo.GetCurSel()) ]; - m_bTotalEncryption = m_chkTotalCrypt.GetState() != 0; - } - - void OnComboChanged(CCtrlCombo*) - { - m_descr.SetText(m_provs[m_combo.GetItemData(m_combo.GetCurSel())]->ptszDescr); - } - -public: - CSelectCryptoDialog(CRYPTO_PROVIDER **provs, size_t count) : - CDlgBase(g_hInst, IDD_SELECT_CRYPTOPROVIDER), - m_combo(this, IDC_SELECTCRYPT_COMBO), - m_descr(this, IDC_CRYPTOPROVIDER_DESCR), - m_chkTotalCrypt(this, IDC_CHECK_TOTALCRYPT), - m_provs(provs), - m_provscount(count), - m_selected(nullptr) - { - m_combo.OnChange = Callback(this, &CSelectCryptoDialog::OnComboChanged); - } - - inline CRYPTO_PROVIDER* GetSelected() - { - return m_selected; - } - inline bool TotalSelected() - { - return m_bTotalEncryption; - } -}; - -struct DlgChangePassParam -{ - CDbxMdb *db; - TCHAR newPass[100]; - unsigned short wrongPass; -}; - -class CEnterPasswordDialog : public CDlgBase -{ - CCtrlData m_header; - CCtrlData m_language; - CCtrlEdit m_passwordEdit; - CCtrlButton m_buttonOK; - - DlgChangePassParam *m_param; - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) - { - if (msg == WM_TIMER) - { - UINT_PTR LangID = (UINT_PTR)GetKeyboardLayout(0); - char Lang[3] = { 0 }; - GetLocaleInfoA(MAKELCID((LangID & 0xffffffff), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, Lang, 2); - Lang[0] = toupper(Lang[0]); - Lang[1] = tolower(Lang[1]); - m_language.SetTextA(Lang); - return FALSE; - } - else if (msg == WM_CTLCOLORSTATIC) - { - if ((HWND)lParam == m_language.GetHwnd()) { - SetTextColor((HDC)wParam, GetSysColor(COLOR_HIGHLIGHTTEXT)); - SetBkMode((HDC)wParam, TRANSPARENT); - return (INT_PTR)GetSysColorBrush(COLOR_HIGHLIGHT); - } - } - return CDlgBase::DlgProc(msg, wParam, lParam); - } - - void OnInitDialog() - { - m_header.SendMsg(WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_hInst, MAKEINTRESOURCE(iconList[0].defIconID))); - if (m_param->wrongPass) - { - if (m_param->wrongPass > 2) - { - m_passwordEdit.Disable(); - m_buttonOK.Disable(); - m_header.SetText(TranslateT("Too many errors!")); - } - else - { - m_header.SetText(TranslateT("Password is not correct!")); - } - } - else - { - m_header.SetText(TranslateT("Please type in your password")); - } - SetTimer(m_hwnd, 1, 200, NULL); - } - - void OnOK(CCtrlButton*) - { - m_passwordEdit.GetText(m_param->newPass, _countof(m_param->newPass)); - EndDialog(m_hwnd, -128); - } - - void OnDestroy() - { - KillTimer(m_hwnd, 1); - } - -public: - CEnterPasswordDialog(DlgChangePassParam *param) : - CDlgBase(g_hInst, IDD_LOGIN), - m_header(this, IDC_HEADERBAR), - m_language(this, IDC_LANG), - m_passwordEdit(this, IDC_USERPASS), - m_buttonOK(this, IDOK), - m_param(param) - { - m_buttonOK.OnClick = Callback(this, &CEnterPasswordDialog::OnOK); - } - -}; diff --git a/plugins/Dbx_mdb/src/version.h b/plugins/Dbx_mdb/src/version.h deleted file mode 100644 index 6d7f18b748..0000000000 --- a/plugins/Dbx_mdb/src/version.h +++ /dev/null @@ -1,13 +0,0 @@ -#define __MAJOR_VERSION 0 -#define __MINOR_VERSION 95 -#define __RELEASE_NUM 8 -#define __BUILD_NUM 1 - -#include - -#define __PLUGIN_NAME "Miranda NG LMDB database driver" -#define __FILENAME "Dbx_mdb.dll" -#define __DESCRIPTION "Provides Miranda database support: global settings, contacts, history, settings per contact." -#define __AUTHOR "Miranda-NG project" -#define __AUTHORWEB "https://miranda-ng.org/p/Dbx_mdb/" -#define __COPYRIGHT "© 2015-18 Miranda NG team" diff --git a/plugins/Dbx_mdbx/dbx_mdbx.vcxproj b/plugins/Dbx_mdbx/dbx_mdbx.vcxproj new file mode 100644 index 0000000000..54c0214bd5 --- /dev/null +++ b/plugins/Dbx_mdbx/dbx_mdbx.vcxproj @@ -0,0 +1,51 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + Dbx_mdbx + {E0ACDEA0-0AC9-4431-8CA3-6B0CCACB2E18} + + + + + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + + + + + + Sync + MDB_DEBUG=5;%(PreprocessorDefinitions) + + + \ No newline at end of file diff --git a/plugins/Dbx_mdbx/dbx_mdbx.vcxproj.filters b/plugins/Dbx_mdbx/dbx_mdbx.vcxproj.filters new file mode 100644 index 0000000000..de5ad9f66c --- /dev/null +++ b/plugins/Dbx_mdbx/dbx_mdbx.vcxproj.filters @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/plugins/Dbx_mdbx/res/dbx_mdbx.rc b/plugins/Dbx_mdbx/res/dbx_mdbx.rc new file mode 100644 index 0000000000..03c0486fe6 --- /dev/null +++ b/plugins/Dbx_mdbx/res/dbx_mdbx.rc @@ -0,0 +1,177 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Английский (США) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_SELECT_CRYPTOPROVIDER DIALOGEX 0, 0, 229, 76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Select crypto provider" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,113,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,172,55,50,14 + COMBOBOX IDC_SELECTCRYPT_COMBO,16,12,199,30,CBS_DROPDOWNLIST | CBS_SORT | WS_TABSTOP + LTEXT "",IDC_CRYPTOPROVIDER_DESCR,17,29,197,14,NOT WS_GROUP + CONTROL "Total encryption (Recommended only for paranoid users)",IDC_CHECK_TOTALCRYPT, + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,14,45,89,24 +END + +IDD_LOGIN DIALOGEX 0, 0, 190, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW +CAPTION "Login to Miranda NG" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,190,26 + CTEXT "",IDC_LANG,158,34,13,13,SS_CENTERIMAGE | NOT WS_GROUP + EDITTEXT IDC_USERPASS,21,34,128,14,ES_PASSWORD | ES_AUTOHSCROLL | WS_GROUP + DEFPUSHBUTTON "OK",IDOK,36,64,50,14 + PUSHBUTTON "Cancel",IDCANCEL,102,64,50,14 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,55,190,1 +END + +IDD_NEWPASS DIALOGEX 0, 0, 190, 102 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW +CAPTION "New password" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Please enter your new password",IDC_HEADERBAR, + "MHeaderbarCtrl",0x0,0,0,190,26 + CTEXT "",IDC_LANG,158,34,13,13,SS_CENTERIMAGE | NOT WS_GROUP + EDITTEXT IDC_USERPASS1,21,34,128,14,ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT IDC_USERPASS2,21,54,128,14,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "OK",IDOK,36,84,50,14 + PUSHBUTTON "Cancel",IDCANCEL,100,84,50,14 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,77,190,1 +END + +IDD_CHANGEPASS DIALOGEX 0, 0, 190, 148 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_TOOLWINDOW +CAPTION "Enter password" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Change password",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,190,26 + CTEXT "",IDC_LANG,158,42,13,13,SS_CENTERIMAGE | NOT WS_GROUP + EDITTEXT IDC_OLDPASS,21,42,128,14,ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT IDC_USERPASS1,21,77,128,14,ES_PASSWORD | ES_AUTOHSCROLL + EDITTEXT IDC_USERPASS2,21,98,128,14,ES_PASSWORD | ES_AUTOHSCROLL + DEFPUSHBUTTON "Change",IDOK,11,127,50,14 + PUSHBUTTON "Remove",IDREMOVE,69,127,50,14 + PUSHBUTTON "Cancel",IDCANCEL,126,127,50,14 + LTEXT "New password",IDC_STATIC,11,66,163,10,0,WS_EX_TRANSPARENT + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,0,119,190,1 + LTEXT "Old password",IDC_STATIC,11,31,140,10,0,WS_EX_TRANSPARENT +END + +IDD_OPTIONS DIALOGEX 0, 0, 318, 176 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "Database encryption mode",IDC_STATIC,6,22,305,125 + CONTROL "Standard",IDC_STANDARD,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,12,38,292,12 + CONTROL "Total",IDC_TOTAL,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,12,95,292,12 + LTEXT "Only critical data are encrypted (passwords, security tokens, etc). All other settings and history remains unencrypted. Fast and effective, suitable for the most cases",IDC_STATIC,22,54,284,37 + LTEXT "All string settings and all events in histories are encrypted. It also makes Miranda much slower and creates a risk of losing everything you've stored in a profile in case of losing password. Recommended only for paranoid users",IDC_STATIC,22,110,284,33 + PUSHBUTTON "Set password",IDC_USERPASS,200,153,111,17 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICONPASS ICON "pass.ico" +IDI_LOGO ICON "logo.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_SELECT_CRYPTOPROVIDER, DIALOG + BEGIN + END + + IDD_LOGIN, DIALOG + BEGIN + END + + IDD_CHANGEPASS, DIALOG + BEGIN + END + + IDD_OPTIONS, DIALOG + BEGIN + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include \0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Английский (США) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Dbx_mdbx/res/logo.ico b/plugins/Dbx_mdbx/res/logo.ico new file mode 100644 index 0000000000..f49bbe83d6 Binary files /dev/null and b/plugins/Dbx_mdbx/res/logo.ico differ diff --git a/plugins/Dbx_mdbx/res/pass.ico b/plugins/Dbx_mdbx/res/pass.ico new file mode 100644 index 0000000000..dc47a6ed4f Binary files /dev/null and b/plugins/Dbx_mdbx/res/pass.ico differ diff --git a/plugins/Dbx_mdbx/res/version.rc b/plugins/Dbx_mdbx/res/version.rc new file mode 100644 index 0000000000..fdeb14668c --- /dev/null +++ b/plugins/Dbx_mdbx/res/version.rc @@ -0,0 +1,55 @@ +// Microsoft Visual C++ generated resource script. +// +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include "..\src\version.h" + +#define APSTUDIO_READONLY_SYMBOLS +#include "afxres.h" +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Author", __AUTHOR + VALUE "FileDescription", __DESCRIPTION + VALUE "FileVersion", __VERSION_STRING + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// diff --git a/plugins/Dbx_mdbx/src/dbcontacts.cpp b/plugins/Dbx_mdbx/src/dbcontacts.cpp new file mode 100644 index 0000000000..1195c0af6e --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbcontacts.cpp @@ -0,0 +1,247 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +STDMETHODIMP_(LONG) CDbxMDBX::GetContactCount(void) +{ + return m_contactCount; +} + +STDMETHODIMP_(LONG) CDbxMDBX::GetContactSize(void) +{ + return sizeof(DBCachedContact); +} + +STDMETHODIMP_(LONG) CDbxMDBX::DeleteContact(MCONTACT contactID) +{ + if (contactID == 0) // global contact cannot be removed + return 1; + + NotifyEventHooks(hContactDeletedEvent, contactID, 0); + { + OBJLIST events(50); + GatherContactHistory(contactID, events); + while (events.getCount()) { + DeleteEvent(contactID, events[0].eventId); + events.remove(0); + } + } + { + MDBX_val key, data; + DBSettingKey keyS = { contactID, 0, 0 }; + + txn_ptr txn(m_env); + cursor_ptr cursor(txn, m_dbSettings); + + key.iov_len = sizeof(keyS); key.iov_base = &keyS; + + for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { + const DBSettingKey *pKey = (const DBSettingKey*)key.iov_base; + if (pKey->hContact != contactID) + break; + mdbx_cursor_del(cursor, 0); + } + + txn.commit(); + } + + MDBX_val key = { &contactID, sizeof(MCONTACT) }; + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_del(trnlck, m_dbContacts, &key, nullptr), 1); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + + InterlockedDecrement(&m_contactCount); + + return 0; +} + +STDMETHODIMP_(MCONTACT) CDbxMDBX::AddContact() +{ + MCONTACT dwContactId = InterlockedIncrement(&m_maxContactId); + + DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); + + MDBX_val key = { &dwContactId, sizeof(MCONTACT) }; + MDBX_val data = { &cc->dbc, sizeof(cc->dbc) }; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &key, &data, 0), 0); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + + InterlockedIncrement(&m_contactCount); + NotifyEventHooks(hContactAddedEvent, dwContactId, 0); + return dwContactId; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::IsDbContact(MCONTACT contactID) +{ + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + return (cc != NULL); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CDbxMDBX::GatherContactHistory(MCONTACT hContact, LIST &list) +{ + DBEventSortingKey keyVal = { 0, 0, hContact }; + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + + txn_ptr_ro trnlck(m_txn); + cursor_ptr_ro cursor(m_curEventsSort); + + for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { + const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; + if (pKey->hContact != hContact) + return; + + list.insert(new EventItem(pKey->ts, pKey->hEvent)); + } +} + +BOOL CDbxMDBX::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) +{ + LIST list(1000); + GatherContactHistory(ccSub->contactID, list); + + for (int i = 0; i < list.getCount(); i++) { + EventItem *EI = list[i]; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + DBEventSortingKey insVal = { EI->eventId, EI->ts, ccMeta->contactID }; + MDBX_val key = { &insVal, sizeof(insVal) }, data = { (void*)"", 1 }; + mdbx_put(trnlck, m_dbEventsSort, &key, &data, 0); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + ccMeta->dbc.dwEventCount++; + delete EI; + } + + MDBX_val keyc = { &ccMeta->contactID, sizeof(MCONTACT) }, datac = { &ccMeta->dbc, sizeof(ccMeta->dbc) }; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &keyc, &datac, 0), 1); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +BOOL CDbxMDBX::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) +{ + LIST list(1000); + GatherContactHistory(ccSub->contactID, list); + + for (int i = 0; i < list.getCount(); i++) { + EventItem *EI = list[i]; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + DBEventSortingKey insVal = { EI->eventId, EI->ts, ccMeta->contactID }; + MDBX_val key = { &insVal, sizeof(insVal) }, data = { (void*)"", 1 }; + mdbx_del(trnlck, m_dbEventsSort, &key, &data); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + ccMeta->dbc.dwEventCount--; + delete EI; + } + + MDBX_val keyc = { &ccMeta->contactID, sizeof(MCONTACT) }, datac = { &ccMeta->dbc, sizeof(ccMeta->dbc) }; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_put(trnlck, m_dbContacts, &keyc, &datac, 0), 1); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void DBCachedContact::Advance(MEVENT id, DBEvent &dbe) +{ + dbc.dwEventCount++; + + if (dbe.flags & (DBEF_READ | DBEF_SENT)) + return; + + if (dbe.timestamp < dbc.tsFirstUnread || dbc.tsFirstUnread == 0) { + dbc.tsFirstUnread = dbe.timestamp; + dbc.evFirstUnread = id; + } +} + +void DBCachedContact::Snapshot() +{ + tmp_dbc = dbc; +} + +void DBCachedContact::Revert() +{ + dbc = tmp_dbc; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// initial cycle to fill the contacts' cache + +void CDbxMDBX::FillContacts() +{ + LIST arContacts(m_contactCount); + + txn_ptr_ro trnlck(m_txn); + cursor_ptr_ro cursor(m_curContacts); + + MDBX_val key, data; + while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { + DBCachedContact *cc = m_cache->AddContactToCache(*(MCONTACT*)key.iov_base); + cc->dbc = *(DBContact*)data.iov_base; + + CheckProto(cc, ""); + + DBVARIANT dbv; dbv.type = DBVT_DWORD; + cc->nSubs = (0 != GetContactSetting(cc->contactID, META_PROTO, "NumContacts", &dbv)) ? -1 : dbv.dVal; + if (cc->nSubs != -1) { + cc->pSubs = (MCONTACT*)mir_alloc(cc->nSubs * sizeof(MCONTACT)); + for (int k = 0; k < cc->nSubs; k++) { + char setting[100]; + mir_snprintf(setting, _countof(setting), "Handle%d", k); + cc->pSubs[k] = (0 != GetContactSetting(cc->contactID, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; + } + } + cc->nDefault = (0 != GetContactSetting(cc->contactID, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; + cc->parentID = (0 != GetContactSetting(cc->contactID, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; + } +} diff --git a/plugins/Dbx_mdbx/src/dbcrypt.cpp b/plugins/Dbx_mdbx/src/dbcrypt.cpp new file mode 100644 index 0000000000..6142a7b577 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbcrypt.cpp @@ -0,0 +1,226 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +///////////////////////////////////////////////////////////////////////////////////////// + +char DBKey_Crypto_Provider[] = "Provider"; +char DBKey_Crypto_Key[] = "Key"; +char DBKey_Crypto_IsEncrypted[] = "EncryptedDB"; + +CRYPTO_PROVIDER* CDbxMDBX::SelectProvider() +{ + CRYPTO_PROVIDER **ppProvs, *pProv; + int iNumProvs; + Crypto_EnumProviders(&iNumProvs, &ppProvs); + + if (iNumProvs == 0) + return nullptr; + + bool bTotalCrypt = false; + + if (iNumProvs > 1) { + CSelectCryptoDialog dlg(ppProvs, iNumProvs); + dlg.DoModal(); + pProv = dlg.GetSelected(); + bTotalCrypt = dlg.TotalSelected(); + } + else pProv = ppProvs[0]; + + for (;; Remap()) { + txn_ptr txn(m_env); + + MDBX_val key = { DBKey_Crypto_Provider, sizeof(DBKey_Crypto_Provider) }, value = { pProv->pszName, mir_strlen(pProv->pszName) + 1 }; + MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), nullptr); + + key.iov_len = sizeof(DBKey_Crypto_IsEncrypted); key.iov_base = DBKey_Crypto_IsEncrypted; value.iov_len = sizeof(bool); value.iov_base = &bTotalCrypt; + MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), nullptr); + + if (txn.commit() == MDBX_SUCCESS) + break; + } + + return pProv; +} + +int CDbxMDBX::InitCrypt() +{ + CRYPTO_PROVIDER *pProvider; + + txn_ptr_ro txn(m_txn); + + MDBX_val key = { DBKey_Crypto_Provider, sizeof(DBKey_Crypto_Provider) }, value; + if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS) { + pProvider = Crypto_GetProvider((const char*)value.iov_base); + if (pProvider == nullptr) + pProvider = SelectProvider(); + } + else pProvider = SelectProvider(); + + if (pProvider == nullptr) + return 1; + + if ((m_crypto = pProvider->pFactory()) == nullptr) + return 3; + + key.iov_len = sizeof(DBKey_Crypto_Key); key.iov_base = DBKey_Crypto_Key; + if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS && (value.iov_len == m_crypto->getKeyLength())) { + if (!m_crypto->setKey((const BYTE*)value.iov_base, value.iov_len)) { + DlgChangePassParam param = { this }; + CEnterPasswordDialog dlg(¶m); + while (true) { + if (-128 != dlg.DoModal()) + return 4; + m_crypto->setPassword(pass_ptrA(mir_utf8encodeW(param.newPass))); + if (m_crypto->setKey((const BYTE*)value.iov_base, value.iov_len)) { + m_bUsesPassword = true; + SecureZeroMemory(¶m, sizeof(param)); + break; + } + param.wrongPass++; + } + } + } + else { + if (!m_crypto->generateKey()) + return 6; + StoreKey(); + } + + key.iov_len = sizeof(DBKey_Crypto_IsEncrypted); key.iov_base = DBKey_Crypto_IsEncrypted; + + if (mdbx_get(txn, m_dbCrypto, &key, &value) == MDBX_SUCCESS) + m_bEncrypted = *(const bool*)value.iov_base; + else + m_bEncrypted = false; + + InitDialogs(); + return 0; +} + +void CDbxMDBX::StoreKey() +{ + size_t iKeyLength = m_crypto->getKeyLength(); + BYTE *pKey = (BYTE*)_alloca(iKeyLength); + m_crypto->getKey(pKey, iKeyLength); + + for (;; Remap()) { + txn_ptr txn(m_env); + MDBX_val key = { DBKey_Crypto_Key, sizeof(DBKey_Crypto_Key) }, value = { pKey, iKeyLength }; + mdbx_put(txn, m_dbCrypto, &key, &value, 0); + if (txn.commit() == MDBX_SUCCESS) + break; + } + SecureZeroMemory(pKey, iKeyLength); +} + +void CDbxMDBX::SetPassword(const wchar_t *ptszPassword) +{ + if (ptszPassword == NULL || *ptszPassword == 0) { + m_bUsesPassword = false; + m_crypto->setPassword(NULL); + } + else { + m_bUsesPassword = true; + m_crypto->setPassword(pass_ptrA(mir_utf8encodeW(ptszPassword))); + } + UpdateMenuItem(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CDbxMDBX::EnableEncryption(bool bEncrypted) +{ + if (m_bEncrypted == bEncrypted) + return 0; + + { + txn_ptr_ro txnro(m_txn); + + MDBX_stat st; + mdbx_dbi_stat(txnro, m_dbEvents, &st, sizeof(st)); + + std::vector lstEvents; + lstEvents.reserve(st.ms_entries); + + { + cursor_ptr_ro cursor(m_curEvents); + MDBX_val key, data; + while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { + const MEVENT hDbEvent = *(const MEVENT*)key.iov_base; + lstEvents.push_back(hDbEvent); + } + } + for (auto it = lstEvents.begin(); it != lstEvents.end(); ++it) { + MEVENT &hDbEvent = *it; + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + mdbx_get(txnro, m_dbEvents, &key, &data); + + const DBEvent *dbEvent = (const DBEvent*)data.iov_base; + const BYTE *pBlob = (BYTE*)(dbEvent + 1); + + if (((dbEvent->flags & DBEF_ENCRYPTED) != 0) != bEncrypted) { + mir_ptr pNewBlob; + size_t nNewBlob; + uint32_t dwNewFlags; + + if (dbEvent->flags & DBEF_ENCRYPTED) { + pNewBlob = (BYTE*)m_crypto->decodeBuffer(pBlob, dbEvent->cbBlob, &nNewBlob); + dwNewFlags = dbEvent->flags & (~DBEF_ENCRYPTED); + } + else { + pNewBlob = m_crypto->encodeBuffer(pBlob, dbEvent->cbBlob, &nNewBlob); + dwNewFlags = dbEvent->flags | DBEF_ENCRYPTED; + } + + for (;; Remap()) { + txn_ptr txn(m_env); + data.iov_len = sizeof(DBEvent) + nNewBlob; + MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), 1); + + DBEvent *pNewDBEvent = (DBEvent *)data.iov_base; + *pNewDBEvent = *dbEvent; + pNewDBEvent->cbBlob = (uint16_t)nNewBlob; + pNewDBEvent->flags = dwNewFlags; + memcpy(pNewDBEvent + 1, pNewBlob, nNewBlob); + + + if (txn.commit() == MDBX_SUCCESS) + break; + } + } + } + } + + for (;; Remap()) { + txn_ptr txn(m_env); + MDBX_val key = { DBKey_Crypto_IsEncrypted, sizeof(DBKey_Crypto_IsEncrypted) }, value = { &bEncrypted, sizeof(bool) }; + MDBX_CHECK(mdbx_put(txn, m_dbCrypto, &key, &value, 0), 1); + if (txn.commit() == MDBX_SUCCESS) + break; + } + + m_bEncrypted = bEncrypted; + return 0; +} diff --git a/plugins/Dbx_mdbx/src/dbevents.cpp b/plugins/Dbx_mdbx/src/dbevents.cpp new file mode 100644 index 0000000000..3ad663a5a9 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbevents.cpp @@ -0,0 +1,428 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +STDMETHODIMP_(LONG) CDbxMDBX::GetEventCount(MCONTACT contactID) +{ + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + return (cc == NULL) ? 0 : cc->dbc.dwEventCount; +} + +STDMETHODIMP_(MEVENT) CDbxMDBX::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) +{ + if (dbei == NULL) return 0; + if (dbei->timestamp == 0) return 0; + + DBEvent dbe; + dbe.contactID = contactID; // store native or subcontact's id + dbe.iModuleId = GetModuleID(dbei->szModule); + + MCONTACT contactNotifyID = contactID; + DBCachedContact *cc, *ccSub = NULL; + if ((cc = m_cache->GetCachedContact(contactID)) == NULL) + return 0; + + if (cc->IsSub()) { + ccSub = cc; + if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) + return 0; + + // set default sub to the event's source + if (!(dbei->flags & DBEF_SENT)) + db_mc_setDefault(cc->contactID, contactID, false); + contactID = cc->contactID; // and add an event to a metahistory + if (db_mc_isEnabled()) + contactNotifyID = contactID; + } + + if (m_safetyMode) + if (NotifyEventHooks(hEventFilterAddedEvent, contactNotifyID, (LPARAM)dbei)) + return NULL; + + dbe.timestamp = dbei->timestamp; + dbe.flags = dbei->flags; + dbe.wEventType = dbei->eventType; + dbe.cbBlob = dbei->cbBlob; + BYTE *pBlob = dbei->pBlob; + + mir_ptr pCryptBlob; + if (m_bEncrypted) { + size_t len; + BYTE *pResult = m_crypto->encodeBuffer(pBlob, dbe.cbBlob, &len); + if (pResult != NULL) { + pCryptBlob = pBlob = pResult; + dbe.cbBlob = (uint16_t)len; + dbe.flags |= DBEF_ENCRYPTED; + } + } + + + MEVENT dwEventId = InterlockedIncrement(&m_dwMaxEventId); + + const auto Snapshot = [&]() { cc->Snapshot(); if (ccSub) ccSub->Snapshot(); }; + const auto Revert = [&]() { cc->Revert(); if (ccSub) ccSub->Revert(); }; + + for (Snapshot();; Revert(), Remap()) { + txn_ptr txn(m_env); + + MDBX_val key = { &dwEventId, sizeof(MEVENT) }, data = { NULL, sizeof(DBEvent) + dbe.cbBlob }; + MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), 0); + + DBEvent *pNewEvent = (DBEvent*)data.iov_base; + *pNewEvent = dbe; + memcpy(pNewEvent + 1, pBlob, dbe.cbBlob); + + // add a sorting key + DBEventSortingKey key2 = { contactID, dwEventId, dbe.timestamp }; + key.iov_len = sizeof(key2); key.iov_base = &key2; + data.iov_len = 1; data.iov_base = (char*)(""); + MDBX_CHECK(mdbx_put(txn, m_dbEventsSort, &key, &data, 0), 0); + + cc->Advance(dwEventId, dbe); + MDBX_val keyc = { &contactID, sizeof(MCONTACT) }, datac = { &cc->dbc, sizeof(DBContact) }; + MDBX_CHECK(mdbx_put(txn, m_dbContacts, &keyc, &datac, 0), 0); + + // insert an event into a sub's history too + if (ccSub != NULL) { + key2.hContact = ccSub->contactID; + MDBX_CHECK(mdbx_put(txn, m_dbEventsSort, &key, &data, 0), 0); + + ccSub->Advance(dwEventId, dbe); + datac.iov_base = &ccSub->dbc; + keyc.iov_base = &ccSub->contactID; + MDBX_CHECK(mdbx_put(txn, m_dbContacts, &keyc, &datac, 0), 0); + } + + if (txn.commit() == MDBX_SUCCESS) + break; + } + + // Notify only in safe mode or on really new events + if (m_safetyMode) + NotifyEventHooks(hEventAddedEvent, contactNotifyID, dwEventId); + + return dwEventId; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::DeleteEvent(MCONTACT contactID, MEVENT hDbEvent) +{ + DBCachedContact *cc = m_cache->GetCachedContact(contactID), *cc2 = nullptr; + if (cc == NULL || cc->dbc.dwEventCount == 0) + return 1; + + DBEvent dbe; + { + txn_ptr_ro txn(m_txn); + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return 1; + dbe = *(DBEvent*)data.iov_base; + } + + if (contactID != dbe.contactID) { + cc2 = m_cache->GetCachedContact(dbe.contactID); + } + + const auto Snapshot = [&]() { cc->Snapshot(); if (cc2) cc2->Snapshot(); }; + const auto Revert = [&]() { cc->Revert(); if (cc2) cc2->Revert(); }; + + for (Snapshot();; Revert(), Remap()) { + DBEventSortingKey key2 = { contactID, hDbEvent, dbe.timestamp }; + + txn_ptr txn(m_env); + MDBX_val key = { &key2, sizeof(key2) }, data; + + MDBX_CHECK(mdbx_del(txn, m_dbEventsSort, &key, &data), 1) + + { + key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; + cc->dbc.dwEventCount--; + if (cc->dbc.evFirstUnread == hDbEvent) + FindNextUnread(txn, cc, key2); + + data.iov_len = sizeof(DBContact); data.iov_base = &cc->dbc; + MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), 1); + } + + if (cc2) { + key2.hContact = dbe.contactID; + MDBX_CHECK(mdbx_del(txn, m_dbEventsSort, &key, &data), 1); + + key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; + cc2->dbc.dwEventCount--; + if (cc2->dbc.evFirstUnread == hDbEvent) + FindNextUnread(txn, cc2, key2); + + data.iov_len = sizeof(DBContact); data.iov_base = &cc2->dbc; + MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), 1); + + } + + // remove a event + key.iov_len = sizeof(MEVENT); key.iov_base = &hDbEvent; + MDBX_CHECK(mdbx_del(txn, m_dbEvents, &key, &data), 1); + + if (txn.commit() == MDBX_SUCCESS) + break; + } + + NotifyEventHooks(hEventDeletedEvent, contactID, hDbEvent); + + return 0; +} + +STDMETHODIMP_(LONG) CDbxMDBX::GetBlobSize(MEVENT hDbEvent) +{ + txn_ptr_ro txn(m_txn); + + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return -1; + return ((const DBEvent*)data.iov_base)->cbBlob; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei) +{ + if (dbei == NULL) return 1; + if (dbei->cbBlob > 0 && dbei->pBlob == NULL) { + dbei->cbBlob = 0; + return 1; + } + + txn_ptr_ro txn(m_txn); + + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return 1; + + const DBEvent *dbe = (const DBEvent*)data.iov_base; + + dbei->szModule = GetModuleName(dbe->iModuleId); + dbei->timestamp = dbe->timestamp; + dbei->flags = dbe->flags; + dbei->eventType = dbe->wEventType; + size_t bytesToCopy = min(dbei->cbBlob, dbe->cbBlob); + dbei->cbBlob = dbe->cbBlob; + if (bytesToCopy && dbei->pBlob) { + BYTE *pSrc = (BYTE*)data.iov_base + sizeof(DBEvent); + if (dbe->flags & DBEF_ENCRYPTED) { + dbei->flags &= ~DBEF_ENCRYPTED; + size_t len; + BYTE* pBlob = (BYTE*)m_crypto->decodeBuffer(pSrc, dbe->cbBlob, &len); + if (pBlob == NULL) + return 1; + + memcpy(dbei->pBlob, pBlob, bytesToCopy); + if (bytesToCopy > len) + memset(dbei->pBlob + len, 0, bytesToCopy - len); + mir_free(pBlob); + } + else memcpy(dbei->pBlob, pSrc, bytesToCopy); + } + return 0; +} + +void CDbxMDBX::FindNextUnread(const txn_ptr &txn, DBCachedContact *cc, DBEventSortingKey &key2) +{ + cursor_ptr cursor(txn, m_dbEventsSort); + + MDBX_val key = { &key2, sizeof(key2) }, data; + + for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { + const DBEvent *dbe = (const DBEvent*)data.iov_base; + if (dbe->contactID != cc->contactID) + break; + if (!dbe->markedRead()) { + cc->dbc.evFirstUnread = key2.hEvent; + cc->dbc.tsFirstUnread = key2.ts; + return; + } + } + + cc->dbc.evFirstUnread = cc->dbc.tsFirstUnread = 0; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) +{ + if (hDbEvent == 0) return -1; + + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + if (cc == NULL) + return -1; + + uint32_t wRetVal = -1; + + for (cc->Snapshot();; cc->Revert(), Remap()) { + txn_ptr txn(m_env); + + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + MDBX_CHECK(mdbx_get(txn, m_dbEvents, &key, &data), -1); + + const DBEvent *cdbe = (const DBEvent*)data.iov_base; + + if (cdbe->markedRead()) + return cdbe->flags; + + DBEventSortingKey keyVal = { contactID, hDbEvent, cdbe->timestamp }; + + MDBX_CHECK(mdbx_put(txn, m_dbEvents, &key, &data, MDBX_RESERVE), -1); + + DBEvent *pNewEvent = (DBEvent*)data.iov_base; + *pNewEvent = *cdbe; + + wRetVal = (pNewEvent->flags |= DBEF_READ); + + FindNextUnread(txn, cc, keyVal); + key.iov_len = sizeof(MCONTACT); key.iov_base = &contactID; + data.iov_base = &cc->dbc; data.iov_len = sizeof(cc->dbc); + MDBX_CHECK(mdbx_put(txn, m_dbContacts, &key, &data, 0), -1); + + if (txn.commit() == MDBX_SUCCESS) + break; + } + + NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); + return wRetVal; +} + +STDMETHODIMP_(MCONTACT) CDbxMDBX::GetEventContact(MEVENT hDbEvent) +{ + if (hDbEvent == 0) + return INVALID_CONTACT_ID; + + txn_ptr_ro txn(m_txn); + + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return INVALID_CONTACT_ID; + + return ((const DBEvent*)data.iov_base)->contactID; +} + +thread_local uint64_t t_tsLast = 0; +thread_local MEVENT t_evLast = 0; + +STDMETHODIMP_(MEVENT) CDbxMDBX::FindFirstEvent(MCONTACT contactID) +{ + DBEventSortingKey keyVal = { contactID, 0, 0 }; + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + + txn_ptr_ro txn(m_txn); + + cursor_ptr_ro cursor(m_curEventsSort); + if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE) != MDBX_SUCCESS) + return t_evLast = 0; + + const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; + t_tsLast = pKey->ts; + return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; +} + +STDMETHODIMP_(MEVENT) CDbxMDBX::FindFirstUnreadEvent(MCONTACT contactID) +{ + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + return (cc == NULL) ? 0 : cc->dbc.evFirstUnread; +} + +STDMETHODIMP_(MEVENT) CDbxMDBX::FindLastEvent(MCONTACT contactID) +{ + DBEventSortingKey keyVal = { contactID, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + + txn_ptr_ro txn(m_txn); + cursor_ptr_ro cursor(m_curEventsSort); + + if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE) != MDBX_SUCCESS) { + if (mdbx_cursor_get(cursor, &key, &data, MDBX_LAST) != MDBX_SUCCESS) + return t_evLast = 0; + } + else { + if (mdbx_cursor_get(cursor, &key, &data, MDBX_PREV) != MDBX_SUCCESS) + return t_evLast = 0; + } + + const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; + t_tsLast = pKey->ts; + return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; +} + +STDMETHODIMP_(MEVENT) CDbxMDBX::FindNextEvent(MCONTACT contactID, MEVENT hDbEvent) +{ + if (hDbEvent == 0) + return t_evLast = 0; + + txn_ptr_ro txn(m_txn); + + if (t_evLast != hDbEvent) { + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }, data; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return 0; + t_tsLast = ((DBEvent*)data.iov_base)->timestamp; + } + + DBEventSortingKey keyVal = { contactID, hDbEvent, t_tsLast }; + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + + cursor_ptr_ro cursor(m_curEventsSort); + if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET) != MDBX_SUCCESS) + return t_evLast = 0; + + if (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) != MDBX_SUCCESS) + return t_evLast = 0; + + const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; + t_tsLast = pKey->ts; + return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; +} + +STDMETHODIMP_(MEVENT) CDbxMDBX::FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) +{ + if (hDbEvent == 0) + return t_evLast = 0; + + MDBX_val data; + + txn_ptr_ro txn(m_txn); + + if (t_evLast != hDbEvent) { + MDBX_val key = { &hDbEvent, sizeof(MEVENT) }; + if (mdbx_get(txn, m_dbEvents, &key, &data) != MDBX_SUCCESS) + return 0; + t_tsLast = ((DBEvent*)data.iov_base)->timestamp; + } + + DBEventSortingKey keyVal = { contactID, hDbEvent, t_tsLast }; + MDBX_val key = { &keyVal, sizeof(keyVal) }; + + cursor_ptr_ro cursor(m_curEventsSort); + if (mdbx_cursor_get(cursor, &key, &data, MDBX_SET) != MDBX_SUCCESS) + return t_evLast = 0; + + if (mdbx_cursor_get(cursor, &key, &data, MDBX_PREV) != MDBX_SUCCESS) + return t_evLast = 0; + + const DBEventSortingKey *pKey = (const DBEventSortingKey*)key.iov_base; + t_tsLast = pKey->ts; + return t_evLast = (pKey->hContact == contactID) ? pKey->hEvent : 0; +} diff --git a/plugins/Dbx_mdbx/src/dbintf.cpp b/plugins/Dbx_mdbx/src/dbintf.cpp new file mode 100644 index 0000000000..09d350b6c9 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbintf.cpp @@ -0,0 +1,279 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +CDbxMDBX::CDbxMDBX(const TCHAR *tszFileName, int iMode) : + m_safetyMode(true), + m_bReadOnly((iMode & DBMODE_READONLY) != 0), + m_bShared((iMode & DBMODE_SHARED) != 0), + m_maxContactId(0) +{ + m_tszProfileName = mir_wstrdup(tszFileName); + InitDbInstance(this); + + mdbx_env_create(&m_env); + mdbx_env_set_maxdbs(m_env, 10); + mdbx_env_set_userctx(m_env, this); + // mdbx_env_set_assert(m_env, MDBX_FailAssert); +} + +CDbxMDBX::~CDbxMDBX() +{ + mdbx_env_close(m_env); + + DestroyServiceFunction(hService); + UnhookEvent(hHook); + + if (m_crypto) + m_crypto->destroy(); + + DestroyHookableEvent(hContactDeletedEvent); + DestroyHookableEvent(hContactAddedEvent); + DestroyHookableEvent(hSettingChangeEvent); + DestroyHookableEvent(hEventMarkedRead); + + DestroyHookableEvent(hEventAddedEvent); + DestroyHookableEvent(hEventDeletedEvent); + DestroyHookableEvent(hEventFilterAddedEvent); + + DestroyDbInstance(this); + mir_free(m_tszProfileName); +} + +int CDbxMDBX::Load(bool bSkipInit) +{ + if (Map() != MDBX_SUCCESS) + return EGROKPRF_CANTREAD; + + if (!bSkipInit) { + txn_ptr trnlck(m_env); + + unsigned int defFlags = MDBX_CREATE; + + mdbx_dbi_open(trnlck, "global", defFlags | MDBX_INTEGERKEY, &m_dbGlobal); + mdbx_dbi_open(trnlck, "crypto", defFlags, &m_dbCrypto); + mdbx_dbi_open(trnlck, "contacts", defFlags | MDBX_INTEGERKEY, &m_dbContacts); + mdbx_dbi_open(trnlck, "modules", defFlags | MDBX_INTEGERKEY, &m_dbModules); + mdbx_dbi_open(trnlck, "events", defFlags | MDBX_INTEGERKEY, &m_dbEvents); + + mdbx_dbi_open_ex(trnlck, "eventsrt", defFlags, &m_dbEventsSort, DBEventSortingKey::Compare, nullptr); + mdbx_dbi_open_ex(trnlck, "settings", defFlags, &m_dbSettings, DBSettingKey::Compare, nullptr); + { + uint32_t keyVal = 1; + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + if (mdbx_get(trnlck, m_dbGlobal, &key, &data) == MDBX_SUCCESS) { + const DBHeader *hdr = (const DBHeader*)data.iov_base; + if (hdr->dwSignature != DBHEADER_SIGNATURE) + return EGROKPRF_DAMAGED; + if (hdr->dwVersion != DBHEADER_VERSION) + return EGROKPRF_OBSOLETE; + + m_header = *hdr; + } + else { + m_header.dwSignature = DBHEADER_SIGNATURE; + m_header.dwVersion = DBHEADER_VERSION; + data.iov_base = &m_header; data.iov_len = sizeof(m_header); + mdbx_put(trnlck, m_dbGlobal, &key, &data, 0); + } + trnlck.commit(); + } + { + MDBX_val key, val; + + mdbx_txn_begin(m_env, nullptr, MDBX_RDONLY, &m_txn); + + mdbx_cursor_open(m_txn, m_dbEvents, &m_curEvents); + if (mdbx_cursor_get(m_curEvents, &key, &val, MDBX_LAST) == MDBX_SUCCESS) + m_dwMaxEventId = *(MEVENT*)key.iov_base; + + mdbx_cursor_open(m_txn, m_dbEventsSort, &m_curEventsSort); + mdbx_cursor_open(m_txn, m_dbSettings, &m_curSettings); + mdbx_cursor_open(m_txn, m_dbModules, &m_curModules); + + mdbx_cursor_open(m_txn, m_dbContacts, &m_curContacts); + if (mdbx_cursor_get(m_curContacts, &key, &val, MDBX_LAST) == MDBX_SUCCESS) + m_maxContactId = *(MCONTACT*)key.iov_base; + + MDBX_stat st; + mdbx_dbi_stat(m_txn, m_dbContacts, &st, sizeof(st)); + m_contactCount = st.ms_entries; + + mdbx_txn_reset(m_txn); + } + + + if (InitModules()) return EGROKPRF_DAMAGED; + if (InitCrypt()) return EGROKPRF_DAMAGED; + + // everything is ok, go on + if (!m_bReadOnly) { + // retrieve the event handles + hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED); + hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED); + hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED); + hEventMarkedRead = CreateHookableEvent(ME_DB_EVENT_MARKED_READ); + + hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED); + hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED); + hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD); + } + + FillContacts(); + } + + return EGROKPRF_NOERROR; +} + +int CDbxMDBX::Create(void) +{ + return (Map() == MDBX_SUCCESS) ? 0 : EGROKPRF_CANTREAD; +} + +size_t iDefHeaderOffset = 0; +BYTE bDefHeader[] = { 0 }; + +int CDbxMDBX::Check(void) +{ + FILE *pFile = _wfopen(m_tszProfileName, L"rb"); + if (pFile == nullptr) + return EGROKPRF_CANTREAD; + + fseek(pFile, (LONG)iDefHeaderOffset, SEEK_SET); + BYTE buf[_countof(bDefHeader)]; + size_t cbRead = fread(buf, 1, _countof(buf), pFile); + fclose(pFile); + if (cbRead != _countof(buf)) + return EGROKPRF_DAMAGED; + + return (memcmp(buf, bDefHeader, _countof(bDefHeader))) ? EGROKPRF_UNKHEADER : 0; +} + +int CDbxMDBX::PrepareCheck(int*) +{ + InitModules(); + return InitCrypt(); +} + +STDMETHODIMP_(void) CDbxMDBX::SetCacheSafetyMode(BOOL bIsSet) +{ + m_safetyMode = bIsSet != 0; +} + +int CDbxMDBX::Map() +{ + unsigned int mode = MDBX_NOSUBDIR | MDBX_MAPASYNC | MDBX_WRITEMAP | MDBX_NOSYNC; + if (m_bReadOnly) + mode |= MDBX_RDONLY; + mdbx_env_open(m_env, _T2A(m_tszProfileName), mode, 0664); + mdbx_env_set_mapsize(m_env, 0x1000000); + return MDBX_SUCCESS; +} + +bool CDbxMDBX::Remap() +{ + MDBX_envinfo ei; + mdbx_env_info(m_env, &ei, sizeof(ei)); + return mdbx_env_set_geometry(m_env, -1, -1, ei.mi_mapsize + 0x100000, 0x100000, -1, -1) == MDBX_SUCCESS; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static DWORD DatabaseCorrupted = 0; +static const TCHAR *msg = NULL; +static DWORD dwErr = 0; +static wchar_t tszPanic[] = LPGENW("Miranda has detected corruption in your database. This corruption may be fixed by DbChecker plugin. Please download it from https://miranda-ng.org/p/DbChecker/. Miranda will now shut down."); + +EXTERN_C void __cdecl dbpanic(void *) +{ + if (msg) { + if (dwErr == ERROR_DISK_FULL) + msg = TranslateT("Disk is full. Miranda will now shut down."); + + TCHAR err[256]; + mir_snwprintf(err, msg, TranslateT("Database failure. Miranda will now shut down."), dwErr); + + MessageBox(0, err, TranslateT("Database Error"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); + } + else MessageBox(0, TranslateW(tszPanic), TranslateT("Database Panic"), MB_SETFOREGROUND | MB_TOPMOST | MB_APPLMODAL | MB_ICONWARNING | MB_OK); + TerminateProcess(GetCurrentProcess(), 255); +} + + +EXTERN_C void MDBX_FailAssert(MDBX_env *env, const char *text) +{ + ((CDbxMDBX*)mdbx_env_get_userctx(env))->DatabaseCorruption(_A2T(text)); +} + +EXTERN_C void MDBX_Log(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + Netlib_Log(0, CMStringA().FormatV(fmt, args)); + va_end(args); +} + +void CDbxMDBX::DatabaseCorruption(const TCHAR *text) +{ + int kill = 0; + + if (DatabaseCorrupted == 0) { + DatabaseCorrupted++; + kill++; + msg = text; + dwErr = GetLastError(); + } + else { + /* db is already corrupted, someone else is dealing with it, wait here + so that we don't do any more damage */ + Sleep(INFINITE); + return; + } + + if (kill) { + _beginthread(dbpanic, 0, NULL); + Sleep(INFINITE); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// MIDatabaseChecker + +typedef int (CDbxMDBX::*CheckWorker)(int); + +int CDbxMDBX::Start(DBCHeckCallback *callback) +{ + cb = callback; + return ERROR_SUCCESS; +} + +int CDbxMDBX::CheckDb(int, int) +{ + return ERROR_OUT_OF_PAPER; +} + +void CDbxMDBX::Destroy() +{ + delete this; +} diff --git a/plugins/Dbx_mdbx/src/dbintf.h b/plugins/Dbx_mdbx/src/dbintf.h new file mode 100644 index 0000000000..fa5595dba3 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbintf.h @@ -0,0 +1,268 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 OWN_CACHED_CONTACT + +#include + +#pragma warning (disable: 4200) + +#define DBMODE_SHARED 0x0001 +#define DBMODE_READONLY 0x0002 + +#define DBVT_ENCRYPTED 250 +#define DBVT_UNENCRYPTED 251 + +#define MARKED_READ (DBEF_READ | DBEF_SENT) + +#include + +#define DBHEADER_VERSION MAKELONG(1, 4) + +#define DBHEADER_SIGNATURE 0x40DECADEu +struct DBHeader +{ + uint32_t dwSignature; + uint32_t dwVersion; // database format version +}; + +struct DBContact +{ + uint32_t dwEventCount; // number of events in the chain for this contact + MEVENT evFirstUnread; + uint64_t tsFirstUnread; +}; + +struct DBEvent +{ + MCONTACT contactID; // a contact this event belongs to + uint32_t iModuleId; // offset to a DBModuleName struct of the name of + uint64_t timestamp; // seconds since 00:00:00 01/01/1970 + uint32_t flags; // see m_database.h, db/event/add + uint16_t wEventType; // module-defined event type + uint16_t cbBlob; // number of bytes in the blob + + bool __forceinline markedRead() const + { + return (flags & MARKED_READ) != 0; + } +}; + +struct DBEventSortingKey +{ + MCONTACT hContact; + MEVENT hEvent; + uint64_t ts; + + static int Compare(const MDBX_val* a, const MDBX_val* b); +}; + +struct DBSettingKey +{ + MCONTACT hContact; + uint32_t dwModuleId; + char szSettingName[1]; + + static int Compare(const MDBX_val*, const MDBX_val*); +}; + +struct DBSettingValue +{ + BYTE type; + union + { + BYTE bVal; + WORD wVal; + DWORD dwVal; + char szVal[]; + + struct + { + size_t nLength; + BYTE bVal[]; + } blob; + }; +}; + +#include + +struct DBCachedContact : public DBCachedContactBase +{ + void Advance(MEVENT id, DBEvent &dbe); + void Snapshot(); + void Revert(); + DBContact dbc, tmp_dbc; +}; + +struct EventItem +{ + __forceinline EventItem(int _ts, MEVENT _id) : + ts(_ts), eventId(_id) + {} + + uint64_t ts; + MEVENT eventId; +}; + +struct CDbxMDBX : public MDatabaseCommon, public MIDatabaseChecker, public MZeroedObject +{ + friend class MDBXEventCursor; + + CDbxMDBX(const TCHAR *tszFileName, int mode); + virtual ~CDbxMDBX(); + + int Load(bool bSkipInit); + int Create(void); + int Check(void); + + void DatabaseCorruption(const TCHAR *ptszText); + + void StoreKey(void); + void SetPassword(const wchar_t *ptszPassword); + void UpdateMenuItem(void); + + int PrepareCheck(int*); + + __forceinline LPSTR GetMenuTitle() const { return m_bUsesPassword ? (char*)LPGEN("Change/remove password") : (char*)LPGEN("Set password"); } + + __forceinline bool isEncrypted() const { return m_bEncrypted; } + __forceinline bool usesPassword() const { return m_bUsesPassword; } + int EnableEncryption(bool bEnable); +public: + STDMETHODIMP_(BOOL) IsRelational(void) { return TRUE; } + STDMETHODIMP_(void) SetCacheSafetyMode(BOOL); + + STDMETHODIMP_(LONG) GetContactCount(void); + STDMETHODIMP_(LONG) DeleteContact(MCONTACT contactID); + STDMETHODIMP_(MCONTACT) AddContact(void); + STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID); + STDMETHODIMP_(LONG) GetContactSize(void); + + STDMETHODIMP_(LONG) GetEventCount(MCONTACT contactID); + STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, DBEVENTINFO *dbe); + STDMETHODIMP_(BOOL) DeleteEvent(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(LONG) GetBlobSize(MEVENT hDbEvent); + STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe); + STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent); + STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID); + STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent); + STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent); + + STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam); + + STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); + STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws); + STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting); + STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param); + + STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); + STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub); + +protected: + STDMETHODIMP_(BOOL) Start(DBCHeckCallback *callback); + STDMETHODIMP_(BOOL) CheckDb(int phase, int firstTime); + STDMETHODIMP_(VOID) Destroy(); + +protected: + + void FillContacts(void); + + int Map(); + bool Remap(); + +protected: + TCHAR* m_tszProfileName; + bool m_safetyMode, m_bReadOnly, m_bShared, m_bEncrypted, m_bUsesPassword; + + //////////////////////////////////////////////////////////////////////////// + // database stuff +public: + MICryptoEngine *m_crypto; + +protected: + MDBX_env *m_env; + CMDBX_txn_ro m_txn; + + MDBX_dbi m_dbGlobal; + DBHeader m_header; + + HANDLE hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent, hEventMarkedRead; + + //////////////////////////////////////////////////////////////////////////// + // settings + + MDBX_dbi m_dbSettings; + MDBX_cursor *m_curSettings; + + HANDLE hService, hHook; + + //////////////////////////////////////////////////////////////////////////// + // contacts + + MDBX_dbi m_dbContacts; + MDBX_cursor *m_curContacts; + + uint32_t m_contactCount; + MCONTACT m_maxContactId; + + void GatherContactHistory(MCONTACT hContact, LIST &items); + + //////////////////////////////////////////////////////////////////////////// + // events + + MDBX_dbi m_dbEvents, m_dbEventsSort; + MDBX_cursor *m_curEvents, *m_curEventsSort; + MEVENT m_dwMaxEventId; + + HANDLE hEventAddedEvent, hEventDeletedEvent, hEventFilterAddedEvent; + + void FindNextUnread(const txn_ptr &_txn, DBCachedContact *cc, DBEventSortingKey &key2); + + //////////////////////////////////////////////////////////////////////////// + // modules + + MDBX_dbi m_dbModules; + MDBX_cursor *m_curModules; + + std::map m_Modules; + + int InitModules(); + + uint32_t GetModuleID(const char *szName); + char* GetModuleName(uint32_t dwId); + + DBCHeckCallback *cb; + + //////////////////////////////////////////////////////////////////////////// + // encryption + + MDBX_dbi m_dbCrypto; + + int InitCrypt(void); + CRYPTO_PROVIDER* SelectProvider(); + + void InitDialogs(); +}; \ No newline at end of file diff --git a/plugins/Dbx_mdbx/src/dbmodulechain.cpp b/plugins/Dbx_mdbx/src/dbmodulechain.cpp new file mode 100644 index 0000000000..b9b29b4c5a --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbmodulechain.cpp @@ -0,0 +1,72 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +int CDbxMDBX::InitModules() +{ + txn_ptr_ro trnlck(m_txn); + cursor_ptr_ro cursor(m_curModules); + + MDBX_val key, data; + while (mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT) == MDBX_SUCCESS) { + uint32_t iMod = *(uint32_t*)key.iov_base; + const char *szMod = (const char*)data.iov_base; + m_Modules[iMod] = szMod; + } + return 0; +} + +// will create the offset if it needs to +uint32_t CDbxMDBX::GetModuleID(const char *szName) +{ + uint32_t iHash = mir_hashstr(szName); + if (m_Modules.find(iHash) == m_Modules.end()) { + MDBX_val key = { &iHash, sizeof(iHash) }, data = { (void*)szName, strlen(szName) + 1 }; + + for (;; Remap()) { + txn_ptr txn(m_env); + MDBX_CHECK(mdbx_put(txn, m_dbModules, &key, &data, 0), -1); + if (txn.commit() == MDBX_SUCCESS) + break; + } + m_Modules[iHash] = szName; + } + + return iHash; +} + +char* CDbxMDBX::GetModuleName(uint32_t dwId) +{ + auto it = m_Modules.find(dwId); + return it != m_Modules.end() ? const_cast(it->second.c_str()) : nullptr; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam) +{ + for (auto it = m_Modules.begin(); it != m_Modules.end(); ++it) + if (int ret = pFunc(it->second.c_str(), pParam)) + return ret; + + return 0; +} diff --git a/plugins/Dbx_mdbx/src/dbsettings.cpp b/plugins/Dbx_mdbx/src/dbsettings.cpp new file mode 100644 index 0000000000..eacf9d82c4 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbsettings.cpp @@ -0,0 +1,398 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +#define VLT(n) ((n == DBVT_UTF8 || n == DBVT_ENCRYPTED)?DBVT_ASCIIZ:n) + +static bool ValidLookupName(LPCSTR szModule, LPCSTR szSetting) +{ + if (!strcmp(szModule, META_PROTO)) + return strcmp(szSetting, "IsSubcontact") && strcmp(szSetting, "ParentMetaID"); + + if (!strcmp(szModule, "Ignore")) + return false; + + return true; +} + +int CDbxMDBX::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic) +{ + if (szSetting == NULL || szModule == NULL) + return 1; + + size_t settingNameLen = strlen(szSetting); + size_t moduleNameLen = strlen(szModule); + +LBL_Seek: + char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); + + DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); + if (pCachedValue != NULL) { + if (pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8) { + int cbOrigLen = dbv->cchVal; + char *cbOrigPtr = dbv->pszVal; + memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); + if (isStatic) { + int cbLen = 0; + if (pCachedValue->pszVal != NULL) + cbLen = (int)strlen(pCachedValue->pszVal); + + cbOrigLen--; + dbv->pszVal = cbOrigPtr; + if (cbLen < cbOrigLen) + cbOrigLen = cbLen; + memcpy(dbv->pszVal, pCachedValue->pszVal, cbOrigLen); + dbv->pszVal[cbOrigLen] = 0; + dbv->cchVal = cbLen; + } + else { + dbv->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal) + 1); + strcpy(dbv->pszVal, pCachedValue->pszVal); + } + } + else memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); + + return (pCachedValue->type == DBVT_DELETED) ? 1 : 0; + } + + // never look db for the resident variable + if (szCachedSettingName[-1] != 0) + return 1; + + DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; + + txn_ptr_ro trnlck(m_txn); + + DBSettingKey *keyVal = (DBSettingKey *)_alloca(sizeof(DBSettingKey) + settingNameLen); + keyVal->hContact = contactID; + keyVal->dwModuleId = GetModuleID(szModule); + memcpy(&keyVal->szSettingName, szSetting, settingNameLen + 1); + + + MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }, data; + if (mdbx_get(trnlck, m_dbSettings, &key, &data) != MDBX_SUCCESS) { + // try to get the missing mc setting from the active sub + if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { + if (contactID = db_mc_getDefault(contactID)) { + if (szModule = GetContactProto(contactID)) { + moduleNameLen = strlen(szModule); + goto LBL_Seek; + } + } + } + return 1; + } + + const BYTE *pBlob = (const BYTE*)data.iov_base; + if (isStatic && (pBlob[0] & DBVTF_VARIABLELENGTH) && VLT(dbv->type) != VLT(pBlob[0])) + return 1; + + int varLen; + BYTE iType = dbv->type = pBlob[0]; pBlob++; + switch (iType) { + case DBVT_DELETED: /* this setting is deleted */ + dbv->type = DBVT_DELETED; + return 2; + + case DBVT_BYTE: dbv->bVal = *pBlob; break; + case DBVT_WORD: dbv->wVal = *(WORD*)pBlob; break; + case DBVT_DWORD: dbv->dVal = *(DWORD*)pBlob; break; + + case DBVT_UTF8: + case DBVT_ASCIIZ: + varLen = *(WORD*)pBlob; + pBlob += 2; + if (isStatic) { + dbv->cchVal--; + if (varLen < dbv->cchVal) + dbv->cchVal = varLen; + memcpy(dbv->pszVal, pBlob, dbv->cchVal); // decode + dbv->pszVal[dbv->cchVal] = 0; + dbv->cchVal = varLen; + } + else { + dbv->pszVal = (char*)mir_alloc(1 + varLen); + memcpy(dbv->pszVal, pBlob, varLen); + dbv->pszVal[varLen] = 0; + } + break; + + case DBVT_BLOB: + varLen = *(WORD*)pBlob; + pBlob += 2; + if (isStatic) { + if (varLen < dbv->cpbVal) + dbv->cpbVal = varLen; + memcpy(dbv->pbVal, pBlob, dbv->cpbVal); + } + else { + dbv->pbVal = (BYTE *)mir_alloc(varLen); + memcpy(dbv->pbVal, pBlob, varLen); + } + dbv->cpbVal = varLen; + break; + + case DBVT_ENCRYPTED: + if (m_crypto == NULL) + return 1; + + varLen = *(WORD*)pBlob; + pBlob += 2; + + size_t realLen; + ptrA decoded(m_crypto->decodeString(pBlob, varLen, &realLen)); + if (decoded == NULL) + return 1; + + varLen = (WORD)realLen; + dbv->type = DBVT_UTF8; + if (isStatic) { + dbv->cchVal--; + if (varLen < dbv->cchVal) + dbv->cchVal = varLen; + memcpy(dbv->pszVal, decoded, dbv->cchVal); + dbv->pszVal[dbv->cchVal] = 0; + dbv->cchVal = varLen; + } + else { + dbv->pszVal = (char*)mir_alloc(1 + varLen); + memcpy(dbv->pszVal, decoded, varLen); + dbv->pszVal[varLen] = 0; + } + break; + } + + /**** add to cache **********************/ + if (iType != DBVT_BLOB && iType != DBVT_ENCRYPTED) { + pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); + if (pCachedValue != NULL) + m_cache->SetCachedVariant(dbv, pCachedValue); + } + + return 0; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) +{ + if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly) + return 1; + + // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name + size_t settingNameLen = strlen(dbcws->szSetting); + size_t moduleNameLen = strlen(dbcws->szModule); + + // used for notifications + DBCONTACTWRITESETTING dbcwNotif = *dbcws; + if (dbcwNotif.value.type == DBVT_WCHAR) { + if (dbcwNotif.value.pszVal != NULL) { + T2Utf val(dbcwNotif.value.pwszVal); + if (val == NULL) + return 1; + + dbcwNotif.value.pszVal = NEWSTR_ALLOCA(val); + dbcwNotif.value.type = DBVT_UTF8; + } + else return 1; + } + + if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL) + return 1; + + DBCONTACTWRITESETTING dbcwWork = dbcwNotif; + + mir_ptr pEncoded(NULL); + bool bIsEncrypted = false; + switch (dbcwWork.value.type) { + case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD: + break; + + case DBVT_ASCIIZ: case DBVT_UTF8: + bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting); +LBL_WriteString: + if (dbcwWork.value.pszVal == NULL) + return 1; + dbcwWork.value.cchVal = (WORD)strlen(dbcwWork.value.pszVal); + if (bIsEncrypted) { + size_t len; + BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); + if (pResult != NULL) { + pEncoded = dbcwWork.value.pbVal = pResult; + dbcwWork.value.cpbVal = (WORD)len; + dbcwWork.value.type = DBVT_ENCRYPTED; + } + } + break; + + case DBVT_UNENCRYPTED: + dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8; + goto LBL_WriteString; + + case DBVT_BLOB: case DBVT_ENCRYPTED: + if (dbcwWork.value.pbVal == NULL) + return 1; + break; + default: + return 1; + } + + char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); + + // we don't cache blobs and passwords + if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) { + DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); + if (pCachedValue != NULL) { + bool bIsIdentical = false; + if (pCachedValue->type == dbcwWork.value.type) { + switch (dbcwWork.value.type) { + case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal; break; + case DBVT_WORD: bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal; break; + case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal; break; + case DBVT_UTF8: + case DBVT_ASCIIZ: bIsIdentical = strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break; + } + if (bIsIdentical) + return 0; + } + m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); + } + if (szCachedSettingName[-1] != 0) { + NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork); + return 0; + } + } + else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); + + DBSettingKey *keyVal = (DBSettingKey *)_alloca(sizeof(DBSettingKey) + settingNameLen); + keyVal->hContact = contactID; + keyVal->dwModuleId = GetModuleID(dbcws->szModule); + memcpy(&keyVal->szSettingName, dbcws->szSetting, settingNameLen + 1); + + + MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }, data; + + switch (dbcwWork.value.type) { + case DBVT_BYTE: data.iov_len = 2; break; + case DBVT_WORD: data.iov_len = 3; break; + case DBVT_DWORD: data.iov_len = 5; break; + + case DBVT_ASCIIZ: + case DBVT_UTF8: + data.iov_len = 3 + dbcwWork.value.cchVal; break; + + case DBVT_BLOB: + case DBVT_ENCRYPTED: + data.iov_len = 3 + dbcwWork.value.cpbVal; break; + } + + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_put(trnlck, m_dbSettings, &key, &data, MDBX_RESERVE), 1); + + BYTE *pBlob = (BYTE*)data.iov_base; + *pBlob++ = dbcwWork.value.type; + switch (dbcwWork.value.type) { + case DBVT_BYTE: *pBlob = dbcwWork.value.bVal; break; + case DBVT_WORD: *(WORD*)pBlob = dbcwWork.value.wVal; break; + case DBVT_DWORD: *(DWORD*)pBlob = dbcwWork.value.dVal; break; + + case DBVT_ASCIIZ: + case DBVT_UTF8: + data.iov_len = *(WORD*)pBlob = dbcwWork.value.cchVal; + pBlob += 2; + memcpy(pBlob, dbcwWork.value.pszVal, dbcwWork.value.cchVal); + break; + + case DBVT_BLOB: + case DBVT_ENCRYPTED: + data.iov_len = *(WORD*)pBlob = dbcwWork.value.cpbVal; + pBlob += 2; + memcpy(pBlob, dbcwWork.value.pbVal, dbcwWork.value.cpbVal); + } + + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + + // notify + NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif); + return 0; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) +{ + if (!szModule || !szSetting) + return 1; + + size_t settingNameLen = strlen(szSetting); + size_t moduleNameLen = strlen(szModule); + + char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); + + if (szCachedSettingName[-1] == 0) // it's not a resident variable + { + DBSettingKey *keyVal = (DBSettingKey*)_alloca(sizeof(DBSettingKey) + settingNameLen); + keyVal->hContact = contactID; + keyVal->dwModuleId = GetModuleID(szModule); + memcpy(&keyVal->szSettingName, szSetting, settingNameLen + 1); + + MDBX_val key = { keyVal, sizeof(DBSettingKey) + settingNameLen }; + + for (;; Remap()) { + txn_ptr trnlck(m_env); + MDBX_CHECK(mdbx_del(trnlck, m_dbSettings, &key, nullptr), 1); + if (trnlck.commit() == MDBX_SUCCESS) + break; + } + } + + m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1); + + // notify + DBCONTACTWRITESETTING dbcws = { 0 }; + dbcws.szModule = szModule; + dbcws.szSetting = szSetting; + dbcws.value.type = DBVT_DELETED; + NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcws); + return 0; +} + +STDMETHODIMP_(BOOL) CDbxMDBX::EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) +{ + int result = -1; + + DBSettingKey keyVal = { hContact, GetModuleID(szModule), 0 }; + txn_ptr_ro txn(m_txn); + cursor_ptr_ro cursor(m_curSettings); + + MDBX_val key = { &keyVal, sizeof(keyVal) }, data; + + for (int res = mdbx_cursor_get(cursor, &key, &data, MDBX_SET_RANGE); res == MDBX_SUCCESS; res = mdbx_cursor_get(cursor, &key, &data, MDBX_NEXT)) { + const DBSettingKey *pKey = (const DBSettingKey*)key.iov_base; + if (pKey->hContact != hContact || pKey->dwModuleId != keyVal.dwModuleId) + break; + result = pfnEnumProc(pKey->szSettingName, param); + } + + return result; +} diff --git a/plugins/Dbx_mdbx/src/dbutils.cpp b/plugins/Dbx_mdbx/src/dbutils.cpp new file mode 100644 index 0000000000..147b43ef30 --- /dev/null +++ b/plugins/Dbx_mdbx/src/dbutils.cpp @@ -0,0 +1,47 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +#define CMP_UINT(x, y) { if ((x) != (y)) return (x) < (y) ? -1 : 1; } + +int DBEventSortingKey::Compare(const MDBX_val *ax, const MDBX_val *bx) +{ + const DBEventSortingKey *a = (DBEventSortingKey *)ax->iov_base; + const DBEventSortingKey *b = (DBEventSortingKey *)bx->iov_base; + + CMP_UINT(a->hContact, b->hContact); + CMP_UINT(a->ts, b->ts); + CMP_UINT(a->hEvent, b->hEvent); + return 0; +} + +int DBSettingKey::Compare(const MDBX_val *ax, const MDBX_val *bx) +{ + const DBSettingKey *a = (DBSettingKey *)ax->iov_base; + const DBSettingKey *b = (DBSettingKey *)bx->iov_base; + + CMP_UINT(a->hContact, b->hContact); + CMP_UINT(a->dwModuleId, b->dwModuleId); + return strcmp(a->szSettingName, b->szSettingName); +} diff --git a/plugins/Dbx_mdbx/src/init.cpp b/plugins/Dbx_mdbx/src/init.cpp new file mode 100644 index 0000000000..5ab23c14f8 --- /dev/null +++ b/plugins/Dbx_mdbx/src/init.cpp @@ -0,0 +1,133 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +int hLangpack; + +static PLUGININFOEX pluginInfo = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE | STATIC_PLUGIN, + // {7C3D0A33-2646-4001-9107-F35EA299D292} + { 0x7c3d0a33, 0x2646, 0x4001, { 0x91, 0x7, 0xf3, 0x5e, 0xa2, 0x99, 0xd2, 0x92 } } +}; + +HINSTANCE g_hInst = NULL; + +LIST g_Dbs(1, HandleKeySortT); + +///////////////////////////////////////////////////////////////////////////////////////// + +// returns 0 if the profile is created, EMKPRF* +static int makeDatabase(const TCHAR *profile) +{ + std::unique_ptr db(new CDbxMDBX(profile, 0)); + return db->Create(); +} + +// returns 0 if the given profile has a valid header +static int grokHeader(const TCHAR *profile) +{ + std::unique_ptr db(new CDbxMDBX(profile, DBMODE_SHARED | DBMODE_READONLY)); + return db->Check(); +} + +// returns 0 if all the APIs are injected otherwise, 1 +static MIDatabase* LoadDatabase(const TCHAR *profile, BOOL bReadOnly) +{ + // set the memory, lists & UTF8 manager + mir_getLP(&pluginInfo); + + std::unique_ptr db(new CDbxMDBX(profile, (bReadOnly) ? DBMODE_READONLY : 0)); + if (db->Load(false) != ERROR_SUCCESS) + return NULL; + + g_Dbs.insert(db.get()); + return db.release(); +} + +static int UnloadDatabase(MIDatabase *db) +{ + g_Dbs.remove((CDbxMDBX*)db); + delete (CDbxMDBX*)db; + return 0; +} + +MIDatabaseChecker* CheckDb(const TCHAR *profile, int *error) +{ + std::unique_ptr db(new CDbxMDBX(profile, DBMODE_READONLY)); + if (db->Load(true) != ERROR_SUCCESS) { + *error = ERROR_ACCESS_DENIED; + return NULL; + } + + if (db->PrepareCheck(error)) + return NULL; + + return db.release(); +} + +static DATABASELINK dblink = +{ + sizeof(DATABASELINK), + "dbx_mdbx", + L"MDBX database driver", + makeDatabase, + grokHeader, + LoadDatabase, + UnloadDatabase, + CheckDb +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_DATABASE, MIID_LAST }; + +extern "C" __declspec(dllexport) int Load(void) +{ + RegisterDatabasePlugin(&dblink); + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + return 0; +} + +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD, LPVOID) +{ + g_hInst = hInstDLL; + return TRUE; +} diff --git a/plugins/Dbx_mdbx/src/libmdbx b/plugins/Dbx_mdbx/src/libmdbx new file mode 160000 index 0000000000..18432ebfab --- /dev/null +++ b/plugins/Dbx_mdbx/src/libmdbx @@ -0,0 +1 @@ +Subproject commit 18432ebfab158ad2ae68a8a993040952f814dd95 diff --git a/plugins/Dbx_mdbx/src/resource.h b/plugins/Dbx_mdbx/src/resource.h new file mode 100644 index 0000000000..564189306d --- /dev/null +++ b/plugins/Dbx_mdbx/src/resource.h @@ -0,0 +1,35 @@ +//{{NO_DEPENDENCIES}} +// Включаемый файл, созданный в Microsoft Visual C++. +// Используется d:\Others\SVN\MirandaNG\trunk\plugins\Dbx_mdb\res\dbx_mdbx.rc +// +#define IDREMOVE 3 +#define IDI_ICONPASS 100 +#define IDI_LOGO 101 +#define IDD_LOGIN 102 +#define IDD_NEWPASS 103 +#define IDD_CHANGEPASS 104 +#define IDD_OPTIONS 105 +#define IDD_SELECT_CRYPTOPROVIDER 106 +#define IDC_HEADERBAR 1001 +#define IDC_LANG 1002 +#define IDC_USERPASS 1003 +#define IDC_USERPASS1 1004 +#define IDC_USERPASS2 1005 +#define IDC_OLDPASS 1006 +#define IDC_STANDARD 1007 +#define IDC_TOTAL 1008 +#define IDC_SELECTCRYPT_COMBO 1010 +#define IDC_CRYPTOPROVIDER_DESCR 1011 +#define IDC_CHECK1 1012 +#define IDC_CHECK_TOTALCRYPT 1012 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1013 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/Dbx_mdbx/src/stdafx.cxx b/plugins/Dbx_mdbx/src/stdafx.cxx new file mode 100644 index 0000000000..e579779bcc --- /dev/null +++ b/plugins/Dbx_mdbx/src/stdafx.cxx @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-18 Miranda NG team (https://miranda-ng.org) + +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 version 2 +of the License. + +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, see . +*/ + +#include "stdafx.h" \ No newline at end of file diff --git a/plugins/Dbx_mdbx/src/stdafx.h b/plugins/Dbx_mdbx/src/stdafx.h new file mode 100644 index 0000000000..25e91a4001 --- /dev/null +++ b/plugins/Dbx_mdbx/src/stdafx.h @@ -0,0 +1,169 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libmdbx/mdbx.h" + +#ifndef thread_local +# define thread_local __declspec(thread) +#endif + + +class txn_ptr +{ + MDBX_txn *m_txn; +public: + __forceinline txn_ptr(MDBX_env *pEnv) + { + mdbx_txn_begin(pEnv, NULL, 0, &m_txn); + } + + __forceinline ~txn_ptr() + { + if (m_txn) + mdbx_txn_abort(m_txn); + } + + __forceinline operator MDBX_txn*() const { return m_txn; } + + __forceinline int commit() + { + MDBX_txn *tmp = m_txn; + m_txn = nullptr; + return mdbx_txn_commit(tmp); + } + + __forceinline void abort() + { + mdbx_txn_abort(m_txn); + m_txn = NULL; + } +}; + +struct CMDBX_txn_ro +{ + MDBX_txn *m_txn; + bool bIsActive; + mir_cs cs; + + __forceinline CMDBX_txn_ro() : m_txn(nullptr), bIsActive(false) {} + + __forceinline operator MDBX_txn* () { return m_txn; } + __forceinline MDBX_txn** operator &() { return &m_txn; } +}; + +class txn_ptr_ro +{ + CMDBX_txn_ro &m_txn; + bool bNeedReset; + mir_cslock lock; +public: + __forceinline txn_ptr_ro(CMDBX_txn_ro &txn) : m_txn(txn), bNeedReset(!txn.bIsActive), lock(m_txn.cs) + { + if (bNeedReset) + { + mdbx_txn_renew(m_txn); + m_txn.bIsActive = true; + } + } + __forceinline ~txn_ptr_ro() + { + if (bNeedReset) + { + mdbx_txn_reset(m_txn); + m_txn.bIsActive = false; + } + } + __forceinline operator MDBX_txn*() const { return m_txn; } +}; + +class cursor_ptr +{ + MDBX_cursor *m_cursor; + +public: + __forceinline cursor_ptr(MDBX_txn *_txn, MDBX_dbi _dbi) + { + if (mdbx_cursor_open(_txn, _dbi, &m_cursor) != MDBX_SUCCESS) + m_cursor = NULL; + } + + __forceinline ~cursor_ptr() + { + if (m_cursor) + mdbx_cursor_close(m_cursor); + } + + __forceinline operator MDBX_cursor*() const { return m_cursor; } +}; + +class cursor_ptr_ro +{ + MDBX_cursor *m_cursor; +public: + __forceinline cursor_ptr_ro(MDBX_cursor *cursor) : m_cursor(cursor) + { + mdbx_cursor_renew(mdbx_cursor_txn(m_cursor), m_cursor); + } + __forceinline operator MDBX_cursor*() const { return m_cursor; } +}; + +#define MDBX_CHECK(A,B) \ + switch (A) { \ + case MDBX_SUCCESS: break; \ + case MDBX_MAP_FULL: continue; \ + default: return (B); } + + + + +#include "dbintf.h" +#include "resource.h" +#include "version.h" + +extern HINSTANCE g_hInst; +extern LIST g_Dbs; + +#include "ui.h" diff --git a/plugins/Dbx_mdbx/src/ui.cpp b/plugins/Dbx_mdbx/src/ui.cpp new file mode 100644 index 0000000000..6cf2f6bee8 --- /dev/null +++ b/plugins/Dbx_mdbx/src/ui.cpp @@ -0,0 +1,202 @@ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (c) 2012-18 Miranda NG team (https://miranda-ng.org) +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 "stdafx.h" + +static HGENMENU hSetPwdMenu; + +static UINT oldLangID; +void LanguageChanged(HWND hwndDlg) +{ + UINT_PTR LangID = (UINT_PTR)GetKeyboardLayout(0); + char Lang[3] = { 0 }; + if (LangID != oldLangID) { + oldLangID = LangID; + GetLocaleInfoA(MAKELCID((LangID & 0xffffffff), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, Lang, 2); + Lang[0] = toupper(Lang[0]); + Lang[1] = tolower(Lang[1]); + SetDlgItemTextA(hwndDlg, IDC_LANG, Lang); + } +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool CheckOldPassword(HWND hwndDlg, CDbxMDBX *db) +{ + if (db->usesPassword()) + { + TCHAR buf[100]; + GetDlgItemText(hwndDlg, IDC_OLDPASS, buf, _countof(buf)); + pass_ptrA oldPass(mir_utf8encodeW(buf)); + if (!db->m_crypto->checkPassword(oldPass)) + { + SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Wrong old password entered!")); + return false; + } + } + return true; +} + +static INT_PTR CALLBACK sttChangePassword(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + DlgChangePassParam *param = (DlgChangePassParam*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + TCHAR buf[100]; + + switch (uMsg) { + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_SETICON, ICON_SMALL, (LPARAM)IcoLib_GetIconByHandle(iconList[0].hIcolib, true)); + + param = (DlgChangePassParam*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + + oldLangID = 0; + SetTimer(hwndDlg, 1, 200, NULL); + LanguageChanged(hwndDlg); + return TRUE; + + case WM_CTLCOLORSTATIC: + if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_LANG)) { + SetTextColor((HDC)wParam, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkMode((HDC)wParam, TRANSPARENT); + return (INT_PTR)GetSysColorBrush(COLOR_HIGHLIGHT); + } + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hwndDlg, IDCANCEL); + break; + + case IDREMOVE: + if (!CheckOldPassword(hwndDlg, param->db)) { + LBL_Error: + SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_NCPAINT, 0, 0); + SetDlgItemTextA(hwndDlg, IDC_USERPASS1, ""); + SetDlgItemTextA(hwndDlg, IDC_USERPASS2, ""); + } + else { + // param->db->WriteSignature(dbSignatureU); + param->db->SetPassword(nullptr); + param->db->StoreKey(); + EndDialog(hwndDlg, IDREMOVE); + } + break; + + case IDOK: + TCHAR buf2[100]; + GetDlgItemText(hwndDlg, IDC_USERPASS1, buf2, _countof(buf2)); + if (wcslen(buf2) < 3) { + SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Password is too short!")); + goto LBL_Error; + } + + GetDlgItemText(hwndDlg, IDC_USERPASS2, buf, _countof(buf)); + if (wcscmp(buf2, buf)) { + SetDlgItemText(hwndDlg, IDC_HEADERBAR, TranslateT("Passwords do not match!")); + goto LBL_Error; + } + + if (!CheckOldPassword(hwndDlg, param->db)) + goto LBL_Error; + + // param->db->WriteSignature(dbSignatureE); + param->db->SetPassword(buf2); + param->db->StoreKey(); + SecureZeroMemory(buf2, sizeof(buf2)); + EndDialog(hwndDlg, IDOK); + } + break; + + case WM_TIMER: + LanguageChanged(hwndDlg); + return FALSE; + + case WM_DESTROY: + KillTimer(hwndDlg, 1); + IcoLib_ReleaseIcon((HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0)); + } + + return FALSE; +} + +static INT_PTR ChangePassword(void* obj, WPARAM, LPARAM) +{ + CDbxMDBX *db = (CDbxMDBX*)obj; + DlgChangePassParam param = { db }; + DialogBoxParam(g_hInst, MAKEINTRESOURCE(db->usesPassword() ? IDD_CHANGEPASS : IDD_NEWPASS), 0, sttChangePassword, (LPARAM)¶m); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + + +static int OnOptionsInit(PVOID obj, WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = { sizeof(odp) }; + odp.position = -790000000; + odp.flags = ODPF_BOLDGROUPS; + odp.szTitle.a = LPGEN("Database"); + odp.pDialog = new COptionsDialog((CDbxMDBX*)obj); + Options_AddPage(wParam, &odp); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CDbxMDBX::UpdateMenuItem() +{ + Menu_ModifyItem(hSetPwdMenu, _A2T(GetMenuTitle()), iconList[1].hIcolib); +} + +static int OnModulesLoaded(PVOID obj, WPARAM, LPARAM) +{ + CDbxMDBX *db = (CDbxMDBX*)obj; + + Icon_Register(g_hInst, LPGEN("Database"), iconList, _countof(iconList), "mdbx"); + + HookEventObj(ME_OPT_INITIALISE, OnOptionsInit, db); + + CMenuItem mi; + + // main menu item + mi.root = Menu_CreateRoot(MO_MAIN, LPGENW("Database"), 500000000, iconList[0].hIcolib); + Menu_ConfigureItem(mi.root, MCI_OPT_UID, "F7C5567C-D1EE-484B-B4F6-24677A5AAAEF"); + + SET_UID(mi, 0x50321866, 0xba1, 0x46dd, 0xb3, 0xa6, 0xc3, 0xcc, 0x55, 0xf2, 0x42, 0x9e); + mi.hIcolibItem = iconList[1].hIcolib; + mi.name.a = db->GetMenuTitle(); + mi.pszService = MS_DB_CHANGEPASSWORD; + hSetPwdMenu = Menu_AddMainMenuItem(&mi); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CDbxMDBX::InitDialogs() +{ + hService = CreateServiceFunctionObj(MS_DB_CHANGEPASSWORD, ChangePassword, this); + hHook = HookEventObj(ME_SYSTEM_MODULESLOADED, OnModulesLoaded, this); +} diff --git a/plugins/Dbx_mdbx/src/ui.h b/plugins/Dbx_mdbx/src/ui.h new file mode 100644 index 0000000000..704c380cfa --- /dev/null +++ b/plugins/Dbx_mdbx/src/ui.h @@ -0,0 +1,187 @@ +static IconItem iconList[] = +{ + { LPGEN("Logo"), "logo", IDI_LOGO }, + { LPGEN("Password"), "password", IDI_ICONPASS } +}; + +#define MS_DB_CHANGEPASSWORD "DB/UI/ChangePassword" + +class COptionsDialog : public CDlgBase +{ + CCtrlCheck m_chkStandart; + CCtrlCheck m_chkTotal; + CCtrlButton m_btnChangePass; + CDbxMDBX *m_db; + + void OnInitDialog() + { + m_chkStandart.SetState(!m_db->isEncrypted()); + m_chkTotal.SetState(m_db->isEncrypted()); + m_btnChangePass.SetTextA(Translate(m_db->GetMenuTitle())); + } + + void OnApply() + { + m_db->EnableEncryption(m_chkTotal.GetState() != 0); + m_chkStandart.SetState(!m_db->isEncrypted()); + m_chkTotal.SetState(m_db->isEncrypted()); + } + + void ChangePass(CCtrlButton*) + { + CallService(MS_DB_CHANGEPASSWORD, 0, 0); + } + +public: + COptionsDialog(CDbxMDBX *db) : + CDlgBase(g_hInst, IDD_OPTIONS), + m_chkStandart(this, IDC_STANDARD), + m_chkTotal(this, IDC_TOTAL), + m_btnChangePass(this, IDC_USERPASS), + m_db(db) + { + m_btnChangePass.OnClick = Callback(this, &COptionsDialog::ChangePass); + } +}; + +class CSelectCryptoDialog : public CDlgBase +{ + CCtrlCombo m_combo; + CCtrlData m_descr; + CCtrlCheck m_chkTotalCrypt; + CRYPTO_PROVIDER **m_provs; + size_t m_provscount; + CRYPTO_PROVIDER *m_selected; + bool m_bTotalEncryption; + + void OnInitDialog() + { + for (size_t i = 0; i < m_provscount; i++) + { + CRYPTO_PROVIDER *prov = m_provs[i]; + m_combo.AddStringA(prov->pszName, i); + } + m_combo.SetCurSel(0); + m_descr.SetText(m_provs[0]->ptszDescr); + } + + void OnClose() + { + m_selected = m_provs[ m_combo.GetItemData(m_combo.GetCurSel()) ]; + m_bTotalEncryption = m_chkTotalCrypt.GetState() != 0; + } + + void OnComboChanged(CCtrlCombo*) + { + m_descr.SetText(m_provs[m_combo.GetItemData(m_combo.GetCurSel())]->ptszDescr); + } + +public: + CSelectCryptoDialog(CRYPTO_PROVIDER **provs, size_t count) : + CDlgBase(g_hInst, IDD_SELECT_CRYPTOPROVIDER), + m_combo(this, IDC_SELECTCRYPT_COMBO), + m_descr(this, IDC_CRYPTOPROVIDER_DESCR), + m_chkTotalCrypt(this, IDC_CHECK_TOTALCRYPT), + m_provs(provs), + m_provscount(count), + m_selected(nullptr) + { + m_combo.OnChange = Callback(this, &CSelectCryptoDialog::OnComboChanged); + } + + inline CRYPTO_PROVIDER* GetSelected() + { + return m_selected; + } + inline bool TotalSelected() + { + return m_bTotalEncryption; + } +}; + +struct DlgChangePassParam +{ + CDbxMDBX *db; + TCHAR newPass[100]; + unsigned short wrongPass; +}; + +class CEnterPasswordDialog : public CDlgBase +{ + CCtrlData m_header; + CCtrlData m_language; + CCtrlEdit m_passwordEdit; + CCtrlButton m_buttonOK; + + DlgChangePassParam *m_param; + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) + { + if (msg == WM_TIMER) + { + UINT_PTR LangID = (UINT_PTR)GetKeyboardLayout(0); + char Lang[3] = { 0 }; + GetLocaleInfoA(MAKELCID((LangID & 0xffffffff), SORT_DEFAULT), LOCALE_SABBREVLANGNAME, Lang, 2); + Lang[0] = toupper(Lang[0]); + Lang[1] = tolower(Lang[1]); + m_language.SetTextA(Lang); + return FALSE; + } + else if (msg == WM_CTLCOLORSTATIC) + { + if ((HWND)lParam == m_language.GetHwnd()) { + SetTextColor((HDC)wParam, GetSysColor(COLOR_HIGHLIGHTTEXT)); + SetBkMode((HDC)wParam, TRANSPARENT); + return (INT_PTR)GetSysColorBrush(COLOR_HIGHLIGHT); + } + } + return CDlgBase::DlgProc(msg, wParam, lParam); + } + + void OnInitDialog() + { + m_header.SendMsg(WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(g_hInst, MAKEINTRESOURCE(iconList[0].defIconID))); + if (m_param->wrongPass) + { + if (m_param->wrongPass > 2) + { + m_passwordEdit.Disable(); + m_buttonOK.Disable(); + m_header.SetText(TranslateT("Too many errors!")); + } + else + { + m_header.SetText(TranslateT("Password is not correct!")); + } + } + else + { + m_header.SetText(TranslateT("Please type in your password")); + } + SetTimer(m_hwnd, 1, 200, NULL); + } + + void OnOK(CCtrlButton*) + { + m_passwordEdit.GetText(m_param->newPass, _countof(m_param->newPass)); + EndDialog(m_hwnd, -128); + } + + void OnDestroy() + { + KillTimer(m_hwnd, 1); + } + +public: + CEnterPasswordDialog(DlgChangePassParam *param) : + CDlgBase(g_hInst, IDD_LOGIN), + m_header(this, IDC_HEADERBAR), + m_language(this, IDC_LANG), + m_passwordEdit(this, IDC_USERPASS), + m_buttonOK(this, IDOK), + m_param(param) + { + m_buttonOK.OnClick = Callback(this, &CEnterPasswordDialog::OnOK); + } + +}; diff --git a/plugins/Dbx_mdbx/src/version.h b/plugins/Dbx_mdbx/src/version.h new file mode 100644 index 0000000000..0b97e64886 --- /dev/null +++ b/plugins/Dbx_mdbx/src/version.h @@ -0,0 +1,13 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 95 +#define __RELEASE_NUM 8 +#define __BUILD_NUM 1 + +#include + +#define __PLUGIN_NAME "Miranda NG MDBX database driver (https://github.com/leo-yuriev/libmdbx)" +#define __FILENAME "dbx_mdbx.dll" +#define __DESCRIPTION "Provides Miranda database support: global settings, contacts, history, settings per contact." +#define __AUTHOR "Miranda-NG project" +#define __AUTHORWEB "https://miranda-ng.org/p/dbx_mdbx/" +#define __COPYRIGHT "© 2015-18 Miranda NG team" -- cgit v1.2.3