summaryrefslogtreecommitdiff
path: root/plugins/Db3x_mmap/src/dbtool
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Db3x_mmap/src/dbtool')
-rw-r--r--plugins/Db3x_mmap/src/dbtool/aggressive.cpp63
-rw-r--r--plugins/Db3x_mmap/src/dbtool/contactchain.cpp99
-rw-r--r--plugins/Db3x_mmap/src/dbtool/disk.cpp112
-rw-r--r--plugins/Db3x_mmap/src/dbtool/eventchain.cpp363
-rw-r--r--plugins/Db3x_mmap/src/dbtool/finaltasks.cpp78
-rw-r--r--plugins/Db3x_mmap/src/dbtool/initialchecks.cpp81
-rw-r--r--plugins/Db3x_mmap/src/dbtool/modulechain.cpp146
-rw-r--r--plugins/Db3x_mmap/src/dbtool/settingschain.cpp72
-rw-r--r--plugins/Db3x_mmap/src/dbtool/user.cpp71
9 files changed, 1085 insertions, 0 deletions
diff --git a/plugins/Db3x_mmap/src/dbtool/aggressive.cpp b/plugins/Db3x_mmap/src/dbtool/aggressive.cpp
new file mode 100644
index 0000000000..7cafb63043
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/aggressive.cpp
@@ -0,0 +1,63 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+#define BLOCKSIZE 65536
+
+extern DWORD sourceFileSize;
+extern DWORD spaceProcessed;
+extern DWORD sp;
+static DWORD ofsCurrent;
+
+int WorkAggressive(int firstTime)
+{
+ int blockBytes,i;
+ BYTE *buf;
+
+ if (firstTime) {
+ if (!opts.bAggressive)
+ return ERROR_NO_MORE_ITEMS;
+
+ AddToStatus(STATUS_MESSAGE,TranslateT("Performing aggressive pass"));
+ ofsCurrent = 0;
+ spaceProcessed = 0;
+ sp = 0;
+ }
+ blockBytes = min(BLOCKSIZE+3,(int)(sourceFileSize-ofsCurrent));
+ if (blockBytes <= 0)
+ return ERROR_NO_MORE_ITEMS;
+
+ buf = opts.pFile+ofsCurrent;
+ 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;}
+ }
+ }
+ ofsCurrent += BLOCKSIZE;
+ spaceProcessed = ofsCurrent;
+ return ERROR_SUCCESS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/contactchain.cpp b/plugins/Db3x_mmap/src/dbtool/contactchain.cpp
new file mode 100644
index 0000000000..0993371848
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/contactchain.cpp
@@ -0,0 +1,99 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+int WorkSettingsChain(DWORD ofsContact,DBContact *dbc,int firstTime);
+int WorkEventChain(DWORD ofsContact,DBContact *dbc,int firstTime);
+
+static DWORD ofsThisContact,ofsDestPrevContact;
+static DWORD contactCount;
+static DWORD ofsDestThis,ofsNextContact;
+static int phase;
+static DBContact dbc;
+
+int WorkContactChain(int firstTime)
+{
+ int first = 0;
+ int ret;
+
+ if (firstTime) {
+ AddToStatus(STATUS_MESSAGE,TranslateT("Processing contact chain"));
+ ofsDestPrevContact = 0;
+ ofsThisContact = dbhdr.ofsFirstContact;
+ contactCount = 0;
+ dbhdr.ofsFirstContact = 0;
+ phase = 0;
+ }
+
+ switch(phase) {
+ case 0:
+ if (ofsThisContact == 0) {
+LBL_FinishUp:
+ if (contactCount != dbhdr.contactCount)
+ AddToStatus(STATUS_WARNING,TranslateT("Contact count marked wrongly: correcting"));
+ dbhdr.contactCount = contactCount;
+ return ERROR_NO_MORE_ITEMS;
+ }
+ if (!SignatureValid(ofsThisContact,DBCONTACT_SIGNATURE)) {
+ AddToStatus(STATUS_ERROR,TranslateT("Contact chain corrupted, further entries ignored"));
+ goto LBL_FinishUp;
+ }
+ if (ReadSegment(ofsThisContact,&dbc,sizeof(dbc)) != ERROR_SUCCESS)
+ goto LBL_FinishUp;
+
+ ofsNextContact = dbc.ofsNext;
+ dbc.ofsNext = 0;
+ if (!opts.bCheckOnly) {
+ if ((ofsDestThis = WriteSegment(WSOFS_END,&dbc,sizeof(dbc))) == WS_ERROR)
+ return ERROR_HANDLE_DISK_FULL;
+ if (ofsDestPrevContact)
+ WriteSegment(ofsDestPrevContact+offsetof(DBContact,ofsNext),&ofsDestThis,sizeof(DWORD));
+ else
+ dbhdr.ofsFirstContact = ofsDestThis;
+ } else
+ ofsDestThis = ofsThisContact; // needed in event chain worker
+ contactCount++;
+ phase++; first = 1;
+ //fall thru
+ case 1:
+ ret = WorkSettingsChain(ofsDestThis,&dbc,first);
+ if (ret == ERROR_NO_MORE_ITEMS) {
+ phase++; first = 1;
+ }
+ else if (ret) return ret;
+ else break;
+ //fall thru
+ case 2:
+ ret = WorkEventChain(ofsDestThis,&dbc,first);
+ if (ret == ERROR_NO_MORE_ITEMS) {
+ phase++; first = 1;
+ }
+ else if (ret) return ret;
+ else break;
+ //fall thru
+ case 3:
+ if (WriteSegment(ofsDestThis,&dbc,sizeof(DBContact)) == WS_ERROR)
+ return ERROR_HANDLE_DISK_FULL;
+ ofsDestPrevContact = ofsDestThis;
+ ofsThisContact = ofsNextContact;
+ phase = 0;
+ break;
+ }
+ return ERROR_SUCCESS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/disk.cpp b/plugins/Db3x_mmap/src/dbtool/disk.cpp
new file mode 100644
index 0000000000..2cf9136a71
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/disk.cpp
@@ -0,0 +1,112 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "dbtool.h"
+
+extern DWORD spaceProcessed, sourceFileSize;
+
+int SignatureValid(DWORD ofs, DWORD signature)
+{
+ DWORD sig;
+
+ if (ofs+sizeof(sig) >= sourceFileSize) {
+ AddToStatus(STATUS_ERROR, TranslateT("Invalid offset found (database truncated?)"));
+ return 0;
+ }
+
+ sig = *(DWORD*)(opts.pFile+ofs);
+
+ return sig == signature;
+}
+
+int PeekSegment(DWORD ofs, PVOID buf, int cbBytes)
+{
+ DWORD bytesRead;
+
+ if (ofs >= sourceFileSize) {
+ AddToStatus(STATUS_ERROR, TranslateT("Invalid offset found"));
+ return ERROR_SEEK;
+ }
+
+ if (ofs+cbBytes>sourceFileSize)
+ bytesRead = sourceFileSize - ofs;
+ else
+ bytesRead = cbBytes;
+
+ if (bytesRead == 0) {
+ AddToStatus(STATUS_ERROR, TranslateT("Error reading, database truncated? (%u)"), GetLastError());
+ return ERROR_READ_FAULT;
+ }
+
+ CopyMemory(buf, opts.pFile+ofs, bytesRead);
+
+ if ((int)bytesRead<cbBytes) return ERROR_HANDLE_EOF;
+ return ERROR_SUCCESS;
+}
+
+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;
+}
+
+DWORD WriteSegment(DWORD ofs, PVOID buf, int cbBytes)
+{
+ DWORD bytesWritten;
+ if (opts.bCheckOnly) return 0xbfbfbfbf;
+ if (ofs == WSOFS_END) {
+ ofs = dbhdr.ofsFileEnd;
+ dbhdr.ofsFileEnd += cbBytes;
+ }
+ SetFilePointer(opts.hOutFile, ofs, NULL, FILE_BEGIN);
+ WriteFile(opts.hOutFile, buf, cbBytes, &bytesWritten, NULL);
+ if ((int)bytesWritten<cbBytes) {
+ AddToStatus(STATUS_FATAL, TranslateT("Can't write to output file - disk full? (%u)"), GetLastError());
+ return WS_ERROR;
+ }
+ return ofs;
+}
+
+
+int ReadWrittenSegment(DWORD ofs, PVOID buf, int cbBytes)
+{
+ DWORD bytesRead;
+ if (opts.bCheckOnly) return 0xbfbfbfbf;
+ if (ofs + cbBytes > dbhdr.ofsFileEnd)
+ return ERROR_SEEK;
+
+ SetFilePointer(opts.hOutFile, ofs, NULL, FILE_BEGIN);
+ ReadFile(opts.hOutFile, buf, cbBytes, &bytesRead, NULL);
+ if ((int)bytesRead<cbBytes)
+ return ERROR_READ_FAULT;
+
+ return ERROR_SUCCESS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/eventchain.cpp b/plugins/Db3x_mmap/src/dbtool/eventchain.cpp
new file mode 100644
index 0000000000..1e0076371d
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/eventchain.cpp
@@ -0,0 +1,363 @@
+/*
+Miranda Database Tool
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2011 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+static BOOL backLookup;
+static DWORD ofsThisEvent,ofsPrevEvent;
+static DWORD ofsDestPrevEvent;
+static DWORD eventCount;
+static DWORD lastTimestamp;
+static DWORD ofsFirstUnread,timestampFirstUnread;
+static DWORD memsize = 0;
+static DBEvent* memblock = NULL;
+static DBEvent* dbePrevEvent = NULL;
+
+static void ConvertOldEvent(DBEvent*& dbei)
+{
+ int msglen = (int)strlen((char*)dbei->blob) + 1, msglenW = 0;
+ if (msglen != (int) dbei->cbBlob) {
+ int i, count = ((dbei->cbBlob - msglen) / sizeof(WCHAR));
+ WCHAR* p = (WCHAR*)&dbei->blob[ msglen ];
+ for ( i = 0; i < count; i++) {
+ if (p[i] == 0) {
+ msglenW = i;
+ break;
+ } } }
+ else {
+ if (!is_utf8_string((char*)dbei->blob))
+ dbei->flags &= ~DBEF_UTF;
+ }
+
+ if (msglenW > 0 && msglenW <= msglen) {
+ char* utf8str = Utf8EncodeW((WCHAR*)&dbei->blob[ msglen ]);
+ dbei->cbBlob = (DWORD)strlen(utf8str)+1;
+ dbei->flags |= DBEF_UTF;
+ if (offsetof(DBEvent,blob)+dbei->cbBlob > memsize) {
+ memsize = offsetof(DBEvent,blob)+dbei->cbBlob;
+ memblock = (DBEvent*)realloc(memblock, memsize);
+ dbei = memblock;
+ }
+ memcpy(&dbei->blob, utf8str, dbei->cbBlob);
+ free(utf8str);
+} }
+
+static void WriteOfsNextToPrevious(DWORD ofsPrev,DBContact *dbc,DWORD ofsNext)
+{
+ if (ofsPrev)
+ WriteSegment(ofsPrev+offsetof(DBEvent,ofsNext),&ofsNext,sizeof(DWORD));
+ else
+ dbc->ofsFirstEvent = ofsNext;
+}
+
+static void FinishUp(DWORD ofsLast,DBContact *dbc)
+{
+ WriteOfsNextToPrevious(ofsLast,dbc,0);
+ if (eventCount != dbc->eventCount)
+ AddToStatus(STATUS_WARNING,TranslateT("Event count marked wrongly: correcting"));
+ dbc->eventCount = eventCount;
+ dbc->ofsLastEvent = ofsLast;
+ if (opts.bMarkRead) {
+ dbc->ofsFirstUnreadEvent = 0;
+ dbc->timestampFirstUnread = 0;
+ }
+ else {
+ dbc->ofsFirstUnreadEvent = ofsFirstUnread;
+ dbc->timestampFirstUnread = timestampFirstUnread;
+ }
+ if (memsize && memblock) {
+ free(memblock);
+ memsize = 0;
+ memblock = NULL;
+ }
+}
+
+static DWORD WriteEvent(DBEvent *dbe)
+{
+ DWORD ofs = WriteSegment(WSOFS_END, dbe, offsetof(DBEvent,blob)+dbe->cbBlob);
+ if (ofs == WS_ERROR) {
+ free(memblock);
+ memblock = NULL;
+ memsize = 0;
+ return 0;
+ }
+ return ofs;
+}
+
+int 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 = timestampFirstUnread = 0;
+ if (opts.bEraseHistory) {
+ dbc->eventCount = 0;
+ dbc->ofsFirstEvent = 0;
+ dbc->ofsLastEvent = 0;
+ dbc->ofsFirstUnreadEvent = 0;
+ dbc->timestampFirstUnread = 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) {
+ AddToStatus(STATUS_WARNING,TranslateT("Event chain corrupted, trying to recover..."));
+ ofsThisEvent = ofsNew;
+ } else {
+ AddToStatus(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.flags&DBEF_FIRST)) {
+ AddToStatus(STATUS_WARNING,TranslateT("First event not marked as such: correcting"));
+ dbeOld.flags|=DBEF_FIRST;
+ }
+ dbeOld.ofsPrev = ofsContact;
+ lastTimestamp = dbeOld.timestamp;
+ }
+ else if (dbeOld.flags&DBEF_FIRST) {
+ AddToStatus(STATUS_WARNING,TranslateT("Event marked as first which is not: correcting"));
+ dbeOld.flags&=~DBEF_FIRST;
+ }
+
+ if (dbeOld.flags&~(DBEF_FIRST|DBEF_READ|DBEF_SENT|DBEF_RTL|DBEF_UTF)) {
+ AddToStatus(STATUS_WARNING,TranslateT("Extra flags found in event: removing"));
+ dbeOld.flags&=(DBEF_FIRST|DBEF_READ|DBEF_SENT|DBEF_RTL|DBEF_UTF);
+ }
+
+ if (!(dbeOld.flags&(DBEF_READ|DBEF_SENT))) {
+ if (opts.bMarkRead) dbeOld.flags|=DBEF_READ;
+ else if (ofsFirstUnread == 0) {
+ if (dbc->ofsFirstUnreadEvent != ofsThisEvent || dbc->timestampFirstUnread != dbeOld.timestamp)
+ AddToStatus(STATUS_WARNING,TranslateT("First unread event marked wrong: fixing"));
+ isUnread = 1;
+ } }
+
+ if (dbeOld.cbBlob>1024*1024 || dbeOld.cbBlob == 0) {
+ AddToStatus(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)
+ AddToStatus(STATUS_WARNING,TranslateT("Event not backlinked correctly: fixing"));
+
+ dbeNew->flags = dbeOld.flags;
+ dbeNew->ofsPrev = ofsDestPrevEvent;
+ dbeNew->ofsNext = 0;
+
+ if (dbeOld.eventType == EVENTTYPE_MESSAGE && opts.bConvertUtf)
+ ConvertOldEvent(dbeNew);
+
+ if (dbePrev)
+ {
+ if (dbePrev->cbBlob == dbeNew->cbBlob &&
+ dbePrev->ofsModuleName == dbeNew->ofsModuleName &&
+ dbePrev->eventType == dbeNew->eventType &&
+ (dbePrev->flags & DBEF_SENT) == (dbeNew->flags & DBEF_SENT) &&
+ !memcmp(dbePrev->blob, dbeNew->blob, dbeNew->cbBlob)
+ ) {
+ AddToStatus(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 (opts.bCheckOnly)
+ {
+ if (!opts.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;
+ }
+ }
+ AddToStatus(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)
+ AddToStatus(STATUS_WARNING,TranslateT("Event position in chain is not correct: fixing"));
+ else
+ AddToStatus(STATUS_WARNING,TranslateT("Event position in chain is not correct: unable to fix"));
+ }
+
+ // insert before FIRST
+ if (found == 1 && !opts.bCheckOnly) {
+ dbeNew->flags|=DBEF_FIRST;
+ dbeNew->ofsPrev = ofsContact;
+ dbeNew->ofsNext = dbc->ofsFirstEvent;
+
+ ofsDestThis = WriteEvent(dbeNew);
+ if (!ofsDestThis)
+ return ERROR_HANDLE_DISK_FULL;
+
+ if (isUnread && timestampFirstUnread >= dbeNew->timestamp) {
+ ofsFirstUnread = ofsDestThis;
+ timestampFirstUnread = dbeNew->timestamp;
+ }
+ // fix first event
+ WriteOfsNextToPrevious(0,dbc,ofsDestThis);
+ // fix next event
+ WriteSegment(dbeNew->ofsNext+offsetof(DBEvent,ofsPrev),&ofsDestThis,sizeof(DWORD));
+ dbeTmp.flags &=~DBEF_FIRST;
+ WriteSegment(dbeNew->ofsNext+offsetof(DBEvent,flags),&dbeTmp.flags,sizeof(DWORD));
+ }
+ else if (found == 2 && !opts.bCheckOnly) {
+
+ dbeNew->ofsPrev = ofsTmp;
+ dbeNew->ofsNext = dbeTmp.ofsNext;
+
+ ofsDestThis = WriteEvent(dbeNew);
+ if (!ofsDestThis)
+ return ERROR_HANDLE_DISK_FULL;
+
+ if (isUnread && timestampFirstUnread >= dbeNew->timestamp) {
+ ofsFirstUnread = ofsDestThis;
+ timestampFirstUnread = 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;
+ timestampFirstUnread = dbeOld.timestamp;
+ }
+
+ eventCount++;
+ WriteOfsNextToPrevious(ofsDestPrevEvent,dbc,ofsDestThis);
+
+ ofsDestPrevEvent = ofsDestThis;
+ ofsPrevEvent = ofsThisEvent;
+ ofsThisEvent = dbeOld.ofsNext;
+ return ERROR_SUCCESS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp b/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp
new file mode 100644
index 0000000000..939fd680d1
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/finaltasks.cpp
@@ -0,0 +1,78 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+extern int errorCount;
+
+int WorkFinalTasks(int firstTime)
+{
+ FreeModuleChain();
+ AddToStatus(STATUS_MESSAGE,TranslateT("Processing final tasks"));
+ dbhdr.slackSpace = 0;
+ if (WriteSegment(0,&dbhdr,sizeof(dbhdr)) == WS_ERROR)
+ return ERROR_WRITE_FAULT;
+ if (opts.hFile) {
+ CloseHandle(opts.hFile);
+ opts.hFile = NULL;
+ }
+ if (opts.hOutFile) {
+ CloseHandle(opts.hOutFile);
+ opts.hOutFile = NULL;
+ }
+ if (opts.pFile) {
+ UnmapViewOfFile(opts.pFile);
+ opts.pFile = NULL;
+ }
+ if (opts.hMap) {
+ CloseHandle(opts.hMap);
+ opts.hMap = NULL;
+ }
+ if (errorCount && !opts.bBackup && !opts.bCheckOnly) {
+ extern time_t ts;
+ time_t dlg_ts = time(NULL);
+ if (IDYES == MessageBox(NULL,
+ TranslateT("Errors were encountered, however you selected not to backup the original database. It is strongly recommended that you do so in case important data was omitted. Do you wish to keep a backup of the original database?"),
+ TranslateT("Miranda Database Tool"), MB_YESNO))
+ opts.bBackup = 1;
+ ts += time(NULL) - dlg_ts;
+ }
+ if (opts.bBackup) {
+ int i;
+ TCHAR dbPath[MAX_PATH],dbFile[MAX_PATH];
+ _tcscpy(dbPath, opts.filename);
+ TCHAR* str2 = _tcsrchr(dbPath, '\\');
+ if (str2 != NULL) {
+ _tcscpy(dbFile, str2+1);
+ *str2 = 0;
+ }
+ else {
+ _tcscpy(dbFile, dbPath);
+ dbPath[0] = 0;
+ }
+ for(i = 1;;i++) {
+ if (i == 1) wsprintf(opts.backupFilename,TranslateT("%s\\Backup of %s"),dbPath,dbFile);
+ else wsprintf(opts.backupFilename,TranslateT("%s\\Backup (%d) of %s"),dbPath,i,dbFile);
+ if (_taccess(opts.backupFilename,0) == -1) break;
+ }
+ MoveFile(opts.filename,opts.backupFilename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to rename original file"));
+ }
+ else if (!opts.bCheckOnly) DeleteFile(opts.filename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to delete original file"));
+ if (!opts.bCheckOnly) MoveFile(opts.outputFilename,opts.filename) || AddToStatus(STATUS_WARNING,TranslateT("Unable to rename output file"));
+ return ERROR_NO_MORE_ITEMS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp b/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp
new file mode 100644
index 0000000000..21ccff5976
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/initialchecks.cpp
@@ -0,0 +1,81 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+extern DWORD sourceFileSize,spaceUsed;
+
+int WorkInitialChecks(int firstTime)
+{
+ DWORD bytesRead;
+
+ sourceFileSize = GetFileSize(opts.hFile,NULL);
+ if (sourceFileSize == 0) {
+ AddToStatus(STATUS_WARNING,TranslateT("Database is newly created and has no data to process"));
+ AddToStatus(STATUS_SUCCESS,TranslateT("Processing completed successfully"));
+ return ERROR_INVALID_DATA;
+ }
+ ReadFile(opts.hFile,&dbhdr,sizeof(dbhdr),&bytesRead,NULL);
+ if (bytesRead<sizeof(dbhdr)) {
+ AddToStatus(STATUS_FATAL,TranslateT("Database is corrupted and too small to contain any recoverable data"));
+ return ERROR_BAD_FORMAT;
+ }
+ if (memcmp(dbhdr.signature,&dbSignature,sizeof(dbhdr.signature))) {
+ AddToStatus(STATUS_FATAL,TranslateT("Database signature is corrupted, automatic repair is impossible"));
+ return ERROR_BAD_FORMAT;
+ }
+ if (dbhdr.version != 0x00000700) {
+ AddToStatus(STATUS_FATAL,TranslateT("Database is marked as belonging to an unknown version of Miranda"));
+ return ERROR_BAD_FORMAT;
+ }
+ _tcscpy(opts.workingFilename,opts.filename);
+
+ if (opts.bCheckOnly) {
+ _tcscpy(opts.outputFilename, TranslateT("<check only>"));
+ opts.hOutFile = INVALID_HANDLE_VALUE;
+ }
+ else {
+ _tcscpy(opts.outputFilename,opts.filename);
+ *_tcsrchr(opts.outputFilename,'.') = 0;
+ _tcscat(opts.outputFilename,TranslateT(" (Output).dat"));
+ opts.hOutFile = CreateFile(opts.outputFilename,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ if (opts.hOutFile == INVALID_HANDLE_VALUE) {
+ AddToStatus(STATUS_FATAL,TranslateT("Can't create output file (%u)"),GetLastError());
+ return ERROR_ACCESS_DENIED;
+ }
+ }
+
+ opts.hMap = CreateFileMapping(opts.hFile, NULL, opts.bAggressive?PAGE_WRITECOPY:PAGE_READONLY, 0, 0, NULL);
+
+ if (opts.hMap)
+ opts.pFile = (BYTE*)MapViewOfFile(opts.hMap, opts.bAggressive?FILE_MAP_COPY:FILE_MAP_READ, 0, 0 ,0);
+ else {
+ AddToStatus(STATUS_FATAL,TranslateT("Can't create file mapping (%u)"),GetLastError());
+ return ERROR_ACCESS_DENIED;
+ }
+
+ if (!opts.pFile) {
+ AddToStatus(STATUS_FATAL,TranslateT("Can't create map view of file (%u)"),GetLastError());
+ return ERROR_ACCESS_DENIED;
+ }
+ if (ReadSegment(0,&dbhdr,sizeof(dbhdr)) != ERROR_SUCCESS) return ERROR_READ_FAULT;
+ if (WriteSegment(0,&dbhdr,sizeof(dbhdr)) == WS_ERROR) return ERROR_HANDLE_DISK_FULL;
+ spaceUsed = dbhdr.ofsFileEnd-dbhdr.slackSpace;
+ dbhdr.ofsFileEnd = sizeof(dbhdr);
+ return ERROR_NO_MORE_ITEMS;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/modulechain.cpp b/plugins/Db3x_mmap/src/dbtool/modulechain.cpp
new file mode 100644
index 0000000000..f53f63c469
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/modulechain.cpp
@@ -0,0 +1,146 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+struct ModChainEntry {
+ DWORD ofsOld,ofsNew;
+ int size;
+ char name[257];
+} static *modChain = NULL;
+static int modChainCount;
+static DWORD ofsCurrent;
+static int phase,iCurrentModName;
+static DWORD ofsLast;
+static int last_mod = 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*)_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 (!strcmp(modChain[i].name, modChain[iCurrentModName].name)) {
+ modChain[i].ofsNew = modChain[iCurrentModName].ofsNew;
+ n++;
+ }
+ if (n) {
+ TCHAR *pszModuleName;
+
+ TCHAR szModuleName[257];
+ MultiByteToWideChar(CP_ACP, 0, modChain[iCurrentModName].name, -1, szModuleName, sizeof(szModuleName) / sizeof(TCHAR));
+ pszModuleName = szModuleName;
+
+ AddToStatus(STATUS_WARNING,TranslateT("Module name '%s' is not unique: %d duplicates found)"), pszModuleName, 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;
+}
+
+DWORD ConvertModuleNameOfs(DWORD ofsOld)
+{
+ int i;
+
+ if (modChain[last_mod].ofsOld == ofsOld)
+ return modChain[last_mod].ofsNew;
+
+ for(i = 0;i<modChainCount;i++)
+ if (modChain[i].ofsOld == ofsOld) {
+ last_mod = i;
+ return modChain[last_mod].ofsNew;
+ }
+
+ AddToStatus(STATUS_ERROR,TranslateT("Invalid module name offset, skipping data"));
+ return 0;
+}
+
+void FreeModuleChain()
+{
+ if (modChain != NULL) {
+ free(modChain);
+ modChain = NULL;
+ last_mod = 0;
+ }
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/settingschain.cpp b/plugins/Db3x_mmap/src/dbtool/settingschain.cpp
new file mode 100644
index 0000000000..a2bfc48482
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/settingschain.cpp
@@ -0,0 +1,72 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+static DWORD ofsThisSettings,ofsDestPrevSettings;
+
+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*)_alloca(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: skipping"),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;
+}
diff --git a/plugins/Db3x_mmap/src/dbtool/user.cpp b/plugins/Db3x_mmap/src/dbtool/user.cpp
new file mode 100644
index 0000000000..d61add09d4
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbtool/user.cpp
@@ -0,0 +1,71 @@
+/*
+Miranda Database Tool
+Copyright (C) 2001-2005 Richard Hughes
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "..\commonheaders.h"
+
+static DBContact user;
+static int phase;
+static DWORD ofsUser;
+
+int WorkSettingsChain(DWORD ofsContact,DBContact *dbc,int firstTime);
+int WorkEventChain(DWORD ofsContact,DBContact *dbc,int firstTime);
+
+int WorkUser(int firstTime)
+{
+ int first = 0;
+
+ if (firstTime) {
+ AddToStatus(STATUS_MESSAGE,TranslateT("Processing user data"));
+ if (!SignatureValid(dbhdr.ofsUser,DBCONTACT_SIGNATURE)) {
+ AddToStatus(STATUS_ERROR,TranslateT("User corrupted, this could cause major problems"));
+ return ERROR_NO_MORE_ITEMS;
+ }
+ if (ReadSegment(dbhdr.ofsUser,&user,sizeof(DBContact)) != ERROR_SUCCESS)
+ return ERROR_NO_MORE_ITEMS;
+ if (user.ofsNext) {
+ AddToStatus(STATUS_WARNING,TranslateT("More than one user contact: keeping only first"));
+ user.ofsNext = 0;
+ }
+ if ((ofsUser = WriteSegment(WSOFS_END,&user,sizeof(DBContact))) == WS_ERROR)
+ return ERROR_HANDLE_DISK_FULL;
+ dbhdr.ofsUser = ofsUser;
+ phase = 0;
+ first = 1;
+ }
+ switch(phase) {
+ int ret;
+
+ case 0:
+ ret = WorkSettingsChain(ofsUser,&user,first);
+ if (ret == ERROR_NO_MORE_ITEMS) {
+ phase++; first = 1;
+ }
+ else if (ret) return ret;
+ else break;
+ case 1:
+ ret = WorkEventChain(ofsUser,&user,first);
+ if (ret == ERROR_NO_MORE_ITEMS) {
+ if (WriteSegment(ofsUser,&user,sizeof(DBContact)) == WS_ERROR)
+ return ERROR_HANDLE_DISK_FULL;
+ return ERROR_NO_MORE_ITEMS;
+ }
+ else if (ret) return ret;
+ break;
+ }
+ return ERROR_SUCCESS;
+} \ No newline at end of file