Exemplo n.º 1
0
DWORD CDb3Mmap::PeekEvent(DWORD ofs, DWORD dwContactID, DBEvent &dbe)
{
	if (m_dbHeader.version >= DB_095_1_VERSION)
		return PeekSegment(ofs, &dbe, sizeof(DBEvent));

	DBEvent_094 oldEvent;
	DWORD ret = PeekSegment(ofs, &oldEvent, sizeof(oldEvent));
	if (ret != ERROR_SUCCESS)
		return ret;

	dbe.signature = oldEvent.signature;
	dbe.contactID = dwContactID;
	memcpy(&dbe.ofsPrev, &oldEvent.ofsPrev, sizeof(oldEvent) - sizeof(DWORD));
	return ERROR_SUCCESS;
}
Exemplo n.º 2
0
int WorkAggressive(int firstTime)
{
	PBYTE buf;
	int blockBytes,i;

	if(firstTime) {
		if(!opts.bAggressive) return ERROR_NO_MORE_ITEMS;
		AddToStatus(STATUS_MESSAGE,TranslateT("Performing aggressive pass"));
		ofsCurrent=0;
	}
	blockBytes=min(BLOCKSIZE+3,(int)(sourceFileSize-ofsCurrent));
	if(blockBytes<=0) return ERROR_NO_MORE_ITEMS;
	buf=new BYTE[blockBytes];
	if(PeekSegment(ofsCurrent,buf,blockBytes)!=ERROR_SUCCESS)
		return ERROR_READ_FAULT;
	blockBytes-=3;
	for(i=0;i<blockBytes;i++) {
		if(buf[i]) {
			if((*(PDWORD)&buf[i]&0x00FFFFFF)!=0xDECADE)
				AddToStatus(STATUS_WARNING,TranslateT("Aggressive: random junk at %08X: skipping"),ofsCurrent+i);
			else {
				//TODO: give user the option of placing manually
				AddToStatus(STATUS_ERROR,TranslateT("Aggressive: unlinked data at %08X: can't automatically place"),ofsCurrent+i);
			}
			for(;i<blockBytes;i++)
				if(buf[i]==0) {i--; break;}
		}
	}
	delete[] buf;
	ofsCurrent+=BLOCKSIZE;
	return ERROR_SUCCESS;
}
Exemplo n.º 3
0
int WorkSettingsChain(DWORD ofsContact,DBContact *dbc,int firstTime)
{
	DBContactSettings *dbcsNew,dbcsOld;
	DWORD ofsDestThis;
	int ret;

	if(firstTime) {
		ofsDestPrevSettings=0;
		ofsThisSettings=dbc->ofsFirstSettings;
		dbc->ofsFirstSettings=0;
	}
	if(ofsThisSettings==0)
		return ERROR_NO_MORE_ITEMS;
	if(!SignatureValid(ofsThisSettings,DBCONTACTSETTINGS_SIGNATURE)) {
		AddToStatus(STATUS_ERROR,TranslateT("Settings chain corrupted, further entries ignored"));
		return ERROR_NO_MORE_ITEMS;
	}
	if(PeekSegment(ofsThisSettings,&dbcsOld,sizeof(dbcsOld))!=ERROR_SUCCESS)
		return ERROR_NO_MORE_ITEMS;
	if(dbcsOld.cbBlob>256*1024 || dbcsOld.cbBlob==0) {
		AddToStatus(STATUS_ERROR,TranslateT("Infeasibly large settings blob: skipping"));
		ofsThisSettings=dbcsOld.ofsNext;
		return ERROR_SUCCESS;
	}
	dbcsNew=(DBContactSettings*)_malloca(offsetof(DBContactSettings,blob)+dbcsOld.cbBlob);
	if((ret=ReadSegment(ofsThisSettings,dbcsNew,offsetof(DBContactSettings,blob)+dbcsOld.cbBlob))!=ERROR_SUCCESS) {
		if(ret!=ERROR_HANDLE_EOF) {   //eof is OK because blank space at the end doesn't matter
			return ERROR_NO_MORE_ITEMS;
		}
	}
	if((dbcsNew->ofsModuleName=ConvertModuleNameOfs(dbcsOld.ofsModuleName))==0) {
		ofsThisSettings=dbcsOld.ofsNext;
		return ERROR_SUCCESS;
	}
	if(dbcsNew->blob[0]==0) {
		AddToStatus(STATUS_MESSAGE,TranslateT("Empty settings group at %08X: deleting"),ofsThisSettings);
		ofsThisSettings=dbcsOld.ofsNext;
		return ERROR_SUCCESS;
	}
	dbcsNew->ofsNext=0;
	//TODO? validate all settings in blob/compact if necessary
	if((ofsDestThis=WriteSegment(WSOFS_END,dbcsNew,offsetof(DBContactSettings,blob)+dbcsNew->cbBlob))==WS_ERROR) {
		return ERROR_HANDLE_DISK_FULL;
	}
	if(ofsDestPrevSettings) WriteSegment(ofsDestPrevSettings+offsetof(DBContactSettings,ofsNext),&ofsDestThis,sizeof(DWORD));
	else dbc->ofsFirstSettings=ofsDestThis;
	ofsDestPrevSettings=ofsDestThis;
	ofsThisSettings=dbcsOld.ofsNext;
	return ERROR_SUCCESS;
}
Exemplo n.º 4
0
int CDb3Mmap::ReadSegment(DWORD ofs, PVOID buf, int cbBytes)
{
	int ret = PeekSegment(ofs, buf, cbBytes);
	if (ret != ERROR_SUCCESS && ret != ERROR_HANDLE_EOF) return ret;

	if (cb->bAggressive) {
		if (ofs + cbBytes > sourceFileSize) {
			cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Can't write to working file, aggressive mode may be too aggressive now"));
			memset((m_pDbCache + ofs), 0, (sourceFileSize - ofs));
		}
		else memset((m_pDbCache + ofs), 0, cbBytes);
	}
	cb->spaceProcessed += cbBytes;
	return ERROR_SUCCESS;
}
Exemplo n.º 5
0
int ReadSegment(DWORD ofs,PVOID buf,int cbBytes)
{
	int ret;

	ret=PeekSegment(ofs,buf,cbBytes);
	if(ret!=ERROR_SUCCESS && ret!=ERROR_HANDLE_EOF) return ret;

	if(opts.bAggressive) {
		if (ofs+cbBytes>sourceFileSize) {
			AddToStatus(STATUS_WARNING,TranslateT("Can't write to working file, aggressive mode may be too aggressive now"));
			ZeroMemory(opts.pFile+ofs,sourceFileSize-ofs);
		}
		else
			ZeroMemory(opts.pFile+ofs,cbBytes);
	}
	spaceProcessed+=cbBytes;
	return ERROR_SUCCESS;
}
Exemplo n.º 6
0
int WorkModuleChain(int firstTime)
{
	DBModuleName moduleName,*newModName;

	if(firstTime) {
		AddToStatus(STATUS_MESSAGE,TranslateT("Processing module name chain"));
		modChainCount=0;
		last_mod = 0;
		if(modChain!=NULL) free(modChain);
		modChain = (ModChainEntry*)malloc(sizeof(ModChainEntry));
		phase=0;
		ofsCurrent=dbhdr.ofsFirstModuleName;
	}
	switch(phase) {
		case 0:
			if(ofsCurrent==0) {
				phase++;
				return ERROR_SUCCESS;
			}
			if(!SignatureValid(ofsCurrent,DBMODULENAME_SIGNATURE)) {
				AddToStatus(STATUS_ERROR,TranslateT("Module chain corrupted, further entries ignored"));
				phase++;
				return ERROR_SUCCESS;
			}
			if(PeekSegment(ofsCurrent,&moduleName,offsetof(DBModuleName,name))!=ERROR_SUCCESS) {
				phase++;
				return ERROR_SUCCESS;
			}
			if(moduleName.cbName>256)
				AddToStatus(STATUS_WARNING,TranslateT("Unreasonably long module name, skipping"));
			else {
				modChain=(ModChainEntry*)realloc(modChain,sizeof(ModChainEntry)*++modChainCount);

				modChain[modChainCount-1].ofsOld=ofsCurrent;
				modChain[modChainCount-1].size=offsetof(DBModuleName,name)+moduleName.cbName;
				modChain[modChainCount-1].ofsNew=0;

				if (moduleName.cbName)
					PeekSegment(ofsCurrent+offsetof(DBModuleName,name),&modChain[modChainCount-1].name,moduleName.cbName);
				modChain[modChainCount-1].name[moduleName.cbName]=0;
			}
			ofsCurrent=moduleName.ofsNext;
			break;
		case 1:
			ofsLast = 0;
			iCurrentModName=0;
			dbhdr.ofsFirstModuleName=0;
			phase++;
		case 2:
			if(iCurrentModName>=modChainCount) {
				DWORD dw = 0;
				if(ofsLast)	WriteSegment(ofsLast+offsetof(DBModuleName,ofsNext),&dw,sizeof(DWORD));
				return ERROR_NO_MORE_ITEMS;
			}
			if(modChain[iCurrentModName].ofsNew==0) {
				newModName=(DBModuleName*)_malloca(modChain[iCurrentModName].size);
				if(ReadSegment(modChain[iCurrentModName].ofsOld,newModName,modChain[iCurrentModName].size)!=ERROR_SUCCESS)
					return ERROR_NO_MORE_ITEMS;
				if((modChain[iCurrentModName].ofsNew=WriteSegment(WSOFS_END,newModName,modChain[iCurrentModName].size))==WS_ERROR)
					return ERROR_HANDLE_DISK_FULL;
				{ // check duplicated modulenames
					int i, n=0;
					for(i=iCurrentModName+1;i<modChainCount;i++)
						if(!strcmp(modChain[i].name, modChain[iCurrentModName].name)) {
							modChain[i].ofsNew = modChain[iCurrentModName].ofsNew;
							n++;
						}
						if (n) AddToStatus(STATUS_WARNING,TranslateT("Module name '%s' is not unique: %d duplicates found)"), modChain[iCurrentModName].name,n);
				}
				if(iCurrentModName==0)
					dbhdr.ofsFirstModuleName=modChain[iCurrentModName].ofsNew;
				else
					if(WriteSegment(ofsLast+offsetof(DBModuleName,ofsNext),&modChain[iCurrentModName].ofsNew,sizeof(DWORD))==WS_ERROR)
						return ERROR_HANDLE_DISK_FULL;
				ofsLast = modChain[iCurrentModName].ofsNew;
			}
			iCurrentModName++;
			break;
	}
	return ERROR_SUCCESS;
}
Exemplo n.º 7
0
int CDb3Mmap::WorkModuleChain(int firstTime)
{
	DBModuleName moduleName, *newModName;

	if (firstTime) {
		cb->pfnAddLogMessage(STATUS_MESSAGE, TranslateT("Processing module name chain"));
		modChainCount = 0;
		last_mod = 0;
		free(modChain);
		modChain = (ModChainEntry*)malloc(sizeof(ModChainEntry));
		phase = 0;
		ofsCurrent = m_dbHeader.ofsModuleNames;
	}

	switch (phase) {
	case 0:
		if (ofsCurrent == 0) {
			phase++;
			return ERROR_SUCCESS;
		}
		if (!SignatureValid(ofsCurrent, DBMODULENAME_SIGNATURE)) {
			cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Module chain corrupted, further entries ignored"));
			phase++;
			return ERROR_SUCCESS;
		}
		if (PeekSegment(ofsCurrent, &moduleName, offsetof(DBModuleName, name)) != ERROR_SUCCESS) {
			phase++;
			return ERROR_SUCCESS;
		}
		modChain = (ModChainEntry*)realloc(modChain, sizeof(ModChainEntry)*++modChainCount);

		modChain[modChainCount - 1].ofsOld = ofsCurrent;
		modChain[modChainCount - 1].size = offsetof(DBModuleName, name) + moduleName.cbName;
		modChain[modChainCount - 1].ofsNew = 0;

		if (moduleName.cbName)
			PeekSegment(ofsCurrent + offsetof(DBModuleName, name), &modChain[modChainCount - 1].name, moduleName.cbName);
		modChain[modChainCount - 1].name[moduleName.cbName] = 0;
		ofsCurrent = moduleName.ofsNext;
		break;
	case 1:
		ofsLast = 0;
		iCurrentModName = 0;
		m_dbHeader.ofsModuleNames = 0;
		phase++;
	case 2:
		if (iCurrentModName >= modChainCount) {
			DWORD dw = 0;
			if (ofsLast)	WriteSegment(ofsLast + offsetof(DBModuleName, ofsNext), &dw, sizeof(DWORD));
			return ERROR_NO_MORE_ITEMS;
		}
		if (modChain[iCurrentModName].ofsNew == 0) {
			newModName = (DBModuleName*)_alloca(modChain[iCurrentModName].size);
			if (ReadSegment(modChain[iCurrentModName].ofsOld, newModName, modChain[iCurrentModName].size) != ERROR_SUCCESS)
				return ERROR_NO_MORE_ITEMS;
			if ((modChain[iCurrentModName].ofsNew = WriteSegment(WSOFS_END, newModName, modChain[iCurrentModName].size)) == WS_ERROR)
				return ERROR_HANDLE_DISK_FULL;

			// check duplicated modulenames
			int i, n = 0;
			for (i = iCurrentModName + 1; i < modChainCount; i++)
				if (!mir_strcmp(modChain[i].name, modChain[iCurrentModName].name)) {
					modChain[i].ofsNew = modChain[iCurrentModName].ofsNew;
					n++;
				}
			if (n) {
				TCHAR szModuleName[257];
				MultiByteToWideChar(CP_ACP, 0, modChain[iCurrentModName].name, -1, szModuleName, _countof(szModuleName));
				TCHAR *pszModuleName = szModuleName;

				cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Module name '%s' is not unique: %d duplicates found"), pszModuleName, n);
			}

			if (iCurrentModName == 0)
				m_dbHeader.ofsModuleNames = modChain[iCurrentModName].ofsNew;
			else if (WriteSegment(ofsLast + offsetof(DBModuleName, ofsNext), &modChain[iCurrentModName].ofsNew, sizeof(DWORD)) == WS_ERROR)
				return ERROR_HANDLE_DISK_FULL;
			ofsLast = modChain[iCurrentModName].ofsNew;
		}
		iCurrentModName++;
		break;
	}
	return ERROR_SUCCESS;
}
Exemplo n.º 8
0
int CDb3Mmap::WorkEventChain(DWORD ofsContact, DBContact *dbc, int firstTime)
{
	DBEvent *dbeNew, dbeOld;
	DBEvent *dbePrev = NULL;
	DWORD ofsDestThis;
	int isUnread = 0;

	if (firstTime) {
		dbePrevEvent = NULL;
		ofsPrevEvent = 0;
		ofsDestPrevEvent = 0;
		ofsThisEvent = dbc->ofsFirstEvent;
		eventCount = 0;
		backLookup = 0;
		lastTimestamp = 0;
		ofsFirstUnread = tsFirstUnread = 0;
		if (cb->bEraseHistory) {
			dbc->eventCount = 0;
			dbc->ofsFirstEvent = 0;
			dbc->ofsLastEvent = 0;
			dbc->ofsFirstUnread = 0;
			dbc->tsFirstUnread = 0;
			return ERROR_NO_MORE_ITEMS;
		}
	}

	if (ofsThisEvent == 0) {
		FinishUp(ofsDestPrevEvent, dbc);
		return ERROR_NO_MORE_ITEMS;
	}

	if (!SignatureValid(ofsThisEvent, DBEVENT_SIGNATURE)) {
		DWORD ofsNew = 0;
		DWORD ofsTmp = dbc->ofsLastEvent;

		if (!backLookup && ofsTmp) {
			backLookup = 1;
			while (SignatureValid(ofsTmp, DBEVENT_SIGNATURE)) {
				if (PeekSegment(ofsTmp, &dbeOld, sizeof(dbeOld)) != ERROR_SUCCESS)
					break;
				ofsNew = ofsTmp;
				ofsTmp = dbeOld.ofsPrev;
			}
		}
		if (ofsNew) {
			cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event chain corrupted, trying to recover..."));
			ofsThisEvent = ofsNew;
		}
		else {
			cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Event chain corrupted, further entries ignored"));
			FinishUp(ofsDestPrevEvent, dbc);
			return ERROR_NO_MORE_ITEMS;
		}
	}

	if (PeekSegment(ofsThisEvent, &dbeOld, sizeof(dbeOld)) != ERROR_SUCCESS) {
		FinishUp(ofsDestPrevEvent, dbc);
		return ERROR_NO_MORE_ITEMS;
	}

	if (firstTime) {
		if (dbeOld.ofsPrev != 0)
			cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("First event not marked as such: correcting"));

		dbeOld.ofsPrev = 0;
		lastTimestamp = dbeOld.timestamp;
	}
	
	if (dbeOld.flags & 1)
		dbeOld.flags &= ~1;

	if (dbeOld.flags & ~DBEF_ALL) {
		cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Extra flags found in event: removing"));
		dbeOld.flags &= DBEF_ALL;
	}

	if (!(dbeOld.flags & (DBEF_READ | DBEF_SENT))) {
		if (cb->bMarkRead) dbeOld.flags |= DBEF_READ;
		else if (ofsFirstUnread == 0) {
			if (dbc->ofsFirstUnread != ofsThisEvent || dbc->tsFirstUnread != dbeOld.timestamp)
				cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("First unread event marked wrong: fixing"));
			isUnread = 1;
		}
	}

	if (dbeOld.cbBlob > 1024 * 1024 || dbeOld.cbBlob == 0) {
		cb->pfnAddLogMessage(STATUS_ERROR, TranslateT("Infeasibly large event blob: skipping"));
		ofsThisEvent = dbeOld.ofsNext;
		return ERROR_SUCCESS;
	}

	if (dbePrevEvent && dbeOld.timestamp == lastTimestamp) {
		int len = offsetof(DBEvent, blob) + dbePrevEvent->cbBlob;
		dbePrev = (DBEvent*)malloc(len);
		memcpy(dbePrev, dbePrevEvent, len);
	}

	if (offsetof(DBEvent, blob) + dbeOld.cbBlob > memsize) {
		memsize = offsetof(DBEvent, blob) + dbeOld.cbBlob;
		memblock = (DBEvent*)realloc(memblock, memsize);
	}
	dbeNew = memblock;

	if (ReadSegment(ofsThisEvent, dbeNew, offsetof(DBEvent, blob) + dbeOld.cbBlob) != ERROR_SUCCESS) {
		FinishUp(ofsDestPrevEvent, dbc);
		return ERROR_NO_MORE_ITEMS;
	}

	if ((dbeNew->ofsModuleName = ConvertModuleNameOfs(dbeOld.ofsModuleName)) == 0) {
		ofsThisEvent = dbeOld.ofsNext;
		return ERROR_SUCCESS;
	}

	if (!firstTime && dbeOld.ofsPrev != ofsPrevEvent)
		cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event not backlinked correctly: fixing"));

	dbeNew->flags = dbeOld.flags;
	dbeNew->ofsPrev = ofsDestPrevEvent;
	dbeNew->ofsNext = 0;
	if (dbeNew->contactID == 0)
		dbeNew->contactID = dbc->dwContactID;

	if (dbeOld.wEventType == EVENTTYPE_MESSAGE && cb->bConvertUtf && !(dbeOld.flags & DBEF_ENCRYPTED)) {
		DWORD oldSize = dbeNew->cbBlob;
		BYTE* pOldMemo = (BYTE*)_alloca(dbeNew->cbBlob);
		memcpy(pOldMemo, dbeNew->blob, dbeNew->cbBlob);
		MoveMemory(dbeNew->blob, pOldMemo, dbeNew->cbBlob); // decode
		ConvertOldEvent(dbeNew);
		if (dbeNew->cbBlob > oldSize)
			pOldMemo = (BYTE*)_alloca(dbeNew->cbBlob);
		memcpy(pOldMemo, dbeNew->blob, dbeNew->cbBlob);
		MoveMemory(dbeNew->blob, pOldMemo, dbeNew->cbBlob);   // encode
	}

	if (dbePrev) {
		if (dbePrev->cbBlob == dbeNew->cbBlob &&
			 dbePrev->ofsModuleName == dbeNew->ofsModuleName &&
			 dbePrev->wEventType == dbeNew->wEventType &&
			(dbePrev->flags & DBEF_SENT) == (dbeNew->flags & DBEF_SENT) && !memcmp(dbePrev->blob, dbeNew->blob, dbeNew->cbBlob))
		{
			cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Duplicate event was found: skipping"));
			if (dbc->eventCount)
				dbc->eventCount--;
			free(dbePrev);
			// ofsDestPrevEvent is still the same!
			ofsPrevEvent = ofsThisEvent;
			ofsThisEvent = dbeOld.ofsNext;
			return ERROR_SUCCESS;
		}
		free(dbePrev);
	}
	else if (!firstTime && dbeNew->timestamp < lastTimestamp) {
		DWORD found = 0;
		DBEvent dbeTmp;
		DWORD ofsTmp;

		if (cb->bCheckOnly) {
			if (!cb->bAggressive) {
				ofsTmp = dbeOld.ofsPrev;
				while (PeekSegment(ofsTmp, &dbeTmp, sizeof(dbeTmp)) == ERROR_SUCCESS) {
					if (dbeTmp.ofsPrev == ofsContact) {
						found = 1;
						break;
					}
					if (dbeTmp.timestamp < dbeNew->timestamp) {
						found = 2;
						break;
					}
					ofsTmp = dbeTmp.ofsPrev;
				}
			}
			cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct"));
		}
		else {
			ofsTmp = ofsDestPrevEvent;
			while (ReadWrittenSegment(ofsTmp, &dbeTmp, sizeof(dbeTmp)) == ERROR_SUCCESS) {
				if (dbeTmp.ofsPrev == ofsContact) {
					found = 1;
					break;
				}
				if (dbeTmp.timestamp < dbeNew->timestamp) {
					found = 2;
					break;
				}
				ofsTmp = dbeTmp.ofsPrev;
			}
			if (found)
				cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct: fixing"));
			else
				cb->pfnAddLogMessage(STATUS_WARNING, TranslateT("Event position in chain is not correct: unable to fix"));
		}

		// insert before FIRST
		if (found == 1 && !cb->bCheckOnly) {
			dbeNew->ofsPrev = 0;
			dbeNew->ofsNext = dbc->ofsFirstEvent;

			ofsDestThis = WriteEvent(dbeNew);
			if (!ofsDestThis)
				return ERROR_HANDLE_DISK_FULL;

			if (isUnread && tsFirstUnread >= dbeNew->timestamp) {
				ofsFirstUnread = ofsDestThis;
				tsFirstUnread = dbeNew->timestamp;
			}
			// fix first event
			WriteOfsNextToPrevious(0, dbc, ofsDestThis);
			// fix next event
			WriteSegment(dbeNew->ofsNext + offsetof(DBEvent, ofsPrev), &ofsDestThis, sizeof(DWORD));
		}
		else if (found == 2 && !cb->bCheckOnly) {
			dbeNew->ofsPrev = ofsTmp;
			dbeNew->ofsNext = dbeTmp.ofsNext;

			ofsDestThis = WriteEvent(dbeNew);
			if (!ofsDestThis)
				return ERROR_HANDLE_DISK_FULL;

			if (isUnread && tsFirstUnread >= dbeNew->timestamp) {
				ofsFirstUnread = ofsDestThis;
				tsFirstUnread = dbeNew->timestamp;
			}
			// fix previous event
			WriteOfsNextToPrevious(dbeNew->ofsPrev, dbc, ofsDestThis);
			// fix next event
			WriteSegment(dbeNew->ofsNext + offsetof(DBEvent, ofsPrev), &ofsDestThis, sizeof(DWORD));
		}

		if (found) {
			eventCount++;
			// ofsDestPrevEvent is still the same!
			ofsPrevEvent = ofsThisEvent;
			ofsThisEvent = dbeOld.ofsNext;
			return ERROR_SUCCESS;
		}
	}

	lastTimestamp = dbeNew->timestamp;
	dbePrevEvent = dbeNew;

	ofsDestThis = WriteEvent(dbeNew);
	if (!ofsDestThis)
		return ERROR_HANDLE_DISK_FULL;

	if (isUnread) {
		ofsFirstUnread = ofsDestThis;
		tsFirstUnread = dbeOld.timestamp;
	}

	eventCount++;
	WriteOfsNextToPrevious(ofsDestPrevEvent, dbc, ofsDestThis);

	ofsDestPrevEvent = ofsDestThis;
	ofsPrevEvent = ofsThisEvent;
	ofsThisEvent = dbeOld.ofsNext;
	return ERROR_SUCCESS;
}