From cdad72e9512d163ed15bc89bd0a93e7da2ee4c50 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 18 Jan 2015 16:47:07 +0000 Subject: first working version of events git-svn-id: http://svn.miranda-ng.org/main/trunk@11872 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Dbx_mdb/src/dbcontacts.cpp | 38 +++--- plugins/Dbx_mdb/src/dbevents.cpp | 235 ++++++++++++++++++++++++++++++++----- plugins/Dbx_mdb/src/dbintf.cpp | 20 +++- plugins/Dbx_mdb/src/dbintf.h | 41 ++----- plugins/Dbx_mdb/src/dbsettings.cpp | 8 +- 5 files changed, 267 insertions(+), 75 deletions(-) (limited to 'plugins/Dbx_mdb/src') diff --git a/plugins/Dbx_mdb/src/dbcontacts.cpp b/plugins/Dbx_mdb/src/dbcontacts.cpp index 48c8b7e7cb..cf13a782b9 100644 --- a/plugins/Dbx_mdb/src/dbcontacts.cpp +++ b/plugins/Dbx_mdb/src/dbcontacts.cpp @@ -171,38 +171,44 @@ BOOL CDbxMdb::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) void CDbxMdb::FillContacts() { - m_contactCount = 0; + LIST arContacts(10); txn_ptr trnlck(m_pMdbEnv); mdb_open(trnlck, "contacts", MDB_INTEGERKEY, &m_dbContacts); + { + cursor_ptr cursor(trnlck, m_dbContacts); - cursor_ptr cursor(trnlck, m_dbContacts); + MDB_val key, data; + while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == 0) { + DBContact *dbc = (DBContact*)data.mv_data; + if (dbc->signature != DBCONTACT_SIGNATURE) + DatabaseCorruption(NULL); - MDB_val key, data; - while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == 0) { - DBContact *dbc = (DBContact*)data.mv_data; - if (dbc->signature != DBCONTACT_SIGNATURE) - DatabaseCorruption(NULL); + DBCachedContact *cc = m_cache->AddContactToCache(*(DWORD*)key.mv_data); + cc->dwDriverData = dbc->eventCount; + arContacts.insert(cc); + } + } - DWORD dwContactId = *(DWORD*)key.mv_data; - DBCachedContact *cc = m_cache->AddContactToCache(dwContactId); - cc->dwDriverData = 0; + m_contactCount = 0; + for (int i = 0; i < arContacts.getCount(); i++) { + DBCachedContact *cc = arContacts[i]; CheckProto(cc, ""); - - m_dwMaxContactId = dwContactId + 1; + + m_dwMaxContactId = cc->contactID+1; m_contactCount++; DBVARIANT dbv; dbv.type = DBVT_DWORD; - cc->nSubs = (0 != GetContactSetting(dwContactId, META_PROTO, "NumContacts", &dbv)) ? -1 : dbv.dVal; + 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 i = 0; i < cc->nSubs; i++) { char setting[100]; mir_snprintf(setting, SIZEOF(setting), "Handle%d", i); - cc->pSubs[i] = (0 != GetContactSetting(dwContactId, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; + cc->pSubs[i] = (0 != GetContactSetting(cc->contactID, META_PROTO, setting, &dbv)) ? NULL : dbv.dVal; } } - cc->nDefault = (0 != GetContactSetting(dwContactId, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; - cc->parentID = (0 != GetContactSetting(dwContactId, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; + cc->nDefault = (0 != GetContactSetting(cc->contactID, META_PROTO, "Default", &dbv)) ? -1 : dbv.dVal; + cc->parentID = (0 != GetContactSetting(cc->contactID, META_PROTO, "ParentMeta", &dbv)) ? NULL : dbv.dVal; } } diff --git a/plugins/Dbx_mdb/src/dbevents.cpp b/plugins/Dbx_mdb/src/dbevents.cpp index ae5344ae4e..5db1d6714b 100644 --- a/plugins/Dbx_mdb/src/dbevents.cpp +++ b/plugins/Dbx_mdb/src/dbevents.cpp @@ -23,10 +23,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "commonheaders.h" +struct DBEventSortingKey +{ + DWORD dwContactId, ts, dwEventId; +}; + STDMETHODIMP_(LONG) CDbxMdb::GetEventCount(MCONTACT contactID) { mir_cslock lck(m_csDbAccess); - return -1; + if (contactID == NULL) + return m_header.eventCount; + + DBCachedContact *cc = m_cache->GetCachedContact(contactID); + return (cc == NULL) ? 0 : cc->dwDriverData; } STDMETHODIMP_(MEVENT) CDbxMdb::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) @@ -37,6 +46,7 @@ STDMETHODIMP_(MEVENT) CDbxMdb::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) DBEvent dbe; dbe.signature = DBEVENT_SIGNATURE; dbe.contactID = contactID; // store native or subcontact's id + dbe.ofsModuleName = GetModuleNameOfs(dbei->szModule); dbe.timestamp = dbei->timestamp; dbe.flags = dbei->flags; dbe.wEventType = dbei->eventType; @@ -44,11 +54,10 @@ STDMETHODIMP_(MEVENT) CDbxMdb::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) BYTE *pBlob = dbei->pBlob; MCONTACT contactNotifyID = contactID; - DBCachedContact *ccSub = NULL; + DBCachedContact *cc = NULL, *ccSub = NULL; if (contactID != 0) { - DBCachedContact *cc = m_cache->GetCachedContact(contactID); - if (cc == NULL) - return NULL; + if ((cc = m_cache->GetCachedContact(contactID)) == NULL) + return 0; if (cc->IsSub()) { ccSub = cc; @@ -76,32 +85,92 @@ STDMETHODIMP_(MEVENT) CDbxMdb::AddEvent(MCONTACT contactID, DBEVENTINFO *dbei) } mir_cslockfull lck(m_csDbAccess); + DWORD dwEventId = (contactID == NULL) ? ++m_header.eventCount : ++m_dwMaxEventId; + + txn_ptr txn(m_pMdbEnv); + + for (;; Remap()) { + MDB_val key = { sizeof(int), &dwEventId }, data = { sizeof(DBEvent) + dbe.cbBlob, NULL }; + if (mdb_put(txn, m_dbEvents, &key, &data, MDB_RESERVE) != MDB_SUCCESS) + return 0; + + BYTE *pDest = (BYTE*)data.mv_data; + memcpy(pDest, &dbe, sizeof(DBEvent)); + memcpy(pDest + sizeof(DBEvent), pBlob, dbe.cbBlob); + + // add a sorting key + DBEventSortingKey key2 = { contactID, dbe.timestamp, dwEventId }; + key.mv_size = sizeof(key2); key.mv_data = &key2; + data.mv_size = 1; data.mv_data = ""; + if (mdb_put(txn, m_dbEventsSort, &key, &data, 0) != MDB_SUCCESS) + return 0; + + if (contactID != NULL) { + DBContact dbc = { DBCONTACT_SIGNATURE, ++cc->dwDriverData }; + MDB_val keyc = { sizeof(int), &contactID }, datac = { sizeof(DBContact), &dbc }; + mdb_put(txn, m_dbContacts, &keyc, &datac, 0); + + // insert an event into a sub's history too + if (ccSub != NULL) { + key2.dwContactId = ccSub->contactID; + mdb_put(txn, m_dbEventsSort, &key, &data, 0); + + dbc.eventCount = ++ccSub->dwDriverData; + keyc.mv_data = &ccSub->contactID; + mdb_put(txn, m_dbContacts, &keyc, &datac, 0); + } + } + else { + DWORD keyVal = 1; + MDB_val key = { sizeof(DWORD), &keyVal }; + data.mv_data = &m_header; data.mv_size = sizeof(m_header); + mdb_put(txn, m_dbGlobal, &key, &data, 0); + } + + if (txn.commit()) + break; + } lck.unlock(); // Notify only in safe mode or on really new events - NotifyEventHooks(hEventAddedEvent, contactNotifyID, (LPARAM)-1); + NotifyEventHooks(hEventAddedEvent, contactNotifyID, dwEventId); - return (MEVENT)0; + return dwEventId; } STDMETHODIMP_(BOOL) CDbxMdb::DeleteEvent(MCONTACT contactID, MEVENT hDbEvent) { - DBCachedContact *cc; - if (contactID) { - if ((cc = m_cache->GetCachedContact(contactID)) == NULL) - return 2; - if (cc->IsSub()) - if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) - return 3; - } - else cc = NULL; - mir_cslockfull lck(m_csDbAccess); + txn_ptr txn(m_pMdbEnv); + + for (;; Remap()) { + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 1; + + DBEvent *dbe = (DBEvent*)data.mv_data; + DWORD dwSavedContact = dbe->contactID; + DBEventSortingKey key2 = { contactID, dbe->timestamp, hDbEvent }; + mdb_del(txn, m_dbEvents, &key, &data); + + // remove a sorting key + key.mv_size = sizeof(key2); key.mv_data = &key2; + mdb_del(txn, m_dbEventsSort, &key, &data); + + // remove a sub's history entry too + if (contactID != dwSavedContact) { + key2.dwContactId = dwSavedContact; + mdb_del(txn, m_dbEventsSort, &key, &data); + } + + if (txn.commit()) + break; + } lck.unlock(); // call notifier while outside mutex - NotifyEventHooks(hEventDeletedEvent, contactID, (LPARAM)hDbEvent); + NotifyEventHooks(hEventDeletedEvent, contactID, hDbEvent); // get back in lck.lock(); @@ -111,7 +180,14 @@ STDMETHODIMP_(BOOL) CDbxMdb::DeleteEvent(MCONTACT contactID, MEVENT hDbEvent) STDMETHODIMP_(LONG) CDbxMdb::GetBlobSize(MEVENT hDbEvent) { mir_cslock lck(m_csDbAccess); - return -1; + txn_ptr txn(m_pMdbEnv, true); + + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 0; + + DBEvent *dbe = (DBEvent*)data.mv_data; + return (dbe->signature == DBEVENT_SIGNATURE) ? dbe->cbBlob : 0; } STDMETHODIMP_(BOOL) CDbxMdb::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei) @@ -123,6 +199,38 @@ STDMETHODIMP_(BOOL) CDbxMdb::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei) } mir_cslock lck(m_csDbAccess); + txn_ptr txn(m_pMdbEnv, true); + + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 1; + + DBEvent *dbe = (DBEvent*)data.mv_data; + if (dbe->signature != DBEVENT_SIGNATURE) + return 1; + + dbei->szModule = GetModuleNameByOfs(dbe->ofsModuleName); + dbei->timestamp = dbe->timestamp; + dbei->flags = dbe->flags; + dbei->eventType = dbe->wEventType; + int bytesToCopy = (dbei->cbBlob < dbe->cbBlob) ? dbei->cbBlob : dbe->cbBlob; + dbei->cbBlob = dbe->cbBlob; + if (bytesToCopy && dbei->pBlob) { + BYTE *pSrc = (BYTE*)data.mv_data + sizeof(DBEvent); + if (dbe->flags & DBEF_ENCRYPTED) { + dbei->flags &= ~DBEF_ENCRYPTED; + size_t len; + BYTE* pBlob = (BYTE*)m_crypto->decodeBuffer(pSrc, dbe->cbBlob, &len); + if (pBlob == NULL) + return 1; + + memcpy(dbei->pBlob, pBlob, bytesToCopy); + if (bytesToCopy > (int)len) + memset(dbei->pBlob + len, 0, bytesToCopy - len); + mir_free(pBlob); + } + else memcpy(dbei->pBlob, pSrc, bytesToCopy); + } return 0; } @@ -139,22 +247,55 @@ STDMETHODIMP_(BOOL) CDbxMdb::MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) else cc = NULL; mir_cslockfull lck(m_csDbAccess); + txn_ptr txn(m_pMdbEnv); + + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 0; + + DBEvent *dbe = (DBEvent*)data.mv_data; + if (dbe->signature != DBEVENT_SIGNATURE) + return -1; + + if (dbe->markedRead()) + return dbe->flags; + + dbe->flags |= DBEF_READ; + mdb_put(txn, m_dbEvents, &key, &data, 0); + txn.commit(); lck.unlock(); NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); - return -11; + return dbe->flags; } STDMETHODIMP_(MCONTACT) CDbxMdb::GetEventContact(MEVENT hDbEvent) { mir_cslock lck(m_csDbAccess); - return INVALID_CONTACT_ID; + txn_ptr txn(m_pMdbEnv, true); + + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 0; + + DBEvent *dbe = (DBEvent*)data.mv_data; + return (dbe->signature == DBEVENT_SIGNATURE) ? dbe->contactID: INVALID_CONTACT_ID; } STDMETHODIMP_(MEVENT) CDbxMdb::FindFirstEvent(MCONTACT contactID) { + DBEventSortingKey keyVal = { contactID, 0, 0 }; + MDB_val key = { sizeof(keyVal), &keyVal }, data; + mir_cslock lck(m_csDbAccess); - return NULL; + txn_ptr txn(m_pMdbEnv, true); + + cursor_ptr cursor(txn, m_dbEventsSort); + if (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) != MDB_SUCCESS) + return 0; + + DBEventSortingKey *pKey = (DBEventSortingKey*)key.mv_data; + return (pKey->dwContactId == contactID) ? pKey->dwEventId : 0; } STDMETHODIMP_(MEVENT) CDbxMdb::FindFirstUnreadEvent(MCONTACT contactID) @@ -165,24 +306,64 @@ STDMETHODIMP_(MEVENT) CDbxMdb::FindFirstUnreadEvent(MCONTACT contactID) STDMETHODIMP_(MEVENT) CDbxMdb::FindLastEvent(MCONTACT contactID) { + DBEventSortingKey keyVal = { contactID, 0, 0 }; + MDB_val key = { sizeof(keyVal), &keyVal }, data; + mir_cslock lck(m_csDbAccess); - return NULL; + txn_ptr txn(m_pMdbEnv, true); + + cursor_ptr cursor(txn, m_dbEventsSort); + if (mdb_cursor_get(cursor, &key, &data, MDB_PREV) != MDB_SUCCESS) + return 0; + + DBEventSortingKey *pKey = (DBEventSortingKey*)key.mv_data; + return (pKey->dwContactId == contactID) ? pKey->dwEventId : 0; } STDMETHODIMP_(MEVENT) CDbxMdb::FindNextEvent(MCONTACT contactID, MEVENT hDbEvent) { - DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; mir_cslock lck(m_csDbAccess); - return NULL; + txn_ptr txn(m_pMdbEnv, true); + + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 0; + + DBEvent *dbe = (DBEvent*)data.mv_data; + DBEventSortingKey keyVal = { contactID, dbe->timestamp, hDbEvent+1 }; + key.mv_size = sizeof(keyVal); key.mv_data = &keyVal; + + cursor_ptr cursor(txn, m_dbEventsSort); + if (mdb_cursor_get(cursor, &key, &data, MDB_SET_KEY) != MDB_SUCCESS) + if (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) != MDB_SUCCESS) + return 0; + + DBEventSortingKey *pKey = (DBEventSortingKey*)key.mv_data; + return (pKey->dwContactId == contactID) ? pKey->dwEventId : 0; } STDMETHODIMP_(MEVENT) CDbxMdb::FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) { - DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL; + MDB_val key = { sizeof(MEVENT), &hDbEvent }, data; mir_cslock lck(m_csDbAccess); - return NULL; + txn_ptr txn(m_pMdbEnv, true); + + if (mdb_get(txn, m_dbEvents, &key, &data) != MDB_SUCCESS) + return 0; + + DBEvent *dbe = (DBEvent*)data.mv_data; + DBEventSortingKey keyVal = { contactID, dbe->timestamp, hDbEvent - 1 }; + key.mv_size = sizeof(keyVal); key.mv_data = &keyVal; + + cursor_ptr cursor(txn, m_dbEventsSort); + if (mdb_cursor_get(cursor, &key, &data, MDB_SET_KEY) != MDB_SUCCESS) + if (mdb_cursor_get(cursor, &key, &data, MDB_PREV) != MDB_SUCCESS) + return 0; + + DBEventSortingKey *pKey = (DBEventSortingKey*)key.mv_data; + return (pKey->dwContactId == contactID) ? pKey->dwEventId : 0; } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/Dbx_mdb/src/dbintf.cpp b/plugins/Dbx_mdb/src/dbintf.cpp index f519d3dd4b..01bbfe4fed 100644 --- a/plugins/Dbx_mdb/src/dbintf.cpp +++ b/plugins/Dbx_mdb/src/dbintf.cpp @@ -90,11 +90,29 @@ int CDbxMdb::Load(bool bSkipInit) if (!bSkipInit) { txn_ptr trnlck(m_pMdbEnv); + mdb_open(trnlck, "global", MDB_CREATE | MDB_INTEGERKEY, &m_dbGlobal); mdb_open(trnlck, "contacts", MDB_CREATE | MDB_INTEGERKEY, &m_dbContacts); mdb_open(trnlck, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules); mdb_open(trnlck, "events", MDB_CREATE | MDB_INTEGERKEY, &m_dbEvents); - mdb_open(trnlck, "eventsrt", MDB_CREATE, &m_dbEvents); + mdb_open(trnlck, "eventsrt", MDB_CREATE | MDB_INTEGERKEY, &m_dbEventsSort); mdb_open(trnlck, "settings", MDB_CREATE, &m_dbSettings); + + DWORD keyVal = 1; + MDB_val key = { sizeof(DWORD), &keyVal }, data; + if (mdb_get(trnlck, m_dbGlobal, &key, &data) == MDB_SUCCESS) { + DBHeader *hdr = (DBHeader*)data.mv_data; + if (hdr->signature != DBHEADER_SIGNATURE) + DatabaseCorruption(NULL); + + memcpy(&m_header, data.mv_data, sizeof(m_header)); + } + else { + m_header.signature = DBHEADER_SIGNATURE; + m_header.dwVersion = 1; + m_header.eventCount = 0; + data.mv_data = &m_header; data.mv_size = sizeof(m_header); + mdb_put(trnlck, m_dbGlobal, &key, &data, 0); + } trnlck.commit(); if (InitModuleNames()) return EGROKPRF_CANTREAD; diff --git a/plugins/Dbx_mdb/src/dbintf.h b/plugins/Dbx_mdb/src/dbintf.h index 26f7c29629..cf9600eadf 100644 --- a/plugins/Dbx_mdb/src/dbintf.h +++ b/plugins/Dbx_mdb/src/dbintf.h @@ -47,31 +47,11 @@ DBHeader #define DBMODE_SHARED 0x0001 #define DBMODE_READONLY 0x0002 -#define DB_OLD_VERSION 0x00000700u -#define DB_094_VERSION 0x00000701u -#define DB_095_VERSION 0x00000800u -#define DB_095_1_VERSION 0x00000801u - -#define DB_SETTINGS_RESIZE_GRANULARITY 128 - -#define WSOFS_END 0xFFFFFFFF -#define WS_ERROR 0xFFFFFFFF - #define DBVT_ENCRYPTED 250 #define DBVT_UNENCRYPTED 251 #define MARKED_READ (DBEF_READ | DBEF_SENT) -#define NeedBytes(n) if (bytesRemaining<(n)) pBlob = (PBYTE)DBRead(ofsBlobPtr,&bytesRemaining) -#define MoveAlong(n) {int x = n; pBlob += (x); ofsBlobPtr += (x); bytesRemaining -= (x);} - -DWORD __forceinline GetSettingValueLength(PBYTE pSetting) -{ - if (pSetting[0] & DBVTF_VARIABLELENGTH) - return 2 + *(PWORD)(pSetting + 1); - return pSetting[0]; -} - struct ModuleName { char *name; @@ -80,21 +60,22 @@ struct ModuleName #include -struct DBSettingKey +#define DBHEADER_SIGNATURE 0x40DECADEu +struct DBHeader { - DWORD dwContactID; - DWORD dwOfsModule; - char szSettingName[100]; + DWORD signature; + DWORD dwVersion; // database format version + DWORD eventCount; // number of events in the chain for this contact }; -#define DBCONTACT_SIGNATURE 0x43DECADEu +#define DBCONTACT_SIGNATURE 0x43DECADEu struct DBContact { DWORD signature; DWORD eventCount; // number of events in the chain for this contact }; -#define DBMODULENAME_SIGNATURE 0x4DDECADEu +#define DBMODULENAME_SIGNATURE 0x4DDECADEu struct DBModuleName { DWORD signature; @@ -111,8 +92,7 @@ struct DBEvent DWORD timestamp; // seconds since 00:00:00 01/01/1970 DWORD flags; // see m_database.h, db/event/add WORD wEventType; // module-defined event type - DWORD cbBlob; // number of bytes in the blob - BYTE blob[1]; // the blob. module-defined formatting + WORD cbBlob; // number of bytes in the blob bool __forceinline markedRead() const { @@ -219,6 +199,8 @@ public: protected: MDB_env *m_pMdbEnv; DWORD m_dwFileSize; + MDB_dbi m_dbGlobal; + DBHeader m_header; HANDLE hSettingChangeEvent, hContactDeletedEvent, hContactAddedEvent, hEventMarkedRead; @@ -244,7 +226,8 @@ protected: //////////////////////////////////////////////////////////////////////////// // events - MDB_dbi m_dbEvents; + MDB_dbi m_dbEvents, m_dbEventsSort; + DWORD m_dwMaxEventId; //////////////////////////////////////////////////////////////////////////// // modules diff --git a/plugins/Dbx_mdb/src/dbsettings.cpp b/plugins/Dbx_mdb/src/dbsettings.cpp index f8b307936f..2955466c50 100644 --- a/plugins/Dbx_mdb/src/dbsettings.cpp +++ b/plugins/Dbx_mdb/src/dbsettings.cpp @@ -23,8 +23,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "commonheaders.h" -DWORD GetModuleNameOfs(const char *szName); -DBCachedContact* AddToCachedContactList(MCONTACT contactID, int index); +struct DBSettingKey +{ + DWORD dwContactID; + DWORD dwOfsModule; + char szSettingName[100]; +}; #define VLT(n) ((n == DBVT_UTF8 || n == DBVT_ENCRYPTED)?DBVT_ASCIIZ:n) -- cgit v1.2.3