From de40f3be3f08487937525c2ef096dad665dda61d Mon Sep 17 00:00:00 2001 From: dartraiden Date: Sat, 14 Jan 2023 01:30:59 +0300 Subject: Convert sources to CR+LF --- src/mir_app/src/MDatabaseCommon.cpp | 1322 +++++++++++------------ src/mir_core/src/Windows/CCtrlTreeOpts.cpp | 418 ++++---- src/mir_core/src/Windows/CCtrlTreeView.cpp | 1600 ++++++++++++++-------------- src/mir_core/src/Windows/miranda.cpp | 812 +++++++------- src/mir_core/src/db.cpp | 1152 ++++++++++---------- 5 files changed, 2652 insertions(+), 2652 deletions(-) (limited to 'src') diff --git a/src/mir_app/src/MDatabaseCommon.cpp b/src/mir_app/src/MDatabaseCommon.cpp index 323954a516..b8084148f7 100644 --- a/src/mir_app/src/MDatabaseCommon.cpp +++ b/src/mir_app/src/MDatabaseCommon.cpp @@ -1,661 +1,661 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-23 Miranda NG team, -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" -#include "database.h" - -static int stringCompare2(const char *p1, const char *p2) -{ - return mir_strcmp(p1, p2); -} - -MDatabaseCommon::MDatabaseCommon() : - m_lResidentSettings(50, stringCompare2) -{ - m_codePage = Langpack_GetDefaultCodePage(); - m_cache = new MDatabaseCache(this); -} - -MDatabaseCommon::~MDatabaseCommon() -{ - if (m_crypto) - m_crypto->destroy(); - - UnlockName(); - delete (MDatabaseCache*)m_cache; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int MDatabaseCommon::CheckProto(DBCachedContact *cc, const char *proto) -{ - if (cc->szProto == nullptr) { - char protobuf[MAX_PATH] = { 0 }; - DBVARIANT dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = protobuf; - dbv.cchVal = sizeof(protobuf); - if (GetContactSettingStatic(cc->contactID, "Protocol", "p", &dbv) != 0 || (dbv.type != DBVT_ASCIIZ)) - return 0; - - cc->szProto = m_cache->GetCachedSetting(nullptr, protobuf, 0, mir_strlen(protobuf)); - } - - return !mir_strcmp(cc->szProto, proto); -} - -void MDatabaseCommon::FillContactSettings() -{ - for (DBCachedContact *cc = m_cache->GetFirstContact(); cc; cc = m_cache->GetNextContact(cc->contactID)) { - 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)) ? 0 : 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)) ? 0 : dbv.dVal; - } -} - -bool MDatabaseCommon::LockName(const wchar_t *pwszProfileName) -{ - if (m_hLock != nullptr) - return true; - - if (pwszProfileName == nullptr) - return false; - - CMStringW wszPhysName(pwszProfileName); - wszPhysName.Replace(L"\\", L"_"); - wszPhysName.Insert(0, L"Global\\"); - - HANDLE hMutex = ::CreateMutexW(nullptr, false, wszPhysName); - if (hMutex == nullptr) - return false; - - if (GetLastError() == ERROR_ALREADY_EXISTS) { - ::CloseHandle(hMutex); - return false; - } - - m_hLock = hMutex; - return true; -} - -void MDatabaseCommon::UnlockName() -{ - if (m_hLock) { - CloseHandle(m_hLock); - m_hLock = nullptr; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Modules - -static int sttEnumVars(const char *szVarName, void *param) -{ - LIST* vars = (LIST*)param; - vars->insert(mir_strdup(szVarName)); - return 0; -} - -BOOL MDatabaseCommon::DeleteModule(MCONTACT hContact, LPCSTR szModule) -{ - LIST vars(20); - EnumContactSettings(hContact, sttEnumVars, szModule, &vars); - - for (auto &it : vars.rev_iter()) { - DeleteContactSetting(hContact, szModule, it); - mir_free(it); - } - return 0; -} - -BOOL MDatabaseCommon::Compact(void) -{ - return ERROR_NOT_SUPPORTED; -} - -BOOL MDatabaseCommon::Backup(LPCWSTR) -{ - return ERROR_NOT_SUPPORTED; -} - -BOOL MDatabaseCommon::Flush(void) -{ - return ERROR_NOT_SUPPORTED; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Contacts - -STDMETHODIMP_(MCONTACT) MDatabaseCommon::FindFirstContact(const char *szProto) -{ - mir_cslock lck(m_csDbAccess); - DBCachedContact *cc = m_cache->GetFirstContact(); - if (cc == nullptr) - return 0; - - if (!szProto || CheckProto(cc, szProto)) - return cc->contactID; - - return FindNextContact(cc->contactID, szProto); -} - -STDMETHODIMP_(MCONTACT) MDatabaseCommon::FindNextContact(MCONTACT contactID, const char *szProto) -{ - mir_cslock lck(m_csDbAccess); - while (contactID) { - DBCachedContact *cc = m_cache->GetNextContact(contactID); - if (cc == nullptr) - break; - - if (!szProto || CheckProto(cc, szProto)) - return cc->contactID; - - contactID = cc->contactID; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Meta-contacts support - -BOOL MDatabaseCommon::MetaDetouchSub(DBCachedContact *cc, int nSub) -{ - return DeleteModule(cc->pSubs[nSub], META_PROTO); -} - -BOOL MDatabaseCommon::MetaSetDefault(DBCachedContact *cc) -{ - DBVARIANT dbv; - dbv.type = DBVT_DWORD; - dbv.dVal = cc->nDefault; - return WriteContactSetting(cc->contactID, META_PROTO, "Default", &dbv); -} - -BOOL MDatabaseCommon::MetaRemoveSubHistory(DBCachedContact*) -{ - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Getting settings - -STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) -{ - dbv->type = 0; - if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 0)) - return 1; - - if (dbv->type == DBVT_UTF8) { - wchar_t *tmp = mir_utf8decodeW(dbv->pszVal); - if (tmp != nullptr) { - mir_free(dbv->pszVal); - dbv->type = DBVT_WCHAR; - dbv->pwszVal = tmp; - } - else { - dbv->type = DBVT_ASCIIZ; - mir_free(tmp); - } - } - - return 0; -} - -STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) -{ - int iSaveType = dbv->type; - - if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 0)) - return 1; - - if (iSaveType == 0 || iSaveType == dbv->type) - return 0; - - if (dbv->type != DBVT_ASCIIZ && dbv->type != DBVT_UTF8) - return 1; - - if (iSaveType == DBVT_WCHAR) { - if (dbv->type != DBVT_UTF8) { - int len = MultiByteToWideChar(CP_ACP, 0, dbv->pszVal, -1, nullptr, 0); - wchar_t* wszResult = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); - if (wszResult == nullptr) - return 1; - - MultiByteToWideChar(CP_ACP, 0, dbv->pszVal, -1, wszResult, len); - wszResult[len] = 0; - mir_free(dbv->pszVal); - dbv->pwszVal = wszResult; - } - else { - char* savePtr = NEWSTR_ALLOCA(dbv->pszVal); - mir_free(dbv->pszVal); - if (!mir_utf8decode(savePtr, &dbv->pwszVal)) - return 1; - } - } - else if (iSaveType == DBVT_UTF8) { - char* tmpBuf = mir_utf8encode(dbv->pszVal); - if (tmpBuf == nullptr) - return 1; - - mir_free(dbv->pszVal); - dbv->pszVal = tmpBuf; - } - else if (iSaveType == DBVT_ASCIIZ) - mir_utf8decode(dbv->pszVal, nullptr); - - dbv->type = iSaveType; - return 0; -} - -STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) -{ - bool bNeedsWchars; - size_t cbSaved = 0; - - if (dbv->type == DBVT_WCHAR) { // there's no wchar_t strings in a database, we need conversion - cbSaved = dbv->cchVal - 1; - dbv->cchVal *= sizeof(wchar_t); // extend a room for the utf8 string - dbv->type = DBVT_UTF8; - bNeedsWchars = true; - } - else bNeedsWchars = false; - - if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 1)) - return 1; - - if (bNeedsWchars) { - char *pBuf = NEWSTR_ALLOCA(dbv->pszVal); - int cbLen = Utf8toUcs2(pBuf, dbv->cchVal, dbv->pwszVal, cbSaved); - if (cbLen < 0) - return 1; - - dbv->pwszVal[cbLen] = 0; - } - else if (dbv->type == DBVT_UTF8) { - mir_utf8decode(dbv->pszVal, nullptr); - dbv->type = DBVT_ASCIIZ; - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static bool ValidLookupName(const char *szModule, const char *szSetting) -{ - if (!strcmp(szModule, META_PROTO)) - return strcmp(szSetting, "IsSubcontact") && strcmp(szSetting, "ParentMetaID"); - - return false; -} - -STDMETHODIMP_(int) MDatabaseCommon::GetContactSettingWorker(MCONTACT contactID, const char *szModule, const char *szSetting, DBVARIANT *dbv, int isStatic) -{ - if (szSetting == nullptr || szModule == nullptr) - return 1; - - DBVARIANT *pCachedValue; - size_t settingNameLen = strlen(szSetting); - size_t moduleNameLen = strlen(szModule); - { - mir_cslock lck(m_csDbAccess); - -LBL_Seek: - char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); - - pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); - if (pCachedValue == nullptr) { - // if nothing was faund, try to lookup the same setting from meta's default contact - if (contactID) { - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { - if (contactID = db_mc_getDefault(contactID)) { - szModule = Proto_GetBaseAccountName(contactID); - if (szModule == nullptr) // smth went wrong - return 1; - - moduleNameLen = strlen(szModule); - goto LBL_Seek; - } - } - } - - // otherwise fail - return 1; - } - } - - switch(pCachedValue->type) { - case DBVT_ASCIIZ: - case DBVT_UTF8: - dbv->type = pCachedValue->type; - if (isStatic) { - int cbLen = (int)mir_strlen(pCachedValue->pszVal); - int cbOrigLen = dbv->cchVal; - cbOrigLen--; - 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); - dbv->cchVal = pCachedValue->cchVal; - } - break; - - case DBVT_BLOB: - dbv->type = DBVT_BLOB; - if (isStatic) { - if (pCachedValue->cpbVal < dbv->cpbVal) - dbv->cpbVal = pCachedValue->cpbVal; - memcpy(dbv->pbVal, pCachedValue->pbVal, dbv->cpbVal); - } - else { - dbv->pbVal = (uint8_t *)mir_alloc(pCachedValue->cpbVal); - memcpy(dbv->pbVal, pCachedValue->pbVal, pCachedValue->cpbVal); - } - dbv->cpbVal = pCachedValue->cpbVal; - break; - - case DBVT_ENCRYPTED: - if (m_crypto != nullptr) { - size_t realLen; - ptrA decoded(m_crypto->decodeString(pCachedValue->pbVal, pCachedValue->cpbVal, &realLen)); - if (decoded == nullptr) - return 1; - - dbv->type = DBVT_UTF8; - if (isStatic) { - dbv->cchVal--; - if (realLen < dbv->cchVal) - dbv->cchVal = uint16_t(realLen); - memcpy(dbv->pszVal, decoded, dbv->cchVal); - dbv->pszVal[dbv->cchVal] = 0; - dbv->cchVal = uint16_t(realLen); - } - else { - dbv->pszVal = (char *)mir_alloc(1 + realLen); - memcpy(dbv->pszVal, decoded, realLen); - dbv->pszVal[realLen] = 0; - } - break; - } - return 1; - - default: - memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP_(BOOL) MDatabaseCommon::FreeVariant(DBVARIANT *dbv) -{ - if (dbv == nullptr) return 1; - - switch (dbv->type) { - case DBVT_ASCIIZ: - case DBVT_UTF8: - case DBVT_WCHAR: - if (dbv->pszVal) mir_free(dbv->pszVal); - dbv->pszVal = nullptr; - break; - case DBVT_BLOB: - if (dbv->pbVal) mir_free(dbv->pbVal); - dbv->pbVal = nullptr; - break; - } - dbv->type = 0; - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP_(BOOL) MDatabaseCommon::WriteContactSetting(MCONTACT contactID, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (dbv == nullptr || szSetting == nullptr || szModule == nullptr) - return 1; - - // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name - size_t settingNameLen = strlen(szSetting); - size_t moduleNameLen = strlen(szModule); - - // used for notifications - DBCONTACTWRITESETTING dbcwNotif = {szModule, szSetting, *dbv}; - if (dbcwNotif.value.type == DBVT_WCHAR) { - if (dbcwNotif.value.pszVal != nullptr) { - T2Utf val(dbcwNotif.value.pwszVal); - if (!val) - return 1; - - dbcwNotif.value.pszVal = NEWSTR_ALLOCA(val); - dbcwNotif.value.type = DBVT_UTF8; - } - else return 1; - } - - if (dbcwNotif.szModule == nullptr || dbcwNotif.szSetting == nullptr) - return 1; - - DBCONTACTWRITESETTING dbcwWork = dbcwNotif; - - mir_ptr pEncoded(nullptr); - 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(szModule, szSetting); - if (dbcwWork.value.pszVal == nullptr) - return 1; - - dbcwWork.value.cchVal = (uint16_t)strlen(dbcwWork.value.pszVal); - if (bIsEncrypted && m_crypto) { - size_t len; - uint8_t *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); - if (pResult != nullptr) { - pEncoded = dbcwWork.value.pbVal = pResult; - dbcwWork.value.cpbVal = (uint16_t)len; - dbcwWork.value.type = DBVT_ENCRYPTED; - } - } - break; - - case DBVT_BLOB: - case DBVT_ENCRYPTED: - if (dbcwWork.value.pbVal == nullptr) - return 1; - break; - - default: - return 1; - } - - mir_cslockfull lck(m_csDbAccess); - char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); - - DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); - if (pCachedValue != nullptr) { - 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; - case DBVT_BLOB: - case DBVT_ENCRYPTED: - if (pCachedValue->cpbVal == dbcwWork.value.cchVal) - bIsIdentical = memcmp(pCachedValue->pbVal, dbcwWork.value.pbVal, dbcwWork.value.cchVal); - break; - } - if (bIsIdentical) - return 0; - } - m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); - } - - // for non-resident settings we call a write worker - if (szCachedSettingName[-1] == 0) - if (WriteContactSettingWorker(contactID, dbcwWork)) - return 1; - - lck.unlock(); - NotifyEventHooks(g_hevSettingChanged, contactID, (LPARAM)&dbcwNotif); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Resident settings - -STDMETHODIMP_(BOOL) MDatabaseCommon::EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam) -{ - for (auto &it : m_lResidentSettings) { - int ret = pFunc(it, pParam); - if (ret) - return ret; - } - return 0; -} - -STDMETHODIMP_(BOOL) MDatabaseCommon::SetSettingResident(BOOL bIsResident, const char *pszSettingName) -{ - char *szSetting = m_cache->GetCachedSetting(nullptr, pszSettingName, 0, mir_strlen(pszSettingName)); - szSetting[-1] = (char)bIsResident; - - mir_cslock lck(m_csDbAccess); - int idx = m_lResidentSettings.getIndex(szSetting); - if (idx == -1) { - if (bIsResident) - m_lResidentSettings.insert(szSetting); - } - else if (!bIsResident) - m_lResidentSettings.remove(idx); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -class MDefaultChecker : public MIDatabaseChecker -{ - STDMETHODIMP_(int) Start(DBCHeckCallback*) override - { return ERROR_SUCCESS; - } - - STDMETHODIMP_(BOOL) CheckDb(int /*phase*/) override - { return ERROR_OUT_OF_PAPER; - } - - STDMETHODIMP_(VOID) Destroy() override - {} -}; - -static MDefaultChecker sttDefaultChecker; - -STDMETHODIMP_(MIDatabaseChecker *) MDatabaseCommon::GetChecker() -{ - return &sttDefaultChecker; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Event cursors - -class CCompatiblityCursor : public DB::EventCursor -{ - MDatabaseCommon *db; - MEVENT curr; - -public: - CCompatiblityCursor(MDatabaseCommon *pDb, MCONTACT hContact, MEVENT hEvent) : - DB::EventCursor(hContact), - db(pDb) - { - curr = (hEvent == 0) ? db->FindFirstEvent(hContact) : db->FindNextEvent(hContact, hEvent); - } - - MEVENT FetchNext() override - { - if (curr == 0) - return 0; - - MEVENT ret = curr; curr = db->FindNextEvent(hContact, curr); - return ret; - } -}; - -STDMETHODIMP_(DB::EventCursor*) MDatabaseCommon::EventCursor(MCONTACT hContact, MEVENT hEvent) -{ - return new CCompatiblityCursor(this, hContact, hEvent); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -class CCompatiblityCursorRev : public DB::EventCursor -{ - MDatabaseCommon *db; - MEVENT curr; - -public: - CCompatiblityCursorRev(MDatabaseCommon *pDb, MCONTACT hContact, MEVENT hEvent) : - DB::EventCursor(hContact), - db(pDb) - { - curr = (hEvent == 0) ? db->FindLastEvent(hContact) : db->FindPrevEvent(hContact, hEvent); - } - - MEVENT FetchNext() override - { - if (curr == 0) - return 0; - - MEVENT ret = curr; curr = db->FindPrevEvent(hContact, curr); - return ret; - } -}; - -STDMETHODIMP_(DB::EventCursor*) MDatabaseCommon::EventCursorRev(MCONTACT hContact, MEVENT hEvent) -{ - return new CCompatiblityCursorRev(this, hContact, hEvent); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 Miranda NG team, +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" +#include "database.h" + +static int stringCompare2(const char *p1, const char *p2) +{ + return mir_strcmp(p1, p2); +} + +MDatabaseCommon::MDatabaseCommon() : + m_lResidentSettings(50, stringCompare2) +{ + m_codePage = Langpack_GetDefaultCodePage(); + m_cache = new MDatabaseCache(this); +} + +MDatabaseCommon::~MDatabaseCommon() +{ + if (m_crypto) + m_crypto->destroy(); + + UnlockName(); + delete (MDatabaseCache*)m_cache; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int MDatabaseCommon::CheckProto(DBCachedContact *cc, const char *proto) +{ + if (cc->szProto == nullptr) { + char protobuf[MAX_PATH] = { 0 }; + DBVARIANT dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = protobuf; + dbv.cchVal = sizeof(protobuf); + if (GetContactSettingStatic(cc->contactID, "Protocol", "p", &dbv) != 0 || (dbv.type != DBVT_ASCIIZ)) + return 0; + + cc->szProto = m_cache->GetCachedSetting(nullptr, protobuf, 0, mir_strlen(protobuf)); + } + + return !mir_strcmp(cc->szProto, proto); +} + +void MDatabaseCommon::FillContactSettings() +{ + for (DBCachedContact *cc = m_cache->GetFirstContact(); cc; cc = m_cache->GetNextContact(cc->contactID)) { + 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)) ? 0 : 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)) ? 0 : dbv.dVal; + } +} + +bool MDatabaseCommon::LockName(const wchar_t *pwszProfileName) +{ + if (m_hLock != nullptr) + return true; + + if (pwszProfileName == nullptr) + return false; + + CMStringW wszPhysName(pwszProfileName); + wszPhysName.Replace(L"\\", L"_"); + wszPhysName.Insert(0, L"Global\\"); + + HANDLE hMutex = ::CreateMutexW(nullptr, false, wszPhysName); + if (hMutex == nullptr) + return false; + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + ::CloseHandle(hMutex); + return false; + } + + m_hLock = hMutex; + return true; +} + +void MDatabaseCommon::UnlockName() +{ + if (m_hLock) { + CloseHandle(m_hLock); + m_hLock = nullptr; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Modules + +static int sttEnumVars(const char *szVarName, void *param) +{ + LIST* vars = (LIST*)param; + vars->insert(mir_strdup(szVarName)); + return 0; +} + +BOOL MDatabaseCommon::DeleteModule(MCONTACT hContact, LPCSTR szModule) +{ + LIST vars(20); + EnumContactSettings(hContact, sttEnumVars, szModule, &vars); + + for (auto &it : vars.rev_iter()) { + DeleteContactSetting(hContact, szModule, it); + mir_free(it); + } + return 0; +} + +BOOL MDatabaseCommon::Compact(void) +{ + return ERROR_NOT_SUPPORTED; +} + +BOOL MDatabaseCommon::Backup(LPCWSTR) +{ + return ERROR_NOT_SUPPORTED; +} + +BOOL MDatabaseCommon::Flush(void) +{ + return ERROR_NOT_SUPPORTED; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Contacts + +STDMETHODIMP_(MCONTACT) MDatabaseCommon::FindFirstContact(const char *szProto) +{ + mir_cslock lck(m_csDbAccess); + DBCachedContact *cc = m_cache->GetFirstContact(); + if (cc == nullptr) + return 0; + + if (!szProto || CheckProto(cc, szProto)) + return cc->contactID; + + return FindNextContact(cc->contactID, szProto); +} + +STDMETHODIMP_(MCONTACT) MDatabaseCommon::FindNextContact(MCONTACT contactID, const char *szProto) +{ + mir_cslock lck(m_csDbAccess); + while (contactID) { + DBCachedContact *cc = m_cache->GetNextContact(contactID); + if (cc == nullptr) + break; + + if (!szProto || CheckProto(cc, szProto)) + return cc->contactID; + + contactID = cc->contactID; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Meta-contacts support + +BOOL MDatabaseCommon::MetaDetouchSub(DBCachedContact *cc, int nSub) +{ + return DeleteModule(cc->pSubs[nSub], META_PROTO); +} + +BOOL MDatabaseCommon::MetaSetDefault(DBCachedContact *cc) +{ + DBVARIANT dbv; + dbv.type = DBVT_DWORD; + dbv.dVal = cc->nDefault; + return WriteContactSetting(cc->contactID, META_PROTO, "Default", &dbv); +} + +BOOL MDatabaseCommon::MetaRemoveSubHistory(DBCachedContact*) +{ + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Getting settings + +STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) +{ + dbv->type = 0; + if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 0)) + return 1; + + if (dbv->type == DBVT_UTF8) { + wchar_t *tmp = mir_utf8decodeW(dbv->pszVal); + if (tmp != nullptr) { + mir_free(dbv->pszVal); + dbv->type = DBVT_WCHAR; + dbv->pwszVal = tmp; + } + else { + dbv->type = DBVT_ASCIIZ; + mir_free(tmp); + } + } + + return 0; +} + +STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) +{ + int iSaveType = dbv->type; + + if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 0)) + return 1; + + if (iSaveType == 0 || iSaveType == dbv->type) + return 0; + + if (dbv->type != DBVT_ASCIIZ && dbv->type != DBVT_UTF8) + return 1; + + if (iSaveType == DBVT_WCHAR) { + if (dbv->type != DBVT_UTF8) { + int len = MultiByteToWideChar(CP_ACP, 0, dbv->pszVal, -1, nullptr, 0); + wchar_t* wszResult = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); + if (wszResult == nullptr) + return 1; + + MultiByteToWideChar(CP_ACP, 0, dbv->pszVal, -1, wszResult, len); + wszResult[len] = 0; + mir_free(dbv->pszVal); + dbv->pwszVal = wszResult; + } + else { + char* savePtr = NEWSTR_ALLOCA(dbv->pszVal); + mir_free(dbv->pszVal); + if (!mir_utf8decode(savePtr, &dbv->pwszVal)) + return 1; + } + } + else if (iSaveType == DBVT_UTF8) { + char* tmpBuf = mir_utf8encode(dbv->pszVal); + if (tmpBuf == nullptr) + return 1; + + mir_free(dbv->pszVal); + dbv->pszVal = tmpBuf; + } + else if (iSaveType == DBVT_ASCIIZ) + mir_utf8decode(dbv->pszVal, nullptr); + + dbv->type = iSaveType; + return 0; +} + +STDMETHODIMP_(BOOL) MDatabaseCommon::GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) +{ + bool bNeedsWchars; + size_t cbSaved = 0; + + if (dbv->type == DBVT_WCHAR) { // there's no wchar_t strings in a database, we need conversion + cbSaved = dbv->cchVal - 1; + dbv->cchVal *= sizeof(wchar_t); // extend a room for the utf8 string + dbv->type = DBVT_UTF8; + bNeedsWchars = true; + } + else bNeedsWchars = false; + + if (GetContactSettingWorker(contactID, szModule, szSetting, dbv, 1)) + return 1; + + if (bNeedsWchars) { + char *pBuf = NEWSTR_ALLOCA(dbv->pszVal); + int cbLen = Utf8toUcs2(pBuf, dbv->cchVal, dbv->pwszVal, cbSaved); + if (cbLen < 0) + return 1; + + dbv->pwszVal[cbLen] = 0; + } + else if (dbv->type == DBVT_UTF8) { + mir_utf8decode(dbv->pszVal, nullptr); + dbv->type = DBVT_ASCIIZ; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static bool ValidLookupName(const char *szModule, const char *szSetting) +{ + if (!strcmp(szModule, META_PROTO)) + return strcmp(szSetting, "IsSubcontact") && strcmp(szSetting, "ParentMetaID"); + + return false; +} + +STDMETHODIMP_(int) MDatabaseCommon::GetContactSettingWorker(MCONTACT contactID, const char *szModule, const char *szSetting, DBVARIANT *dbv, int isStatic) +{ + if (szSetting == nullptr || szModule == nullptr) + return 1; + + DBVARIANT *pCachedValue; + size_t settingNameLen = strlen(szSetting); + size_t moduleNameLen = strlen(szModule); + { + mir_cslock lck(m_csDbAccess); + +LBL_Seek: + char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen); + + pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0); + if (pCachedValue == nullptr) { + // if nothing was faund, try to lookup the same setting from meta's default contact + if (contactID) { + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) { + if (contactID = db_mc_getDefault(contactID)) { + szModule = Proto_GetBaseAccountName(contactID); + if (szModule == nullptr) // smth went wrong + return 1; + + moduleNameLen = strlen(szModule); + goto LBL_Seek; + } + } + } + + // otherwise fail + return 1; + } + } + + switch(pCachedValue->type) { + case DBVT_ASCIIZ: + case DBVT_UTF8: + dbv->type = pCachedValue->type; + if (isStatic) { + int cbLen = (int)mir_strlen(pCachedValue->pszVal); + int cbOrigLen = dbv->cchVal; + cbOrigLen--; + 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); + dbv->cchVal = pCachedValue->cchVal; + } + break; + + case DBVT_BLOB: + dbv->type = DBVT_BLOB; + if (isStatic) { + if (pCachedValue->cpbVal < dbv->cpbVal) + dbv->cpbVal = pCachedValue->cpbVal; + memcpy(dbv->pbVal, pCachedValue->pbVal, dbv->cpbVal); + } + else { + dbv->pbVal = (uint8_t *)mir_alloc(pCachedValue->cpbVal); + memcpy(dbv->pbVal, pCachedValue->pbVal, pCachedValue->cpbVal); + } + dbv->cpbVal = pCachedValue->cpbVal; + break; + + case DBVT_ENCRYPTED: + if (m_crypto != nullptr) { + size_t realLen; + ptrA decoded(m_crypto->decodeString(pCachedValue->pbVal, pCachedValue->cpbVal, &realLen)); + if (decoded == nullptr) + return 1; + + dbv->type = DBVT_UTF8; + if (isStatic) { + dbv->cchVal--; + if (realLen < dbv->cchVal) + dbv->cchVal = uint16_t(realLen); + memcpy(dbv->pszVal, decoded, dbv->cchVal); + dbv->pszVal[dbv->cchVal] = 0; + dbv->cchVal = uint16_t(realLen); + } + else { + dbv->pszVal = (char *)mir_alloc(1 + realLen); + memcpy(dbv->pszVal, decoded, realLen); + dbv->pszVal[realLen] = 0; + } + break; + } + return 1; + + default: + memcpy(dbv, pCachedValue, sizeof(DBVARIANT)); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP_(BOOL) MDatabaseCommon::FreeVariant(DBVARIANT *dbv) +{ + if (dbv == nullptr) return 1; + + switch (dbv->type) { + case DBVT_ASCIIZ: + case DBVT_UTF8: + case DBVT_WCHAR: + if (dbv->pszVal) mir_free(dbv->pszVal); + dbv->pszVal = nullptr; + break; + case DBVT_BLOB: + if (dbv->pbVal) mir_free(dbv->pbVal); + dbv->pbVal = nullptr; + break; + } + dbv->type = 0; + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +STDMETHODIMP_(BOOL) MDatabaseCommon::WriteContactSetting(MCONTACT contactID, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (dbv == nullptr || szSetting == nullptr || szModule == nullptr) + return 1; + + // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name + size_t settingNameLen = strlen(szSetting); + size_t moduleNameLen = strlen(szModule); + + // used for notifications + DBCONTACTWRITESETTING dbcwNotif = {szModule, szSetting, *dbv}; + if (dbcwNotif.value.type == DBVT_WCHAR) { + if (dbcwNotif.value.pszVal != nullptr) { + T2Utf val(dbcwNotif.value.pwszVal); + if (!val) + return 1; + + dbcwNotif.value.pszVal = NEWSTR_ALLOCA(val); + dbcwNotif.value.type = DBVT_UTF8; + } + else return 1; + } + + if (dbcwNotif.szModule == nullptr || dbcwNotif.szSetting == nullptr) + return 1; + + DBCONTACTWRITESETTING dbcwWork = dbcwNotif; + + mir_ptr pEncoded(nullptr); + 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(szModule, szSetting); + if (dbcwWork.value.pszVal == nullptr) + return 1; + + dbcwWork.value.cchVal = (uint16_t)strlen(dbcwWork.value.pszVal); + if (bIsEncrypted && m_crypto) { + size_t len; + uint8_t *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len); + if (pResult != nullptr) { + pEncoded = dbcwWork.value.pbVal = pResult; + dbcwWork.value.cpbVal = (uint16_t)len; + dbcwWork.value.type = DBVT_ENCRYPTED; + } + } + break; + + case DBVT_BLOB: + case DBVT_ENCRYPTED: + if (dbcwWork.value.pbVal == nullptr) + return 1; + break; + + default: + return 1; + } + + mir_cslockfull lck(m_csDbAccess); + char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen); + + DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1); + if (pCachedValue != nullptr) { + 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; + case DBVT_BLOB: + case DBVT_ENCRYPTED: + if (pCachedValue->cpbVal == dbcwWork.value.cchVal) + bIsIdentical = memcmp(pCachedValue->pbVal, dbcwWork.value.pbVal, dbcwWork.value.cchVal); + break; + } + if (bIsIdentical) + return 0; + } + m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue); + } + + // for non-resident settings we call a write worker + if (szCachedSettingName[-1] == 0) + if (WriteContactSettingWorker(contactID, dbcwWork)) + return 1; + + lck.unlock(); + NotifyEventHooks(g_hevSettingChanged, contactID, (LPARAM)&dbcwNotif); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Resident settings + +STDMETHODIMP_(BOOL) MDatabaseCommon::EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam) +{ + for (auto &it : m_lResidentSettings) { + int ret = pFunc(it, pParam); + if (ret) + return ret; + } + return 0; +} + +STDMETHODIMP_(BOOL) MDatabaseCommon::SetSettingResident(BOOL bIsResident, const char *pszSettingName) +{ + char *szSetting = m_cache->GetCachedSetting(nullptr, pszSettingName, 0, mir_strlen(pszSettingName)); + szSetting[-1] = (char)bIsResident; + + mir_cslock lck(m_csDbAccess); + int idx = m_lResidentSettings.getIndex(szSetting); + if (idx == -1) { + if (bIsResident) + m_lResidentSettings.insert(szSetting); + } + else if (!bIsResident) + m_lResidentSettings.remove(idx); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +class MDefaultChecker : public MIDatabaseChecker +{ + STDMETHODIMP_(int) Start(DBCHeckCallback*) override + { return ERROR_SUCCESS; + } + + STDMETHODIMP_(BOOL) CheckDb(int /*phase*/) override + { return ERROR_OUT_OF_PAPER; + } + + STDMETHODIMP_(VOID) Destroy() override + {} +}; + +static MDefaultChecker sttDefaultChecker; + +STDMETHODIMP_(MIDatabaseChecker *) MDatabaseCommon::GetChecker() +{ + return &sttDefaultChecker; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Event cursors + +class CCompatiblityCursor : public DB::EventCursor +{ + MDatabaseCommon *db; + MEVENT curr; + +public: + CCompatiblityCursor(MDatabaseCommon *pDb, MCONTACT hContact, MEVENT hEvent) : + DB::EventCursor(hContact), + db(pDb) + { + curr = (hEvent == 0) ? db->FindFirstEvent(hContact) : db->FindNextEvent(hContact, hEvent); + } + + MEVENT FetchNext() override + { + if (curr == 0) + return 0; + + MEVENT ret = curr; curr = db->FindNextEvent(hContact, curr); + return ret; + } +}; + +STDMETHODIMP_(DB::EventCursor*) MDatabaseCommon::EventCursor(MCONTACT hContact, MEVENT hEvent) +{ + return new CCompatiblityCursor(this, hContact, hEvent); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +class CCompatiblityCursorRev : public DB::EventCursor +{ + MDatabaseCommon *db; + MEVENT curr; + +public: + CCompatiblityCursorRev(MDatabaseCommon *pDb, MCONTACT hContact, MEVENT hEvent) : + DB::EventCursor(hContact), + db(pDb) + { + curr = (hEvent == 0) ? db->FindLastEvent(hContact) : db->FindPrevEvent(hContact, hEvent); + } + + MEVENT FetchNext() override + { + if (curr == 0) + return 0; + + MEVENT ret = curr; curr = db->FindPrevEvent(hContact, curr); + return ret; + } +}; + +STDMETHODIMP_(DB::EventCursor*) MDatabaseCommon::EventCursorRev(MCONTACT hContact, MEVENT hEvent) +{ + return new CCompatiblityCursorRev(this, hContact, hEvent); +} diff --git a/src/mir_core/src/Windows/CCtrlTreeOpts.cpp b/src/mir_core/src/Windows/CCtrlTreeOpts.cpp index 7935283285..0366201369 100644 --- a/src/mir_core/src/Windows/CCtrlTreeOpts.cpp +++ b/src/mir_core/src/Windows/CCtrlTreeOpts.cpp @@ -1,209 +1,209 @@ -/* - -Object UI extensions -Copyright (c) 2008 Victor Pavlychko, George Hazan -Copyright (C) 2012-23 Miranda NG team - -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" - -enum { IMG_SHIT, IMG_GRPOPEN, IMG_GRPCLOSED }; - -CCtrlTreeOpts::CCtrlTreeOpts(CDlgBase* dlg, int ctrlId): - CCtrlTreeView(dlg, ctrlId), - m_options(5) -{ - m_bCheckBox = true; -} - -CCtrlTreeOpts::~CCtrlTreeOpts() -{ -} - -void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option) -{ - auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::CMOPTION); - p->m_option = &option; - m_options.insert(p, m_options.getCount()); -} - -void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, bool &option) -{ - auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::BOOL); - p->m_pBool = &option; - m_options.insert(p, m_options.getCount()); -} - -void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, uint32_t &option, uint32_t mask) -{ - auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::MASK); - p->m_pDword = &option; - p->m_mask = mask; - m_options.insert(p, m_options.getCount()); -} - -BOOL CCtrlTreeOpts::OnNotify(int idCtrl, NMHDR *pnmh) -{ - switch (pnmh->code) { - case TVN_KEYDOWN: - { - LPNMTVKEYDOWN lpnmtvkd = (LPNMTVKEYDOWN)pnmh; - HTREEITEM hti; - if ((lpnmtvkd->wVKey == VK_SPACE) && (hti = GetSelection())) - ProcessItemClick(hti); - } - break; - - case NM_CLICK: - TVHITTESTINFO htti; - htti.pt.x = (short)LOWORD(GetMessagePos()); - htti.pt.y = (short)HIWORD(GetMessagePos()); - ScreenToClient(pnmh->hwndFrom, &htti.pt); - if (HitTest(&htti)) - if (htti.flags & TVHT_ONITEMICON) - ProcessItemClick(htti.hItem); - break; - - case TVN_ITEMEXPANDED: - LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW)pnmh; - TVITEM tvi; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - tvi.hItem = lpnmtv->itemNew.hItem; - tvi.iImage = tvi.iSelectedImage = (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; - SendMessage(pnmh->hwndFrom, TVM_SETITEM, 0, (LPARAM)&tvi); - break; - } - - return CSuper::OnNotify(idCtrl, pnmh); -} - -void CCtrlTreeOpts::OnInit() -{ - CSuper::OnInit(); - - SelectItem(nullptr); - DeleteAllItems(); - - HIMAGELIST hImgLst = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_COLOR32 | ILC_MASK, 5, 1); - ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_BLANK); - ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPOPEN); - ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPSHUT); - SetImageList(hImgLst, TVSIL_NORMAL); - - /* build options tree. based on code from IcoLib */ - for (auto &it : m_options) { - if (it->m_pwszSection) { - HTREEITEM hSection = FindNamedItem(nullptr, it->m_pwszSection); - if (!hSection) { - TVINSERTSTRUCT tvis = {}; - tvis.hParent = hSection; - tvis.hInsertAfter = TVI_LAST; - tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; - tvis.item.pszText = (LPWSTR)it->m_pwszSection; - tvis.item.state = TVIS_EXPANDED | TVIS_BOLD | INDEXTOSTATEIMAGEMASK(3); - tvis.item.stateMask = TVIS_EXPANDED | TVIS_BOLD | TVIS_STATEIMAGEMASK; - tvis.item.iImage = tvis.item.iSelectedImage = IMG_GRPOPEN; - hSection = InsertItem(&tvis); - } - - bool bValue; - switch (it->m_type) { - case COptionsItem::CMOPTION: - bValue = *it->m_option; - break; - case COptionsItem::BOOL: - bValue = *it->m_pBool; - break; - case COptionsItem::MASK: - bValue = (*it->m_pDword & it->m_mask) != 0; - break; - default: - continue; - } - - TVINSERTSTRUCT tvis = {}; - tvis.hParent = hSection; - tvis.hInsertAfter = TVI_LAST; - tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE; - tvis.item.pszText = (LPWSTR)it->m_pwszName; - tvis.item.lParam = m_options.indexOf(&it); - tvis.item.iImage = -1; - tvis.item.state = INDEXTOSTATEIMAGEMASK(bValue ? 2 : 1); - tvis.item.stateMask = TVIS_STATEIMAGEMASK; - it->m_hItem = InsertItem(&tvis); - } - } - - TranslateTree(); - ShowWindow(m_hwnd, SW_SHOW); - SelectItem(FindNamedItem(nullptr, nullptr)); -} - -void CCtrlTreeOpts::OnDestroy() -{ - ImageList_Destroy(GetImageList(TVSIL_NORMAL)); -} - -bool CCtrlTreeOpts::OnApply() -{ - CSuper::OnApply(); - - for (auto &it : m_options) { - TVITEMEX tvi; - tvi.mask = TVIF_STATE; - GetItem(it->m_hItem, &tvi); - - bool bValue = (tvi.state >> 12) == 2; - switch (it->m_type) { - case COptionsItem::CMOPTION: - *it->m_option = bValue; - break; - case COptionsItem::BOOL: - *it->m_pBool = bValue; - break; - case COptionsItem::MASK: - if (bValue) - *it->m_pDword |= it->m_mask; - else - *it->m_pDword &= ~it->m_mask; - break; - } - } - return true; -} - -void CCtrlTreeOpts::ProcessItemClick(HTREEITEM hti) -{ - TVITEMEX tvi; - tvi.mask = TVIF_IMAGE; - GetItem(hti, &tvi); - switch (tvi.iImage) { - case IMG_GRPOPEN: - tvi.iImage = tvi.iSelectedImage = IMG_GRPCLOSED; - Expand(tvi.hItem, TVE_COLLAPSE); - break; - - case IMG_GRPCLOSED: - tvi.iImage = tvi.iSelectedImage = IMG_GRPOPEN; - Expand(tvi.hItem, TVE_EXPAND); - break; - - } - - SetItem(&tvi); -} +/* + +Object UI extensions +Copyright (c) 2008 Victor Pavlychko, George Hazan +Copyright (C) 2012-23 Miranda NG team + +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" + +enum { IMG_SHIT, IMG_GRPOPEN, IMG_GRPCLOSED }; + +CCtrlTreeOpts::CCtrlTreeOpts(CDlgBase* dlg, int ctrlId): + CCtrlTreeView(dlg, ctrlId), + m_options(5) +{ + m_bCheckBox = true; +} + +CCtrlTreeOpts::~CCtrlTreeOpts() +{ +} + +void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option) +{ + auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::CMOPTION); + p->m_option = &option; + m_options.insert(p, m_options.getCount()); +} + +void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, bool &option) +{ + auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::BOOL); + p->m_pBool = &option; + m_options.insert(p, m_options.getCount()); +} + +void CCtrlTreeOpts::AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, uint32_t &option, uint32_t mask) +{ + auto *p = new COptionsItem(pwszSection, pwszName, COptionsItem::MASK); + p->m_pDword = &option; + p->m_mask = mask; + m_options.insert(p, m_options.getCount()); +} + +BOOL CCtrlTreeOpts::OnNotify(int idCtrl, NMHDR *pnmh) +{ + switch (pnmh->code) { + case TVN_KEYDOWN: + { + LPNMTVKEYDOWN lpnmtvkd = (LPNMTVKEYDOWN)pnmh; + HTREEITEM hti; + if ((lpnmtvkd->wVKey == VK_SPACE) && (hti = GetSelection())) + ProcessItemClick(hti); + } + break; + + case NM_CLICK: + TVHITTESTINFO htti; + htti.pt.x = (short)LOWORD(GetMessagePos()); + htti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(pnmh->hwndFrom, &htti.pt); + if (HitTest(&htti)) + if (htti.flags & TVHT_ONITEMICON) + ProcessItemClick(htti.hItem); + break; + + case TVN_ITEMEXPANDED: + LPNMTREEVIEW lpnmtv = (LPNMTREEVIEW)pnmh; + TVITEM tvi; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + tvi.hItem = lpnmtv->itemNew.hItem; + tvi.iImage = tvi.iSelectedImage = (lpnmtv->itemNew.state & TVIS_EXPANDED) ? IMG_GRPOPEN : IMG_GRPCLOSED; + SendMessage(pnmh->hwndFrom, TVM_SETITEM, 0, (LPARAM)&tvi); + break; + } + + return CSuper::OnNotify(idCtrl, pnmh); +} + +void CCtrlTreeOpts::OnInit() +{ + CSuper::OnInit(); + + SelectItem(nullptr); + DeleteAllItems(); + + HIMAGELIST hImgLst = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_COLOR32 | ILC_MASK, 5, 1); + ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_BLANK); + ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPOPEN); + ImageList_AddSkinIcon(hImgLst, SKINICON_OTHER_GROUPSHUT); + SetImageList(hImgLst, TVSIL_NORMAL); + + /* build options tree. based on code from IcoLib */ + for (auto &it : m_options) { + if (it->m_pwszSection) { + HTREEITEM hSection = FindNamedItem(nullptr, it->m_pwszSection); + if (!hSection) { + TVINSERTSTRUCT tvis = {}; + tvis.hParent = hSection; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; + tvis.item.pszText = (LPWSTR)it->m_pwszSection; + tvis.item.state = TVIS_EXPANDED | TVIS_BOLD | INDEXTOSTATEIMAGEMASK(3); + tvis.item.stateMask = TVIS_EXPANDED | TVIS_BOLD | TVIS_STATEIMAGEMASK; + tvis.item.iImage = tvis.item.iSelectedImage = IMG_GRPOPEN; + hSection = InsertItem(&tvis); + } + + bool bValue; + switch (it->m_type) { + case COptionsItem::CMOPTION: + bValue = *it->m_option; + break; + case COptionsItem::BOOL: + bValue = *it->m_pBool; + break; + case COptionsItem::MASK: + bValue = (*it->m_pDword & it->m_mask) != 0; + break; + default: + continue; + } + + TVINSERTSTRUCT tvis = {}; + tvis.hParent = hSection; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE; + tvis.item.pszText = (LPWSTR)it->m_pwszName; + tvis.item.lParam = m_options.indexOf(&it); + tvis.item.iImage = -1; + tvis.item.state = INDEXTOSTATEIMAGEMASK(bValue ? 2 : 1); + tvis.item.stateMask = TVIS_STATEIMAGEMASK; + it->m_hItem = InsertItem(&tvis); + } + } + + TranslateTree(); + ShowWindow(m_hwnd, SW_SHOW); + SelectItem(FindNamedItem(nullptr, nullptr)); +} + +void CCtrlTreeOpts::OnDestroy() +{ + ImageList_Destroy(GetImageList(TVSIL_NORMAL)); +} + +bool CCtrlTreeOpts::OnApply() +{ + CSuper::OnApply(); + + for (auto &it : m_options) { + TVITEMEX tvi; + tvi.mask = TVIF_STATE; + GetItem(it->m_hItem, &tvi); + + bool bValue = (tvi.state >> 12) == 2; + switch (it->m_type) { + case COptionsItem::CMOPTION: + *it->m_option = bValue; + break; + case COptionsItem::BOOL: + *it->m_pBool = bValue; + break; + case COptionsItem::MASK: + if (bValue) + *it->m_pDword |= it->m_mask; + else + *it->m_pDword &= ~it->m_mask; + break; + } + } + return true; +} + +void CCtrlTreeOpts::ProcessItemClick(HTREEITEM hti) +{ + TVITEMEX tvi; + tvi.mask = TVIF_IMAGE; + GetItem(hti, &tvi); + switch (tvi.iImage) { + case IMG_GRPOPEN: + tvi.iImage = tvi.iSelectedImage = IMG_GRPCLOSED; + Expand(tvi.hItem, TVE_COLLAPSE); + break; + + case IMG_GRPCLOSED: + tvi.iImage = tvi.iSelectedImage = IMG_GRPOPEN; + Expand(tvi.hItem, TVE_EXPAND); + break; + + } + + SetItem(&tvi); +} diff --git a/src/mir_core/src/Windows/CCtrlTreeView.cpp b/src/mir_core/src/Windows/CCtrlTreeView.cpp index 178b6b730e..92ad166f91 100644 --- a/src/mir_core/src/Windows/CCtrlTreeView.cpp +++ b/src/mir_core/src/Windows/CCtrlTreeView.cpp @@ -1,800 +1,800 @@ -/* - -Object UI extensions -Copyright (c) 2008 Victor Pavlychko, George Hazan -Copyright (C) 2012-23 Miranda NG team - -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 ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId) -{ - HICON hIcon = Skin_LoadIcon(iconId); - int res = ImageList_AddIcon(hIml, hIcon); - IcoLib_ReleaseIcon(hIcon); - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -CCtrlTreeView::CCtrlTreeView(CDlgBase *dlg, int ctrlId) : - CCtrlBase(dlg, ctrlId), - m_dwFlags(0), - m_hDragItem(nullptr) -{} - -void CCtrlTreeView::SetFlags(uint32_t dwFlags) -{ - if (dwFlags & MTREE_CHECKBOX) - m_bCheckBox = true; - - if (dwFlags & MTREE_MULTISELECT) - m_bMultiSelect = true; - - if (dwFlags & MTREE_DND) { - m_bDndEnabled = true; - m_bDragging = false; - m_hDragItem = nullptr; - } -} - -void CCtrlTreeView::OnInit() -{ - CSuper::OnInit(); - - Subclass(); - - if (m_bCheckBox) - SetWindowLongW(m_hwnd, GWL_STYLE, TVS_CHECKBOXES | GetWindowLongW(m_hwnd, GWL_STYLE)); -} - -HTREEITEM CCtrlTreeView::MoveItemAbove(HTREEITEM hItem, HTREEITEM hInsertAfter, HTREEITEM hParent) -{ - if (hItem == nullptr || hInsertAfter == nullptr) - return nullptr; - - if (hItem == hInsertAfter) - return hItem; - - wchar_t name[128]; - TVINSERTSTRUCT tvis = {}; - tvis.itemex.mask = (UINT)-1; - tvis.itemex.pszText = name; - tvis.itemex.cchTextMax = _countof(name); - tvis.itemex.hItem = hItem; - if (!GetItem(&tvis.itemex)) - return nullptr; - - OBJLIST arChildren(1); - for (HTREEITEM p = GetChild(hItem); p; p = GetNextSibling(p)) { - wchar_t buf[128]; - TVINSERTSTRUCT tvis2 = {}; - tvis2.itemex.mask = (UINT)-1; - tvis2.itemex.pszText = buf; - tvis2.itemex.cchTextMax = _countof(buf); - tvis2.itemex.hItem = p; - if (GetItem(&tvis2.itemex)) { - tvis2.itemex.pszText = mir_wstrdup(tvis2.itemex.pszText); - arChildren.insert(new TVINSERTSTRUCT(tvis2)); - - tvis2.itemex.lParam = 0; - SetItem(&tvis2.itemex); - } - } - - // the pointed lParam will be freed inside TVN_DELETEITEM - // so lets substitute it with 0 - LPARAM saveOldData = tvis.itemex.lParam; - tvis.itemex.lParam = 0; - SetItem(&tvis.itemex); - - // now current item contain lParam = 0 we can delete it. the memory will be kept. - DeleteItem(hItem); - - for (auto &it : arChildren) - DeleteItem(it->itemex.hItem); - - tvis.itemex.stateMask = tvis.itemex.state; - tvis.itemex.lParam = saveOldData; - tvis.hParent = hParent; - tvis.hInsertAfter = hInsertAfter; - auto hNewItem = InsertItem(&tvis); - - hInsertAfter = nullptr; - for (auto &it : arChildren) { - it->hParent = hNewItem; - it->hInsertAfter = hInsertAfter; - hInsertAfter = InsertItem(it); - - mir_free(it->itemex.pszText); - } - - return hNewItem; -} - -LRESULT CCtrlTreeView::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - TVHITTESTINFO hti; - - switch (msg) { - case WM_MOUSEMOVE: - if (m_bDragging) { - hti.pt.x = (short)LOWORD(lParam); - hti.pt.y = (short)HIWORD(lParam); - HitTest(&hti); - if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) { - HTREEITEM it = hti.hItem; - hti.pt.y -= GetItemHeight() / 2; - HitTest(&hti); - if (!(hti.flags & TVHT_ABOVE)) - SetInsertMark(hti.hItem, 1); - else - SetInsertMark(it, 0); - } - else { - if (hti.flags & TVHT_ABOVE) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); - if (hti.flags & TVHT_BELOW) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); - SetInsertMark(nullptr, 0); - } - } - break; - - case WM_LBUTTONUP: - if (m_bDragging) { - SetInsertMark(nullptr, 0); - m_bDragging = false; - ReleaseCapture(); - - hti.pt.x = (short)LOWORD(lParam); - hti.pt.y = (short)HIWORD(lParam) - GetItemHeight() / 2; - HitTest(&hti); - if (m_hDragItem == hti.hItem) - break; - - if (hti.flags & TVHT_ABOVE) - hti.hItem = TVI_FIRST; - else if (hti.flags & TVHT_BELOW) - hti.hItem = TVI_LAST; - - HTREEITEM insertAfter = hti.hItem, hParent; - if (insertAfter != TVI_FIRST) { - hParent = GetParent(insertAfter); - if (GetChild(insertAfter) != nullptr) { - hParent = insertAfter; - insertAfter = TVI_FIRST; - } - } - else hParent = nullptr; - - HTREEITEM FirstItem = nullptr; - if (m_bMultiSelect) { - LIST<_TREEITEM> arItems(10); - GetSelected(arItems); - - // Proceed moving - for (auto &it : arItems) { - if (!insertAfter) - break; - if (GetParent(it) != hParent) // prevent subitems from being inserted at the same level - continue; - - insertAfter = MoveItemAbove(it, insertAfter, hParent); - if (it == arItems[0]) - FirstItem = insertAfter; - } - } - else FirstItem = MoveItemAbove(m_hDragItem, insertAfter, hParent); - if (FirstItem) - SelectItem(FirstItem); - - NotifyChange(); - } - break; - - case WM_LBUTTONDOWN: - if (!m_bMultiSelect) - break; - - hti.pt.x = (short)LOWORD(lParam); - hti.pt.y = (short)HIWORD(lParam); - if (!TreeView_HitTest(m_hwnd, &hti)) { - UnselectAll(); - break; - } - - if (!m_bDndEnabled) - if (!(wParam & (MK_CONTROL | MK_SHIFT)) || !(hti.flags & (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMRIGHT))) { - UnselectAll(); - TreeView_SelectItem(m_hwnd, hti.hItem); - break; - } - - if (wParam & MK_CONTROL) { - LIST<_TREEITEM> selected(1); - GetSelected(selected); - - // Check if have to deselect it - for (int i = 0; i < selected.getCount(); i++) { - if (selected[i] == hti.hItem) { - // Deselect it - UnselectAll(); - selected.remove(i); - - if (i > 0) - hti.hItem = selected[0]; - else if (i < selected.getCount()) - hti.hItem = selected[i]; - else - hti.hItem = nullptr; - break; - } - } - - TreeView_SelectItem(m_hwnd, hti.hItem); - Select(selected); - } - else if (wParam & MK_SHIFT) { - HTREEITEM hItem = TreeView_GetSelection(m_hwnd); - if (hItem == nullptr) - break; - - LIST<_TREEITEM> selected(1); - GetSelected(selected); - - TreeView_SelectItem(m_hwnd, hti.hItem); - Select(selected); - SelectRange(hItem, hti.hItem); - } - break; - } - - return CSuper::CustomWndProc(msg, wParam, lParam); -} - -BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) -{ - TEventInfo evt = { this, pnmh }; - - switch (pnmh->code) { - case NM_RCLICK: OnRightClick(&evt); return TRUE; - case NM_CUSTOMDRAW: OnCustomDraw(&evt); return TRUE; - case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; - case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; - case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; - case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; - case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; - case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; - case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; - case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; - case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; - case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; - case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; - case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; - - case TVN_BEGINDRAG: - OnBeginDrag(&evt); - - // user-defined can clear the event code to disable dragging - if (m_bDndEnabled && pnmh->code) { - ::SetCapture(m_hwnd); - m_bDragging = true; - m_hDragItem = evt.nmtv->itemNew.hItem; - SelectItem(m_hDragItem); - } - return TRUE; - - case TVN_KEYDOWN: - if (evt.nmtvkey->wVKey == VK_SPACE) { - evt.hItem = GetSelection(); - OnItemChanged(&evt); - NotifyChange(); - } - - OnKeyDown(&evt); - return TRUE; - } - - if (pnmh->code == NM_CLICK) { - TVHITTESTINFO hti; - hti.pt.x = (short)LOWORD(GetMessagePos()); - hti.pt.y = (short)HIWORD(GetMessagePos()); - ScreenToClient(pnmh->hwndFrom, &hti.pt); - if (HitTest(&hti)) { - if (hti.flags & TVHT_ONITEMSTATEICON) { - SelectItem(hti.hItem); - - evt.hItem = hti.hItem; - OnItemChanged(&evt); - NotifyChange(); - } - } - } - - return FALSE; -} - -void CCtrlTreeView::InvertCheck(HTREEITEM hItem) -{ - TVITEMEX tvi; - tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATEEX; - tvi.hItem = hItem; - if (!GetItem(&tvi)) - return; - - if (IsWinVerVistaPlus() && (tvi.uStateEx & TVIS_EX_DISABLED)) - return; - - tvi.iImage = tvi.iSelectedImage = !tvi.iImage; - SetItem(&tvi); - - SelectItem(hItem); -} - -void CCtrlTreeView::TranslateItem(HTREEITEM hItem) -{ - TVITEMEX tvi; - wchar_t buf[128]; - GetItem(hItem, &tvi, buf, _countof(buf)); - tvi.pszText = TranslateW_LP(tvi.pszText); - SetItem(&tvi); -} - -void CCtrlTreeView::TranslateTree() -{ - HTREEITEM hItem = GetRoot(); - while (hItem) { - TranslateItem(hItem); - - HTREEITEM hItemTmp = nullptr; - if (hItemTmp = GetChild(hItem)) - hItem = hItemTmp; - else if (hItemTmp = GetNextSibling(hItem)) - hItem = hItemTmp; - else { - while (true) { - if (!(hItem = GetParent(hItem))) - break; - if (hItemTmp = GetNextSibling(hItem)) { - hItem = hItemTmp; - break; - } - } - } - } -} - -HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const wchar_t *name) -{ - TVITEMEX tvi = { 0 }; - wchar_t str[MAX_PATH]; - - if (hItem) - tvi.hItem = GetChild(hItem); - else - tvi.hItem = GetRoot(); - - if (!name) - return tvi.hItem; - - tvi.mask = TVIF_TEXT; - tvi.pszText = str; - tvi.cchTextMax = _countof(str); - - while (tvi.hItem) { - GetItem(&tvi); - - if (!mir_wstrcmp(tvi.pszText, name)) - return tvi.hItem; - - tvi.hItem = GetNextSibling(tvi.hItem); - } - return nullptr; -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) const -{ - memset(tvi, 0, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE; - tvi->hItem = hItem; - GetItem(tvi); -} - -void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, wchar_t *szText, int iTextLength) const -{ - memset(tvi, 0, sizeof(*tvi)); - tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_TEXT; - tvi->hItem = hItem; - tvi->pszText = szText; - tvi->cchTextMax = iTextLength; - GetItem(tvi); -} - -bool CCtrlTreeView::IsSelected(HTREEITEM hItem) -{ - return (TVIS_SELECTED & TreeView_GetItemState(m_hwnd, hItem, TVIS_SELECTED)) == TVIS_SELECTED; -} - -void CCtrlTreeView::Select(HTREEITEM hItem) -{ - TreeView_SetItemState(m_hwnd, hItem, TVIS_SELECTED, TVIS_SELECTED); -} - -void CCtrlTreeView::Unselect(HTREEITEM hItem) -{ - TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_SELECTED); -} - -void CCtrlTreeView::DropHilite(HTREEITEM hItem) -{ - TreeView_SetItemState(m_hwnd, hItem, TVIS_DROPHILITED, TVIS_DROPHILITED); -} - -void CCtrlTreeView::DropUnhilite(HTREEITEM hItem) -{ - TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_DROPHILITED); -} - -void CCtrlTreeView::SelectAll() -{ - TreeView_SelectItem(m_hwnd, nullptr); - - HTREEITEM hItem = TreeView_GetRoot(m_hwnd); - while (hItem) { - Select(hItem); - hItem = TreeView_GetNextSibling(m_hwnd, hItem); - } -} - -void CCtrlTreeView::UnselectAll() -{ - TreeView_SelectItem(m_hwnd, nullptr); - - HTREEITEM hItem = TreeView_GetRoot(m_hwnd); - while (hItem) { - Unselect(hItem); - hItem = TreeView_GetNextSibling(m_hwnd, hItem); - } -} - -void CCtrlTreeView::SelectRange(HTREEITEM hStart, HTREEITEM hEnd) -{ - int start = 0, end = 0, i = 0; - HTREEITEM hItem = TreeView_GetRoot(m_hwnd); - while (hItem) { - if (hItem == hStart) - start = i; - if (hItem == hEnd) - end = i; - - i++; - hItem = TreeView_GetNextSibling(m_hwnd, hItem); - } - - if (end < start) { - int tmp = start; - start = end; - end = tmp; - } - - i = 0; - hItem = TreeView_GetRoot(m_hwnd); - while (hItem) { - if (i >= start) - Select(hItem); - if (i == end) - break; - - i++; - hItem = TreeView_GetNextSibling(m_hwnd, hItem); - } -} - -int CCtrlTreeView::GetNumSelected() -{ - int ret = 0; - for (HTREEITEM hItem = TreeView_GetRoot(m_hwnd); hItem; hItem = TreeView_GetNextSibling(m_hwnd, hItem)) - if (IsSelected(hItem)) - ret++; - - return ret; -} - -void CCtrlTreeView::GetSelected(LIST<_TREEITEM> &selected) -{ - HTREEITEM hItem = TreeView_GetRoot(m_hwnd); - while (hItem) { - if (IsSelected(hItem)) - selected.insert(hItem); - hItem = TreeView_GetNextSibling(m_hwnd, hItem); - } -} - -void CCtrlTreeView::Select(LIST<_TREEITEM> &selected) -{ - for (auto &it : selected) - if (it != nullptr) - Select(it); -} - -void CCtrlTreeView::GetCaretPos(CContextMenuPos &pos) const -{ - pos.pCtrl = this; - - // position is empty, let's fill it using selection - if (pos.pt.x == 0 && pos.pt.y == 0) { - HTREEITEM hItem = GetSelection(); - if (hItem != nullptr) { - pos.pCtrl = this; - pos.hItem = hItem; - - RECT rc; - GetItemRect(hItem, &rc, TRUE); - pos.pt.x = rc.left + 8; - pos.pt.y = rc.top + 8; - ClientToScreen(m_hwnd, &pos.pt); - return; - } - } - // position is present, let's calculate current item - else { - TVHITTESTINFO hti; - hti.pt = pos.pt; - ScreenToClient(m_hwnd, &hti.pt); - if (HitTest(&hti) && (hti.flags & TVHT_ONITEM)) { - pos.hItem = hti.hItem; - return; - } - } - - CSuper::GetCaretPos(pos); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) -{ return TreeView_CreateDragImage(m_hwnd, hItem); -} - -void CCtrlTreeView::DeleteAllItems() -{ TreeView_DeleteAllItems(m_hwnd); -} - -void CCtrlTreeView::DeleteItem(HTREEITEM hItem) -{ TreeView_DeleteItem(m_hwnd, hItem); -} - -HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) -{ return TreeView_EditLabel(m_hwnd, hItem); -} - -void CCtrlTreeView::EndEditLabelNow(BOOL cancel) -{ TreeView_EndEditLabelNow(m_hwnd, cancel); -} - -void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) -{ TreeView_EnsureVisible(m_hwnd, hItem); -} - -void CCtrlTreeView::Expand(HTREEITEM hItem, uint32_t flag) -{ TreeView_Expand(m_hwnd, hItem, flag); -} - -COLORREF CCtrlTreeView::GetBkColor() const -{ return TreeView_GetBkColor(m_hwnd); -} - -uint32_t CCtrlTreeView::GetCheckState(HTREEITEM hItem) const -{ return TreeView_GetCheckState(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) const -{ return TreeView_GetChild(m_hwnd, hItem); -} - -int CCtrlTreeView::GetCount() const -{ return TreeView_GetCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetDropHilight() const -{ return TreeView_GetDropHilight(m_hwnd); -} - -HWND CCtrlTreeView::GetEditControl() const -{ return TreeView_GetEditControl(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetFirstVisible() const -{ return TreeView_GetFirstVisible(m_hwnd); -} - -HIMAGELIST CCtrlTreeView::GetImageList(int iImage) const -{ return TreeView_GetImageList(m_hwnd, iImage); -} - -int CCtrlTreeView::GetIndent() const -{ return TreeView_GetIndent(m_hwnd); -} - -COLORREF CCtrlTreeView::GetInsertMarkColor() const -{ return TreeView_GetInsertMarkColor(m_hwnd); -} - -bool CCtrlTreeView::GetItem(TVITEMEX *tvi) const -{ return TreeView_GetItem(m_hwnd, tvi) == TRUE; -} - -int CCtrlTreeView::GetItemHeight() const -{ return TreeView_GetItemHeight(m_hwnd); -} - -void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) const -{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); -} - -uint32_t CCtrlTreeView::GetItemState(HTREEITEM hItem, uint32_t stateMask) const -{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); -} - -HTREEITEM CCtrlTreeView::GetLastVisible() const -{ return TreeView_GetLastVisible(m_hwnd); -} - -COLORREF CCtrlTreeView::GetLineColor() const -{ return TreeView_GetLineColor(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, uint32_t flag) const -{ return TreeView_GetNextItem(m_hwnd, hItem, flag); -} - -HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) const -{ return TreeView_GetNextSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) const -{ return TreeView_GetNextVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) const -{ return TreeView_GetParent(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) const -{ return TreeView_GetPrevSibling(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) const -{ return TreeView_GetPrevVisible(m_hwnd, hItem); -} - -HTREEITEM CCtrlTreeView::GetRoot() const -{ return TreeView_GetRoot(m_hwnd); -} - -uint32_t CCtrlTreeView::GetScrollTime() const -{ return TreeView_GetScrollTime(m_hwnd); -} - -HTREEITEM CCtrlTreeView::GetSelection() const -{ return TreeView_GetSelection(m_hwnd); -} - -COLORREF CCtrlTreeView::GetTextColor() const -{ return TreeView_GetTextColor(m_hwnd); -} - -HWND CCtrlTreeView::GetToolTips() const -{ return TreeView_GetToolTips(m_hwnd); -} - -BOOL CCtrlTreeView::GetUnicodeFormat() const -{ return TreeView_GetUnicodeFormat(m_hwnd); -} - -unsigned CCtrlTreeView::GetVisibleCount() const -{ return TreeView_GetVisibleCount(m_hwnd); -} - -HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) const -{ return TreeView_HitTest(m_hwnd, hti); -} - -HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) -{ return TreeView_InsertItem(m_hwnd, tvis); -} - -void CCtrlTreeView::Select(HTREEITEM hItem, uint32_t flag) -{ TreeView_Select(m_hwnd, hItem, flag); -} - -void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) -{ TreeView_SelectDropTarget(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectItem(HTREEITEM hItem) -{ TreeView_SelectItem(m_hwnd, hItem); -} - -void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) -{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); -} - -COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) -{ return TreeView_SetBkColor(m_hwnd, clBack); -} - -void CCtrlTreeView::SetCheckState(HTREEITEM hItem, uint32_t state) -{ TreeView_SetCheckState(m_hwnd, hItem, state); -} - -HIMAGELIST CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) -{ return TreeView_SetImageList(m_hwnd, hIml, iImage); -} - -void CCtrlTreeView::SetIndent(int iIndent) -{ TreeView_SetIndent(m_hwnd, iIndent); -} - -void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) -{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); -} - -COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) -{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); -} - -void CCtrlTreeView::SetItem(TVITEMEX *tvi) -{ TreeView_SetItem(m_hwnd, tvi); -} - -void CCtrlTreeView::SetItemHeight(short cyItem) -{ TreeView_SetItemHeight(m_hwnd, cyItem); -} - -void CCtrlTreeView::SetItemState(HTREEITEM hItem, uint32_t state, uint32_t stateMask) -{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); -} - -COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) -{ return TreeView_SetLineColor(m_hwnd, clLine); -} - -void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) -{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); -} - -COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) -{ return TreeView_SetTextColor(m_hwnd, clText); -} - -HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) -{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); -} - -BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) -{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); -} - -void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) -{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); -} - -void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) -{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); -} +/* + +Object UI extensions +Copyright (c) 2008 Victor Pavlychko, George Hazan +Copyright (C) 2012-23 Miranda NG team + +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 ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId) +{ + HICON hIcon = Skin_LoadIcon(iconId); + int res = ImageList_AddIcon(hIml, hIcon); + IcoLib_ReleaseIcon(hIcon); + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +CCtrlTreeView::CCtrlTreeView(CDlgBase *dlg, int ctrlId) : + CCtrlBase(dlg, ctrlId), + m_dwFlags(0), + m_hDragItem(nullptr) +{} + +void CCtrlTreeView::SetFlags(uint32_t dwFlags) +{ + if (dwFlags & MTREE_CHECKBOX) + m_bCheckBox = true; + + if (dwFlags & MTREE_MULTISELECT) + m_bMultiSelect = true; + + if (dwFlags & MTREE_DND) { + m_bDndEnabled = true; + m_bDragging = false; + m_hDragItem = nullptr; + } +} + +void CCtrlTreeView::OnInit() +{ + CSuper::OnInit(); + + Subclass(); + + if (m_bCheckBox) + SetWindowLongW(m_hwnd, GWL_STYLE, TVS_CHECKBOXES | GetWindowLongW(m_hwnd, GWL_STYLE)); +} + +HTREEITEM CCtrlTreeView::MoveItemAbove(HTREEITEM hItem, HTREEITEM hInsertAfter, HTREEITEM hParent) +{ + if (hItem == nullptr || hInsertAfter == nullptr) + return nullptr; + + if (hItem == hInsertAfter) + return hItem; + + wchar_t name[128]; + TVINSERTSTRUCT tvis = {}; + tvis.itemex.mask = (UINT)-1; + tvis.itemex.pszText = name; + tvis.itemex.cchTextMax = _countof(name); + tvis.itemex.hItem = hItem; + if (!GetItem(&tvis.itemex)) + return nullptr; + + OBJLIST arChildren(1); + for (HTREEITEM p = GetChild(hItem); p; p = GetNextSibling(p)) { + wchar_t buf[128]; + TVINSERTSTRUCT tvis2 = {}; + tvis2.itemex.mask = (UINT)-1; + tvis2.itemex.pszText = buf; + tvis2.itemex.cchTextMax = _countof(buf); + tvis2.itemex.hItem = p; + if (GetItem(&tvis2.itemex)) { + tvis2.itemex.pszText = mir_wstrdup(tvis2.itemex.pszText); + arChildren.insert(new TVINSERTSTRUCT(tvis2)); + + tvis2.itemex.lParam = 0; + SetItem(&tvis2.itemex); + } + } + + // the pointed lParam will be freed inside TVN_DELETEITEM + // so lets substitute it with 0 + LPARAM saveOldData = tvis.itemex.lParam; + tvis.itemex.lParam = 0; + SetItem(&tvis.itemex); + + // now current item contain lParam = 0 we can delete it. the memory will be kept. + DeleteItem(hItem); + + for (auto &it : arChildren) + DeleteItem(it->itemex.hItem); + + tvis.itemex.stateMask = tvis.itemex.state; + tvis.itemex.lParam = saveOldData; + tvis.hParent = hParent; + tvis.hInsertAfter = hInsertAfter; + auto hNewItem = InsertItem(&tvis); + + hInsertAfter = nullptr; + for (auto &it : arChildren) { + it->hParent = hNewItem; + it->hInsertAfter = hInsertAfter; + hInsertAfter = InsertItem(it); + + mir_free(it->itemex.pszText); + } + + return hNewItem; +} + +LRESULT CCtrlTreeView::CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + TVHITTESTINFO hti; + + switch (msg) { + case WM_MOUSEMOVE: + if (m_bDragging) { + hti.pt.x = (short)LOWORD(lParam); + hti.pt.y = (short)HIWORD(lParam); + HitTest(&hti); + if (hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT)) { + HTREEITEM it = hti.hItem; + hti.pt.y -= GetItemHeight() / 2; + HitTest(&hti); + if (!(hti.flags & TVHT_ABOVE)) + SetInsertMark(hti.hItem, 1); + else + SetInsertMark(it, 0); + } + else { + if (hti.flags & TVHT_ABOVE) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0); + if (hti.flags & TVHT_BELOW) SendMsg(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0); + SetInsertMark(nullptr, 0); + } + } + break; + + case WM_LBUTTONUP: + if (m_bDragging) { + SetInsertMark(nullptr, 0); + m_bDragging = false; + ReleaseCapture(); + + hti.pt.x = (short)LOWORD(lParam); + hti.pt.y = (short)HIWORD(lParam) - GetItemHeight() / 2; + HitTest(&hti); + if (m_hDragItem == hti.hItem) + break; + + if (hti.flags & TVHT_ABOVE) + hti.hItem = TVI_FIRST; + else if (hti.flags & TVHT_BELOW) + hti.hItem = TVI_LAST; + + HTREEITEM insertAfter = hti.hItem, hParent; + if (insertAfter != TVI_FIRST) { + hParent = GetParent(insertAfter); + if (GetChild(insertAfter) != nullptr) { + hParent = insertAfter; + insertAfter = TVI_FIRST; + } + } + else hParent = nullptr; + + HTREEITEM FirstItem = nullptr; + if (m_bMultiSelect) { + LIST<_TREEITEM> arItems(10); + GetSelected(arItems); + + // Proceed moving + for (auto &it : arItems) { + if (!insertAfter) + break; + if (GetParent(it) != hParent) // prevent subitems from being inserted at the same level + continue; + + insertAfter = MoveItemAbove(it, insertAfter, hParent); + if (it == arItems[0]) + FirstItem = insertAfter; + } + } + else FirstItem = MoveItemAbove(m_hDragItem, insertAfter, hParent); + if (FirstItem) + SelectItem(FirstItem); + + NotifyChange(); + } + break; + + case WM_LBUTTONDOWN: + if (!m_bMultiSelect) + break; + + hti.pt.x = (short)LOWORD(lParam); + hti.pt.y = (short)HIWORD(lParam); + if (!TreeView_HitTest(m_hwnd, &hti)) { + UnselectAll(); + break; + } + + if (!m_bDndEnabled) + if (!(wParam & (MK_CONTROL | MK_SHIFT)) || !(hti.flags & (TVHT_ONITEMICON | TVHT_ONITEMLABEL | TVHT_ONITEMRIGHT))) { + UnselectAll(); + TreeView_SelectItem(m_hwnd, hti.hItem); + break; + } + + if (wParam & MK_CONTROL) { + LIST<_TREEITEM> selected(1); + GetSelected(selected); + + // Check if have to deselect it + for (int i = 0; i < selected.getCount(); i++) { + if (selected[i] == hti.hItem) { + // Deselect it + UnselectAll(); + selected.remove(i); + + if (i > 0) + hti.hItem = selected[0]; + else if (i < selected.getCount()) + hti.hItem = selected[i]; + else + hti.hItem = nullptr; + break; + } + } + + TreeView_SelectItem(m_hwnd, hti.hItem); + Select(selected); + } + else if (wParam & MK_SHIFT) { + HTREEITEM hItem = TreeView_GetSelection(m_hwnd); + if (hItem == nullptr) + break; + + LIST<_TREEITEM> selected(1); + GetSelected(selected); + + TreeView_SelectItem(m_hwnd, hti.hItem); + Select(selected); + SelectRange(hItem, hti.hItem); + } + break; + } + + return CSuper::CustomWndProc(msg, wParam, lParam); +} + +BOOL CCtrlTreeView::OnNotify(int, NMHDR *pnmh) +{ + TEventInfo evt = { this, pnmh }; + + switch (pnmh->code) { + case NM_RCLICK: OnRightClick(&evt); return TRUE; + case NM_CUSTOMDRAW: OnCustomDraw(&evt); return TRUE; + case TVN_BEGINLABELEDIT: OnBeginLabelEdit(&evt); return TRUE; + case TVN_BEGINRDRAG: OnBeginRDrag(&evt); return TRUE; + case TVN_DELETEITEM: OnDeleteItem(&evt); return TRUE; + case TVN_ENDLABELEDIT: OnEndLabelEdit(&evt); return TRUE; + case TVN_GETDISPINFO: OnGetDispInfo(&evt); return TRUE; + case TVN_GETINFOTIP: OnGetInfoTip(&evt); return TRUE; + case TVN_ITEMEXPANDED: OnItemExpanded(&evt); return TRUE; + case TVN_ITEMEXPANDING: OnItemExpanding(&evt); return TRUE; + case TVN_SELCHANGED: OnSelChanged(&evt); return TRUE; + case TVN_SELCHANGING: OnSelChanging(&evt); return TRUE; + case TVN_SETDISPINFO: OnSetDispInfo(&evt); return TRUE; + case TVN_SINGLEEXPAND: OnSingleExpand(&evt); return TRUE; + + case TVN_BEGINDRAG: + OnBeginDrag(&evt); + + // user-defined can clear the event code to disable dragging + if (m_bDndEnabled && pnmh->code) { + ::SetCapture(m_hwnd); + m_bDragging = true; + m_hDragItem = evt.nmtv->itemNew.hItem; + SelectItem(m_hDragItem); + } + return TRUE; + + case TVN_KEYDOWN: + if (evt.nmtvkey->wVKey == VK_SPACE) { + evt.hItem = GetSelection(); + OnItemChanged(&evt); + NotifyChange(); + } + + OnKeyDown(&evt); + return TRUE; + } + + if (pnmh->code == NM_CLICK) { + TVHITTESTINFO hti; + hti.pt.x = (short)LOWORD(GetMessagePos()); + hti.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(pnmh->hwndFrom, &hti.pt); + if (HitTest(&hti)) { + if (hti.flags & TVHT_ONITEMSTATEICON) { + SelectItem(hti.hItem); + + evt.hItem = hti.hItem; + OnItemChanged(&evt); + NotifyChange(); + } + } + } + + return FALSE; +} + +void CCtrlTreeView::InvertCheck(HTREEITEM hItem) +{ + TVITEMEX tvi; + tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATEEX; + tvi.hItem = hItem; + if (!GetItem(&tvi)) + return; + + if (IsWinVerVistaPlus() && (tvi.uStateEx & TVIS_EX_DISABLED)) + return; + + tvi.iImage = tvi.iSelectedImage = !tvi.iImage; + SetItem(&tvi); + + SelectItem(hItem); +} + +void CCtrlTreeView::TranslateItem(HTREEITEM hItem) +{ + TVITEMEX tvi; + wchar_t buf[128]; + GetItem(hItem, &tvi, buf, _countof(buf)); + tvi.pszText = TranslateW_LP(tvi.pszText); + SetItem(&tvi); +} + +void CCtrlTreeView::TranslateTree() +{ + HTREEITEM hItem = GetRoot(); + while (hItem) { + TranslateItem(hItem); + + HTREEITEM hItemTmp = nullptr; + if (hItemTmp = GetChild(hItem)) + hItem = hItemTmp; + else if (hItemTmp = GetNextSibling(hItem)) + hItem = hItemTmp; + else { + while (true) { + if (!(hItem = GetParent(hItem))) + break; + if (hItemTmp = GetNextSibling(hItem)) { + hItem = hItemTmp; + break; + } + } + } + } +} + +HTREEITEM CCtrlTreeView::FindNamedItem(HTREEITEM hItem, const wchar_t *name) +{ + TVITEMEX tvi = { 0 }; + wchar_t str[MAX_PATH]; + + if (hItem) + tvi.hItem = GetChild(hItem); + else + tvi.hItem = GetRoot(); + + if (!name) + return tvi.hItem; + + tvi.mask = TVIF_TEXT; + tvi.pszText = str; + tvi.cchTextMax = _countof(str); + + while (tvi.hItem) { + GetItem(&tvi); + + if (!mir_wstrcmp(tvi.pszText, name)) + return tvi.hItem; + + tvi.hItem = GetNextSibling(tvi.hItem); + } + return nullptr; +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi) const +{ + memset(tvi, 0, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE; + tvi->hItem = hItem; + GetItem(tvi); +} + +void CCtrlTreeView::GetItem(HTREEITEM hItem, TVITEMEX *tvi, wchar_t *szText, int iTextLength) const +{ + memset(tvi, 0, sizeof(*tvi)); + tvi->mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_INTEGRAL | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_TEXT; + tvi->hItem = hItem; + tvi->pszText = szText; + tvi->cchTextMax = iTextLength; + GetItem(tvi); +} + +bool CCtrlTreeView::IsSelected(HTREEITEM hItem) +{ + return (TVIS_SELECTED & TreeView_GetItemState(m_hwnd, hItem, TVIS_SELECTED)) == TVIS_SELECTED; +} + +void CCtrlTreeView::Select(HTREEITEM hItem) +{ + TreeView_SetItemState(m_hwnd, hItem, TVIS_SELECTED, TVIS_SELECTED); +} + +void CCtrlTreeView::Unselect(HTREEITEM hItem) +{ + TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_SELECTED); +} + +void CCtrlTreeView::DropHilite(HTREEITEM hItem) +{ + TreeView_SetItemState(m_hwnd, hItem, TVIS_DROPHILITED, TVIS_DROPHILITED); +} + +void CCtrlTreeView::DropUnhilite(HTREEITEM hItem) +{ + TreeView_SetItemState(m_hwnd, hItem, 0, TVIS_DROPHILITED); +} + +void CCtrlTreeView::SelectAll() +{ + TreeView_SelectItem(m_hwnd, nullptr); + + HTREEITEM hItem = TreeView_GetRoot(m_hwnd); + while (hItem) { + Select(hItem); + hItem = TreeView_GetNextSibling(m_hwnd, hItem); + } +} + +void CCtrlTreeView::UnselectAll() +{ + TreeView_SelectItem(m_hwnd, nullptr); + + HTREEITEM hItem = TreeView_GetRoot(m_hwnd); + while (hItem) { + Unselect(hItem); + hItem = TreeView_GetNextSibling(m_hwnd, hItem); + } +} + +void CCtrlTreeView::SelectRange(HTREEITEM hStart, HTREEITEM hEnd) +{ + int start = 0, end = 0, i = 0; + HTREEITEM hItem = TreeView_GetRoot(m_hwnd); + while (hItem) { + if (hItem == hStart) + start = i; + if (hItem == hEnd) + end = i; + + i++; + hItem = TreeView_GetNextSibling(m_hwnd, hItem); + } + + if (end < start) { + int tmp = start; + start = end; + end = tmp; + } + + i = 0; + hItem = TreeView_GetRoot(m_hwnd); + while (hItem) { + if (i >= start) + Select(hItem); + if (i == end) + break; + + i++; + hItem = TreeView_GetNextSibling(m_hwnd, hItem); + } +} + +int CCtrlTreeView::GetNumSelected() +{ + int ret = 0; + for (HTREEITEM hItem = TreeView_GetRoot(m_hwnd); hItem; hItem = TreeView_GetNextSibling(m_hwnd, hItem)) + if (IsSelected(hItem)) + ret++; + + return ret; +} + +void CCtrlTreeView::GetSelected(LIST<_TREEITEM> &selected) +{ + HTREEITEM hItem = TreeView_GetRoot(m_hwnd); + while (hItem) { + if (IsSelected(hItem)) + selected.insert(hItem); + hItem = TreeView_GetNextSibling(m_hwnd, hItem); + } +} + +void CCtrlTreeView::Select(LIST<_TREEITEM> &selected) +{ + for (auto &it : selected) + if (it != nullptr) + Select(it); +} + +void CCtrlTreeView::GetCaretPos(CContextMenuPos &pos) const +{ + pos.pCtrl = this; + + // position is empty, let's fill it using selection + if (pos.pt.x == 0 && pos.pt.y == 0) { + HTREEITEM hItem = GetSelection(); + if (hItem != nullptr) { + pos.pCtrl = this; + pos.hItem = hItem; + + RECT rc; + GetItemRect(hItem, &rc, TRUE); + pos.pt.x = rc.left + 8; + pos.pt.y = rc.top + 8; + ClientToScreen(m_hwnd, &pos.pt); + return; + } + } + // position is present, let's calculate current item + else { + TVHITTESTINFO hti; + hti.pt = pos.pt; + ScreenToClient(m_hwnd, &hti.pt); + if (HitTest(&hti) && (hti.flags & TVHT_ONITEM)) { + pos.hItem = hti.hItem; + return; + } + } + + CSuper::GetCaretPos(pos); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +HIMAGELIST CCtrlTreeView::CreateDragImage(HTREEITEM hItem) +{ return TreeView_CreateDragImage(m_hwnd, hItem); +} + +void CCtrlTreeView::DeleteAllItems() +{ TreeView_DeleteAllItems(m_hwnd); +} + +void CCtrlTreeView::DeleteItem(HTREEITEM hItem) +{ TreeView_DeleteItem(m_hwnd, hItem); +} + +HWND CCtrlTreeView::EditLabel(HTREEITEM hItem) +{ return TreeView_EditLabel(m_hwnd, hItem); +} + +void CCtrlTreeView::EndEditLabelNow(BOOL cancel) +{ TreeView_EndEditLabelNow(m_hwnd, cancel); +} + +void CCtrlTreeView::EnsureVisible(HTREEITEM hItem) +{ TreeView_EnsureVisible(m_hwnd, hItem); +} + +void CCtrlTreeView::Expand(HTREEITEM hItem, uint32_t flag) +{ TreeView_Expand(m_hwnd, hItem, flag); +} + +COLORREF CCtrlTreeView::GetBkColor() const +{ return TreeView_GetBkColor(m_hwnd); +} + +uint32_t CCtrlTreeView::GetCheckState(HTREEITEM hItem) const +{ return TreeView_GetCheckState(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetChild(HTREEITEM hItem) const +{ return TreeView_GetChild(m_hwnd, hItem); +} + +int CCtrlTreeView::GetCount() const +{ return TreeView_GetCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetDropHilight() const +{ return TreeView_GetDropHilight(m_hwnd); +} + +HWND CCtrlTreeView::GetEditControl() const +{ return TreeView_GetEditControl(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetFirstVisible() const +{ return TreeView_GetFirstVisible(m_hwnd); +} + +HIMAGELIST CCtrlTreeView::GetImageList(int iImage) const +{ return TreeView_GetImageList(m_hwnd, iImage); +} + +int CCtrlTreeView::GetIndent() const +{ return TreeView_GetIndent(m_hwnd); +} + +COLORREF CCtrlTreeView::GetInsertMarkColor() const +{ return TreeView_GetInsertMarkColor(m_hwnd); +} + +bool CCtrlTreeView::GetItem(TVITEMEX *tvi) const +{ return TreeView_GetItem(m_hwnd, tvi) == TRUE; +} + +int CCtrlTreeView::GetItemHeight() const +{ return TreeView_GetItemHeight(m_hwnd); +} + +void CCtrlTreeView::GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) const +{ TreeView_GetItemRect(m_hwnd, hItem, rcItem, fItemRect); +} + +uint32_t CCtrlTreeView::GetItemState(HTREEITEM hItem, uint32_t stateMask) const +{ return TreeView_GetItemState(m_hwnd, hItem, stateMask); +} + +HTREEITEM CCtrlTreeView::GetLastVisible() const +{ return TreeView_GetLastVisible(m_hwnd); +} + +COLORREF CCtrlTreeView::GetLineColor() const +{ return TreeView_GetLineColor(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetNextItem(HTREEITEM hItem, uint32_t flag) const +{ return TreeView_GetNextItem(m_hwnd, hItem, flag); +} + +HTREEITEM CCtrlTreeView::GetNextSibling(HTREEITEM hItem) const +{ return TreeView_GetNextSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetNextVisible(HTREEITEM hItem) const +{ return TreeView_GetNextVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetParent(HTREEITEM hItem) const +{ return TreeView_GetParent(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevSibling(HTREEITEM hItem) const +{ return TreeView_GetPrevSibling(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetPrevVisible(HTREEITEM hItem) const +{ return TreeView_GetPrevVisible(m_hwnd, hItem); +} + +HTREEITEM CCtrlTreeView::GetRoot() const +{ return TreeView_GetRoot(m_hwnd); +} + +uint32_t CCtrlTreeView::GetScrollTime() const +{ return TreeView_GetScrollTime(m_hwnd); +} + +HTREEITEM CCtrlTreeView::GetSelection() const +{ return TreeView_GetSelection(m_hwnd); +} + +COLORREF CCtrlTreeView::GetTextColor() const +{ return TreeView_GetTextColor(m_hwnd); +} + +HWND CCtrlTreeView::GetToolTips() const +{ return TreeView_GetToolTips(m_hwnd); +} + +BOOL CCtrlTreeView::GetUnicodeFormat() const +{ return TreeView_GetUnicodeFormat(m_hwnd); +} + +unsigned CCtrlTreeView::GetVisibleCount() const +{ return TreeView_GetVisibleCount(m_hwnd); +} + +HTREEITEM CCtrlTreeView::HitTest(TVHITTESTINFO *hti) const +{ return TreeView_HitTest(m_hwnd, hti); +} + +HTREEITEM CCtrlTreeView::InsertItem(TVINSERTSTRUCT *tvis) +{ return TreeView_InsertItem(m_hwnd, tvis); +} + +void CCtrlTreeView::Select(HTREEITEM hItem, uint32_t flag) +{ TreeView_Select(m_hwnd, hItem, flag); +} + +void CCtrlTreeView::SelectDropTarget(HTREEITEM hItem) +{ TreeView_SelectDropTarget(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectItem(HTREEITEM hItem) +{ TreeView_SelectItem(m_hwnd, hItem); +} + +void CCtrlTreeView::SelectSetFirstVisible(HTREEITEM hItem) +{ TreeView_SelectSetFirstVisible(m_hwnd, hItem); +} + +COLORREF CCtrlTreeView::SetBkColor(COLORREF clBack) +{ return TreeView_SetBkColor(m_hwnd, clBack); +} + +void CCtrlTreeView::SetCheckState(HTREEITEM hItem, uint32_t state) +{ TreeView_SetCheckState(m_hwnd, hItem, state); +} + +HIMAGELIST CCtrlTreeView::SetImageList(HIMAGELIST hIml, int iImage) +{ return TreeView_SetImageList(m_hwnd, hIml, iImage); +} + +void CCtrlTreeView::SetIndent(int iIndent) +{ TreeView_SetIndent(m_hwnd, iIndent); +} + +void CCtrlTreeView::SetInsertMark(HTREEITEM hItem, BOOL fAfter) +{ TreeView_SetInsertMark(m_hwnd, hItem, fAfter); +} + +COLORREF CCtrlTreeView::SetInsertMarkColor(COLORREF clMark) +{ return TreeView_SetInsertMarkColor(m_hwnd, clMark); +} + +void CCtrlTreeView::SetItem(TVITEMEX *tvi) +{ TreeView_SetItem(m_hwnd, tvi); +} + +void CCtrlTreeView::SetItemHeight(short cyItem) +{ TreeView_SetItemHeight(m_hwnd, cyItem); +} + +void CCtrlTreeView::SetItemState(HTREEITEM hItem, uint32_t state, uint32_t stateMask) +{ TreeView_SetItemState(m_hwnd, hItem, state, stateMask); +} + +COLORREF CCtrlTreeView::SetLineColor(COLORREF clLine) +{ return TreeView_SetLineColor(m_hwnd, clLine); +} + +void CCtrlTreeView::SetScrollTime(UINT uMaxScrollTime) +{ TreeView_SetScrollTime(m_hwnd, uMaxScrollTime); +} + +COLORREF CCtrlTreeView::SetTextColor(COLORREF clText) +{ return TreeView_SetTextColor(m_hwnd, clText); +} + +HWND CCtrlTreeView::SetToolTips(HWND hwndToolTips) +{ return TreeView_SetToolTips(m_hwnd, hwndToolTips); +} + +BOOL CCtrlTreeView::SetUnicodeFormat(BOOL fUnicode) +{ return TreeView_SetUnicodeFormat(m_hwnd, fUnicode); +} + +void CCtrlTreeView::SortChildren(HTREEITEM hItem, BOOL fRecurse) +{ TreeView_SortChildren(m_hwnd, hItem, fRecurse); +} + +void CCtrlTreeView::SortChildrenCB(TVSORTCB *cb, BOOL fRecurse) +{ TreeView_SortChildrenCB(m_hwnd, cb, fRecurse); +} diff --git a/src/mir_core/src/Windows/miranda.cpp b/src/mir_core/src/Windows/miranda.cpp index ce52b20b0b..5649a69e4c 100644 --- a/src/mir_core/src/Windows/miranda.cpp +++ b/src/mir_core/src/Windows/miranda.cpp @@ -1,406 +1,406 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ - -#include "../stdafx.h" - -HWND hAPCWindow = nullptr; - -int InitPathUtils(void); -void RecalculateTime(void); - -void CheckLogs(); -void InitLogs(); -void UninitLogs(); - -void InitColourPicker(); -void InitHyperlink(); -void InitTimeZones(); -void InitWinver(); - -HINSTANCE g_hInst = nullptr; - -HCURSOR g_hCursorNS, g_hCursorWE; -HANDLE hThreadQueueEmpty; -HANDLE hShutdownEvent, hPreShutdownEvent; -uint32_t mir_tls = 0; - -static bool g_bMirandaTerminated = false; -bool g_bEnableDpiAware = false; - -MIR_CORE_DLL(bool) Miranda_IsTerminated() -{ - return g_bMirandaTerminated; -} - -MIR_CORE_DLL(void) Miranda_SetTerminated(void) -{ - g_bMirandaTerminated = true; - - NotifyEventHooks(hPreShutdownEvent, 0, 0); - NotifyEventHooks(hShutdownEvent, 0, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct MWaitableObject -{ - MWaitableObject(MWaitableStub pFunc, HANDLE hEvent) : - m_bOwnsEvent(false), - m_hEvent(hEvent), - m_pFunc(pFunc), - m_pInfo(INVALID_HANDLE_VALUE) - { - if (hEvent == nullptr) { - m_hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr); - m_bOwnsEvent = true; - } - } - - MWaitableObject(MWaitableStubEx pFunc, void *pInfo) : - m_bOwnsEvent(true), - m_hEvent(CreateEvent(nullptr, TRUE, TRUE, nullptr)), - m_pFuncEx(pFunc), - m_pInfo(pInfo) - {} - - ~MWaitableObject() - { - if (m_bOwnsEvent) - ::CloseHandle(m_hEvent); - } - - HANDLE m_hEvent; - union - { - MWaitableStub m_pFunc; - MWaitableStubEx m_pFuncEx; - }; - void *m_pInfo; - - bool m_bOwnsEvent; -}; - -static OBJLIST arWaitableObjects(1, HandleKeySortT); - -MIR_CORE_DLL(void) Miranda_WaitOnHandle(MWaitableStub pFunc, HANDLE hEvent) -{ - arWaitableObjects.insert(new MWaitableObject(pFunc, hEvent)); -} - -MIR_CORE_DLL(void) Miranda_WaitOnHandleEx(MWaitableStubEx pFunc, void *pInfo) -{ - arWaitableObjects.insert(new MWaitableObject(pFunc, pInfo)); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static INT_PTR RestartMiranda(WPARAM wParam, LPARAM lParam) -{ - wchar_t mirandaPath[MAX_PATH], cmdLine[MAX_PATH]; - if (lParam) - wcsncpy_s(mirandaPath, (const wchar_t*)lParam, _TRUNCATE); - else - GetModuleFileName(nullptr, mirandaPath, _countof(mirandaPath)); - - if (wParam) { - VARSW profilename(L"%miranda_profilename%"); - mir_snwprintf(cmdLine, L"\"%s\" /restart:%d /profile=%s", mirandaPath, GetCurrentProcessId(), (wchar_t*)profilename); - } - else mir_snwprintf(cmdLine, L"\"%s\" /restart:%d", mirandaPath, GetCurrentProcessId()); - - CallService("CloseAction", 0, 0); - - PROCESS_INFORMATION pi; - STARTUPINFO startupInfo = { 0 }; - startupInfo.cb = sizeof(startupInfo); - CreateProcess(mirandaPath, cmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &pi); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// module init - -static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_USER+1) { - PAPCFUNC pFunc = (PAPCFUNC)wParam; - pFunc((ULONG_PTR)lParam); - return 0; - } - - if (msg == WM_TIMER) - CheckLogs(); - - if (msg == WM_TIMECHANGE) - RecalculateTime(); - - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -static void LoadCoreModule(void) -{ - INITCOMMONCONTROLSEX icce = {0}; - icce.dwSize = sizeof(icce); - icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES; - InitCommonControlsEx(&icce); - - hAPCWindow = CreateWindowEx(0, L"ComboLBox", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); - SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW); - DestroyWindow(hAPCWindow); - - hAPCWindow = CreateWindowEx(0, L"STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); - SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc); - SetTimer(hAPCWindow, 1, 1000, nullptr); - hThreadQueueEmpty = CreateEvent(nullptr, TRUE, TRUE, nullptr); - - InitWinver(); - InitPathUtils(); - InitLogs(); - InitColourPicker(); - InitHyperlink(); - InitTimeZones(); - InitialiseModularEngine(); - - wchar_t wszIniPath[MAX_PATH]; - PathToAbsoluteW(L"mirandaboot.ini", wszIniPath); - if (GetPrivateProfileIntW(L"Interface", L"DpiAware", 0, wszIniPath) == 1) - g_bEnableDpiAware = true; - - CreateServiceFunction(MS_SYSTEM_RESTART, RestartMiranda); - - hShutdownEvent = CreateHookableEvent(ME_SYSTEM_SHUTDOWN); - hPreShutdownEvent = CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN); - - pfnRtlGenRandom = (PGENRANDOM)GetProcAddress(GetModuleHandleA("advapi32"), "SystemFunction036"); -} - -MIR_CORE_DLL(void) UnloadCoreModule(void) -{ - DestroyWindow(hAPCWindow); - CloseHandle(hThreadQueueEmpty); - TlsFree(mir_tls); - - DestroyModularEngine(); - UninitLogs(); - UnloadLangPackModule(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Message loop - -static HMODULE hThemeAPI; - -typedef HRESULT(STDAPICALLTYPE *pfnBufferedPaintInit)(void); -pfnBufferedPaintInit bufferedPaintInit; - -typedef HRESULT(STDAPICALLTYPE *pfnBufferedPaintUninit)(void); -pfnBufferedPaintUninit bufferedPaintUninit; - -static void crtErrorHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned, uintptr_t) -{} - -static void __cdecl compactHeapsThread(void*) -{ - Thread_SetName("compactHeapsThread"); - - while (!Miranda_IsTerminated()) { - SleepEx((1000 * 60) * 5, TRUE); // every 5 minutes - - HANDLE hHeaps[256]; - uint32_t hc = GetProcessHeaps(255, (PHANDLE)&hHeaps); - if (hc != 0 && hc < 256) { - __try { - for (uint32_t j = 0; j < hc; j++) - HeapCompact(hHeaps[j], 0); - } - __except (EXCEPTION_EXECUTE_HANDLER) - {} - } - } -} - -static void EnableDpiAware() -{ - if (HMODULE hInst = GetModuleHandleW(L"user32")) { - typedef void (WINAPI *pfnSetProcessDpiAwarenessContext)(HANDLE); - if (auto *pFunc = (pfnSetProcessDpiAwarenessContext)GetProcAddress(hInst, "SetProcessDpiAwarenessContext")) { - pFunc(HANDLE(-4)); - return; - } - - typedef void (WINAPI *pfnSetProcessDpiAwareness)(DWORD); - if (auto *pFunc = (pfnSetProcessDpiAwareness)GetProcAddress(hInst, "SetProcessDpiAwareness")) { - pFunc(2); - return; - } - - typedef void (WINAPI *pfnSetProcessDPIAware_t)(void); - if (auto *pFunc = (pfnSetProcessDPIAware_t)GetProcAddress(hInst, "SetProcessDPIAware")) - pFunc(); - } -} - -MIR_CORE_DLL(void) BeginMessageLoop() -{ - _set_invalid_parameter_handler(&crtErrorHandler); - - #ifdef _DEBUG - _CrtSetReportMode(_CRT_ASSERT, 0); - #endif - - #ifdef _DEBUG - if (CmdLine_GetOption(L"memdebug")) - _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); - #endif - - hThemeAPI = LoadLibrary(L"uxtheme.dll"); - if (hThemeAPI) { - bufferedPaintInit = (pfnBufferedPaintInit)GetProcAddress(hThemeAPI, "BufferedPaintInit"); - bufferedPaintUninit = (pfnBufferedPaintUninit)GetProcAddress(hThemeAPI, "BufferedPaintUninit"); - } - - if (g_bEnableDpiAware) - EnableDpiAware(); - - if (bufferedPaintInit) - bufferedPaintInit(); - - OleInitialize(nullptr); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static uint32_t dwEventTime = 0; - -void checkIdle(MSG *msg) -{ - switch (msg->message) { - case WM_MOUSEACTIVATE: - case WM_MOUSEMOVE: - case WM_CHAR: - dwEventTime = GetTickCount(); - } -} - -MIR_CORE_DLL(uint32_t) Miranda_GetIdle() -{ - return dwEventTime; -} - -static uint32_t myWait() -{ - HANDLE *hWaitObjects = (HANDLE *)_alloca(arWaitableObjects.getCount() * sizeof(HANDLE)); - for (int i = 0; i < arWaitableObjects.getCount(); i++) - hWaitObjects[i] = arWaitableObjects[i].m_hEvent; - - return MsgWaitForMultipleObjectsEx(arWaitableObjects.getCount(), hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); -} - -MIR_CORE_DLL(void) EnterMessageLoop() -{ - mir_forkthread(compactHeapsThread); - dwEventTime = GetTickCount(); - uint32_t myPid = GetCurrentProcessId(); - - bool messageloop = true; - while (messageloop) { - MSG msg; - BOOL dying = FALSE; - uint32_t rc = myWait(); - if (rc < WAIT_OBJECT_0 + arWaitableObjects.getCount()) { - auto &pWait = arWaitableObjects[rc - WAIT_OBJECT_0]; - if (pWait.m_pInfo == INVALID_HANDLE_VALUE) - (*pWait.m_pFunc)(); - else - (*pWait.m_pFuncEx)(pWait.m_pInfo); - - if (pWait.m_bOwnsEvent) - arWaitableObjects.remove(&pWait); - } - - while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { - if (msg.message != WM_QUIT) { - HWND h = GetForegroundWindow(); - DWORD pid = 0; - checkIdle(&msg); - if (h != nullptr && GetWindowThreadProcessId(h, &pid) && pid == myPid && GetClassLongPtr(h, GCW_ATOM) == 32770) - if (h != nullptr && IsDialogMessage(h, &msg)) /* Wine fix. */ - continue; - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else if (!dying) { - dying++; - g_bMirandaTerminated = true; - NotifyEventHooks(hPreShutdownEvent, 0, 0); - - // this spins and processes the msg loop, objects and APC. - Thread_Wait(); - NotifyEventHooks(hShutdownEvent, 0, 0); - // if the hooks generated any messages, it'll get processed before the second WM_QUIT - PostQuitMessage(0); - } - else if (dying) - messageloop = false; - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) LeaveMessageLoop() -{ - // Dragons live there... - __try { - OleUninitialize(); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - } - - if (bufferedPaintUninit) { - bufferedPaintUninit(); - FreeLibrary(hThemeAPI); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// entry point - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, uint32_t fdwReason, LPVOID) -{ - if (fdwReason == DLL_PROCESS_ATTACH) { - g_hInst = hinstDLL; - mir_tls = TlsAlloc(); - LoadCoreModule(); - } - else if (fdwReason == DLL_THREAD_DETACH) { - HANDLE hEvent = TlsGetValue(mir_tls); - if (hEvent) - CloseHandle(hEvent); - } - return TRUE; -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "../stdafx.h" + +HWND hAPCWindow = nullptr; + +int InitPathUtils(void); +void RecalculateTime(void); + +void CheckLogs(); +void InitLogs(); +void UninitLogs(); + +void InitColourPicker(); +void InitHyperlink(); +void InitTimeZones(); +void InitWinver(); + +HINSTANCE g_hInst = nullptr; + +HCURSOR g_hCursorNS, g_hCursorWE; +HANDLE hThreadQueueEmpty; +HANDLE hShutdownEvent, hPreShutdownEvent; +uint32_t mir_tls = 0; + +static bool g_bMirandaTerminated = false; +bool g_bEnableDpiAware = false; + +MIR_CORE_DLL(bool) Miranda_IsTerminated() +{ + return g_bMirandaTerminated; +} + +MIR_CORE_DLL(void) Miranda_SetTerminated(void) +{ + g_bMirandaTerminated = true; + + NotifyEventHooks(hPreShutdownEvent, 0, 0); + NotifyEventHooks(hShutdownEvent, 0, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct MWaitableObject +{ + MWaitableObject(MWaitableStub pFunc, HANDLE hEvent) : + m_bOwnsEvent(false), + m_hEvent(hEvent), + m_pFunc(pFunc), + m_pInfo(INVALID_HANDLE_VALUE) + { + if (hEvent == nullptr) { + m_hEvent = CreateEvent(nullptr, TRUE, TRUE, nullptr); + m_bOwnsEvent = true; + } + } + + MWaitableObject(MWaitableStubEx pFunc, void *pInfo) : + m_bOwnsEvent(true), + m_hEvent(CreateEvent(nullptr, TRUE, TRUE, nullptr)), + m_pFuncEx(pFunc), + m_pInfo(pInfo) + {} + + ~MWaitableObject() + { + if (m_bOwnsEvent) + ::CloseHandle(m_hEvent); + } + + HANDLE m_hEvent; + union + { + MWaitableStub m_pFunc; + MWaitableStubEx m_pFuncEx; + }; + void *m_pInfo; + + bool m_bOwnsEvent; +}; + +static OBJLIST arWaitableObjects(1, HandleKeySortT); + +MIR_CORE_DLL(void) Miranda_WaitOnHandle(MWaitableStub pFunc, HANDLE hEvent) +{ + arWaitableObjects.insert(new MWaitableObject(pFunc, hEvent)); +} + +MIR_CORE_DLL(void) Miranda_WaitOnHandleEx(MWaitableStubEx pFunc, void *pInfo) +{ + arWaitableObjects.insert(new MWaitableObject(pFunc, pInfo)); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static INT_PTR RestartMiranda(WPARAM wParam, LPARAM lParam) +{ + wchar_t mirandaPath[MAX_PATH], cmdLine[MAX_PATH]; + if (lParam) + wcsncpy_s(mirandaPath, (const wchar_t*)lParam, _TRUNCATE); + else + GetModuleFileName(nullptr, mirandaPath, _countof(mirandaPath)); + + if (wParam) { + VARSW profilename(L"%miranda_profilename%"); + mir_snwprintf(cmdLine, L"\"%s\" /restart:%d /profile=%s", mirandaPath, GetCurrentProcessId(), (wchar_t*)profilename); + } + else mir_snwprintf(cmdLine, L"\"%s\" /restart:%d", mirandaPath, GetCurrentProcessId()); + + CallService("CloseAction", 0, 0); + + PROCESS_INFORMATION pi; + STARTUPINFO startupInfo = { 0 }; + startupInfo.cb = sizeof(startupInfo); + CreateProcess(mirandaPath, cmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &pi); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// module init + +static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_USER+1) { + PAPCFUNC pFunc = (PAPCFUNC)wParam; + pFunc((ULONG_PTR)lParam); + return 0; + } + + if (msg == WM_TIMER) + CheckLogs(); + + if (msg == WM_TIMECHANGE) + RecalculateTime(); + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +static void LoadCoreModule(void) +{ + INITCOMMONCONTROLSEX icce = {0}; + icce.dwSize = sizeof(icce); + icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES; + InitCommonControlsEx(&icce); + + hAPCWindow = CreateWindowEx(0, L"ComboLBox", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); + SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW); + DestroyWindow(hAPCWindow); + + hAPCWindow = CreateWindowEx(0, L"STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); + SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc); + SetTimer(hAPCWindow, 1, 1000, nullptr); + hThreadQueueEmpty = CreateEvent(nullptr, TRUE, TRUE, nullptr); + + InitWinver(); + InitPathUtils(); + InitLogs(); + InitColourPicker(); + InitHyperlink(); + InitTimeZones(); + InitialiseModularEngine(); + + wchar_t wszIniPath[MAX_PATH]; + PathToAbsoluteW(L"mirandaboot.ini", wszIniPath); + if (GetPrivateProfileIntW(L"Interface", L"DpiAware", 0, wszIniPath) == 1) + g_bEnableDpiAware = true; + + CreateServiceFunction(MS_SYSTEM_RESTART, RestartMiranda); + + hShutdownEvent = CreateHookableEvent(ME_SYSTEM_SHUTDOWN); + hPreShutdownEvent = CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN); + + pfnRtlGenRandom = (PGENRANDOM)GetProcAddress(GetModuleHandleA("advapi32"), "SystemFunction036"); +} + +MIR_CORE_DLL(void) UnloadCoreModule(void) +{ + DestroyWindow(hAPCWindow); + CloseHandle(hThreadQueueEmpty); + TlsFree(mir_tls); + + DestroyModularEngine(); + UninitLogs(); + UnloadLangPackModule(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Message loop + +static HMODULE hThemeAPI; + +typedef HRESULT(STDAPICALLTYPE *pfnBufferedPaintInit)(void); +pfnBufferedPaintInit bufferedPaintInit; + +typedef HRESULT(STDAPICALLTYPE *pfnBufferedPaintUninit)(void); +pfnBufferedPaintUninit bufferedPaintUninit; + +static void crtErrorHandler(const wchar_t *, const wchar_t *, const wchar_t *, unsigned, uintptr_t) +{} + +static void __cdecl compactHeapsThread(void*) +{ + Thread_SetName("compactHeapsThread"); + + while (!Miranda_IsTerminated()) { + SleepEx((1000 * 60) * 5, TRUE); // every 5 minutes + + HANDLE hHeaps[256]; + uint32_t hc = GetProcessHeaps(255, (PHANDLE)&hHeaps); + if (hc != 0 && hc < 256) { + __try { + for (uint32_t j = 0; j < hc; j++) + HeapCompact(hHeaps[j], 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + {} + } + } +} + +static void EnableDpiAware() +{ + if (HMODULE hInst = GetModuleHandleW(L"user32")) { + typedef void (WINAPI *pfnSetProcessDpiAwarenessContext)(HANDLE); + if (auto *pFunc = (pfnSetProcessDpiAwarenessContext)GetProcAddress(hInst, "SetProcessDpiAwarenessContext")) { + pFunc(HANDLE(-4)); + return; + } + + typedef void (WINAPI *pfnSetProcessDpiAwareness)(DWORD); + if (auto *pFunc = (pfnSetProcessDpiAwareness)GetProcAddress(hInst, "SetProcessDpiAwareness")) { + pFunc(2); + return; + } + + typedef void (WINAPI *pfnSetProcessDPIAware_t)(void); + if (auto *pFunc = (pfnSetProcessDPIAware_t)GetProcAddress(hInst, "SetProcessDPIAware")) + pFunc(); + } +} + +MIR_CORE_DLL(void) BeginMessageLoop() +{ + _set_invalid_parameter_handler(&crtErrorHandler); + + #ifdef _DEBUG + _CrtSetReportMode(_CRT_ASSERT, 0); + #endif + + #ifdef _DEBUG + if (CmdLine_GetOption(L"memdebug")) + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + #endif + + hThemeAPI = LoadLibrary(L"uxtheme.dll"); + if (hThemeAPI) { + bufferedPaintInit = (pfnBufferedPaintInit)GetProcAddress(hThemeAPI, "BufferedPaintInit"); + bufferedPaintUninit = (pfnBufferedPaintUninit)GetProcAddress(hThemeAPI, "BufferedPaintUninit"); + } + + if (g_bEnableDpiAware) + EnableDpiAware(); + + if (bufferedPaintInit) + bufferedPaintInit(); + + OleInitialize(nullptr); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static uint32_t dwEventTime = 0; + +void checkIdle(MSG *msg) +{ + switch (msg->message) { + case WM_MOUSEACTIVATE: + case WM_MOUSEMOVE: + case WM_CHAR: + dwEventTime = GetTickCount(); + } +} + +MIR_CORE_DLL(uint32_t) Miranda_GetIdle() +{ + return dwEventTime; +} + +static uint32_t myWait() +{ + HANDLE *hWaitObjects = (HANDLE *)_alloca(arWaitableObjects.getCount() * sizeof(HANDLE)); + for (int i = 0; i < arWaitableObjects.getCount(); i++) + hWaitObjects[i] = arWaitableObjects[i].m_hEvent; + + return MsgWaitForMultipleObjectsEx(arWaitableObjects.getCount(), hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE); +} + +MIR_CORE_DLL(void) EnterMessageLoop() +{ + mir_forkthread(compactHeapsThread); + dwEventTime = GetTickCount(); + uint32_t myPid = GetCurrentProcessId(); + + bool messageloop = true; + while (messageloop) { + MSG msg; + BOOL dying = FALSE; + uint32_t rc = myWait(); + if (rc < WAIT_OBJECT_0 + arWaitableObjects.getCount()) { + auto &pWait = arWaitableObjects[rc - WAIT_OBJECT_0]; + if (pWait.m_pInfo == INVALID_HANDLE_VALUE) + (*pWait.m_pFunc)(); + else + (*pWait.m_pFuncEx)(pWait.m_pInfo); + + if (pWait.m_bOwnsEvent) + arWaitableObjects.remove(&pWait); + } + + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + if (msg.message != WM_QUIT) { + HWND h = GetForegroundWindow(); + DWORD pid = 0; + checkIdle(&msg); + if (h != nullptr && GetWindowThreadProcessId(h, &pid) && pid == myPid && GetClassLongPtr(h, GCW_ATOM) == 32770) + if (h != nullptr && IsDialogMessage(h, &msg)) /* Wine fix. */ + continue; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + else if (!dying) { + dying++; + g_bMirandaTerminated = true; + NotifyEventHooks(hPreShutdownEvent, 0, 0); + + // this spins and processes the msg loop, objects and APC. + Thread_Wait(); + NotifyEventHooks(hShutdownEvent, 0, 0); + // if the hooks generated any messages, it'll get processed before the second WM_QUIT + PostQuitMessage(0); + } + else if (dying) + messageloop = false; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) LeaveMessageLoop() +{ + // Dragons live there... + __try { + OleUninitialize(); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + + if (bufferedPaintUninit) { + bufferedPaintUninit(); + FreeLibrary(hThemeAPI); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// entry point + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, uint32_t fdwReason, LPVOID) +{ + if (fdwReason == DLL_PROCESS_ATTACH) { + g_hInst = hinstDLL; + mir_tls = TlsAlloc(); + LoadCoreModule(); + } + else if (fdwReason == DLL_THREAD_DETACH) { + HANDLE hEvent = TlsGetValue(mir_tls); + if (hEvent) + CloseHandle(hEvent); + } + return TRUE; +} diff --git a/src/mir_core/src/db.cpp b/src/mir_core/src/db.cpp index 63899787c7..5b2048c2bb 100644 --- a/src/mir_core/src/db.cpp +++ b/src/mir_core/src/db.cpp @@ -1,576 +1,576 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" - -MIR_CORE_EXPORT MDatabaseCommon* g_pCurrDb = nullptr; - -///////////////////////////////////////////////////////////////////////////////////////// -// database functions - -MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode) -{ - if (g_pCurrDb) - g_pCurrDb->SetCacheSafetyMode(bNewMode != 0); -} - -MIR_CORE_DLL(int) db_get_contact_count(void) -{ - return (g_pCurrDb) ? g_pCurrDb->GetContactCount() : 0; -} - -MIR_CORE_DLL(MDatabaseCommon*) db_get_current() -{ - return g_pCurrDb; -} - -MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName) -{ - return (g_pCurrDb) ? g_pCurrDb->DeleteModule(hContact, szModuleName) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int CheckIfModuleIsEmptyProc(const char *, void *) -{ - return 1; -} - -MIR_CORE_DLL(bool) db_is_module_empty(MCONTACT hContact, const char *szModule) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, CheckIfModuleIsEmptyProc, szModule, 0) < 0 : true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct EnumProcParam -{ - MCONTACT hContact; - LPCSTR szModule, szNewModule; -}; - -static int EnumProc(const char *szSetting, void *lParam) -{ - EnumProcParam *param = (EnumProcParam *)lParam; - - DBVARIANT dbv; - if (!db_get(param->hContact, param->szModule, szSetting, &dbv)) { - db_set(param->hContact, param->szNewModule, szSetting, &dbv); - db_free(&dbv); - } - return 0; -} - -MIR_CORE_DLL(int) db_copy_module(const char *szModule, const char *szNewModule, MCONTACT hContact) -{ - EnumProcParam param = { hContact, szModule, szNewModule }; - return db_enum_settings(hContact, EnumProc, szModule, ¶m); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// contact functions - -MIR_CORE_DLL(MCONTACT) db_add_contact(void) -{ - MCONTACT hNew = (g_pCurrDb) ? g_pCurrDb->AddContact() : 0; - Netlib_Logf(nullptr, "New contact created: %d", hNew); - return hNew; -} - -MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact) -{ - ptrW wszPhoto(db_get_wsa(hContact, "ContactPhoto", "File")); - if (wszPhoto != nullptr) { - #ifdef _MSC_VER - DeleteFileW(wszPhoto); - #else - remove(T2Utf(wszPhoto)); - #endif - } - - Netlib_Logf(nullptr, "Contact deleted: %d", hContact); - return (g_pCurrDb) ? g_pCurrDb->DeleteContact(hContact) : 0; -} - -MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact) -{ - return (g_pCurrDb) ? g_pCurrDb->IsDbContact(hContact) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// enumerators - -MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC pFunc, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumModuleNames(pFunc, param) : 0; -} - -MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumResidentSettings(pFunc, param) : 0; -} - -MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pFunc, const char *szModule, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, pFunc, szModule, param) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// getting data - -MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) - { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return uint8_t(dbv.wVal); - case DBVT_DWORD: return uint8_t(dbv.dVal); - } - g_pCurrDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return uint16_t(dbv.dVal); - } - g_pCurrDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(uint32_t) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, uint32_t errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return dbv.dVal; - } - g_pCurrDb->FreeVariant(&dbv); - } - } - - return errorValue; -} - -MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (g_pCurrDb == nullptr) - return 1; - - return g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) -{ - if (g_pCurrDb == nullptr) - return 1; - - dbv->type = (uint8_t)nType; - return g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_ASCIIZ }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pszVal; - } - - return (szValue == nullptr) ? nullptr : mir_strdup(szValue); -} - -MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_UTF8 }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pszVal; - } - - return (szValue == nullptr) ? nullptr : mir_strdup(szValue); -} - -MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_WCHAR }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pwszVal; - } - - return (szValue == nullptr) ? nullptr : mir_wstrdup(szValue); -} - -MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const char *szValue) -{ - if (g_pCurrDb == nullptr) - return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); - - DBVARIANT dbv = { DBVT_ASCIIZ }; - if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); - - return CMStringA(ptrA(dbv.pszVal).get()); -} - -MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const wchar_t *szValue) -{ - if (g_pCurrDb == nullptr) - return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); - - DBVARIANT dbv = { DBVT_WCHAR }; - if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); - - return CMStringW(ptrW(dbv.pwszVal).get()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// getting static data - -MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_UTF8; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_WCHAR; - dbv.pwszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// setting data - -MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (g_pCurrDb == nullptr) return 1; - - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, uint8_t val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_BYTE; - dbv.bVal = val; - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, uint16_t val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_WORD; - dbv.wVal = val; - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, uint32_t val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_DWORD; - dbv.dVal = val; - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = (char*)(val == nullptr ? "" : val); - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_WCHAR; - dbv.pwszVal = (wchar_t*)(val == nullptr ? L"" : val); - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_UTF8; - dbv.pszVal = (char*)(val == nullptr ? "" : val); - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, const void *val, unsigned len) -{ - if (g_pCurrDb == nullptr) return 1; - - DBVARIANT dbv; - dbv.type = DBVT_BLOB; - dbv.cpbVal = (uint16_t)len; - dbv.pbVal = (unsigned char*)val; - return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// events - -MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->AddEvent(hContact, dbei); -} - -MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventCount(hContact); -} - -MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->DeleteEvent(hDbEvent); -} - -MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EditEvent(hContact, hDbEvent, dbei); -} - -MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstEvent(hContact); -} - -MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstUnreadEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->GetEvent(hDbEvent, dbei); -} - -MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetBlobSize(hDbEvent); -} - -MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventContact(hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindLastEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->MarkEventRead(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindPrevEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_replace(MCONTACT hContact, const DBEVENTINFO *dbei) -{ - MEVENT ret = 0; - if (dbei->szId) - ret = db_event_getById(dbei->szModule, dbei->szId); - if (!ret) - ret = db_event_add(hContact, dbei); - // do not uncomment - // else - // db_event_edit(hContact, ret, dbei); - return ret; -} - -MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventById(szModule, szId); -} - -MIR_CORE_DLL(int) db_event_updateId(MEVENT hDbEvent, const char *szId) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->UpdateEventId(hDbEvent, szId); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// event cursors - -DB::EventCursor::~EventCursor() -{ -} - -MIR_CORE_DLL(DB::EventCursor*) DB::Events(MCONTACT hContact, MEVENT iStartEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursor(hContact, iStartEvent); -} - -MIR_CORE_DLL(DB::EventCursor*) DB::EventsRev(MCONTACT hContact, MEVENT iStartEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursorRev(hContact, iStartEvent); -} - -DB::ECPTR::ECPTR(EventCursor *_pCursor) : - m_cursor(_pCursor), - m_prevFetched(-1), - m_currEvent(0) -{ -} - -DB::ECPTR::~ECPTR() -{ - delete m_cursor; -} - -void DB::ECPTR::DeleteEvent() -{ - m_prevFetched = m_cursor->FetchNext(); - db_event_delete(m_currEvent); -} - -MEVENT DB::ECPTR::FetchNext() -{ - if (m_prevFetched != -1) { - m_currEvent = m_prevFetched; - m_prevFetched = -1; - } - else m_currEvent = m_cursor->FetchNext(); - - return m_currEvent; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// misc functions - -MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) -{ - return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->FreeVariant(dbv); -} - -MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) -{ - if (g_pCurrDb == nullptr) - return 1; - - return g_pCurrDb->DeleteContactSetting(hContact, szModule, szSetting); -} - -MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? nullptr : g_pCurrDb->getCache()->GetCachedContact(hContact); -} - -MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstContact(szProto); -} - -MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextContact(hContact, szProto); -} - -MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db) -{ - g_pCurrDb = _db; - if (g_pCurrDb == nullptr) - return; - - // try to get the langpack's name from a profile - ptrW langpack(db_get_wsa(0, "Langpack", "Current")); - if (langpack && langpack[0] != '\0') - LoadLangPack(langpack); - else - GetDefaultLang(); -} - -MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) -{ - if (g_pCurrDb == nullptr || szModule == nullptr || szService == nullptr) - return FALSE; - - char str[MAXMODULELABELLENGTH * 2]; - mir_snprintf(str, "%s/%s", szModule, szService); - return g_pCurrDb->SetSettingResident(bEnable, str); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" + +MIR_CORE_EXPORT MDatabaseCommon* g_pCurrDb = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// +// database functions + +MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode) +{ + if (g_pCurrDb) + g_pCurrDb->SetCacheSafetyMode(bNewMode != 0); +} + +MIR_CORE_DLL(int) db_get_contact_count(void) +{ + return (g_pCurrDb) ? g_pCurrDb->GetContactCount() : 0; +} + +MIR_CORE_DLL(MDatabaseCommon*) db_get_current() +{ + return g_pCurrDb; +} + +MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName) +{ + return (g_pCurrDb) ? g_pCurrDb->DeleteModule(hContact, szModuleName) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int CheckIfModuleIsEmptyProc(const char *, void *) +{ + return 1; +} + +MIR_CORE_DLL(bool) db_is_module_empty(MCONTACT hContact, const char *szModule) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, CheckIfModuleIsEmptyProc, szModule, 0) < 0 : true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +struct EnumProcParam +{ + MCONTACT hContact; + LPCSTR szModule, szNewModule; +}; + +static int EnumProc(const char *szSetting, void *lParam) +{ + EnumProcParam *param = (EnumProcParam *)lParam; + + DBVARIANT dbv; + if (!db_get(param->hContact, param->szModule, szSetting, &dbv)) { + db_set(param->hContact, param->szNewModule, szSetting, &dbv); + db_free(&dbv); + } + return 0; +} + +MIR_CORE_DLL(int) db_copy_module(const char *szModule, const char *szNewModule, MCONTACT hContact) +{ + EnumProcParam param = { hContact, szModule, szNewModule }; + return db_enum_settings(hContact, EnumProc, szModule, ¶m); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// contact functions + +MIR_CORE_DLL(MCONTACT) db_add_contact(void) +{ + MCONTACT hNew = (g_pCurrDb) ? g_pCurrDb->AddContact() : 0; + Netlib_Logf(nullptr, "New contact created: %d", hNew); + return hNew; +} + +MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact) +{ + ptrW wszPhoto(db_get_wsa(hContact, "ContactPhoto", "File")); + if (wszPhoto != nullptr) { + #ifdef _MSC_VER + DeleteFileW(wszPhoto); + #else + remove(T2Utf(wszPhoto)); + #endif + } + + Netlib_Logf(nullptr, "Contact deleted: %d", hContact); + return (g_pCurrDb) ? g_pCurrDb->DeleteContact(hContact) : 0; +} + +MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact) +{ + return (g_pCurrDb) ? g_pCurrDb->IsDbContact(hContact) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// enumerators + +MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC pFunc, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumModuleNames(pFunc, param) : 0; +} + +MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumResidentSettings(pFunc, param) : 0; +} + +MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pFunc, const char *szModule, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, pFunc, szModule, param) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// getting data + +MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) + { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return uint8_t(dbv.wVal); + case DBVT_DWORD: return uint8_t(dbv.dVal); + } + g_pCurrDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return uint16_t(dbv.dVal); + } + g_pCurrDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(uint32_t) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, uint32_t errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return dbv.dVal; + } + g_pCurrDb->FreeVariant(&dbv); + } + } + + return errorValue; +} + +MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (g_pCurrDb == nullptr) + return 1; + + return g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) +{ + if (g_pCurrDb == nullptr) + return 1; + + dbv->type = (uint8_t)nType; + return g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_ASCIIZ }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pszVal; + } + + return (szValue == nullptr) ? nullptr : mir_strdup(szValue); +} + +MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_UTF8 }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pszVal; + } + + return (szValue == nullptr) ? nullptr : mir_strdup(szValue); +} + +MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_WCHAR }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pwszVal; + } + + return (szValue == nullptr) ? nullptr : mir_wstrdup(szValue); +} + +MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const char *szValue) +{ + if (g_pCurrDb == nullptr) + return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); + + DBVARIANT dbv = { DBVT_ASCIIZ }; + if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); + + return CMStringA(ptrA(dbv.pszVal).get()); +} + +MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const wchar_t *szValue) +{ + if (g_pCurrDb == nullptr) + return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); + + DBVARIANT dbv = { DBVT_WCHAR }; + if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); + + return CMStringW(ptrW(dbv.pwszVal).get()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// getting static data + +MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_UTF8; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_WCHAR; + dbv.pwszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// setting data + +MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (g_pCurrDb == nullptr) return 1; + + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, uint8_t val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_BYTE; + dbv.bVal = val; + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, uint16_t val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_WORD; + dbv.wVal = val; + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, uint32_t val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_DWORD; + dbv.dVal = val; + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = (char*)(val == nullptr ? "" : val); + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_WCHAR; + dbv.pwszVal = (wchar_t*)(val == nullptr ? L"" : val); + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_UTF8; + dbv.pszVal = (char*)(val == nullptr ? "" : val); + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, const void *val, unsigned len) +{ + if (g_pCurrDb == nullptr) return 1; + + DBVARIANT dbv; + dbv.type = DBVT_BLOB; + dbv.cpbVal = (uint16_t)len; + dbv.pbVal = (unsigned char*)val; + return g_pCurrDb->WriteContactSetting(hContact, szModule, szSetting, &dbv); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// events + +MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->AddEvent(hContact, dbei); +} + +MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventCount(hContact); +} + +MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->DeleteEvent(hDbEvent); +} + +MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EditEvent(hContact, hDbEvent, dbei); +} + +MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstEvent(hContact); +} + +MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstUnreadEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->GetEvent(hDbEvent, dbei); +} + +MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetBlobSize(hDbEvent); +} + +MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventContact(hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindLastEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->MarkEventRead(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindPrevEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_replace(MCONTACT hContact, const DBEVENTINFO *dbei) +{ + MEVENT ret = 0; + if (dbei->szId) + ret = db_event_getById(dbei->szModule, dbei->szId); + if (!ret) + ret = db_event_add(hContact, dbei); + // do not uncomment + // else + // db_event_edit(hContact, ret, dbei); + return ret; +} + +MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventById(szModule, szId); +} + +MIR_CORE_DLL(int) db_event_updateId(MEVENT hDbEvent, const char *szId) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->UpdateEventId(hDbEvent, szId); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// event cursors + +DB::EventCursor::~EventCursor() +{ +} + +MIR_CORE_DLL(DB::EventCursor*) DB::Events(MCONTACT hContact, MEVENT iStartEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursor(hContact, iStartEvent); +} + +MIR_CORE_DLL(DB::EventCursor*) DB::EventsRev(MCONTACT hContact, MEVENT iStartEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursorRev(hContact, iStartEvent); +} + +DB::ECPTR::ECPTR(EventCursor *_pCursor) : + m_cursor(_pCursor), + m_prevFetched(-1), + m_currEvent(0) +{ +} + +DB::ECPTR::~ECPTR() +{ + delete m_cursor; +} + +void DB::ECPTR::DeleteEvent() +{ + m_prevFetched = m_cursor->FetchNext(); + db_event_delete(m_currEvent); +} + +MEVENT DB::ECPTR::FetchNext() +{ + if (m_prevFetched != -1) { + m_currEvent = m_prevFetched; + m_prevFetched = -1; + } + else m_currEvent = m_cursor->FetchNext(); + + return m_currEvent; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// misc functions + +MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) +{ + return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->FreeVariant(dbv); +} + +MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) +{ + if (g_pCurrDb == nullptr) + return 1; + + return g_pCurrDb->DeleteContactSetting(hContact, szModule, szSetting); +} + +MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? nullptr : g_pCurrDb->getCache()->GetCachedContact(hContact); +} + +MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstContact(szProto); +} + +MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextContact(hContact, szProto); +} + +MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db) +{ + g_pCurrDb = _db; + if (g_pCurrDb == nullptr) + return; + + // try to get the langpack's name from a profile + ptrW langpack(db_get_wsa(0, "Langpack", "Current")); + if (langpack && langpack[0] != '\0') + LoadLangPack(langpack); + else + GetDefaultLang(); +} + +MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) +{ + if (g_pCurrDb == nullptr || szModule == nullptr || szService == nullptr) + return FALSE; + + char str[MAXMODULELABELLENGTH * 2]; + mir_snprintf(str, "%s/%s", szModule, szService); + return g_pCurrDb->SetSettingResident(bEnable, str); +} -- cgit v1.2.3