STDMETHODIMP_(BOOL) CDb3Mmap::MarkEventRead(MCONTACT contactID, HANDLE hDbEvent) { DBCachedContact *cc; if (contactID) { if ((cc = m_cache->GetCachedContact(contactID)) == NULL) return -1; if (cc->IsSub()) if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return -1; } else cc = NULL; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = (cc) ? cc->dwDriverData : m_dbHeader.ofsUser; DBContact dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); DBEvent *dbe = (DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE || dbc.signature != DBCONTACT_SIGNATURE) return -1; if (dbe->markedRead()) return dbe->flags; // log1("mark read @ %08x", hContact); dbe->flags |= DBEF_READ; DBWrite((DWORD)hDbEvent, dbe, sizeof(DBEvent)); BOOL ret = dbe->flags; if (dbc.ofsFirstUnread == (DWORD)hDbEvent) { for (;;) { if (dbe->ofsNext == 0) { dbc.ofsFirstUnread = 0; dbc.tsFirstUnread = 0; break; } DWORD ofsThis = dbe->ofsNext; dbe = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); if (!dbe->markedRead()) { dbc.ofsFirstUnread = ofsThis; dbc.tsFirstUnread = dbe->timestamp; break; } } } DBWrite(ofsContact, &dbc, sizeof(DBContact)); DBFlush(0); lck.unlock(); NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); return ret; }
STDMETHODIMP_(BOOL) CDbxKyoto::MarkEventRead(MCONTACT contactID, MEVENT hDbEvent) { if (hDbEvent == 0) return -1; DBCachedContact *cc = m_cache->GetCachedContact(contactID); if (cc == NULL) return -1; mir_cslock lck(m_csDbAccess); VisitorCopyRec visitor; if (!m_dbEvents.accept((LPCSTR)&hDbEvent, sizeof(MEVENT), &visitor, false)) return -1; DBEvent *dbe = (DBEvent*)visitor.vbuf_; if (dbe->dwSignature != DBEVENT_SIGNATURE) return -1; if (dbe->markedRead()) return dbe->flags; DBEventSortingKey key2 = { contactID, dbe->timestamp, hDbEvent }; dbe->flags |= DBEF_READ; m_dbEvents.set((LPCSTR)&hDbEvent, sizeof(MEVENT), visitor.vbuf_, visitor.vsiz_); FindNextUnread(cc, key2); m_dbContacts.set((LPCSTR)&contactID, sizeof(int), (LPCSTR)&cc->dbc, sizeof(cc->dbc)); NotifyEventHooks(hEventMarkedRead, contactID, (LPARAM)hDbEvent); return dbe->flags; }
STDMETHODIMP_(HANDLE) CDb3Mmap::FindFirstUnreadEvent(MCONTACT contactID) { DBCachedContact *cc; DWORD ofsContact = GetContactOffset(contactID, &cc); mir_cslock lck(m_csDbAccess); DBContact *dbc = (DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); if (dbc->signature != DBCONTACT_SIGNATURE) return NULL; if (!cc || !cc->IsSub()) return HANDLE(dbc->ofsFirstUnread); if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return NULL; dbc = (DBContact*)DBRead(cc->dwDriverData, sizeof(DBContact), NULL); if (dbc->signature != DBCONTACT_SIGNATURE) return NULL; for (DWORD dwOffset = dbc->ofsFirstUnread; dwOffset != 0;) { DBEvent *dbe = (DBEvent*)DBRead(dwOffset, sizeof(DBEvent), NULL); if (dbe->signature != DBEVENT_SIGNATURE) return NULL; if (dbe->contactID == contactID && !dbe->markedRead()) return HANDLE(dwOffset); dwOffset = dbe->ofsNext; } return NULL; }
STDMETHODIMP_(MEVENT) CDb3Mmap::FindFirstUnreadEvent(MCONTACT contactID) { DBCachedContact *cc; DWORD ofsContact = GetContactOffset(contactID, &cc); mir_cslock lck(m_csDbAccess); DBContact *dbc = (DBContact*)DBRead(ofsContact, nullptr); if (dbc->signature != DBCONTACT_SIGNATURE) return 0; if (!cc || !cc->IsSub()) return MEVENT(dbc->ofsFirstUnread); if ((cc = m_cache->GetCachedContact(cc->parentID)) == nullptr) return 0; dbc = (DBContact*)DBRead(cc->dwOfsContact, nullptr); if (dbc->signature != DBCONTACT_SIGNATURE) return 0; for (DWORD dwOffset = dbc->ofsFirstUnread; dwOffset != 0;) { DBEvent *dbe = AdaptEvent(dwOffset, contactID); if (dbe->signature != DBEVENT_SIGNATURE) return 0; if (dbe->contactID == contactID && !dbe->markedRead()) return MEVENT(dwOffset); dwOffset = dbe->ofsNext; } return 0; }
void CDbxKyoto::FindNextUnread(DBCachedContact *cc, DBEventSortingKey &key2) { key2.dwEventId++; { mir_cslock lck(m_csDbAccess); m_evCursor->jump((LPCSTR)&key2, sizeof(key2)); while (m_evCursor->step()) { size_t size; const char *pRec; delete[] m_evCursor->get(&size, &pRec, &size); DBEvent *dbe = (DBEvent*)pRec; if (!dbe->markedRead()) { cc->dbc.dwFirstUnread = key2.dwEventId; cc->dbc.tsFirstUnread = key2.ts; return; } } } cc->dbc.dwFirstUnread = cc->dbc.tsFirstUnread = 0; }
STDMETHODIMP_(BOOL) CDb3Mmap::DeleteEvent(MCONTACT contactID, HANDLE hDbEvent) { DBCachedContact *cc; if (contactID) { if ((cc = m_cache->GetCachedContact(contactID)) == NULL) return 2; if (cc->IsSub()) if ((cc = m_cache->GetCachedContact(cc->parentID)) == NULL) return 3; } else cc = NULL; mir_cslockfull lck(m_csDbAccess); DWORD ofsContact = (cc) ? cc->dwDriverData : m_dbHeader.ofsUser; DBContact dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); DBEvent dbe = *(DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); if (dbc.signature != DBCONTACT_SIGNATURE || dbe.signature != DBEVENT_SIGNATURE) return 1; lck.unlock(); log1("delete event @ %08x", hContact); // call notifier while outside mutex NotifyEventHooks(hEventDeletedEvent, contactID, (LPARAM)hDbEvent); // get back in lck.lock(); dbc = *(DBContact*)DBRead(ofsContact, sizeof(DBContact), NULL); dbe = *(DBEvent*)DBRead((DWORD)hDbEvent, sizeof(DBEvent), NULL); // check if this was the first unread, if so, recalc the first unread if (dbc.ofsFirstUnread == (DWORD)hDbEvent) { for (DBEvent *dbeNext = &dbe;;) { if (dbeNext->ofsNext == 0) { dbc.ofsFirstUnread = 0; dbc.tsFirstUnread = 0; break; } DWORD ofsThis = dbeNext->ofsNext; dbeNext = (DBEvent*)DBRead(ofsThis, sizeof(DBEvent), NULL); if (!dbeNext->markedRead()) { dbc.ofsFirstUnread = ofsThis; dbc.tsFirstUnread = dbeNext->timestamp; break; } } } // get previous and next events in chain and change offsets if (dbe.ofsPrev == 0) { if (dbe.ofsNext == 0) dbc.ofsFirstEvent = dbc.ofsLastEvent = 0; else { DBEvent *dbeNext = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeNext->ofsPrev = 0; DBWrite(dbe.ofsNext, dbeNext, sizeof(DBEvent)); dbc.ofsFirstEvent = dbe.ofsNext; } } else { if (dbe.ofsNext == 0) { DBEvent *dbePrev = (DBEvent*)DBRead(dbe.ofsPrev, sizeof(DBEvent), NULL); dbePrev->ofsNext = 0; DBWrite(dbe.ofsPrev, dbePrev, sizeof(DBEvent)); dbc.ofsLastEvent = dbe.ofsPrev; } else { DBEvent *dbePrev = (DBEvent*)DBRead(dbe.ofsPrev, sizeof(DBEvent), NULL); dbePrev->ofsNext = dbe.ofsNext; DBWrite(dbe.ofsPrev, dbePrev, sizeof(DBEvent)); DBEvent *dbeNext = (DBEvent*)DBRead(dbe.ofsNext, sizeof(DBEvent), NULL); dbeNext->ofsPrev = dbe.ofsPrev; DBWrite(dbe.ofsNext, dbeNext, sizeof(DBEvent)); } } // decrement event count dbc.eventCount--; DBWrite(ofsContact, &dbc, sizeof(DBContact)); // delete event DeleteSpace((DWORD)hDbEvent, offsetof(DBEvent, blob) + dbe.cbBlob); // also update a sub if (cc && dbe.contactID != cc->contactID) { DBContact *pSub = (DBContact*)DBRead(GetContactOffset(dbe.contactID), sizeof(DBContact), NULL); if (pSub->eventCount > 0) pSub->eventCount--; } DBFlush(0); return 0; }
BOOL CDb3Mmap::MetaSplitHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) { mir_cslock lck(m_csDbAccess); DBContact dbMeta = *(DBContact*)DBRead(ccMeta->dwDriverData, NULL); DBContact dbSub = *(DBContact*)DBRead(ccSub->dwDriverData, NULL); if (dbMeta.signature != DBCONTACT_SIGNATURE || dbSub.signature != DBCONTACT_SIGNATURE) return 1; if (dbMeta.ofsFirstEvent == 0) // nothing to do return 0; BOOL ret = 0; __try { if (ret = WipeContactHistory(&dbSub)) __leave; DWORD dwOffset = dbMeta.ofsFirstEvent; DBEvent *evMeta = NULL, *evSub = NULL; dbMeta.eventCount = 0; dbMeta.ofsFirstEvent = dbMeta.ofsLastEvent = dbMeta.ofsFirstUnread = dbMeta.tsFirstUnread = 0; while (dwOffset != 0) { DBEvent *evCurr = (DBEvent*)DBRead(dwOffset, NULL); if (evCurr->signature != DBEVENT_SIGNATURE) break; DWORD dwNext = evCurr->ofsNext; evCurr->ofsNext = 0; // extract it to sub's chain if (evCurr->contactID == ccSub->contactID) { dbSub.eventCount++; if (evSub != NULL) { evSub->ofsNext = dwOffset; evCurr->ofsPrev = DWORD(PBYTE(evSub) - m_pDbCache); } else { dbSub.ofsFirstEvent = dwOffset; evCurr->ofsPrev = 0; } if (dbSub.ofsFirstUnread == 0 && !evCurr->markedRead()) { dbSub.ofsFirstUnread = dwOffset; dbSub.tsFirstUnread = evCurr->timestamp; } dbSub.ofsLastEvent = dwOffset; evSub = evCurr; } else { dbMeta.eventCount++; if (evMeta != NULL) { evMeta->ofsNext = dwOffset; evCurr->ofsPrev = DWORD(PBYTE(evMeta) - m_pDbCache); } else { dbMeta.ofsFirstEvent = dwOffset; evCurr->ofsPrev = 0; } if (dbMeta.ofsFirstUnread == 0 && !evCurr->markedRead()) { dbMeta.ofsFirstUnread = dwOffset; dbMeta.tsFirstUnread = evCurr->timestamp; } dbMeta.ofsLastEvent = dwOffset; evMeta = evCurr; } dwOffset = dwNext; } DBWrite(ccSub->dwDriverData, &dbSub, sizeof(DBContact)); DBWrite(ccMeta->dwDriverData, &dbMeta, sizeof(DBContact)); } __except (EXCEPTION_EXECUTE_HANDLER) { ret = 3; } FlushViewOfFile(m_pDbCache, 0); return ret; }
BOOL CDb3Mmap::MetaMergeHistory(DBCachedContact *ccMeta, DBCachedContact *ccSub) { mir_cslock lck(m_csDbAccess); DBContact *dbMeta = (DBContact*)DBRead(ccMeta->dwDriverData, NULL); DBContact *dbSub = (DBContact*)DBRead(ccSub->dwDriverData, NULL); if (dbMeta->signature != DBCONTACT_SIGNATURE || dbSub->signature != DBCONTACT_SIGNATURE) return 1; // special cases if (dbSub->ofsFirstEvent == 0) // hurrah, nothing to do return 0; LIST<DBEvent> arEvents(20000, SortEvent); BOOL ret = 0; __try { if (dbMeta->ofsFirstEvent == 0) { // simply chain history to a meta dbMeta->eventCount = dbSub->eventCount; dbMeta->ofsFirstEvent = dbSub->ofsFirstEvent; dbMeta->ofsLastEvent = dbSub->ofsLastEvent; dbMeta->ofsFirstUnread = dbSub->ofsFirstUnread; dbMeta->tsFirstUnread = dbSub->tsFirstUnread; } else { // there're events in both meta's & sub's event chains // relink sub's event chain to meta without changing events themselves for (DWORD ofsMeta = dbMeta->ofsFirstEvent; ofsMeta != 0;) { DBEvent *pev = (DBEvent*)DBRead(ofsMeta, NULL); if (pev->signature != DBEVENT_SIGNATURE) { // broken chain, don't touch it ret = 2; __leave; } arEvents.insert(pev); ofsMeta = pev->ofsNext; } for (DWORD ofsSub = dbSub->ofsFirstEvent; ofsSub != 0;) { DBEvent *pev = (DBEvent*)DBRead(ofsSub, NULL); if (pev->signature != DBEVENT_SIGNATURE) { // broken chain, don't touch it ret = 2; __leave; } arEvents.insert(pev); ofsSub = pev->ofsNext; } // all events are in memory, valid & sorted in the right order. // ready? steady? go! dbMeta->eventCount = arEvents.getCount(); DBEvent *pFirst = arEvents[0]; dbMeta->ofsFirstEvent = DWORD(PBYTE(pFirst) - m_pDbCache); pFirst->ofsPrev = 0; dbMeta->ofsFirstUnread = pFirst->markedRead() ? 0 : dbMeta->ofsFirstEvent; DBEvent *pLast = arEvents[arEvents.getCount() - 1]; dbMeta->ofsLastEvent = DWORD(PBYTE(pLast) - m_pDbCache); pLast->ofsNext = 0; for (int i = 1; i < arEvents.getCount(); i++) { DBEvent *pPrev = arEvents[i - 1], *pNext = arEvents[i]; pPrev->ofsNext = DWORD(PBYTE(pNext) - m_pDbCache); pNext->ofsPrev = DWORD(PBYTE(pPrev) - m_pDbCache); if (dbMeta->ofsFirstUnread == 0 && !pNext->markedRead()) dbMeta->ofsFirstUnread = pPrev->ofsNext; } } // remove any traces of history from sub dbSub->ofsFirstEvent = dbSub->ofsLastEvent = dbSub->ofsFirstUnread = dbSub->tsFirstUnread = 0; } __except (EXCEPTION_EXECUTE_HANDLER) { ret = 3; } FlushViewOfFile(m_pDbCache, 0); return ret; }