summaryrefslogtreecommitdiff
path: root/plugins/Dbx_sqlite
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Dbx_sqlite')
-rw-r--r--plugins/Dbx_sqlite/src/dbcheck.cpp220
-rw-r--r--plugins/Dbx_sqlite/src/dbcontacts.cpp226
-rw-r--r--plugins/Dbx_sqlite/src/dbevents.cpp1398
-rw-r--r--plugins/Dbx_sqlite/src/dbintf.cpp482
-rw-r--r--plugins/Dbx_sqlite/src/dbintf.h376
-rw-r--r--plugins/Dbx_sqlite/src/dbsettings.cpp450
6 files changed, 1576 insertions, 1576 deletions
diff --git a/plugins/Dbx_sqlite/src/dbcheck.cpp b/plugins/Dbx_sqlite/src/dbcheck.cpp
index 658d48cce6..7019503eec 100644
--- a/plugins/Dbx_sqlite/src/dbcheck.cpp
+++ b/plugins/Dbx_sqlite/src/dbcheck.cpp
@@ -1,110 +1,110 @@
-#include "stdafx.h"
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// first try to find events with wrong contact ids
-
-int CDbxSQLite::CheckPhase1()
-{
- sqlite3_stmt *pQuery;
- int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id FROM events WHERE contact_id <> 0 AND contact_id NOT IN (SELECT id FROM contacts)", -1, &pQuery, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc)
- return rc;
-
- while (sqlite3_step(pQuery) == SQLITE_ROW) {
- MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
- MCONTACT hContact = sqlite3_column_int(pQuery, 1);
- cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned event with wrong contact ID %d, deleting"), hContact));
- DeleteEvent(hDbEvent);
- }
-
- sqlite3_finalize(pQuery);
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// then we're wiping orphaned records from Events_srt which have no parent record in Events
-
-int CDbxSQLite::CheckPhase2()
-{
- sqlite3_stmt *pQuery;
- int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id, timestamp FROM events_srt WHERE id NOT IN (SELECT id FROM events)", -1, &pQuery, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc)
- return rc;
-
- while (sqlite3_step(pQuery) == SQLITE_ROW) {
- MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
- MCONTACT hContact = sqlite3_column_int(pQuery, 1);
- uint32_t ts = sqlite3_column_int(pQuery, 2);
-
- DeleteEventSrt(hDbEvent, hContact, ts);
- cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned sorting event with wrong event ID %d:%08X, deleting"), hContact, hDbEvent));
- }
-
- sqlite3_finalize(pQuery);
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// now try to find orphans in backward direction: from Events_srt to Events
-
-int CDbxSQLite::CheckPhase3()
-{
- sqlite3_stmt *pQuery;
- int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id FROM events WHERE id NOT IN (SELECT id FROM events_srt)", -1, &pQuery, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc)
- return rc;
-
- while (sqlite3_step(pQuery) == SQLITE_ROW) {
- MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
- MCONTACT hContact = sqlite3_column_int(pQuery, 1);
-
- DeleteEventMain(hDbEvent);
- cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned event with wrong event ID %d:%08X, deleting"), hContact, hDbEvent));
- }
-
- sqlite3_finalize(pQuery);
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// remove settings with wrong contact ids
-
-int CDbxSQLite::CheckPhase4()
-{
- sqlite3_stmt *pQuery;
- int rc = sqlite3_prepare_v2(m_db, "SELECT contact_id,module,setting FROM settings WHERE contact_id <> 0 AND contact_id NOT IN (SELECT id FROM contacts)", -1, &pQuery, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc)
- return rc;
-
- while (sqlite3_step(pQuery) == SQLITE_ROW) {
- MCONTACT hContact = sqlite3_column_int(pQuery, 0);
- auto *szModule = (const char *)sqlite3_column_text(pQuery, 1);
- auto *szSetting = (const char *)sqlite3_column_text(pQuery, 2);
-
- cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned setting [%S:%S] with wrong contact ID %d, deleting"), szModule, szSetting, hContact));
- DeleteContactSettingWorker(hContact, szModule, szSetting);
- }
-
- sqlite3_finalize(pQuery);
- return 0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// MIDatabaseChecker
-
-int CDbxSQLite::CheckDb(int phase)
-{
- switch (phase) {
- case 0: return CheckPhase1();
- case 1: return CheckPhase2();
- case 2: return CheckPhase3();
- case 3: return CheckPhase4();
- }
-
- DBFlush(true);
- return ERROR_OUT_OF_PAPER;
-}
+#include "stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// first try to find events with wrong contact ids
+
+int CDbxSQLite::CheckPhase1()
+{
+ sqlite3_stmt *pQuery;
+ int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id FROM events WHERE contact_id <> 0 AND contact_id NOT IN (SELECT id FROM contacts)", -1, &pQuery, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc)
+ return rc;
+
+ while (sqlite3_step(pQuery) == SQLITE_ROW) {
+ MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
+ MCONTACT hContact = sqlite3_column_int(pQuery, 1);
+ cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned event with wrong contact ID %d, deleting"), hContact));
+ DeleteEvent(hDbEvent);
+ }
+
+ sqlite3_finalize(pQuery);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// then we're wiping orphaned records from Events_srt which have no parent record in Events
+
+int CDbxSQLite::CheckPhase2()
+{
+ sqlite3_stmt *pQuery;
+ int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id, timestamp FROM events_srt WHERE id NOT IN (SELECT id FROM events)", -1, &pQuery, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc)
+ return rc;
+
+ while (sqlite3_step(pQuery) == SQLITE_ROW) {
+ MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
+ MCONTACT hContact = sqlite3_column_int(pQuery, 1);
+ uint32_t ts = sqlite3_column_int(pQuery, 2);
+
+ DeleteEventSrt(hDbEvent, hContact, ts);
+ cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned sorting event with wrong event ID %d:%08X, deleting"), hContact, hDbEvent));
+ }
+
+ sqlite3_finalize(pQuery);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// now try to find orphans in backward direction: from Events_srt to Events
+
+int CDbxSQLite::CheckPhase3()
+{
+ sqlite3_stmt *pQuery;
+ int rc = sqlite3_prepare_v2(m_db, "SELECT id, contact_id FROM events WHERE id NOT IN (SELECT id FROM events_srt)", -1, &pQuery, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc)
+ return rc;
+
+ while (sqlite3_step(pQuery) == SQLITE_ROW) {
+ MEVENT hDbEvent = sqlite3_column_int(pQuery, 0);
+ MCONTACT hContact = sqlite3_column_int(pQuery, 1);
+
+ DeleteEventMain(hDbEvent);
+ cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned event with wrong event ID %d:%08X, deleting"), hContact, hDbEvent));
+ }
+
+ sqlite3_finalize(pQuery);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// remove settings with wrong contact ids
+
+int CDbxSQLite::CheckPhase4()
+{
+ sqlite3_stmt *pQuery;
+ int rc = sqlite3_prepare_v2(m_db, "SELECT contact_id,module,setting FROM settings WHERE contact_id <> 0 AND contact_id NOT IN (SELECT id FROM contacts)", -1, &pQuery, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc)
+ return rc;
+
+ while (sqlite3_step(pQuery) == SQLITE_ROW) {
+ MCONTACT hContact = sqlite3_column_int(pQuery, 0);
+ auto *szModule = (const char *)sqlite3_column_text(pQuery, 1);
+ auto *szSetting = (const char *)sqlite3_column_text(pQuery, 2);
+
+ cb->pfnAddLogMessage(STATUS_ERROR, CMStringW(FORMAT, TranslateT("Orphaned setting [%S:%S] with wrong contact ID %d, deleting"), szModule, szSetting, hContact));
+ DeleteContactSettingWorker(hContact, szModule, szSetting);
+ }
+
+ sqlite3_finalize(pQuery);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MIDatabaseChecker
+
+int CDbxSQLite::CheckDb(int phase)
+{
+ switch (phase) {
+ case 0: return CheckPhase1();
+ case 1: return CheckPhase2();
+ case 2: return CheckPhase3();
+ case 3: return CheckPhase4();
+ }
+
+ DBFlush(true);
+ return ERROR_OUT_OF_PAPER;
+}
diff --git a/plugins/Dbx_sqlite/src/dbcontacts.cpp b/plugins/Dbx_sqlite/src/dbcontacts.cpp
index 1cd6229da3..f66e5840e8 100644
--- a/plugins/Dbx_sqlite/src/dbcontacts.cpp
+++ b/plugins/Dbx_sqlite/src/dbcontacts.cpp
@@ -1,113 +1,113 @@
-#include "stdafx.h"
-
-void CDbxSQLite::InitContacts()
-{
- sqlite3_stmt *stmt = nullptr;
- sqlite3_prepare_v2(m_db, "SELECT contacts.id, COUNT(es.id) FROM contacts LEFT JOIN events_srt es ON es.contact_id = contacts.id GROUP BY contacts.id;", -1, &stmt, nullptr);
- int rc = 0;
- while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
- MCONTACT hContact = sqlite3_column_int64(stmt, 0);
- DBCachedContact *cc = (hContact) ? m_cache->AddContactToCache(hContact) : &m_system;
- cc->m_count = sqlite3_column_int64(stmt, 1);
- }
- logError(rc, __FILE__, __LINE__);
- sqlite3_finalize(stmt);
-}
-
-int CDbxSQLite::GetContactCount()
-{
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT COUNT(1) FROM contacts LIMIT 1;", qCntCount);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- int count = sqlite3_column_int(stmt, 0);
- sqlite3_reset(stmt);
- return count;
-}
-
-MCONTACT CDbxSQLite::AddContact()
-{
- MCONTACT hContact = INVALID_CONTACT_ID;
- {
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("INSERT INTO contacts VALUES (null);", qCntAdd);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return INVALID_CONTACT_ID;
- hContact = sqlite3_last_insert_rowid(m_db);
- DBFlush();
- }
-
- DBCachedContact *cc = m_cache->AddContactToCache(hContact);
- if (cc == nullptr)
- return INVALID_CONTACT_ID;
-
- NotifyEventHooks(g_hevContactAdded, hContact);
- return hContact;
-}
-
-int CDbxSQLite::DeleteContact(MCONTACT hContact)
-{
- // global contact cannot be removed
- if (hContact == 0)
- return 1;
-
- DBCachedContact *cc = m_cache->GetCachedContact(hContact);
- if (cc == nullptr)
- return 1;
-
- NotifyEventHooks(g_hevContactDeleted, hContact);
-
- mir_cslockfull lock(m_csDbAccess);
-
- sqlite3_stmt *stmt = InitQuery("DELETE FROM events WHERE contact_id = ?;", qCntDelEvents);
- sqlite3_bind_int64(stmt, 1, hContact);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- stmt = InitQuery("DELETE FROM events_srt WHERE contact_id = ?;", qCntDelEventSrt);
- sqlite3_bind_int64(stmt, 1, hContact);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- stmt = InitQuery("DELETE FROM settings WHERE contact_id = ?;", qCntDelSettings);
- sqlite3_bind_int64(stmt, 1, hContact);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- stmt = InitQuery("DELETE FROM contacts WHERE id = ?;", qCntDel);
- sqlite3_bind_int64(stmt, 1, hContact);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- m_cache->FreeCachedContact(hContact);
- lock.unlock();
-
- DBFlush();
- return 0;
-}
-
-BOOL CDbxSQLite::IsDbContact(MCONTACT hContact)
-{
- DBCachedContact *cc = m_cache->GetCachedContact(hContact);
- return (cc != nullptr);
-}
-
-int CDbxSQLite::GetContactSize(void)
-{
- return sizeof(DBCachedContact);
-}
+#include "stdafx.h"
+
+void CDbxSQLite::InitContacts()
+{
+ sqlite3_stmt *stmt = nullptr;
+ sqlite3_prepare_v2(m_db, "SELECT contacts.id, COUNT(es.id) FROM contacts LEFT JOIN events_srt es ON es.contact_id = contacts.id GROUP BY contacts.id;", -1, &stmt, nullptr);
+ int rc = 0;
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
+ MCONTACT hContact = sqlite3_column_int64(stmt, 0);
+ DBCachedContact *cc = (hContact) ? m_cache->AddContactToCache(hContact) : &m_system;
+ cc->m_count = sqlite3_column_int64(stmt, 1);
+ }
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_finalize(stmt);
+}
+
+int CDbxSQLite::GetContactCount()
+{
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT COUNT(1) FROM contacts LIMIT 1;", qCntCount);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ int count = sqlite3_column_int(stmt, 0);
+ sqlite3_reset(stmt);
+ return count;
+}
+
+MCONTACT CDbxSQLite::AddContact()
+{
+ MCONTACT hContact = INVALID_CONTACT_ID;
+ {
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("INSERT INTO contacts VALUES (null);", qCntAdd);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return INVALID_CONTACT_ID;
+ hContact = sqlite3_last_insert_rowid(m_db);
+ DBFlush();
+ }
+
+ DBCachedContact *cc = m_cache->AddContactToCache(hContact);
+ if (cc == nullptr)
+ return INVALID_CONTACT_ID;
+
+ NotifyEventHooks(g_hevContactAdded, hContact);
+ return hContact;
+}
+
+int CDbxSQLite::DeleteContact(MCONTACT hContact)
+{
+ // global contact cannot be removed
+ if (hContact == 0)
+ return 1;
+
+ DBCachedContact *cc = m_cache->GetCachedContact(hContact);
+ if (cc == nullptr)
+ return 1;
+
+ NotifyEventHooks(g_hevContactDeleted, hContact);
+
+ mir_cslockfull lock(m_csDbAccess);
+
+ sqlite3_stmt *stmt = InitQuery("DELETE FROM events WHERE contact_id = ?;", qCntDelEvents);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ stmt = InitQuery("DELETE FROM events_srt WHERE contact_id = ?;", qCntDelEventSrt);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ stmt = InitQuery("DELETE FROM settings WHERE contact_id = ?;", qCntDelSettings);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ stmt = InitQuery("DELETE FROM contacts WHERE id = ?;", qCntDel);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ m_cache->FreeCachedContact(hContact);
+ lock.unlock();
+
+ DBFlush();
+ return 0;
+}
+
+BOOL CDbxSQLite::IsDbContact(MCONTACT hContact)
+{
+ DBCachedContact *cc = m_cache->GetCachedContact(hContact);
+ return (cc != nullptr);
+}
+
+int CDbxSQLite::GetContactSize(void)
+{
+ return sizeof(DBCachedContact);
+}
diff --git a/plugins/Dbx_sqlite/src/dbevents.cpp b/plugins/Dbx_sqlite/src/dbevents.cpp
index f4a4618c2e..c4af7cf487 100644
--- a/plugins/Dbx_sqlite/src/dbevents.cpp
+++ b/plugins/Dbx_sqlite/src/dbevents.cpp
@@ -1,699 +1,699 @@
-#include "stdafx.h"
-
-//TODO: hide it inside cursor class
-static const char normal_order_query[] = "SELECT id FROM events_srt WHERE contact_id = ? ORDER BY timestamp, id;";
-static const char normal_order_pos_query[] = "SELECT id FROM events_srt WHERE contact_id = ? AND id >= ? ORDER BY timestamp, id;";
-
-static const char reverse_order_query[] = "SELECT id FROM events_srt WHERE contact_id = ? ORDER BY timestamp desc, id DESC;";
-static const char reverse_order_pos_query[] = "SELECT id FROM events_srt WHERE contact_id = ? AND id <= ? ORDER BY timestamp desc, id DESC;";
-
-static const char add_event_sort_query[] = "INSERT INTO events_srt(id, contact_id, timestamp) VALUES (?, ?, ?);";
-
-void CDbxSQLite::InitEvents()
-{
- sqlite3_stmt *stmt = nullptr;
- sqlite3_prepare_v2(m_db, "SELECT DISTINCT module FROM events;", -1, &stmt, nullptr);
- int rc = 0;
- while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
- const char *module = (char*)sqlite3_column_text(stmt, 0);
- if (mir_strlen(module) > 0)
- m_modules.insert(mir_strdup(module));
- }
- logError(rc, __FILE__, __LINE__);
- sqlite3_finalize(stmt);
-}
-
-void CDbxSQLite::UninitEvents()
-{
- for (auto &module : m_modules)
- mir_free(module);
- m_modules.destroy();
-}
-
-int CDbxSQLite::GetEventCount(MCONTACT hContact)
-{
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- if (cc->HasCount())
- return cc->m_count;
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT COUNT(1) FROM events_srt WHERE contact_id = ? LIMIT 1;", qEvCount);
- sqlite3_bind_int64(stmt, 1, hContact);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- cc->m_count = (rc != SQLITE_ROW) ? 0 : sqlite3_column_int64(stmt, 0);
- sqlite3_reset(stmt);
- return cc->m_count;
-}
-
-MEVENT CDbxSQLite::AddEvent(MCONTACT hContact, const DBEVENTINFO *dbei)
-{
- if (dbei == nullptr)
- return 0;
-
- if (dbei->timestamp == 0)
- return 0;
-
- MCONTACT hNotifyContact = hContact;
- DBCachedContact *cc, *ccSub = nullptr;
- if (hContact != 0) {
- if ((cc = m_cache->GetCachedContact(hContact)) == nullptr)
- return 0;
-
- if (cc->IsSub()) {
- ccSub = cc;
- if ((cc = m_cache->GetCachedContact(cc->parentID)) == nullptr)
- return 0;
-
- // set default sub to the event's source
- if (!(dbei->flags & DBEF_SENT))
- db_mc_setDefault(cc->contactID, hContact, false);
- if (db_mc_isEnabled())
- hNotifyContact = cc->contactID; // and add an event to a metahistory
- }
- }
- else cc = &m_system;
-
- if (cc == nullptr)
- return 0;
-
- if (m_safetyMode)
- if (NotifyEventHooks(g_hevEventFiltered, hNotifyContact, (LPARAM)dbei))
- return 0;
-
- DBEVENTINFO tmp = *dbei;
- const char *szEventId;
- if (tmp.szId != nullptr) {
- tmp.flags |= DBEF_HAS_ID;
- szEventId = tmp.szId;
- }
- else szEventId = "";
-
- mir_ptr<uint8_t> pCryptBlob;
- if (m_bEncrypted) {
- size_t len;
- uint8_t *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len);
- if (pResult != nullptr) {
- pCryptBlob = tmp.pBlob = pResult;
- tmp.cbBlob = (uint16_t)len;
- tmp.flags |= DBEF_ENCRYPTED;
- }
- }
-
- mir_cslockfull lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("INSERT INTO events(contact_id, module, timestamp, type, flags, data, server_id, is_read) VALUES (?, ?, ?, ?, ?, ?, ?, ?);", qEvAdd);
- sqlite3_bind_int64(stmt, 1, hContact);
- sqlite3_bind_text(stmt, 2, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr);
- sqlite3_bind_int64(stmt, 3, tmp.timestamp);
- sqlite3_bind_int(stmt, 4, tmp.eventType);
- sqlite3_bind_int64(stmt, 5, tmp.flags);
- sqlite3_bind_blob(stmt, 6, tmp.pBlob, tmp.cbBlob, nullptr);
- sqlite3_bind_text(stmt, 7, szEventId, (int)mir_strlen(szEventId), nullptr);
- sqlite3_bind_int(stmt, 8, tmp.markedRead());
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
-
- MEVENT hDbEvent = sqlite3_last_insert_rowid(m_db);
-
- stmt = InitQuery(add_event_sort_query, qEvAddSrt);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- sqlite3_bind_int64(stmt, 2, cc->contactID);
- sqlite3_bind_int64(stmt, 3, tmp.timestamp);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
-
- if (ccSub != nullptr) {
- stmt = InitQuery(add_event_sort_query, qEvAddSrt);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- sqlite3_bind_int64(stmt, 2, ccSub->contactID);
- sqlite3_bind_int64(stmt, 3, tmp.timestamp);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt); //is this necessary ?
- }
-
- char *module = m_modules.find((char *)tmp.szModule);
- if (module == nullptr)
- m_modules.insert(mir_strdup(tmp.szModule));
-
- lock.unlock();
-
- DBFlush();
- if (m_safetyMode && !(tmp.flags & DBEF_TEMPORARY))
- NotifyEventHooks(g_hevEventAdded, hNotifyContact, (LPARAM)hDbEvent);
-
- return hDbEvent;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CDbxSQLite::DeleteEventMain(MEVENT hDbEvent)
-{
- auto *stmt = InitQuery("DELETE FROM events WHERE id = ?;", qEvDel);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- return rc;
-}
-
-int CDbxSQLite::DeleteEventSrt(MEVENT hDbEvent, MCONTACT hContact, uint32_t ts)
-{
- auto *stmt = InitQuery("DELETE FROM events_srt WHERE id = ? AND contact_id = ? AND timestamp = ?;", qEvDelSrt);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- sqlite3_bind_int64(stmt, 2, hContact);
- sqlite3_bind_int64(stmt, 3, ts);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- return rc;
-}
-
-BOOL CDbxSQLite::DeleteEvent(MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return 1;
-
- MEVENT hContact;
- uint32_t ts;
- {
- sqlite3_stmt *stmt = InitQuery("SELECT contact_id, timestamp FROM events WHERE id = ? LIMIT 1;", qEvGetContact2);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return 2;
- }
- hContact = sqlite3_column_int64(stmt, 0);
- ts = sqlite3_column_int64(stmt, 1);
- sqlite3_reset(stmt);
- }
-
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 1;
-
- mir_cslockfull lock(m_csDbAccess);
- int rc = DeleteEventMain(hDbEvent);
- if (rc != SQLITE_DONE)
- return 1;
-
- rc = DeleteEventSrt(hDbEvent, hContact, ts);
- if (rc != SQLITE_DONE)
- return 1;
-
- lock.unlock();
-
- DBFlush();
- NotifyEventHooks(g_hevEventDeleted, hContact, hDbEvent);
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL CDbxSQLite::EditEvent(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei)
-{
- if (dbei == nullptr)
- return 1;
-
- if (dbei->timestamp == 0)
- return 1;
-
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 1;
-
- DBEVENTINFO tmp = *dbei;
- mir_ptr<uint8_t> pCryptBlob;
- if (m_bEncrypted) {
- size_t len;
- uint8_t *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len);
- if (pResult != nullptr) {
- pCryptBlob = tmp.pBlob = pResult;
- tmp.cbBlob = (uint16_t)len;
- tmp.flags |= DBEF_ENCRYPTED;
- }
- }
-
- mir_cslockfull lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("UPDATE events SET module = ?, timestamp = ?, type = ?, flags = ?, data = ?, is_read = ? WHERE id = ?;", qEvEdit);
- sqlite3_bind_text(stmt, 1, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr);
- sqlite3_bind_int64(stmt, 2, tmp.timestamp);
- sqlite3_bind_int(stmt, 3, tmp.eventType);
- sqlite3_bind_int64(stmt, 4, tmp.flags);
- sqlite3_bind_blob(stmt, 5, tmp.pBlob, tmp.cbBlob, nullptr);
- sqlite3_bind_int(stmt, 6, tmp.markedRead());
- sqlite3_bind_int64(stmt, 7, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
-
- char *module = m_modules.find((char *)tmp.szModule);
- if (module == nullptr)
- m_modules.insert(mir_strdup(tmp.szModule));
-
- lock.unlock();
-
- DBFlush();
- NotifyEventHooks(g_hevEventEdited, hContact, (LPARAM)hDbEvent);
- return 0;
-}
-
-int CDbxSQLite::GetBlobSize(MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return -1;
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT LENGTH(data) FROM events WHERE id = ? LIMIT 1;", qEvBlobSize);
- sqlite3_bind_int(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return -1;
- }
-
- LONG res = sqlite3_column_int64(stmt, 0);
- sqlite3_reset(stmt);
- return res;
-}
-
-static char g_szId[100];
-
-BOOL CDbxSQLite::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei)
-{
- if (hDbEvent == 0)
- return 1;
-
- if (dbei == nullptr)
- return 1;
-
- if (dbei->cbBlob > 0 && dbei->pBlob == nullptr) {
- dbei->cbBlob = 0;
- return 1;
- }
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT module, timestamp, type, flags, server_id, length(data), data FROM events WHERE id = ? LIMIT 1;", qEvGet);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return 1;
- }
-
- char *module = (char *)sqlite3_column_text(stmt, 0);
- dbei->szModule = m_modules.find(module);
- if (dbei->szModule == nullptr)
- return 1;
-
- dbei->timestamp = sqlite3_column_int64(stmt, 1);
- dbei->eventType = sqlite3_column_int(stmt, 2);
- dbei->flags = sqlite3_column_int64(stmt, 3);
-
- char *pszId = (char *)sqlite3_column_text(stmt, 4);
- if (mir_strlen(pszId)) {
- mir_strncpy(g_szId, pszId, sizeof(g_szId));
- dbei->szId = g_szId;
- }
- else dbei->szId = nullptr;
-
- int32_t cbBlob = sqlite3_column_int64(stmt, 5);
- size_t bytesToCopy = cbBlob;
- if (dbei->cbBlob == -1)
- dbei->pBlob = (uint8_t*)mir_calloc(cbBlob + 2);
- else if (dbei->cbBlob < cbBlob)
- bytesToCopy = dbei->cbBlob;
-
- dbei->cbBlob = cbBlob;
- if (bytesToCopy && dbei->pBlob) {
- uint8_t *data = (uint8_t *)sqlite3_column_blob(stmt, 6);
-
- if (dbei->flags & DBEF_ENCRYPTED) {
- dbei->flags &= ~DBEF_ENCRYPTED;
- size_t len;
- uint8_t* pBlob = (uint8_t*)m_crypto->decodeBuffer(data, cbBlob, &len);
- if (pBlob == nullptr)
- return 1;
-
- memcpy(dbei->pBlob, pBlob, bytesToCopy);
- if (bytesToCopy > len)
- memset(dbei->pBlob + len, 0, bytesToCopy - len);
-
- mir_free(pBlob);
- }
- else memcpy(dbei->pBlob, data, bytesToCopy);
- }
- sqlite3_reset(stmt);
- return 0;
-}
-
-BOOL CDbxSQLite::MarkEventRead(MCONTACT hContact, MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return -1;
-
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return -1;
-
- int rows;
- {
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("UPDATE events SET flags = flags | 4, is_read = 1 WHERE id = ? AND is_read = 0;", qEvSetFlags);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- rows = sqlite3_changes(m_db);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return -1;
- }
-
- DBFlush();
- NotifyEventHooks(g_hevMarkedRead, hContact, (LPARAM)hDbEvent);
- return (rows == 0 ? 0 : DBEF_READ);
-}
-
-MCONTACT CDbxSQLite::GetEventContact(MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return INVALID_CONTACT_ID;
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT contact_id FROM events WHERE id = ? LIMIT 1;", qEvGetContact);
- sqlite3_bind_int64(stmt, 1, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return INVALID_CONTACT_ID;
- }
- MCONTACT hContact = sqlite3_column_int64(stmt, 0);
- sqlite3_reset(stmt);
- return hContact;
-}
-
-MEVENT CDbxSQLite::FindFirstUnreadEvent(MCONTACT hContact)
-{
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- mir_cslock lock(m_csDbAccess);
-
- if (cc->IsMeta()) {
- if (cc->nSubs == 0)
- return 0;
-
- CMStringA query("SELECT id FROM events WHERE is_read = 0 AND contact_id IN (");
- for (int k = 0; k < cc->nSubs; k++)
- query.AppendFormat("%lu, ", cc->pSubs[k]);
- query.Delete(query.GetLength() - 2, 2);
- query.Append(") ORDER BY timestamp LIMIT 1;");
-
- sqlite3_stmt *stmt;
- sqlite3_prepare_v2(m_db, query, -1, &stmt, nullptr);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_finalize(stmt);
- return 0;
- }
-
- MEVENT ret = sqlite3_column_int64(stmt, 0);
- sqlite3_finalize(stmt);
- return ret;
- }
-
- sqlite3_stmt *stmt = InitQuery("SELECT id FROM events WHERE contact_id = ? AND is_read = 0 ORDER BY timestamp LIMIT 1;", qEvFindUnread);
- sqlite3_bind_int64(stmt, 1, hContact);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return 0;
- }
-
- MEVENT ret = sqlite3_column_int64(stmt, 0);
- sqlite3_reset(stmt);
- return ret;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// First/next event
-
-MEVENT CDbxSQLite::FindFirstEvent(MCONTACT hContact)
-{
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- mir_cslock lock(m_csDbAccess);
-
- if (fwd.cur)
- sqlite3_reset(fwd.cur);
-
- fwd.hContact = hContact;
- fwd.cur = InitQuery(normal_order_query, qEvFindFirst);
- sqlite3_bind_int64(fwd.cur, 1, hContact);
-
- int rc = sqlite3_step(fwd.cur);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- fwd.clear();
- return 0;
- }
- return fwd.hEvent = sqlite3_column_int64(fwd.cur, 0);
-}
-
-MEVENT CDbxSQLite::FindNextEvent(MCONTACT hContact, MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return 0;
-
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- if (hContact != fwd.hContact || hDbEvent != fwd.hEvent) {
- if (fwd.cur)
- sqlite3_reset(fwd.cur);
-
- fwd.hContact = hContact;
- fwd.cur = InitQuery("SELECT id FROM events_srt WHERE contact_id = ? AND id > ? ORDER BY timestamp, id;", qEvFindNext);
- sqlite3_bind_int64(fwd.cur, 1, hContact);
- sqlite3_bind_int64(fwd.cur, 2, hDbEvent);
- }
-
- int rc = sqlite3_step(fwd.cur);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- fwd.clear();
- return 0;
- }
-
- return fwd.hEvent = sqlite3_column_int64(fwd.cur, 0);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Last/prev event
-
-MEVENT CDbxSQLite::FindLastEvent(MCONTACT hContact)
-{
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- mir_cslock lock(m_csDbAccess);
-
- if (back.cur)
- sqlite3_reset(back.cur);
-
- back.hContact = hContact;
- back.cur = InitQuery(reverse_order_query, qEvFindLast);
- sqlite3_bind_int64(back.cur, 1, hContact);
- int rc = sqlite3_step(back.cur);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- back.clear();
- return 0;
- }
-
- return back.hEvent = sqlite3_column_int64(back.cur, 0);
-}
-
-MEVENT CDbxSQLite::FindPrevEvent(MCONTACT hContact, MEVENT hDbEvent)
-{
- if (hDbEvent == 0)
- return 0;
-
- DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
- if (cc == nullptr)
- return 0;
-
- if (hContact != back.hContact || hDbEvent != back.hEvent) {
- if (back.cur)
- sqlite3_reset(back.cur);
-
- back.hContact = hContact;
- back.cur = InitQuery("SELECT id FROM events_srt WHERE contact_id = ? AND id < ? ORDER BY timestamp desc, id DESC;", qEvFindPrev);
- sqlite3_bind_int64(back.cur, 1, hContact);
- sqlite3_bind_int64(back.cur, 2, hDbEvent);
- }
-
- int rc = sqlite3_step(back.cur);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- back.clear();
- return 0;
- }
-
- return back.hEvent = sqlite3_column_int64(back.cur, 0);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Metacontacts
-
-BOOL CDbxSQLite::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub)
-{
- //TODO: test this
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT id, timestamp FROM events WHERE contact_id = ?;", qEvMetaMerge);
- sqlite3_bind_int64(stmt, 1, ccSub->contactID);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- while (rc == SQLITE_ROW) {
- sqlite3_stmt *stmt2 = InitQuery(add_event_sort_query, qEvAddSrt);
- sqlite3_bind_int64(stmt2, 1, sqlite3_column_int64(stmt, 0));
- sqlite3_bind_int64(stmt2, 2, ccMeta->contactID);
- sqlite3_bind_int64(stmt2, 3, sqlite3_column_int64(stmt, 1));
- int rc2 = sqlite3_step(stmt2);
- logError(rc2, __FILE__, __LINE__);
- sqlite3_reset(stmt2);
- rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- }
-
- sqlite3_reset(stmt);
- DBFlush();
- return TRUE;
-}
-
-BOOL CDbxSQLite::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *)
-{
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("DELETE FROM events_srt WHERE contact_id = ?;", qEvMetaSplit);
- sqlite3_bind_int64(stmt, 1, ccMeta->contactID);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- DBFlush();
- return TRUE;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Server ids
-
-MEVENT CDbxSQLite::GetEventById(LPCSTR szModule, LPCSTR szId)
-{
- if (szModule == nullptr || szId == nullptr)
- return 0;
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT id, timestamp FROM events WHERE module = ? AND server_id = ? LIMIT 1;", qEvGetById);
- sqlite3_bind_text(stmt, 1, szModule, (int)mir_strlen(szModule), nullptr);
- sqlite3_bind_text(stmt, 2, szId, (int)mir_strlen(szId), nullptr);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- sqlite3_reset(stmt);
- return 0;
- }
- MEVENT hDbEvent = sqlite3_column_int64(stmt, 0);
- sqlite3_reset(stmt);
- return hDbEvent;
-}
-
-int CDbxSQLite::UpdateEventId(MEVENT hDbEvent, LPCSTR szId)
-{
- if (hDbEvent == 0 || mir_strlen(szId) == 0)
- return 1;
-
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("UPDATE events SET server_id = ? WHERE id = ?;", qEvUpdateId);
- sqlite3_bind_text(stmt, 1, szId, (int)mir_strlen(szId), nullptr);
- sqlite3_bind_int64(stmt, 2, hDbEvent);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- int rows = sqlite3_changes(m_db);
- sqlite3_reset(stmt);
- return (rows == 0) ? 2 : 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Event cursors
-
-STDMETHODIMP_(DB::EventCursor *) CDbxSQLite::EventCursor(MCONTACT hContact, MEVENT hDbEvent)
-{
- return new CDbxSQLiteEventCursor(hContact, m_db, hDbEvent);
-}
-
-STDMETHODIMP_(DB::EventCursor *) CDbxSQLite::EventCursorRev(MCONTACT hContact, MEVENT hDbEvent)
-{
- return new CDbxSQLiteEventCursor(hContact, m_db, hDbEvent, true);
-}
-
-CDbxSQLiteEventCursor::CDbxSQLiteEventCursor(MCONTACT _1, sqlite3 *_db, MEVENT hDbEvent, bool reverse) :
- EventCursor(_1), m_db(_db)
-{
- if (reverse) {
- if (!hDbEvent)
- sqlite3_prepare_v2(m_db, reverse_order_query, -1, &cursor, nullptr);
- else
- sqlite3_prepare_v2(m_db, reverse_order_pos_query, -1, &cursor, nullptr);
- }
- else {
- if (!hDbEvent)
- sqlite3_prepare_v2(m_db, normal_order_query, -1, &cursor, nullptr);
- else
- sqlite3_prepare_v2(m_db, normal_order_pos_query, -1, &cursor, nullptr);
- }
- sqlite3_bind_int64(cursor, 1, hContact);
- if (hDbEvent)
- sqlite3_bind_int64(cursor, 2, hDbEvent);
-}
-
-CDbxSQLiteEventCursor::~CDbxSQLiteEventCursor()
-{
- if (cursor)
- sqlite3_reset(cursor);
-}
-
-MEVENT CDbxSQLiteEventCursor::FetchNext()
-{
- if (!cursor)
- return 0;
-
- int rc = sqlite3_step(cursor);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_ROW) {
- //empty response
- //reset sql cursor
- sqlite3_reset(cursor);
- cursor = nullptr;
- return 0;
- }
- return sqlite3_column_int64(cursor, 0);
-}
+#include "stdafx.h"
+
+//TODO: hide it inside cursor class
+static const char normal_order_query[] = "SELECT id FROM events_srt WHERE contact_id = ? ORDER BY timestamp, id;";
+static const char normal_order_pos_query[] = "SELECT id FROM events_srt WHERE contact_id = ? AND id >= ? ORDER BY timestamp, id;";
+
+static const char reverse_order_query[] = "SELECT id FROM events_srt WHERE contact_id = ? ORDER BY timestamp desc, id DESC;";
+static const char reverse_order_pos_query[] = "SELECT id FROM events_srt WHERE contact_id = ? AND id <= ? ORDER BY timestamp desc, id DESC;";
+
+static const char add_event_sort_query[] = "INSERT INTO events_srt(id, contact_id, timestamp) VALUES (?, ?, ?);";
+
+void CDbxSQLite::InitEvents()
+{
+ sqlite3_stmt *stmt = nullptr;
+ sqlite3_prepare_v2(m_db, "SELECT DISTINCT module FROM events;", -1, &stmt, nullptr);
+ int rc = 0;
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
+ const char *module = (char*)sqlite3_column_text(stmt, 0);
+ if (mir_strlen(module) > 0)
+ m_modules.insert(mir_strdup(module));
+ }
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_finalize(stmt);
+}
+
+void CDbxSQLite::UninitEvents()
+{
+ for (auto &module : m_modules)
+ mir_free(module);
+ m_modules.destroy();
+}
+
+int CDbxSQLite::GetEventCount(MCONTACT hContact)
+{
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ if (cc->HasCount())
+ return cc->m_count;
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT COUNT(1) FROM events_srt WHERE contact_id = ? LIMIT 1;", qEvCount);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ cc->m_count = (rc != SQLITE_ROW) ? 0 : sqlite3_column_int64(stmt, 0);
+ sqlite3_reset(stmt);
+ return cc->m_count;
+}
+
+MEVENT CDbxSQLite::AddEvent(MCONTACT hContact, const DBEVENTINFO *dbei)
+{
+ if (dbei == nullptr)
+ return 0;
+
+ if (dbei->timestamp == 0)
+ return 0;
+
+ MCONTACT hNotifyContact = hContact;
+ DBCachedContact *cc, *ccSub = nullptr;
+ if (hContact != 0) {
+ if ((cc = m_cache->GetCachedContact(hContact)) == nullptr)
+ return 0;
+
+ if (cc->IsSub()) {
+ ccSub = cc;
+ if ((cc = m_cache->GetCachedContact(cc->parentID)) == nullptr)
+ return 0;
+
+ // set default sub to the event's source
+ if (!(dbei->flags & DBEF_SENT))
+ db_mc_setDefault(cc->contactID, hContact, false);
+ if (db_mc_isEnabled())
+ hNotifyContact = cc->contactID; // and add an event to a metahistory
+ }
+ }
+ else cc = &m_system;
+
+ if (cc == nullptr)
+ return 0;
+
+ if (m_safetyMode)
+ if (NotifyEventHooks(g_hevEventFiltered, hNotifyContact, (LPARAM)dbei))
+ return 0;
+
+ DBEVENTINFO tmp = *dbei;
+ const char *szEventId;
+ if (tmp.szId != nullptr) {
+ tmp.flags |= DBEF_HAS_ID;
+ szEventId = tmp.szId;
+ }
+ else szEventId = "";
+
+ mir_ptr<uint8_t> pCryptBlob;
+ if (m_bEncrypted) {
+ size_t len;
+ uint8_t *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len);
+ if (pResult != nullptr) {
+ pCryptBlob = tmp.pBlob = pResult;
+ tmp.cbBlob = (uint16_t)len;
+ tmp.flags |= DBEF_ENCRYPTED;
+ }
+ }
+
+ mir_cslockfull lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("INSERT INTO events(contact_id, module, timestamp, type, flags, data, server_id, is_read) VALUES (?, ?, ?, ?, ?, ?, ?, ?);", qEvAdd);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ sqlite3_bind_text(stmt, 2, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr);
+ sqlite3_bind_int64(stmt, 3, tmp.timestamp);
+ sqlite3_bind_int(stmt, 4, tmp.eventType);
+ sqlite3_bind_int64(stmt, 5, tmp.flags);
+ sqlite3_bind_blob(stmt, 6, tmp.pBlob, tmp.cbBlob, nullptr);
+ sqlite3_bind_text(stmt, 7, szEventId, (int)mir_strlen(szEventId), nullptr);
+ sqlite3_bind_int(stmt, 8, tmp.markedRead());
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+
+ MEVENT hDbEvent = sqlite3_last_insert_rowid(m_db);
+
+ stmt = InitQuery(add_event_sort_query, qEvAddSrt);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ sqlite3_bind_int64(stmt, 2, cc->contactID);
+ sqlite3_bind_int64(stmt, 3, tmp.timestamp);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+
+ if (ccSub != nullptr) {
+ stmt = InitQuery(add_event_sort_query, qEvAddSrt);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ sqlite3_bind_int64(stmt, 2, ccSub->contactID);
+ sqlite3_bind_int64(stmt, 3, tmp.timestamp);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt); //is this necessary ?
+ }
+
+ char *module = m_modules.find((char *)tmp.szModule);
+ if (module == nullptr)
+ m_modules.insert(mir_strdup(tmp.szModule));
+
+ lock.unlock();
+
+ DBFlush();
+ if (m_safetyMode && !(tmp.flags & DBEF_TEMPORARY))
+ NotifyEventHooks(g_hevEventAdded, hNotifyContact, (LPARAM)hDbEvent);
+
+ return hDbEvent;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDbxSQLite::DeleteEventMain(MEVENT hDbEvent)
+{
+ auto *stmt = InitQuery("DELETE FROM events WHERE id = ?;", qEvDel);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ return rc;
+}
+
+int CDbxSQLite::DeleteEventSrt(MEVENT hDbEvent, MCONTACT hContact, uint32_t ts)
+{
+ auto *stmt = InitQuery("DELETE FROM events_srt WHERE id = ? AND contact_id = ? AND timestamp = ?;", qEvDelSrt);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ sqlite3_bind_int64(stmt, 2, hContact);
+ sqlite3_bind_int64(stmt, 3, ts);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ return rc;
+}
+
+BOOL CDbxSQLite::DeleteEvent(MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return 1;
+
+ MEVENT hContact;
+ uint32_t ts;
+ {
+ sqlite3_stmt *stmt = InitQuery("SELECT contact_id, timestamp FROM events WHERE id = ? LIMIT 1;", qEvGetContact2);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return 2;
+ }
+ hContact = sqlite3_column_int64(stmt, 0);
+ ts = sqlite3_column_int64(stmt, 1);
+ sqlite3_reset(stmt);
+ }
+
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 1;
+
+ mir_cslockfull lock(m_csDbAccess);
+ int rc = DeleteEventMain(hDbEvent);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ rc = DeleteEventSrt(hDbEvent, hContact, ts);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ lock.unlock();
+
+ DBFlush();
+ NotifyEventHooks(g_hevEventDeleted, hContact, hDbEvent);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL CDbxSQLite::EditEvent(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei)
+{
+ if (dbei == nullptr)
+ return 1;
+
+ if (dbei->timestamp == 0)
+ return 1;
+
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 1;
+
+ DBEVENTINFO tmp = *dbei;
+ mir_ptr<uint8_t> pCryptBlob;
+ if (m_bEncrypted) {
+ size_t len;
+ uint8_t *pResult = m_crypto->encodeBuffer(tmp.pBlob, tmp.cbBlob, &len);
+ if (pResult != nullptr) {
+ pCryptBlob = tmp.pBlob = pResult;
+ tmp.cbBlob = (uint16_t)len;
+ tmp.flags |= DBEF_ENCRYPTED;
+ }
+ }
+
+ mir_cslockfull lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("UPDATE events SET module = ?, timestamp = ?, type = ?, flags = ?, data = ?, is_read = ? WHERE id = ?;", qEvEdit);
+ sqlite3_bind_text(stmt, 1, tmp.szModule, (int)mir_strlen(tmp.szModule), nullptr);
+ sqlite3_bind_int64(stmt, 2, tmp.timestamp);
+ sqlite3_bind_int(stmt, 3, tmp.eventType);
+ sqlite3_bind_int64(stmt, 4, tmp.flags);
+ sqlite3_bind_blob(stmt, 5, tmp.pBlob, tmp.cbBlob, nullptr);
+ sqlite3_bind_int(stmt, 6, tmp.markedRead());
+ sqlite3_bind_int64(stmt, 7, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+
+ char *module = m_modules.find((char *)tmp.szModule);
+ if (module == nullptr)
+ m_modules.insert(mir_strdup(tmp.szModule));
+
+ lock.unlock();
+
+ DBFlush();
+ NotifyEventHooks(g_hevEventEdited, hContact, (LPARAM)hDbEvent);
+ return 0;
+}
+
+int CDbxSQLite::GetBlobSize(MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return -1;
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT LENGTH(data) FROM events WHERE id = ? LIMIT 1;", qEvBlobSize);
+ sqlite3_bind_int(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return -1;
+ }
+
+ LONG res = sqlite3_column_int64(stmt, 0);
+ sqlite3_reset(stmt);
+ return res;
+}
+
+static char g_szId[100];
+
+BOOL CDbxSQLite::GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbei)
+{
+ if (hDbEvent == 0)
+ return 1;
+
+ if (dbei == nullptr)
+ return 1;
+
+ if (dbei->cbBlob > 0 && dbei->pBlob == nullptr) {
+ dbei->cbBlob = 0;
+ return 1;
+ }
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT module, timestamp, type, flags, server_id, length(data), data FROM events WHERE id = ? LIMIT 1;", qEvGet);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return 1;
+ }
+
+ char *module = (char *)sqlite3_column_text(stmt, 0);
+ dbei->szModule = m_modules.find(module);
+ if (dbei->szModule == nullptr)
+ return 1;
+
+ dbei->timestamp = sqlite3_column_int64(stmt, 1);
+ dbei->eventType = sqlite3_column_int(stmt, 2);
+ dbei->flags = sqlite3_column_int64(stmt, 3);
+
+ char *pszId = (char *)sqlite3_column_text(stmt, 4);
+ if (mir_strlen(pszId)) {
+ mir_strncpy(g_szId, pszId, sizeof(g_szId));
+ dbei->szId = g_szId;
+ }
+ else dbei->szId = nullptr;
+
+ int32_t cbBlob = sqlite3_column_int64(stmt, 5);
+ size_t bytesToCopy = cbBlob;
+ if (dbei->cbBlob == -1)
+ dbei->pBlob = (uint8_t*)mir_calloc(cbBlob + 2);
+ else if (dbei->cbBlob < cbBlob)
+ bytesToCopy = dbei->cbBlob;
+
+ dbei->cbBlob = cbBlob;
+ if (bytesToCopy && dbei->pBlob) {
+ uint8_t *data = (uint8_t *)sqlite3_column_blob(stmt, 6);
+
+ if (dbei->flags & DBEF_ENCRYPTED) {
+ dbei->flags &= ~DBEF_ENCRYPTED;
+ size_t len;
+ uint8_t* pBlob = (uint8_t*)m_crypto->decodeBuffer(data, cbBlob, &len);
+ if (pBlob == nullptr)
+ return 1;
+
+ memcpy(dbei->pBlob, pBlob, bytesToCopy);
+ if (bytesToCopy > len)
+ memset(dbei->pBlob + len, 0, bytesToCopy - len);
+
+ mir_free(pBlob);
+ }
+ else memcpy(dbei->pBlob, data, bytesToCopy);
+ }
+ sqlite3_reset(stmt);
+ return 0;
+}
+
+BOOL CDbxSQLite::MarkEventRead(MCONTACT hContact, MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return -1;
+
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return -1;
+
+ int rows;
+ {
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("UPDATE events SET flags = flags | 4, is_read = 1 WHERE id = ? AND is_read = 0;", qEvSetFlags);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ rows = sqlite3_changes(m_db);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return -1;
+ }
+
+ DBFlush();
+ NotifyEventHooks(g_hevMarkedRead, hContact, (LPARAM)hDbEvent);
+ return (rows == 0 ? 0 : DBEF_READ);
+}
+
+MCONTACT CDbxSQLite::GetEventContact(MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return INVALID_CONTACT_ID;
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT contact_id FROM events WHERE id = ? LIMIT 1;", qEvGetContact);
+ sqlite3_bind_int64(stmt, 1, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return INVALID_CONTACT_ID;
+ }
+ MCONTACT hContact = sqlite3_column_int64(stmt, 0);
+ sqlite3_reset(stmt);
+ return hContact;
+}
+
+MEVENT CDbxSQLite::FindFirstUnreadEvent(MCONTACT hContact)
+{
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ mir_cslock lock(m_csDbAccess);
+
+ if (cc->IsMeta()) {
+ if (cc->nSubs == 0)
+ return 0;
+
+ CMStringA query("SELECT id FROM events WHERE is_read = 0 AND contact_id IN (");
+ for (int k = 0; k < cc->nSubs; k++)
+ query.AppendFormat("%lu, ", cc->pSubs[k]);
+ query.Delete(query.GetLength() - 2, 2);
+ query.Append(") ORDER BY timestamp LIMIT 1;");
+
+ sqlite3_stmt *stmt;
+ sqlite3_prepare_v2(m_db, query, -1, &stmt, nullptr);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_finalize(stmt);
+ return 0;
+ }
+
+ MEVENT ret = sqlite3_column_int64(stmt, 0);
+ sqlite3_finalize(stmt);
+ return ret;
+ }
+
+ sqlite3_stmt *stmt = InitQuery("SELECT id FROM events WHERE contact_id = ? AND is_read = 0 ORDER BY timestamp LIMIT 1;", qEvFindUnread);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return 0;
+ }
+
+ MEVENT ret = sqlite3_column_int64(stmt, 0);
+ sqlite3_reset(stmt);
+ return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// First/next event
+
+MEVENT CDbxSQLite::FindFirstEvent(MCONTACT hContact)
+{
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ mir_cslock lock(m_csDbAccess);
+
+ if (fwd.cur)
+ sqlite3_reset(fwd.cur);
+
+ fwd.hContact = hContact;
+ fwd.cur = InitQuery(normal_order_query, qEvFindFirst);
+ sqlite3_bind_int64(fwd.cur, 1, hContact);
+
+ int rc = sqlite3_step(fwd.cur);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ fwd.clear();
+ return 0;
+ }
+ return fwd.hEvent = sqlite3_column_int64(fwd.cur, 0);
+}
+
+MEVENT CDbxSQLite::FindNextEvent(MCONTACT hContact, MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return 0;
+
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ if (hContact != fwd.hContact || hDbEvent != fwd.hEvent) {
+ if (fwd.cur)
+ sqlite3_reset(fwd.cur);
+
+ fwd.hContact = hContact;
+ fwd.cur = InitQuery("SELECT id FROM events_srt WHERE contact_id = ? AND id > ? ORDER BY timestamp, id;", qEvFindNext);
+ sqlite3_bind_int64(fwd.cur, 1, hContact);
+ sqlite3_bind_int64(fwd.cur, 2, hDbEvent);
+ }
+
+ int rc = sqlite3_step(fwd.cur);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ fwd.clear();
+ return 0;
+ }
+
+ return fwd.hEvent = sqlite3_column_int64(fwd.cur, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Last/prev event
+
+MEVENT CDbxSQLite::FindLastEvent(MCONTACT hContact)
+{
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ mir_cslock lock(m_csDbAccess);
+
+ if (back.cur)
+ sqlite3_reset(back.cur);
+
+ back.hContact = hContact;
+ back.cur = InitQuery(reverse_order_query, qEvFindLast);
+ sqlite3_bind_int64(back.cur, 1, hContact);
+ int rc = sqlite3_step(back.cur);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ back.clear();
+ return 0;
+ }
+
+ return back.hEvent = sqlite3_column_int64(back.cur, 0);
+}
+
+MEVENT CDbxSQLite::FindPrevEvent(MCONTACT hContact, MEVENT hDbEvent)
+{
+ if (hDbEvent == 0)
+ return 0;
+
+ DBCachedContact *cc = (hContact) ? m_cache->GetCachedContact(hContact) : &m_system;
+ if (cc == nullptr)
+ return 0;
+
+ if (hContact != back.hContact || hDbEvent != back.hEvent) {
+ if (back.cur)
+ sqlite3_reset(back.cur);
+
+ back.hContact = hContact;
+ back.cur = InitQuery("SELECT id FROM events_srt WHERE contact_id = ? AND id < ? ORDER BY timestamp desc, id DESC;", qEvFindPrev);
+ sqlite3_bind_int64(back.cur, 1, hContact);
+ sqlite3_bind_int64(back.cur, 2, hDbEvent);
+ }
+
+ int rc = sqlite3_step(back.cur);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ back.clear();
+ return 0;
+ }
+
+ return back.hEvent = sqlite3_column_int64(back.cur, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Metacontacts
+
+BOOL CDbxSQLite::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub)
+{
+ //TODO: test this
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT id, timestamp FROM events WHERE contact_id = ?;", qEvMetaMerge);
+ sqlite3_bind_int64(stmt, 1, ccSub->contactID);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ while (rc == SQLITE_ROW) {
+ sqlite3_stmt *stmt2 = InitQuery(add_event_sort_query, qEvAddSrt);
+ sqlite3_bind_int64(stmt2, 1, sqlite3_column_int64(stmt, 0));
+ sqlite3_bind_int64(stmt2, 2, ccMeta->contactID);
+ sqlite3_bind_int64(stmt2, 3, sqlite3_column_int64(stmt, 1));
+ int rc2 = sqlite3_step(stmt2);
+ logError(rc2, __FILE__, __LINE__);
+ sqlite3_reset(stmt2);
+ rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ }
+
+ sqlite3_reset(stmt);
+ DBFlush();
+ return TRUE;
+}
+
+BOOL CDbxSQLite::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *)
+{
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("DELETE FROM events_srt WHERE contact_id = ?;", qEvMetaSplit);
+ sqlite3_bind_int64(stmt, 1, ccMeta->contactID);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ DBFlush();
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Server ids
+
+MEVENT CDbxSQLite::GetEventById(LPCSTR szModule, LPCSTR szId)
+{
+ if (szModule == nullptr || szId == nullptr)
+ return 0;
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT id, timestamp FROM events WHERE module = ? AND server_id = ? LIMIT 1;", qEvGetById);
+ sqlite3_bind_text(stmt, 1, szModule, (int)mir_strlen(szModule), nullptr);
+ sqlite3_bind_text(stmt, 2, szId, (int)mir_strlen(szId), nullptr);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ sqlite3_reset(stmt);
+ return 0;
+ }
+ MEVENT hDbEvent = sqlite3_column_int64(stmt, 0);
+ sqlite3_reset(stmt);
+ return hDbEvent;
+}
+
+int CDbxSQLite::UpdateEventId(MEVENT hDbEvent, LPCSTR szId)
+{
+ if (hDbEvent == 0 || mir_strlen(szId) == 0)
+ return 1;
+
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("UPDATE events SET server_id = ? WHERE id = ?;", qEvUpdateId);
+ sqlite3_bind_text(stmt, 1, szId, (int)mir_strlen(szId), nullptr);
+ sqlite3_bind_int64(stmt, 2, hDbEvent);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ int rows = sqlite3_changes(m_db);
+ sqlite3_reset(stmt);
+ return (rows == 0) ? 2 : 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Event cursors
+
+STDMETHODIMP_(DB::EventCursor *) CDbxSQLite::EventCursor(MCONTACT hContact, MEVENT hDbEvent)
+{
+ return new CDbxSQLiteEventCursor(hContact, m_db, hDbEvent);
+}
+
+STDMETHODIMP_(DB::EventCursor *) CDbxSQLite::EventCursorRev(MCONTACT hContact, MEVENT hDbEvent)
+{
+ return new CDbxSQLiteEventCursor(hContact, m_db, hDbEvent, true);
+}
+
+CDbxSQLiteEventCursor::CDbxSQLiteEventCursor(MCONTACT _1, sqlite3 *_db, MEVENT hDbEvent, bool reverse) :
+ EventCursor(_1), m_db(_db)
+{
+ if (reverse) {
+ if (!hDbEvent)
+ sqlite3_prepare_v2(m_db, reverse_order_query, -1, &cursor, nullptr);
+ else
+ sqlite3_prepare_v2(m_db, reverse_order_pos_query, -1, &cursor, nullptr);
+ }
+ else {
+ if (!hDbEvent)
+ sqlite3_prepare_v2(m_db, normal_order_query, -1, &cursor, nullptr);
+ else
+ sqlite3_prepare_v2(m_db, normal_order_pos_query, -1, &cursor, nullptr);
+ }
+ sqlite3_bind_int64(cursor, 1, hContact);
+ if (hDbEvent)
+ sqlite3_bind_int64(cursor, 2, hDbEvent);
+}
+
+CDbxSQLiteEventCursor::~CDbxSQLiteEventCursor()
+{
+ if (cursor)
+ sqlite3_reset(cursor);
+}
+
+MEVENT CDbxSQLiteEventCursor::FetchNext()
+{
+ if (!cursor)
+ return 0;
+
+ int rc = sqlite3_step(cursor);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_ROW) {
+ //empty response
+ //reset sql cursor
+ sqlite3_reset(cursor);
+ cursor = nullptr;
+ return 0;
+ }
+ return sqlite3_column_int64(cursor, 0);
+}
diff --git a/plugins/Dbx_sqlite/src/dbintf.cpp b/plugins/Dbx_sqlite/src/dbintf.cpp
index a34551b617..035a651ccf 100644
--- a/plugins/Dbx_sqlite/src/dbintf.cpp
+++ b/plugins/Dbx_sqlite/src/dbintf.cpp
@@ -1,241 +1,241 @@
-#include "stdafx.h"
-
-CDbxSQLite::CDbxSQLite(const wchar_t *pwszFileName, bool bReadOnly, bool bShared) :
- m_impl(*this),
- m_wszFileName(mir_wstrdup(pwszFileName)),
- m_safetyMode(true),
- m_bReadOnly(bReadOnly),
- m_bShared(bShared),
- m_modules(1, strcmp)
-{
-}
-
-CDbxSQLite::~CDbxSQLite()
-{
- if (m_bTranStarted) {
- int rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- }
-
- UninitEvents();
-
- if (m_db) {
- int rc = sqlite3_close(m_db);
- logError(rc, __FILE__, __LINE__);
-
- m_db = nullptr;
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CDbxSQLite::Create()
-{
- ptrA path(mir_utf8encodeW(m_wszFileName));
- int rc = sqlite3_open_v2(path, &m_db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXCLUSIVE, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc != SQLITE_OK) {
- logError(rc, __FILE__, __LINE__);
- return 1;
- }
-
- rc = sqlite3_exec(m_db, "CREATE TABLE contacts (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE TABLE crypto (id INTEGER NOT NULL PRIMARY KEY, data NOT NULL);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE TABLE events (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, contact_id INTEGER NOT NULL, module TEXT NOT NULL,"
- "timestamp INTEGER NOT NULL, type INTEGER NOT NULL, flags INTEGER NOT NULL, data BLOB, server_id TEXT, is_read INTEGER NOT NULL DEFAULT 0);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_contactid_timestamp ON events(contact_id, timestamp);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_module_serverid ON events(module, server_id);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_isread ON events(contact_id, is_read, timestamp);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE TABLE events_srt (id INTEGER NOT NULL, contact_id INTEGER NOT NULL, timestamp INTEGER, PRIMARY KEY(contact_id, timestamp, id));", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE TABLE settings (contact_id INTEGER NOT NULL, module TEXT NOT NULL, setting TEXT NOT NULL, type INTEGER NOT NULL, value NOT NULL,"
- "PRIMARY KEY(contact_id, module, setting)) WITHOUT ROWID;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE INDEX idx_settings_module ON settings(module);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CDbxSQLite::Check()
-{
- FILE *hFile = _wfopen(m_wszFileName, L"rb");
- if (hFile == INVALID_HANDLE_VALUE)
- return EGROKPRF_CANTREAD;
-
- char header[16] = {};
- size_t size = sizeof(header);
-
- if (fread(header, sizeof(char), size, hFile) != size) {
- fclose(hFile);
- return EGROKPRF_CANTREAD;
- }
-
- fclose(hFile);
-
- if (memcmp(header, SQLITE_HEADER_STR, mir_strlen(SQLITE_HEADER_STR)) != 0)
- return EGROKPRF_UNKHEADER;
-
- sqlite3 *database = nullptr;
- ptrA path(mir_utf8encodeW(m_wszFileName));
- int rc = sqlite3_open_v2(path, &database, SQLITE_OPEN_READONLY | SQLITE_OPEN_EXCLUSIVE, nullptr);
- if (rc != SQLITE_OK) {
- logError(rc, __FILE__, __LINE__);
- return EGROKPRF_DAMAGED;
- }
-
- sqlite3_close(database);
-
- return EGROKPRF_NOERROR;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CDbxSQLite::Load()
-{
- if (!LockName(m_wszFileName))
- return EGROKPRF_CANTREAD;
-
- ptrA path(mir_utf8encodeW(m_wszFileName));
- int flags = 0;
- if (!m_bShared)
- flags |= SQLITE_OPEN_EXCLUSIVE;
- if (m_bReadOnly)
- flags |= SQLITE_OPEN_READONLY;
- else
- flags |= SQLITE_OPEN_READWRITE;
-
- int rc = sqlite3_open_v2(path, &m_db, flags, nullptr);
- if (rc != SQLITE_OK) {
- logError(rc, __FILE__, __LINE__);
- return EGROKPRF_CANTREAD;
- }
-
- rc = sqlite3_exec(m_db, "pragma locking_mode = EXCLUSIVE;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- rc = sqlite3_exec(m_db, "pragma synchronous = NORMAL;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- rc = sqlite3_exec(m_db, "pragma foreign_keys = OFF;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- rc = sqlite3_exec(m_db, "pragma journal_mode = OFF;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- if (rc == SQLITE_BUSY) {
- sqlite3_close(m_db);
- return EGROKPRF_CANTREAD;
- }
-
- InitContacts();
- InitEncryption();
- InitSettings();
- InitEvents();
-
- if (InitCrypt())
- return EGROKPRF_CANTREAD;
-
- m_bTranStarted = true;
- rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- return EGROKPRF_NOERROR;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL CDbxSQLite::Backup(LPCWSTR profile)
-{
- sqlite3 *database = nullptr;
- ptrA path(mir_utf8encodeW(profile));
- int rc = sqlite3_open_v2(path, &database, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXCLUSIVE, nullptr);
- if (rc != SQLITE_OK) {
- logError(rc, __FILE__, __LINE__);
- return rc;
- }
-
- mir_cslock lock(m_csDbAccess);
-
- sqlite3_backup *backup = sqlite3_backup_init(database, "main", m_db, "main");
- if (backup == nullptr) {
- sqlite3_close(database);
- DeleteFileW(profile);
- return ERROR_BACKUP_CONTROLLER;
- }
-
- rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- logError(sqlite3_backup_step(backup, -1), __FILE__, __LINE__);
- logError(sqlite3_backup_finish(backup), __FILE__, __LINE__);
- sqlite3_close(database);
-
- rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- return 0;
-}
-
-BOOL CDbxSQLite::Compact()
-{
- mir_cslock lck(m_csDbAccess);
- int rc = sqlite3_exec(m_db, "pragma optimize;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "vacuum;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- return 0;
-}
-
-void CDbxSQLite::DBFlush(bool bForce)
-{
- if (bForce) {
- mir_cslock lck(m_csDbAccess);
-
- int rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
- }
- else if (m_safetyMode)
- m_impl.m_timer.Start(50);
-}
-
-BOOL CDbxSQLite::Flush()
-{
- DBFlush(true);
- sqlite3_db_cacheflush(m_db);
- return ERROR_SUCCESS;
-}
-
-BOOL CDbxSQLite::IsRelational()
-{
- return TRUE;
-}
-
-void CDbxSQLite::SetCacheSafetyMode(BOOL value)
-{
- // hack to increase import speed
- if (!value)
- sqlite3_exec(m_db, "pragma synchronous = OFF;", nullptr, nullptr, nullptr);
- else
- sqlite3_exec(m_db, "pragma synchronous = NORMAL;", nullptr, nullptr, nullptr);
- m_safetyMode = value != FALSE;
-}
+#include "stdafx.h"
+
+CDbxSQLite::CDbxSQLite(const wchar_t *pwszFileName, bool bReadOnly, bool bShared) :
+ m_impl(*this),
+ m_wszFileName(mir_wstrdup(pwszFileName)),
+ m_safetyMode(true),
+ m_bReadOnly(bReadOnly),
+ m_bShared(bShared),
+ m_modules(1, strcmp)
+{
+}
+
+CDbxSQLite::~CDbxSQLite()
+{
+ if (m_bTranStarted) {
+ int rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ }
+
+ UninitEvents();
+
+ if (m_db) {
+ int rc = sqlite3_close(m_db);
+ logError(rc, __FILE__, __LINE__);
+
+ m_db = nullptr;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDbxSQLite::Create()
+{
+ ptrA path(mir_utf8encodeW(m_wszFileName));
+ int rc = sqlite3_open_v2(path, &m_db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXCLUSIVE, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc != SQLITE_OK) {
+ logError(rc, __FILE__, __LINE__);
+ return 1;
+ }
+
+ rc = sqlite3_exec(m_db, "CREATE TABLE contacts (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE TABLE crypto (id INTEGER NOT NULL PRIMARY KEY, data NOT NULL);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE TABLE events (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, contact_id INTEGER NOT NULL, module TEXT NOT NULL,"
+ "timestamp INTEGER NOT NULL, type INTEGER NOT NULL, flags INTEGER NOT NULL, data BLOB, server_id TEXT, is_read INTEGER NOT NULL DEFAULT 0);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_contactid_timestamp ON events(contact_id, timestamp);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_module_serverid ON events(module, server_id);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_isread ON events(contact_id, is_read, timestamp);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE TABLE events_srt (id INTEGER NOT NULL, contact_id INTEGER NOT NULL, timestamp INTEGER, PRIMARY KEY(contact_id, timestamp, id));", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE TABLE settings (contact_id INTEGER NOT NULL, module TEXT NOT NULL, setting TEXT NOT NULL, type INTEGER NOT NULL, value NOT NULL,"
+ "PRIMARY KEY(contact_id, module, setting)) WITHOUT ROWID;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE INDEX idx_settings_module ON settings(module);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDbxSQLite::Check()
+{
+ FILE *hFile = _wfopen(m_wszFileName, L"rb");
+ if (hFile == INVALID_HANDLE_VALUE)
+ return EGROKPRF_CANTREAD;
+
+ char header[16] = {};
+ size_t size = sizeof(header);
+
+ if (fread(header, sizeof(char), size, hFile) != size) {
+ fclose(hFile);
+ return EGROKPRF_CANTREAD;
+ }
+
+ fclose(hFile);
+
+ if (memcmp(header, SQLITE_HEADER_STR, mir_strlen(SQLITE_HEADER_STR)) != 0)
+ return EGROKPRF_UNKHEADER;
+
+ sqlite3 *database = nullptr;
+ ptrA path(mir_utf8encodeW(m_wszFileName));
+ int rc = sqlite3_open_v2(path, &database, SQLITE_OPEN_READONLY | SQLITE_OPEN_EXCLUSIVE, nullptr);
+ if (rc != SQLITE_OK) {
+ logError(rc, __FILE__, __LINE__);
+ return EGROKPRF_DAMAGED;
+ }
+
+ sqlite3_close(database);
+
+ return EGROKPRF_NOERROR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDbxSQLite::Load()
+{
+ if (!LockName(m_wszFileName))
+ return EGROKPRF_CANTREAD;
+
+ ptrA path(mir_utf8encodeW(m_wszFileName));
+ int flags = 0;
+ if (!m_bShared)
+ flags |= SQLITE_OPEN_EXCLUSIVE;
+ if (m_bReadOnly)
+ flags |= SQLITE_OPEN_READONLY;
+ else
+ flags |= SQLITE_OPEN_READWRITE;
+
+ int rc = sqlite3_open_v2(path, &m_db, flags, nullptr);
+ if (rc != SQLITE_OK) {
+ logError(rc, __FILE__, __LINE__);
+ return EGROKPRF_CANTREAD;
+ }
+
+ rc = sqlite3_exec(m_db, "pragma locking_mode = EXCLUSIVE;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ rc = sqlite3_exec(m_db, "pragma synchronous = NORMAL;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ rc = sqlite3_exec(m_db, "pragma foreign_keys = OFF;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ rc = sqlite3_exec(m_db, "pragma journal_mode = OFF;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ if (rc == SQLITE_BUSY) {
+ sqlite3_close(m_db);
+ return EGROKPRF_CANTREAD;
+ }
+
+ InitContacts();
+ InitEncryption();
+ InitSettings();
+ InitEvents();
+
+ if (InitCrypt())
+ return EGROKPRF_CANTREAD;
+
+ m_bTranStarted = true;
+ rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ return EGROKPRF_NOERROR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL CDbxSQLite::Backup(LPCWSTR profile)
+{
+ sqlite3 *database = nullptr;
+ ptrA path(mir_utf8encodeW(profile));
+ int rc = sqlite3_open_v2(path, &database, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_EXCLUSIVE, nullptr);
+ if (rc != SQLITE_OK) {
+ logError(rc, __FILE__, __LINE__);
+ return rc;
+ }
+
+ mir_cslock lock(m_csDbAccess);
+
+ sqlite3_backup *backup = sqlite3_backup_init(database, "main", m_db, "main");
+ if (backup == nullptr) {
+ sqlite3_close(database);
+ DeleteFileW(profile);
+ return ERROR_BACKUP_CONTROLLER;
+ }
+
+ rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ logError(sqlite3_backup_step(backup, -1), __FILE__, __LINE__);
+ logError(sqlite3_backup_finish(backup), __FILE__, __LINE__);
+ sqlite3_close(database);
+
+ rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ return 0;
+}
+
+BOOL CDbxSQLite::Compact()
+{
+ mir_cslock lck(m_csDbAccess);
+ int rc = sqlite3_exec(m_db, "pragma optimize;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "vacuum;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ return 0;
+}
+
+void CDbxSQLite::DBFlush(bool bForce)
+{
+ if (bForce) {
+ mir_cslock lck(m_csDbAccess);
+
+ int rc = sqlite3_exec(m_db, "commit;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "begin transaction;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+ }
+ else if (m_safetyMode)
+ m_impl.m_timer.Start(50);
+}
+
+BOOL CDbxSQLite::Flush()
+{
+ DBFlush(true);
+ sqlite3_db_cacheflush(m_db);
+ return ERROR_SUCCESS;
+}
+
+BOOL CDbxSQLite::IsRelational()
+{
+ return TRUE;
+}
+
+void CDbxSQLite::SetCacheSafetyMode(BOOL value)
+{
+ // hack to increase import speed
+ if (!value)
+ sqlite3_exec(m_db, "pragma synchronous = OFF;", nullptr, nullptr, nullptr);
+ else
+ sqlite3_exec(m_db, "pragma synchronous = NORMAL;", nullptr, nullptr, nullptr);
+ m_safetyMode = value != FALSE;
+}
diff --git a/plugins/Dbx_sqlite/src/dbintf.h b/plugins/Dbx_sqlite/src/dbintf.h
index e7a88591c5..35404505cb 100644
--- a/plugins/Dbx_sqlite/src/dbintf.h
+++ b/plugins/Dbx_sqlite/src/dbintf.h
@@ -1,188 +1,188 @@
-#pragma once
-
-#define OWN_CACHED_CONTACT
-
-#include <m_db_int.h>
-
-struct CQuery
-{
- ~CQuery();
-
- sqlite3_stmt *pQuery = nullptr;
-};
-
-struct DBCachedContact : public DBCachedContactBase
-{
- int32_t m_count;
-
- DBCachedContact() :
- m_count(-1)
- {}
-
- __forceinline bool HasCount() const {
- return m_count > -1;
- }
-};
-
-struct CDbxSQLiteEventCursor : public DB::EventCursor
-{
- CDbxSQLiteEventCursor(MCONTACT _1, sqlite3* m_db, MEVENT hDbEvent, bool reverse = false);
- ~CDbxSQLiteEventCursor() override;
- MEVENT FetchNext() override;
-
-private:
- sqlite3 *m_db;
- sqlite3_stmt *cursor;
-};
-
-class CDbxSQLite : public MDatabaseCommon, public MIDatabaseChecker, public MZeroedObject
-{
- ptrW m_wszFileName;
- sqlite3 *m_db = nullptr;
-
- struct {
- sqlite3_stmt *cur;
- MCONTACT hContact;
- MEVENT hEvent;
-
- void clear() {
- if (cur)
- sqlite3_reset(cur);
- memset(this, 0, sizeof(*this));
- }
- }
- fwd, back;
-
- DBCachedContact m_system;
-
- struct Impl {
- CDbxSQLite &pro;
-
- CTimer m_timer;
- void OnTimer(CTimer *pTimer)
- {
- pTimer->Stop();
- pro.DBFlush(true);
- }
-
- Impl(CDbxSQLite &_p) :
- pro(_p),
- m_timer(Miranda_GetSystemWindow(), UINT_PTR(this))
- {
- m_timer.OnEvent = Callback(this, &Impl::OnTimer);
- }
- } m_impl;
-
- bool m_safetyMode, m_bReadOnly, m_bShared, m_bTranStarted;
-
- // contacts
- void InitContacts();
- CQuery qCntCount, qCntAdd, qCntDel, qCntDelSettings, qCntDelEvents, qCntDelEventSrt;
-
- // encryption
- void InitEncryption();
- CQuery qCryptGetMode, qCryptSetMode, qCryptGetProvider, qCryptSetProvider, qCryptGetKey, qCryptSetKey, qCryptEnc1, qCryptEnc2;
-
- // events
- LIST<char> m_modules;
- void InitEvents();
- void UninitEvents();
- CQuery qEvCount, qEvAdd, qEvDel, qEvEdit, qEvBlobSize, qEvGet, qEvGetFlags, qEvSetFlags, qEvGetContact, qEvGetContact2;
- CQuery qEvFindFirst, qEvFindNext, qEvFindLast, qEvFindPrev, qEvFindUnread, qEvAddSrt, qEvDelSrt, qEvMetaSplit, qEvMetaMerge;
- CQuery qEvGetById, qEvUpdateId;
- int DeleteEventMain(MEVENT);
- int DeleteEventSrt(MEVENT, MCONTACT, uint32_t);
-
- // settings
- void InitSettings();
- CQuery qSettModules, qSettWrite, qSettDel, qSettEnum, qSettChanges;
- int DeleteContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting);
-
- void DBFlush(bool bForce = false);
- sqlite3_stmt* InitQuery(const char *szQuery, CQuery &stmt);
-
-public:
- CDbxSQLite(const wchar_t *pwszFileName, bool bReadOnly, bool bShared);
- ~CDbxSQLite();
-
- int Create();
- int Check();
- int Load();
-
- STDMETHODIMP_(BOOL) IsRelational(void) override;
- STDMETHODIMP_(void) SetCacheSafetyMode(BOOL) override;
-
- STDMETHODIMP_(int) GetContactCount(void) override;
- STDMETHODIMP_(int) DeleteContact(MCONTACT contactID) override;
- STDMETHODIMP_(MCONTACT) AddContact(void) override;
- STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID) override;
- STDMETHODIMP_(int) GetContactSize(void) override;
-
- STDMETHODIMP_(int) GetEventCount(MCONTACT contactID) override;
- STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, const DBEVENTINFO *dbe) override;
- STDMETHODIMP_(BOOL) DeleteEvent(MEVENT hDbEvent) override;
- STDMETHODIMP_(BOOL) EditEvent(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) override;
- STDMETHODIMP_(int) GetBlobSize(MEVENT hDbEvent) override;
- STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe) override;
- STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) override;
- STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent) override;
- STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID) override;
- STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID) override;
- STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID) override;
- STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent) override;
- STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) override;
-
- STDMETHODIMP_(MEVENT) GetEventById(LPCSTR szModule, LPCSTR szId) override;
- STDMETHODIMP_(int) UpdateEventId(MEVENT hDbEvent, LPCSTR szId) override;
-
- STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam) override;
-
- STDMETHODIMP_(BOOL) ReadCryptoKey(MBinBuffer&) override;
- STDMETHODIMP_(BOOL) StoreCryptoKey() override;
-
- STDMETHODIMP_(CRYPTO_PROVIDER*) ReadProvider() override;
- STDMETHODIMP_(BOOL) StoreProvider(CRYPTO_PROVIDER*) override;
-
- STDMETHODIMP_(BOOL) EnableEncryption(BOOL) override;
- STDMETHODIMP_(BOOL) ReadEncryption() override;
-
- STDMETHODIMP_(BOOL) WriteContactSettingWorker(MCONTACT contactID, DBCONTACTWRITESETTING &dbcws) override;
- STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) override;
- STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) override;
-
- STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) override;
- STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) override;
-
- STDMETHODIMP_(BOOL) Compact() override;
- STDMETHODIMP_(BOOL) Backup(LPCWSTR) override;
- STDMETHODIMP_(BOOL) Flush() override;
-
- STDMETHODIMP_(DATABASELINK*) GetDriver() override;
-
- STDMETHODIMP_(DB::EventCursor*) EventCursor(MCONTACT hContact, MEVENT hDbEvent) override;
- STDMETHODIMP_(DB::EventCursor*) EventCursorRev(MCONTACT hContact, MEVENT hDbEvent) override;
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // database checker interface implementation
-
-protected:
- STDMETHODIMP_(MIDatabaseChecker *) GetChecker() override
- { return this;
- }
-
- STDMETHODIMP_(BOOL) Start(DBCHeckCallback *callback) override
- {
- cb = callback;
- return ERROR_SUCCESS;
- }
-
- STDMETHODIMP_(BOOL) CheckDb(int phase) override;
- STDMETHODIMP_(VOID) Destroy() override
- {}
-
- DBCHeckCallback *cb;
- int CheckPhase1(void);
- int CheckPhase2(void);
- int CheckPhase3(void);
- int CheckPhase4(void);
-};
+#pragma once
+
+#define OWN_CACHED_CONTACT
+
+#include <m_db_int.h>
+
+struct CQuery
+{
+ ~CQuery();
+
+ sqlite3_stmt *pQuery = nullptr;
+};
+
+struct DBCachedContact : public DBCachedContactBase
+{
+ int32_t m_count;
+
+ DBCachedContact() :
+ m_count(-1)
+ {}
+
+ __forceinline bool HasCount() const {
+ return m_count > -1;
+ }
+};
+
+struct CDbxSQLiteEventCursor : public DB::EventCursor
+{
+ CDbxSQLiteEventCursor(MCONTACT _1, sqlite3* m_db, MEVENT hDbEvent, bool reverse = false);
+ ~CDbxSQLiteEventCursor() override;
+ MEVENT FetchNext() override;
+
+private:
+ sqlite3 *m_db;
+ sqlite3_stmt *cursor;
+};
+
+class CDbxSQLite : public MDatabaseCommon, public MIDatabaseChecker, public MZeroedObject
+{
+ ptrW m_wszFileName;
+ sqlite3 *m_db = nullptr;
+
+ struct {
+ sqlite3_stmt *cur;
+ MCONTACT hContact;
+ MEVENT hEvent;
+
+ void clear() {
+ if (cur)
+ sqlite3_reset(cur);
+ memset(this, 0, sizeof(*this));
+ }
+ }
+ fwd, back;
+
+ DBCachedContact m_system;
+
+ struct Impl {
+ CDbxSQLite &pro;
+
+ CTimer m_timer;
+ void OnTimer(CTimer *pTimer)
+ {
+ pTimer->Stop();
+ pro.DBFlush(true);
+ }
+
+ Impl(CDbxSQLite &_p) :
+ pro(_p),
+ m_timer(Miranda_GetSystemWindow(), UINT_PTR(this))
+ {
+ m_timer.OnEvent = Callback(this, &Impl::OnTimer);
+ }
+ } m_impl;
+
+ bool m_safetyMode, m_bReadOnly, m_bShared, m_bTranStarted;
+
+ // contacts
+ void InitContacts();
+ CQuery qCntCount, qCntAdd, qCntDel, qCntDelSettings, qCntDelEvents, qCntDelEventSrt;
+
+ // encryption
+ void InitEncryption();
+ CQuery qCryptGetMode, qCryptSetMode, qCryptGetProvider, qCryptSetProvider, qCryptGetKey, qCryptSetKey, qCryptEnc1, qCryptEnc2;
+
+ // events
+ LIST<char> m_modules;
+ void InitEvents();
+ void UninitEvents();
+ CQuery qEvCount, qEvAdd, qEvDel, qEvEdit, qEvBlobSize, qEvGet, qEvGetFlags, qEvSetFlags, qEvGetContact, qEvGetContact2;
+ CQuery qEvFindFirst, qEvFindNext, qEvFindLast, qEvFindPrev, qEvFindUnread, qEvAddSrt, qEvDelSrt, qEvMetaSplit, qEvMetaMerge;
+ CQuery qEvGetById, qEvUpdateId;
+ int DeleteEventMain(MEVENT);
+ int DeleteEventSrt(MEVENT, MCONTACT, uint32_t);
+
+ // settings
+ void InitSettings();
+ CQuery qSettModules, qSettWrite, qSettDel, qSettEnum, qSettChanges;
+ int DeleteContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting);
+
+ void DBFlush(bool bForce = false);
+ sqlite3_stmt* InitQuery(const char *szQuery, CQuery &stmt);
+
+public:
+ CDbxSQLite(const wchar_t *pwszFileName, bool bReadOnly, bool bShared);
+ ~CDbxSQLite();
+
+ int Create();
+ int Check();
+ int Load();
+
+ STDMETHODIMP_(BOOL) IsRelational(void) override;
+ STDMETHODIMP_(void) SetCacheSafetyMode(BOOL) override;
+
+ STDMETHODIMP_(int) GetContactCount(void) override;
+ STDMETHODIMP_(int) DeleteContact(MCONTACT contactID) override;
+ STDMETHODIMP_(MCONTACT) AddContact(void) override;
+ STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID) override;
+ STDMETHODIMP_(int) GetContactSize(void) override;
+
+ STDMETHODIMP_(int) GetEventCount(MCONTACT contactID) override;
+ STDMETHODIMP_(MEVENT) AddEvent(MCONTACT contactID, const DBEVENTINFO *dbe) override;
+ STDMETHODIMP_(BOOL) DeleteEvent(MEVENT hDbEvent) override;
+ STDMETHODIMP_(BOOL) EditEvent(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) override;
+ STDMETHODIMP_(int) GetBlobSize(MEVENT hDbEvent) override;
+ STDMETHODIMP_(BOOL) GetEvent(MEVENT hDbEvent, DBEVENTINFO *dbe) override;
+ STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) override;
+ STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT hDbEvent) override;
+ STDMETHODIMP_(MEVENT) FindFirstEvent(MCONTACT contactID) override;
+ STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT contactID) override;
+ STDMETHODIMP_(MEVENT) FindLastEvent(MCONTACT contactID) override;
+ STDMETHODIMP_(MEVENT) FindNextEvent(MCONTACT contactID, MEVENT hDbEvent) override;
+ STDMETHODIMP_(MEVENT) FindPrevEvent(MCONTACT contactID, MEVENT hDbEvent) override;
+
+ STDMETHODIMP_(MEVENT) GetEventById(LPCSTR szModule, LPCSTR szId) override;
+ STDMETHODIMP_(int) UpdateEventId(MEVENT hDbEvent, LPCSTR szId) override;
+
+ STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC pFunc, void *pParam) override;
+
+ STDMETHODIMP_(BOOL) ReadCryptoKey(MBinBuffer&) override;
+ STDMETHODIMP_(BOOL) StoreCryptoKey() override;
+
+ STDMETHODIMP_(CRYPTO_PROVIDER*) ReadProvider() override;
+ STDMETHODIMP_(BOOL) StoreProvider(CRYPTO_PROVIDER*) override;
+
+ STDMETHODIMP_(BOOL) EnableEncryption(BOOL) override;
+ STDMETHODIMP_(BOOL) ReadEncryption() override;
+
+ STDMETHODIMP_(BOOL) WriteContactSettingWorker(MCONTACT contactID, DBCONTACTWRITESETTING &dbcws) override;
+ STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) override;
+ STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) override;
+
+ STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) override;
+ STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) override;
+
+ STDMETHODIMP_(BOOL) Compact() override;
+ STDMETHODIMP_(BOOL) Backup(LPCWSTR) override;
+ STDMETHODIMP_(BOOL) Flush() override;
+
+ STDMETHODIMP_(DATABASELINK*) GetDriver() override;
+
+ STDMETHODIMP_(DB::EventCursor*) EventCursor(MCONTACT hContact, MEVENT hDbEvent) override;
+ STDMETHODIMP_(DB::EventCursor*) EventCursorRev(MCONTACT hContact, MEVENT hDbEvent) override;
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // database checker interface implementation
+
+protected:
+ STDMETHODIMP_(MIDatabaseChecker *) GetChecker() override
+ { return this;
+ }
+
+ STDMETHODIMP_(BOOL) Start(DBCHeckCallback *callback) override
+ {
+ cb = callback;
+ return ERROR_SUCCESS;
+ }
+
+ STDMETHODIMP_(BOOL) CheckDb(int phase) override;
+ STDMETHODIMP_(VOID) Destroy() override
+ {}
+
+ DBCHeckCallback *cb;
+ int CheckPhase1(void);
+ int CheckPhase2(void);
+ int CheckPhase3(void);
+ int CheckPhase4(void);
+};
diff --git a/plugins/Dbx_sqlite/src/dbsettings.cpp b/plugins/Dbx_sqlite/src/dbsettings.cpp
index 2fe4d3c18e..c4bd196cb4 100644
--- a/plugins/Dbx_sqlite/src/dbsettings.cpp
+++ b/plugins/Dbx_sqlite/src/dbsettings.cpp
@@ -1,225 +1,225 @@
-#include "stdafx.h"
-
-void CDbxSQLite::InitSettings()
-{
- sqlite3_stmt *stmt = nullptr;
- sqlite3_prepare_v2(m_db, "SELECT type, value, contact_id, module, setting FROM settings;", -1, &stmt, nullptr);
- while (sqlite3_step(stmt) == SQLITE_ROW) {
- MCONTACT hContact = sqlite3_column_int64(stmt, 2);
- auto *szModule = (const char *)sqlite3_column_text(stmt, 3);
- auto *szSetting = (const char *)sqlite3_column_text(stmt, 4);
-
- size_t settingNameLen = strlen(szSetting);
- size_t moduleNameLen = strlen(szModule);
-
- char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen);
-
- DBVARIANT *dbv = m_cache->GetCachedValuePtr(hContact, szCachedSettingName, 1);
- if (dbv == nullptr) // garbage! a setting for removed/non-existent contact
- continue;
-
- dbv->type = (int)sqlite3_column_int(stmt, 0);
- switch (dbv->type) {
- case DBVT_BYTE:
- dbv->bVal = sqlite3_column_int(stmt, 1);
- break;
-
- case DBVT_WORD:
- dbv->wVal = sqlite3_column_int(stmt, 1);
- break;
-
- case DBVT_DWORD:
- dbv->dVal = sqlite3_column_int64(stmt, 1);
- break;
-
- case DBVT_ASCIIZ:
- case DBVT_UTF8:
- dbv->cchVal = sqlite3_column_bytes(stmt, 1);
- {
- const char *value = (const char *)sqlite3_column_text(stmt, 1);
- dbv->pszVal = (char *)mir_alloc(dbv->cchVal + 1);
- memcpy(dbv->pszVal, value, dbv->cchVal);
- dbv->pszVal[dbv->cchVal] = 0;
- }
- break;
-
- case DBVT_ENCRYPTED:
- case DBVT_BLOB:
- dbv->cpbVal = sqlite3_column_bytes(stmt, 1);
- {
- const char *data = (const char *)sqlite3_column_blob(stmt, 1);
- dbv->pbVal = (uint8_t *)mir_alloc(dbv->cpbVal + 1);
- memcpy(dbv->pbVal, data, dbv->cpbVal);
- dbv->pbVal[dbv->cpbVal] = 0;
- }
- break;
- }
- }
- sqlite3_finalize(stmt);
-
- FillContactSettings();
-
- DBVARIANT dbv; dbv.type = DBVT_BYTE;
- if (GetContactSetting(0, "Compatibility", "Sqlite", &dbv))
- dbv.bVal = 0;
-
- if (dbv.bVal < 1) {
- int rc = sqlite3_exec(m_db, "ALTER TABLE events ADD COLUMN is_read INTEGER NOT NULL DEFAULT 0;", 0, 0, 0);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_isread ON events(contact_id, is_read, timestamp);", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- rc = sqlite3_exec(m_db, "UPDATE events SET is_read=1 WHERE (flags & 6) <> 0;", nullptr, nullptr, nullptr);
- logError(rc, __FILE__, __LINE__);
-
- dbv.type = DBVT_BYTE;
- dbv.dVal = 1;
- WriteContactSetting(0, "Compatibility", "Sqlite", &dbv);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL CDbxSQLite::EnumModuleNames(DBMODULEENUMPROC pFunc, void *param)
-{
- LIST<char> modules(100);
- {
- sqlite3_stmt *stmt = InitQuery("SELECT DISTINCT module FROM settings;", qSettModules);
- int rc = 0;
- while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
- const char *value = (const char *)sqlite3_column_text(stmt, 0);
- modules.insert(mir_strdup(value));
- }
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- }
-
- int result = -1;
- for (auto &module : modules) {
- result = pFunc(module, param);
- mir_free(module);
- }
- return result;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL CDbxSQLite::WriteContactSettingWorker(MCONTACT hContact, DBCONTACTWRITESETTING &dbcws)
-{
- sqlite3_stmt *stmt = InitQuery("REPLACE INTO settings(contact_id, module, setting, type, value) VALUES (?, ?, ?, ?, ?);", qSettWrite);
- sqlite3_bind_int64(stmt, 1, hContact);
- sqlite3_bind_text(stmt, 2, dbcws.szModule, (int)mir_strlen(dbcws.szModule), nullptr);
- sqlite3_bind_text(stmt, 3, dbcws.szSetting, (int)mir_strlen(dbcws.szSetting), nullptr);
- sqlite3_bind_int(stmt, 4, dbcws.value.type);
- switch (dbcws.value.type) {
- case DBVT_BYTE:
- sqlite3_bind_int(stmt, 5, dbcws.value.bVal);
- break;
- case DBVT_WORD:
- sqlite3_bind_int(stmt, 5, dbcws.value.wVal);
- break;
- case DBVT_DWORD:
- sqlite3_bind_int64(stmt, 5, dbcws.value.dVal);
- break;
- case DBVT_ASCIIZ:
- case DBVT_UTF8:
- sqlite3_bind_text(stmt, 5, dbcws.value.pszVal, dbcws.value.cchVal, nullptr);
- break;
- case DBVT_ENCRYPTED:
- case DBVT_BLOB:
- sqlite3_bind_blob(stmt, 5, dbcws.value.pbVal, dbcws.value.cpbVal, nullptr);
- break;
- }
-
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- if (rc != SQLITE_DONE)
- return 1;
-
- DBFlush();
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-int CDbxSQLite::DeleteContactSettingWorker(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting)
-{
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("DELETE FROM settings WHERE contact_id = ? AND module = ? AND setting = ?;", qSettDel);
- sqlite3_bind_int64(stmt, 1, hContact);
- sqlite3_bind_text(stmt, 2, szModule, (int)mir_strlen(szModule), nullptr);
- sqlite3_bind_text(stmt, 3, szSetting, (int)mir_strlen(szSetting), nullptr);
- int rc = sqlite3_step(stmt);
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- return rc;
-}
-
-BOOL CDbxSQLite::DeleteContactSetting(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting)
-{
- if (szSetting == nullptr || szModule == nullptr)
- return 1;
-
- if (hContact) {
- DBCachedContact *cc = m_cache->GetCachedContact(hContact);
- if (cc == nullptr)
- return 1;
- }
-
- // if a setting isn't found in cache, then return an error - we don't cache misses anymore
- char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, mir_strlen(szModule), mir_strlen(szSetting));
- if (m_cache->GetCachedValuePtr(hContact, szCachedSettingName, -1) == nullptr)
- return 1;
-
- if (szCachedSettingName[-1] == 0) { // it's not a resident variable
- DeleteContactSettingWorker(hContact, szModule, szSetting);
- DBFlush();
- }
-
- // notify
- DBCONTACTWRITESETTING dbcws = { 0 };
- dbcws.szModule = szModule;
- dbcws.szSetting = szSetting;
- dbcws.value.type = DBVT_DELETED;
- NotifyEventHooks(g_hevSettingChanged, hContact, (LPARAM)&dbcws);
-
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-BOOL CDbxSQLite::EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param)
-{
- if (szModule == nullptr)
- return -1;
-
- if (hContact) {
- DBCachedContact *cc = m_cache->GetCachedContact(hContact);
- if (cc == nullptr)
- return -1;
- }
-
- LIST<char> settings(100);
- {
- mir_cslock lock(m_csDbAccess);
- sqlite3_stmt *stmt = InitQuery("SELECT setting FROM settings WHERE contact_id = ? AND module = ?;", qSettEnum);
- sqlite3_bind_int64(stmt, 1, hContact);
- sqlite3_bind_text(stmt, 2, szModule, (int)mir_strlen(szModule), nullptr);
- int rc = 0;
- while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
- const char *value = (const char *)sqlite3_column_text(stmt, 0);
- settings.insert(mir_strdup(value));
- }
- logError(rc, __FILE__, __LINE__);
- sqlite3_reset(stmt);
- }
-
- int result = -1;
- for (auto &setting : settings) {
- result = pfnEnumProc(setting, param);
- mir_free(setting);
- }
- return result;
-}
+#include "stdafx.h"
+
+void CDbxSQLite::InitSettings()
+{
+ sqlite3_stmt *stmt = nullptr;
+ sqlite3_prepare_v2(m_db, "SELECT type, value, contact_id, module, setting FROM settings;", -1, &stmt, nullptr);
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ MCONTACT hContact = sqlite3_column_int64(stmt, 2);
+ auto *szModule = (const char *)sqlite3_column_text(stmt, 3);
+ auto *szSetting = (const char *)sqlite3_column_text(stmt, 4);
+
+ size_t settingNameLen = strlen(szSetting);
+ size_t moduleNameLen = strlen(szModule);
+
+ char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen);
+
+ DBVARIANT *dbv = m_cache->GetCachedValuePtr(hContact, szCachedSettingName, 1);
+ if (dbv == nullptr) // garbage! a setting for removed/non-existent contact
+ continue;
+
+ dbv->type = (int)sqlite3_column_int(stmt, 0);
+ switch (dbv->type) {
+ case DBVT_BYTE:
+ dbv->bVal = sqlite3_column_int(stmt, 1);
+ break;
+
+ case DBVT_WORD:
+ dbv->wVal = sqlite3_column_int(stmt, 1);
+ break;
+
+ case DBVT_DWORD:
+ dbv->dVal = sqlite3_column_int64(stmt, 1);
+ break;
+
+ case DBVT_ASCIIZ:
+ case DBVT_UTF8:
+ dbv->cchVal = sqlite3_column_bytes(stmt, 1);
+ {
+ const char *value = (const char *)sqlite3_column_text(stmt, 1);
+ dbv->pszVal = (char *)mir_alloc(dbv->cchVal + 1);
+ memcpy(dbv->pszVal, value, dbv->cchVal);
+ dbv->pszVal[dbv->cchVal] = 0;
+ }
+ break;
+
+ case DBVT_ENCRYPTED:
+ case DBVT_BLOB:
+ dbv->cpbVal = sqlite3_column_bytes(stmt, 1);
+ {
+ const char *data = (const char *)sqlite3_column_blob(stmt, 1);
+ dbv->pbVal = (uint8_t *)mir_alloc(dbv->cpbVal + 1);
+ memcpy(dbv->pbVal, data, dbv->cpbVal);
+ dbv->pbVal[dbv->cpbVal] = 0;
+ }
+ break;
+ }
+ }
+ sqlite3_finalize(stmt);
+
+ FillContactSettings();
+
+ DBVARIANT dbv; dbv.type = DBVT_BYTE;
+ if (GetContactSetting(0, "Compatibility", "Sqlite", &dbv))
+ dbv.bVal = 0;
+
+ if (dbv.bVal < 1) {
+ int rc = sqlite3_exec(m_db, "ALTER TABLE events ADD COLUMN is_read INTEGER NOT NULL DEFAULT 0;", 0, 0, 0);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "CREATE INDEX idx_events_isread ON events(contact_id, is_read, timestamp);", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ rc = sqlite3_exec(m_db, "UPDATE events SET is_read=1 WHERE (flags & 6) <> 0;", nullptr, nullptr, nullptr);
+ logError(rc, __FILE__, __LINE__);
+
+ dbv.type = DBVT_BYTE;
+ dbv.dVal = 1;
+ WriteContactSetting(0, "Compatibility", "Sqlite", &dbv);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL CDbxSQLite::EnumModuleNames(DBMODULEENUMPROC pFunc, void *param)
+{
+ LIST<char> modules(100);
+ {
+ sqlite3_stmt *stmt = InitQuery("SELECT DISTINCT module FROM settings;", qSettModules);
+ int rc = 0;
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
+ const char *value = (const char *)sqlite3_column_text(stmt, 0);
+ modules.insert(mir_strdup(value));
+ }
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ }
+
+ int result = -1;
+ for (auto &module : modules) {
+ result = pFunc(module, param);
+ mir_free(module);
+ }
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL CDbxSQLite::WriteContactSettingWorker(MCONTACT hContact, DBCONTACTWRITESETTING &dbcws)
+{
+ sqlite3_stmt *stmt = InitQuery("REPLACE INTO settings(contact_id, module, setting, type, value) VALUES (?, ?, ?, ?, ?);", qSettWrite);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ sqlite3_bind_text(stmt, 2, dbcws.szModule, (int)mir_strlen(dbcws.szModule), nullptr);
+ sqlite3_bind_text(stmt, 3, dbcws.szSetting, (int)mir_strlen(dbcws.szSetting), nullptr);
+ sqlite3_bind_int(stmt, 4, dbcws.value.type);
+ switch (dbcws.value.type) {
+ case DBVT_BYTE:
+ sqlite3_bind_int(stmt, 5, dbcws.value.bVal);
+ break;
+ case DBVT_WORD:
+ sqlite3_bind_int(stmt, 5, dbcws.value.wVal);
+ break;
+ case DBVT_DWORD:
+ sqlite3_bind_int64(stmt, 5, dbcws.value.dVal);
+ break;
+ case DBVT_ASCIIZ:
+ case DBVT_UTF8:
+ sqlite3_bind_text(stmt, 5, dbcws.value.pszVal, dbcws.value.cchVal, nullptr);
+ break;
+ case DBVT_ENCRYPTED:
+ case DBVT_BLOB:
+ sqlite3_bind_blob(stmt, 5, dbcws.value.pbVal, dbcws.value.cpbVal, nullptr);
+ break;
+ }
+
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ if (rc != SQLITE_DONE)
+ return 1;
+
+ DBFlush();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDbxSQLite::DeleteContactSettingWorker(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting)
+{
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("DELETE FROM settings WHERE contact_id = ? AND module = ? AND setting = ?;", qSettDel);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ sqlite3_bind_text(stmt, 2, szModule, (int)mir_strlen(szModule), nullptr);
+ sqlite3_bind_text(stmt, 3, szSetting, (int)mir_strlen(szSetting), nullptr);
+ int rc = sqlite3_step(stmt);
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ return rc;
+}
+
+BOOL CDbxSQLite::DeleteContactSetting(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting)
+{
+ if (szSetting == nullptr || szModule == nullptr)
+ return 1;
+
+ if (hContact) {
+ DBCachedContact *cc = m_cache->GetCachedContact(hContact);
+ if (cc == nullptr)
+ return 1;
+ }
+
+ // if a setting isn't found in cache, then return an error - we don't cache misses anymore
+ char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, mir_strlen(szModule), mir_strlen(szSetting));
+ if (m_cache->GetCachedValuePtr(hContact, szCachedSettingName, -1) == nullptr)
+ return 1;
+
+ if (szCachedSettingName[-1] == 0) { // it's not a resident variable
+ DeleteContactSettingWorker(hContact, szModule, szSetting);
+ DBFlush();
+ }
+
+ // notify
+ DBCONTACTWRITESETTING dbcws = { 0 };
+ dbcws.szModule = szModule;
+ dbcws.szSetting = szSetting;
+ dbcws.value.type = DBVT_DELETED;
+ NotifyEventHooks(g_hevSettingChanged, hContact, (LPARAM)&dbcws);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+BOOL CDbxSQLite::EnumContactSettings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param)
+{
+ if (szModule == nullptr)
+ return -1;
+
+ if (hContact) {
+ DBCachedContact *cc = m_cache->GetCachedContact(hContact);
+ if (cc == nullptr)
+ return -1;
+ }
+
+ LIST<char> settings(100);
+ {
+ mir_cslock lock(m_csDbAccess);
+ sqlite3_stmt *stmt = InitQuery("SELECT setting FROM settings WHERE contact_id = ? AND module = ?;", qSettEnum);
+ sqlite3_bind_int64(stmt, 1, hContact);
+ sqlite3_bind_text(stmt, 2, szModule, (int)mir_strlen(szModule), nullptr);
+ int rc = 0;
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
+ const char *value = (const char *)sqlite3_column_text(stmt, 0);
+ settings.insert(mir_strdup(value));
+ }
+ logError(rc, __FILE__, __LINE__);
+ sqlite3_reset(stmt);
+ }
+
+ int result = -1;
+ for (auto &setting : settings) {
+ result = pfnEnumProc(setting, param);
+ mir_free(setting);
+ }
+ return result;
+}