summaryrefslogtreecommitdiff
path: root/plugins/Db3x/src
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-07-17 10:17:31 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-07-17 10:17:31 +0000
commit073f9d0d8e6629115e1768266aaa8221efff92bf (patch)
tree53ab979b0fc77168acc700de25abcc3bf4830b80 /plugins/Db3x/src
parente736ab21213b66669dde5d9a9003596706eee8bd (diff)
Db3x: changed folder structure
git-svn-id: http://svn.miranda-ng.org/main/trunk@1003 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Db3x/src')
-rw-r--r--plugins/Db3x/src/commonheaders.h69
-rw-r--r--plugins/Db3x/src/database.cpp158
-rw-r--r--plugins/Db3x/src/database.h214
-rw-r--r--plugins/Db3x/src/dbcache.cpp224
-rw-r--r--plugins/Db3x/src/dbcontacts.cpp294
-rw-r--r--plugins/Db3x/src/dbevents.cpp425
-rw-r--r--plugins/Db3x/src/dbheaders.cpp74
-rw-r--r--plugins/Db3x/src/dbmodulechain.cpp129
-rw-r--r--plugins/Db3x/src/dbsettings.cpp975
-rw-r--r--plugins/Db3x/src/encrypt.cpp66
-rw-r--r--plugins/Db3x/src/init.cpp176
-rw-r--r--plugins/Db3x/src/resource.h30
-rw-r--r--plugins/Db3x/src/version.h5
13 files changed, 2839 insertions, 0 deletions
diff --git a/plugins/Db3x/src/commonheaders.h b/plugins/Db3x/src/commonheaders.h
new file mode 100644
index 0000000000..415bb7448d
--- /dev/null
+++ b/plugins/Db3x/src/commonheaders.h
@@ -0,0 +1,69 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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.
+*/
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#define MIRANDA_VER 0x0A00
+
+#define _WIN32_WINNT 0x0501
+
+#include "m_stdhdr.h"
+
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <string.h>
+#include <direct.h>
+
+#include <newpluginapi.h>
+#include <win2k.h>
+#include <m_plugins.h>
+#include <m_system.h>
+#include <m_database.h>
+#include <m_langpack.h>
+
+#include "version.h"
+#include "database.h"
+#include "resource.h"
+
+extern HANDLE hDbFile;
+extern CRITICAL_SECTION csDbAccess;
+extern struct DBHeader dbHeader;
+extern HANDLE hCacheHeap;
+extern SortedList lContacts;
+extern char szDbPath[MAX_PATH];
+
+#ifdef __GNUC__
+#define mir_i64(x) (x##LL)
+#else
+#define mir_i64(x) (x##i64)
+#endif
+
+#ifndef MODULAR
+void Encrypt(char*msg,BOOL up);
+#endif
diff --git a/plugins/Db3x/src/database.cpp b/plugins/Db3x/src/database.cpp
new file mode 100644
index 0000000000..0172bde5b2
--- /dev/null
+++ b/plugins/Db3x/src/database.cpp
@@ -0,0 +1,158 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+int ProfileManager(char *szDbDest,int cbDbDest);
+int ShouldAutoCreate(void);
+int CreateDbHeaders(HANDLE hFile);
+int InitialiseDbHeaders(void);
+int InitSettings(void);
+void UninitSettings(void);
+int InitContacts(void);
+void UninitContacts(void);
+int InitEvents(void);
+void UninitEvents(void);
+int InitCrypt(void);
+int InitModuleNames(void);
+void UninitModuleNames(void);
+int InitCache(void);
+void UninitCache(void);
+int InitIni(void);
+void UninitIni(void);
+
+HANDLE hDbFile=INVALID_HANDLE_VALUE;
+CRITICAL_SECTION csDbAccess;
+struct DBHeader dbHeader;
+char szDbPath[MAX_PATH];
+
+static void UnloadDatabase(void)
+{
+ CloseHandle(hDbFile);
+}
+
+DWORD CreateNewSpace(int bytes)
+{
+ DWORD ofsNew;
+
+ ofsNew=dbHeader.ofsFileEnd;
+ dbHeader.ofsFileEnd+=bytes;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ log2("newspace %d@%08x",bytes,ofsNew);
+ return ofsNew;
+}
+
+void DeleteSpace(DWORD ofs,int bytes)
+{
+ PBYTE buf;
+ log2("deletespace %d@%08x",bytes,ofs);
+ dbHeader.slackSpace+=bytes;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ buf=(PBYTE)mir_alloc(bytes);
+ memset(buf,0,bytes);
+ DBWrite(ofs,buf,bytes);
+ mir_free(buf);
+}
+
+void UnloadDatabaseModule(void)
+{
+ //UninitIni();
+ UninitEvents();
+ UninitSettings();
+ UninitContacts();
+ UninitModuleNames();
+ UninitCache();
+ UnloadDatabase();
+ DeleteCriticalSection(&csDbAccess);
+}
+
+int LoadDatabaseModule(void)
+{
+ InitializeCriticalSection(&csDbAccess);
+ log0("DB logging running");
+ {
+ DWORD dummy=0;
+ hDbFile=CreateFileA(szDbPath,GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
+ if ( hDbFile == INVALID_HANDLE_VALUE ) {
+ return 1;
+ }
+ if ( !ReadFile(hDbFile,&dbHeader,sizeof(dbHeader),&dummy,NULL)) {
+ CloseHandle(hDbFile);
+ return 1;
+ }
+ }
+ //if(ParseCommandLine()) return 1;
+ if(InitCache()) return 1;
+ if(InitModuleNames()) return 1;
+ if(InitContacts()) return 1;
+ if(InitSettings()) return 1;
+ if(InitEvents()) return 1;
+ if(InitCrypt()) return 1;
+ return 0;
+}
+
+static DWORD DatabaseCorrupted=0;
+
+void __cdecl dbpanic(void *arg)
+{
+ MessageBox(0,TranslateT("Miranda has detected corruption in your database. This corruption maybe fixed by DBTool. Please download it from http://www.miranda-im.org. Miranda will now shutdown."),TranslateT("Database Panic"),MB_SETFOREGROUND|MB_TOPMOST|MB_APPLMODAL|MB_ICONWARNING|MB_OK);
+ TerminateProcess(GetCurrentProcess(),255);
+ return;
+}
+
+void DatabaseCorruption(void)
+{
+ int kill=0;
+
+ EnterCriticalSection(&csDbAccess);
+ if (DatabaseCorrupted==0) {
+ DatabaseCorrupted++;
+ kill++;
+ } else {
+ /* db is already corrupted, someone else is dealing with it, wait here
+ so that we don't do any more damage */
+ LeaveCriticalSection(&csDbAccess);
+ Sleep(INFINITE);
+ return;
+ }
+ LeaveCriticalSection(&csDbAccess);
+ if (kill) {
+ _beginthread(dbpanic,0,NULL);
+ Sleep(INFINITE);
+ }
+}
+
+#ifdef DBLOGGING
+void DBLog(const char *file,int line,const char *fmt,...)
+{
+ FILE *fp;
+ va_list vararg;
+ char str[1024];
+
+ va_start(vararg,fmt);
+ mir_vsnprintf(str,sizeof(str),fmt,vararg);
+ va_end(vararg);
+ fp=fopen("c:\\mirandadatabase.log.txt","at");
+ fprintf(fp,"%u: %s %d: %s\n",GetTickCount(),file,line,str);
+ fclose(fp);
+}
+#endif
diff --git a/plugins/Db3x/src/database.h b/plugins/Db3x/src/database.h
new file mode 100644
index 0000000000..334e47002d
--- /dev/null
+++ b/plugins/Db3x/src/database.h
@@ -0,0 +1,214 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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.
+*/
+
+
+//all offsets are relative to the start of the file
+//offsets are 0 if there is nothing in the chain or this is the last in the
+//chain
+
+/* tree diagram
+
+DBHeader
+ |-->end of file (plain offset)
+ |-->first contact (DBContact)
+ | |-->next contact (DBContact)
+ | | \--> ...
+ | |-->first settings (DBContactSettings)
+ | | |-->next settings (DBContactSettings)
+ | | | \--> ...
+ | | \-->module name (DBModuleName)
+ | \-->first/last/firstunread event
+ |-->user contact (DBContact)
+ | |-->next contact=NULL
+ | |-->first settings as above
+ | \-->first/last/firstunread event as above
+ \-->first module name (DBModuleName)
+ \-->next module name (DBModuleName)
+ \--> ...
+*/
+
+#define DB_RESIZE_GRANULARITY 16384
+#define DB_THIS_VERSION 0x00000700u
+#define DB_SETTINGS_RESIZE_GRANULARITY 128
+
+#include <pshpack1.h>
+struct DBHeader {
+ BYTE signature[16]; // 'Miranda ICQ DB',0,26
+ DWORD version; //as 4 bytes, ie 1.2.3.10=0x0102030a
+ //this version is 0x00000700
+ DWORD ofsFileEnd; //offset of the end of the database - place to write
+ //new structures
+ DWORD slackSpace; //a counter of the number of bytes that have been
+ //wasted so far due to deleting structures and/or
+ //re-making them at the end. We should compact when
+ //this gets above a threshold
+ DWORD contactCount; //number of contacts in the chain,excluding the user
+ DWORD ofsFirstContact; //offset to first struct DBContact in the chain
+ DWORD ofsUser; //offset to struct DBContact representing the user
+ DWORD ofsFirstModuleName; //offset to first struct DBModuleName in the chain
+};
+
+#define DBCONTACT_SIGNATURE 0x43DECADEu
+struct DBContact {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next contact in the chain. zero if
+ //this is the 'user' contact or the last contact
+ //in the chain
+ DWORD ofsFirstSettings; //offset to the first DBContactSettings in the
+ //chain for this contact.
+ DWORD eventCount; //number of events in the chain for this contact
+ DWORD ofsFirstEvent,ofsLastEvent; //offsets to the first and last DBEvent in
+ //the chain for this contact
+ DWORD ofsFirstUnreadEvent; //offset to the first (chronological) unread event
+ //in the chain, 0 if all are read
+ DWORD timestampFirstUnread; //timestamp of the event at ofsFirstUnreadEvent
+};
+
+#define DBMODULENAME_SIGNATURE 0x4DDECADEu
+struct DBModuleName {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next module name in the chain
+ BYTE cbName; //number of characters in this module name
+ char name[1]; //name, no nul terminator
+};
+
+#define DBCONTACTSETTINGS_SIGNATURE 0x53DECADEu
+struct DBContactSettings {
+ DWORD signature;
+ DWORD ofsNext; //offset to the next contactsettings in the chain
+ DWORD ofsModuleName; //offset to the DBModuleName of the owner of these
+ //settings
+ DWORD cbBlob; //size of the blob in bytes. May be larger than the
+ //actual size for reducing the number of moves
+ //required using granularity in resizing
+ BYTE blob[1]; //the blob. a back-to-back sequence of DBSetting
+ //structs, the last has cbName=0
+};
+
+/* not a valid structure, content is figured out on the fly
+struct DBSetting {
+ BYTE cbName; //number of bytes in the name of this setting
+ //this =0 marks the end
+ char szName[...]; //setting name, excluding nul
+ BYTE dataType; //type of data. see m_database.h, db/contact/getsetting
+ union { //a load of types of data, length is defined by dataType
+ BYTE bVal; WORD wVal; DWORD dVal;
+ struct {
+ WORD cbString;
+ char szVal[...]; //excludes nul terminator
+ };
+ struct {
+ WORD cbBlob;
+ BYTE blobVal[...];
+ };
+ };
+};
+*/
+
+#define DBEVENT_SIGNATURE 0x45DECADEu
+struct DBEvent {
+ DWORD signature;
+ DWORD ofsPrev,ofsNext; //offset to the previous and next events in the
+ //chain. Chain is sorted chronologically
+ DWORD ofsModuleName; //offset to a DBModuleName struct of the name of
+ //the owner of this event
+ DWORD timestamp; //seconds since 00:00:00 01/01/1970
+ DWORD flags; //see m_database.h, db/event/add
+ WORD eventType; //module-defined event type
+ DWORD cbBlob; //number of bytes in the blob
+ BYTE blob[1]; //the blob. module-defined formatting
+};
+#include <poppack.h>
+
+typedef struct
+{
+ BYTE bIsResident;
+ char name[1];
+}
+ DBCachedSettingName;
+
+typedef struct
+{
+ char* name;
+ DBVARIANT value;
+}
+ DBCachedGlobalValue;
+
+typedef struct DBCachedContactValue_tag
+{
+ char* name;
+ DBVARIANT value;
+ struct DBCachedContactValue_tag* next;
+}
+ DBCachedContactValue;
+
+typedef struct
+{
+ HANDLE hContact;
+ HANDLE hNext;
+ DBCachedContactValue* first;
+}
+ DBCachedContactValueList;
+
+
+//databasecorruption: called if any signatures are broken. very very fatal
+void DatabaseCorruption(void);
+PBYTE DBRead(DWORD ofs,int bytesRequired,int *bytesAvail); //any preview result could be invalidated by the next call
+void DBWrite(DWORD ofs,PVOID pData,int count);
+void DBFlush(int setting);
+void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes);
+DWORD CreateNewSpace(int bytes);
+void DeleteSpace(DWORD ofs,int bytes);
+void GetProfileDirectory(char *szPath,int cbPath);
+int GetDefaultProfilePath(char *szPath,int cbPath,int *specified);
+int ShouldShowProfileManager(void);
+int CheckDbHeaders(struct DBHeader * hdr);
+int CreateDbHeaders(HANDLE hFile);
+int LoadDatabaseModule(void);
+void UnloadDatabaseModule(void);
+
+#ifdef _DEBUG
+#define MAXCACHEDREADSIZE 512
+#else
+#define MAXCACHEDREADSIZE 2048 //push it to 1K //technically 4096 would work, but I'm not going to push it
+#endif
+
+#ifdef _DEBUG
+//#define DBLOGGING
+#endif
+#ifdef DBLOGGING
+void DBLog(const char *file,int line,const char *fmt,...);
+#define logg() DBLog(__FILE__,__LINE__,"")
+#define log0(s) DBLog(__FILE__,__LINE__,s)
+#define log1(s,a) DBLog(__FILE__,__LINE__,s,a)
+#define log2(s,a,b) DBLog(__FILE__,__LINE__,s,a,b)
+#define log3(s,a,b,c) DBLog(__FILE__,__LINE__,s,a,b,c)
+#define log4(s,a,b,c,d) DBLog(__FILE__,__LINE__,s,a,b,c,d)
+#else
+#define logg()
+#define log0(s)
+#define log1(s,a)
+#define log2(s,a,b)
+#define log3(s,a,b,c)
+#define log4(s,a,b,c,d)
+#endif
diff --git a/plugins/Db3x/src/dbcache.cpp b/plugins/Db3x/src/dbcache.cpp
new file mode 100644
index 0000000000..10d34e1ec3
--- /dev/null
+++ b/plugins/Db3x/src/dbcache.cpp
@@ -0,0 +1,224 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+#define CACHESECTIONSIZE 4096
+#define CACHESECTIONCOUNT 32
+
+static BOOL safetyMode=TRUE;
+static PBYTE pDbCache;
+static DWORD lastUseCounter;
+struct DBCacheSectionInfo {
+ DWORD ofsBase;
+ DWORD lastUsed;
+} static cacheSectionInfo[CACHESECTIONCOUNT];
+
+static __inline int FindSectionForOffset(const DWORD ofs)
+{
+ int i;
+ for(i=0;i<CACHESECTIONCOUNT;i++)
+ if(ofs>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE)
+ return i;
+ return -1;
+}
+
+static __inline int FindLRUSection(void)
+{
+ int i,lru=0;
+ DWORD lowestLastUse=cacheSectionInfo[0].lastUsed;
+ for(i=1;i<CACHESECTIONCOUNT;i++) if(cacheSectionInfo[i].lastUsed<lowestLastUse) {lru=i; lowestLastUse=cacheSectionInfo[i].lastUsed;}
+ return lru;
+}
+
+static __inline void LoadSection(const int i,DWORD ofs)
+{
+ cacheSectionInfo[i].ofsBase=ofs-ofs%CACHESECTIONSIZE;
+ log1("readsect %08x",ofs);
+ SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&ofs,NULL);
+}
+
+static __inline void MoveSection(int *sectId,int dest)
+{
+ CopyMemory(pDbCache+dest*CACHESECTIONSIZE,pDbCache+(*sectId)*CACHESECTIONSIZE,CACHESECTIONSIZE);
+ cacheSectionInfo[dest].ofsBase=cacheSectionInfo[*sectId].ofsBase;
+ *sectId=dest;
+}
+
+
+
+//we are assumed to be in a mutex here
+PBYTE DBRead(DWORD ofs,int bytesRequired,int *bytesAvail)
+{
+
+ int part1sect;
+ int part2sect;
+
+
+ part1sect = FindSectionForOffset(ofs);
+ if (ofs%CACHESECTIONSIZE+bytesRequired<CACHESECTIONSIZE) {
+ //only one section required
+ if(part1sect==-1) {
+ part1sect=FindLRUSection();
+ LoadSection(part1sect,ofs);
+ }
+ cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
+ if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect].ofsBase+CACHESECTIONSIZE-ofs;
+ return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
+ }
+ //two sections are required
+ part2sect=FindSectionForOffset(ofs+CACHESECTIONSIZE);
+ if(part1sect!=-1) {
+ if(part2sect==-1) { //first part in cache, but not second part
+ if(part1sect==CACHESECTIONCOUNT-1) MoveSection(&part1sect,0);
+ LoadSection(part1sect+1,ofs+CACHESECTIONSIZE);
+ }
+ else if(part2sect!=part1sect+1) { //both parts are in cache, but not already consecutive
+ if(part1sect==CACHESECTIONCOUNT-1) {
+ //first part is at end, move to before second part
+ if(part2sect==0) //second part is at start: need to move both
+ MoveSection(&part2sect,1);
+ MoveSection(&part1sect,part2sect-1);
+ }
+ else //move second part to after first part
+ MoveSection(&part2sect,part1sect+1);
+ }
+ }
+ else {
+ if(part2sect==-1) { //neither section is in cache
+ part1sect=0; part2sect=1;
+ LoadSection(part1sect,ofs); LoadSection(part2sect,ofs+CACHESECTIONSIZE);
+ }
+ else { //part 2 is in cache, but not part 1
+ if(part2sect==0) MoveSection(&part2sect,1);
+ part1sect=part2sect-1;
+ LoadSection(part1sect,ofs);
+ }
+ }
+ //both sections are now consecutive, starting at part1sect
+ cacheSectionInfo[part1sect].lastUsed=++lastUseCounter;
+ cacheSectionInfo[part1sect+1].lastUsed=++lastUseCounter;
+ if(bytesAvail!=NULL) *bytesAvail=cacheSectionInfo[part1sect+1].ofsBase+CACHESECTIONSIZE-ofs;
+ return pDbCache+part1sect*CACHESECTIONSIZE+(ofs-cacheSectionInfo[part1sect].ofsBase);
+}
+
+
+
+//we are assumed to be in a mutex here
+void DBWrite(DWORD ofs,PVOID pData,int bytes)
+{
+ //write direct, and rely on Windows' write caching
+ DWORD bytesWritten;
+ int i;
+
+ log2("write %d@%08x",bytes,ofs);
+ SetFilePointer(hDbFile,ofs,NULL,FILE_BEGIN);
+ if (WriteFile(hDbFile,pData,bytes,&bytesWritten,NULL)==0)
+ {
+ DatabaseCorruption();
+ }
+ logg();
+ //check if any of the cache sections contain this bit
+ for(i=0;i<CACHESECTIONCOUNT;i++) {
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase && ofs<cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) {
+ if(ofs<cacheSectionInfo[i].ofsBase) { //don't start at beginning
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
+ CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,CACHESECTIONSIZE);
+ else CopyMemory(pDbCache+i*CACHESECTIONSIZE,(PBYTE)pData+cacheSectionInfo[i].ofsBase-ofs,bytes-(cacheSectionInfo[i].ofsBase-ofs));
+ }
+ else { //start at beginning
+ if(ofs+bytes>=cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE) //don't finish at end
+ CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,cacheSectionInfo[i].ofsBase+CACHESECTIONSIZE-ofs);
+ else CopyMemory(pDbCache+i*CACHESECTIONSIZE+ofs-cacheSectionInfo[i].ofsBase,pData,bytes);
+ }
+ }
+ }
+}
+
+void DBMoveChunk(DWORD ofsDest,DWORD ofsSource,int bytes)
+{
+ DWORD bytesRead;
+ PBYTE buf;
+
+ log3("move %d %08x->%08x",bytes,ofsSource,ofsDest);
+ buf=(PBYTE)mir_alloc(bytes);
+ SetFilePointer(hDbFile,ofsSource,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,buf,bytes,&bytesRead,NULL);
+ DBWrite(ofsDest,buf,bytes);
+ mir_free(buf);
+ logg();
+}
+
+static UINT_PTR flushBuffersTimerId;
+static VOID CALLBACK DoBufferFlushTimerProc(HWND hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime)
+{
+ KillTimer(NULL,flushBuffersTimerId);
+ log0("tflush1");
+ FlushFileBuffers(hDbFile);
+ log0("tflush2");
+}
+
+void DBFlush(int setting)
+{
+ if (!setting) {
+ log0("nflush1");
+ if(safetyMode) FlushFileBuffers(hDbFile);
+ log0("nflush2");
+ return;
+ }
+ KillTimer(NULL,flushBuffersTimerId);
+ flushBuffersTimerId=SetTimer(NULL,flushBuffersTimerId,50,DoBufferFlushTimerProc);
+}
+
+static INT_PTR CacheSetSafetyMode(WPARAM wParam,LPARAM lParam)
+{
+ EnterCriticalSection(&csDbAccess);
+ safetyMode=wParam;
+ LeaveCriticalSection(&csDbAccess);
+ if(safetyMode) FlushFileBuffers(hDbFile);
+ return 0;
+}
+
+int InitCache(void)
+{
+ int i;
+ DWORD bytesRead;
+
+ CreateServiceFunction(MS_DB_SETSAFETYMODE,CacheSetSafetyMode);
+ pDbCache=(PBYTE)mir_alloc(CACHESECTIONSIZE*CACHESECTIONCOUNT);
+ lastUseCounter=CACHESECTIONCOUNT;
+ for(i=0;i<CACHESECTIONCOUNT;i++) {
+ cacheSectionInfo[i].ofsBase=0;
+ cacheSectionInfo[i].lastUsed=i;
+ SetFilePointer(hDbFile,cacheSectionInfo[i].ofsBase,NULL,FILE_BEGIN);
+ ReadFile(hDbFile,pDbCache+i*CACHESECTIONSIZE,CACHESECTIONSIZE,&bytesRead,NULL);
+ }
+ return 0;
+}
+
+void UninitCache(void)
+{
+ mir_free(pDbCache);
+ KillTimer(NULL,flushBuffersTimerId);
+}
diff --git a/plugins/Db3x/src/dbcontacts.cpp b/plugins/Db3x/src/dbcontacts.cpp
new file mode 100644
index 0000000000..ef128a491e
--- /dev/null
+++ b/plugins/Db3x/src/dbcontacts.cpp
@@ -0,0 +1,294 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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 INT_PTR GetContactCount(WPARAM wParam,LPARAM lParam);
+static INT_PTR FindFirstContact(WPARAM wParam,LPARAM lParam);
+static INT_PTR FindNextContact(WPARAM wParam,LPARAM lParam);
+static INT_PTR DeleteContact(WPARAM wParam,LPARAM lParam);
+static INT_PTR AddContact(WPARAM wParam,LPARAM lParam);
+static INT_PTR IsDbContact(WPARAM wParam,LPARAM lParam);
+
+static HANDLE hContactDeletedEvent,hContactAddedEvent;
+
+int InitContacts(void)
+{
+ CreateServiceFunction(MS_DB_CONTACT_GETCOUNT,GetContactCount);
+ CreateServiceFunction(MS_DB_CONTACT_FINDFIRST,FindFirstContact);
+ CreateServiceFunction(MS_DB_CONTACT_FINDNEXT,FindNextContact);
+ CreateServiceFunction(MS_DB_CONTACT_DELETE,DeleteContact);
+ CreateServiceFunction(MS_DB_CONTACT_ADD,AddContact);
+ CreateServiceFunction(MS_DB_CONTACT_IS,IsDbContact);
+ hContactDeletedEvent=CreateHookableEvent(ME_DB_CONTACT_DELETED);
+ hContactAddedEvent=CreateHookableEvent(ME_DB_CONTACT_ADDED);
+ return 0;
+}
+
+void UninitContacts(void)
+{
+}
+
+INT_PTR GetContactSettingStatic(WPARAM wParam,LPARAM lParam);
+
+static INT_PTR GetContactCount(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+
+ EnterCriticalSection(&csDbAccess);
+ ret=dbHeader.contactCount;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+#define proto_module "Protocol"
+#define proto_setting "p"
+
+static int CheckProto(HANDLE hContact, const char *proto)
+{
+ static char protobuf[MAX_PATH] = {0};
+ static DBVARIANT dbv;
+ static DBCONTACTGETSETTING sVal = {proto_module,proto_setting,&dbv};
+
+ dbv.type = DBVT_ASCIIZ;
+ dbv.pszVal = protobuf;
+ dbv.cchVal = sizeof(protobuf);
+
+ if (GetContactSettingStatic((WPARAM)hContact, (LPARAM )&sVal) != 0
+ || (dbv.type != DBVT_ASCIIZ)) return 0;
+
+ return !strcmp(protobuf,proto);
+}
+
+static INT_PTR FindFirstContact(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret = 0;
+ EnterCriticalSection(&csDbAccess);
+ ret = (INT_PTR)dbHeader.ofsFirstContact;
+ if (lParam && !CheckProto((HANDLE)ret,(const char*)lParam))
+ ret = FindNextContact((WPARAM)ret,lParam);
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindNextContact(WPARAM wParam,LPARAM lParam)
+{
+ int index;
+ struct DBContact *dbc;
+ DBCachedContactValueList VLtemp, *VL = NULL;
+ VLtemp.hContact = (HANDLE)wParam;
+ EnterCriticalSection(&csDbAccess);
+ while ( VLtemp.hContact ) {
+ if ( List_GetIndex(&lContacts,&VLtemp,&index)) {
+ VL = ( DBCachedContactValueList* )lContacts.items[index];
+ if (VL->hNext != NULL) {
+ if (!lParam || CheckProto(VL->hNext,(const char*)lParam)) {
+ LeaveCriticalSection(&csDbAccess);
+ return (INT_PTR)VL->hNext;
+ }
+
+ VLtemp.hContact = VL->hNext;
+ continue;
+ } }
+
+ dbc=(struct DBContact*)DBRead((DWORD)VLtemp.hContact,sizeof(struct DBContact),NULL);
+ if (dbc->signature!=DBCONTACT_SIGNATURE)
+ break;
+ else {
+ if ( VL == NULL ) {
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = VLtemp.hContact;
+ List_Insert(&lContacts,VL,index);
+ }
+ VL->hNext = (HANDLE)dbc->ofsNext;
+ if (VL->hNext != NULL && (!lParam || CheckProto(VL->hNext,(const char*)lParam))) {
+ LeaveCriticalSection(&csDbAccess);
+ return (INT_PTR)VL->hNext;
+ }
+ VLtemp.hContact = VL->hNext;
+ } }
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static INT_PTR DeleteContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact *dbc,*dbcPrev;
+ DWORD ofsThis,ofsNext,ofsFirstEvent;
+ struct DBContactSettings *dbcs;
+ struct DBEvent *dbe;
+ int index;
+
+ if ((HANDLE)wParam==NULL) return 1;
+ EnterCriticalSection(&csDbAccess);
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ if ( (HANDLE)wParam == (HANDLE)dbHeader.ofsUser ) {
+ LeaveCriticalSection(&csDbAccess);
+ log0("FATAL: del of user chain attempted.");
+ return 1;
+ }
+ log0("del contact");
+ LeaveCriticalSection(&csDbAccess);
+ //call notifier while outside mutex
+ NotifyEventHooks(hContactDeletedEvent,wParam,0);
+ //get back in
+ EnterCriticalSection(&csDbAccess);
+
+ { DBCachedContactValueList VLtemp;
+ VLtemp.hContact = (HANDLE)wParam;
+ if ( List_GetIndex(&lContacts,&VLtemp,&index))
+ {
+ DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index];
+ DBCachedContactValue* V = VL->first;
+ while ( V != NULL ) {
+ DBCachedContactValue* V1 = V->next;
+ if ( V->value.type == DBVT_ASCIIZ )
+ HeapFree( hCacheHeap, 0, V->value.pszVal );
+ HeapFree( hCacheHeap, 0, V );
+ V = V1;
+ }
+ HeapFree( hCacheHeap, 0, VL );
+
+ List_Remove(&lContacts,index);
+ } }
+
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ //delete settings chain
+ ofsThis=dbc->ofsFirstSettings;
+ ofsFirstEvent=dbc->ofsFirstEvent;
+ while(ofsThis) {
+ dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL);
+ ofsNext=dbcs->ofsNext;
+ DeleteSpace(ofsThis,offsetof(struct DBContactSettings,blob)+dbcs->cbBlob);
+ ofsThis=ofsNext;
+ }
+ //delete event chain
+ ofsThis=ofsFirstEvent;
+ while(ofsThis) {
+ dbe=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ ofsNext=dbe->ofsNext;
+ DeleteSpace(ofsThis,offsetof(struct DBEvent,blob)+dbe->cbBlob);
+ ofsThis=ofsNext;
+ }
+ //find previous contact in chain and change ofsNext
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbHeader.ofsFirstContact==wParam) {
+ dbHeader.ofsFirstContact=dbc->ofsNext;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ }
+ else {
+ ofsNext=dbc->ofsNext;
+ ofsThis=dbHeader.ofsFirstContact;
+ dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL);
+ while(dbcPrev->ofsNext!=wParam) {
+ if(dbcPrev->ofsNext==0) DatabaseCorruption();
+ ofsThis=dbcPrev->ofsNext;
+ dbcPrev=(struct DBContact*)DBRead(ofsThis,sizeof(struct DBContact),NULL);
+ }
+ dbcPrev->ofsNext=ofsNext;
+ DBWrite(ofsThis,dbcPrev,sizeof(struct DBContact));
+ {
+ DBCachedContactValueList VLtemp;
+ VLtemp.hContact = (HANDLE)ofsThis;
+ if ( List_GetIndex(&lContacts,&VLtemp,&index))
+ {
+ DBCachedContactValueList *VL = ( DBCachedContactValueList* )lContacts.items[index];
+ VL->hNext = ( HANDLE )ofsNext;
+ } }
+ }
+ //delete contact
+ DeleteSpace(wParam,sizeof(struct DBContact));
+ //decrement contact count
+ dbHeader.contactCount--;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBFlush(0);
+ //quit
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static INT_PTR AddContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsNew;
+
+ log0("add contact");
+ EnterCriticalSection(&csDbAccess);
+ ofsNew=CreateNewSpace(sizeof(struct DBContact));
+ dbc.signature=DBCONTACT_SIGNATURE;
+ dbc.eventCount=0;
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=0;
+ dbc.ofsFirstSettings=0;
+ dbc.ofsNext=dbHeader.ofsFirstContact;
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ dbHeader.ofsFirstContact=ofsNew;
+ dbHeader.contactCount++;
+ DBWrite(ofsNew,&dbc,sizeof(struct DBContact));
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBFlush(0);
+
+ { int index;
+
+ DBCachedContactValueList *VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = (HANDLE)ofsNew;
+
+ List_GetIndex(&lContacts,VL,&index);
+ List_Insert(&lContacts,VL,index);
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ NotifyEventHooks(hContactAddedEvent,(WPARAM)ofsNew,0);
+ return (INT_PTR)ofsNew;
+}
+
+static INT_PTR IsDbContact(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsContact=(DWORD)wParam;
+ INT_PTR ret;
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ int index;
+ DBCachedContactValueList VLtemp,*VL;
+ VLtemp.hContact = (HANDLE)wParam;
+ if ( List_GetIndex(&lContacts,&VLtemp,&index))
+ ret = TRUE;
+ else {
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ ret=dbc.signature==DBCONTACT_SIGNATURE;
+
+ if (ret) {
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = (HANDLE)wParam;
+ List_Insert(&lContacts,VL,index);
+ } } }
+
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
diff --git a/plugins/Db3x/src/dbevents.cpp b/plugins/Db3x/src/dbevents.cpp
new file mode 100644
index 0000000000..be50babe57
--- /dev/null
+++ b/plugins/Db3x/src/dbevents.cpp
@@ -0,0 +1,425 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+DWORD GetModuleNameOfs(const char *szName);
+char *GetModuleNameByOfs(DWORD ofs);
+
+static HANDLE hEventDeletedEvent,hEventAddedEvent,hEventFilterAddedEvent;
+
+static INT_PTR GetEventCount(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=-1;
+ else ret=dbc->eventCount;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR AddEvent(WPARAM wParam,LPARAM lParam)
+{
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ struct DBContact dbc;
+ struct DBEvent dbe,*dbeTest;
+ DWORD ofsNew,ofsModuleName,ofsContact,ofsThis;
+
+ if(dbei==NULL||dbei->cbSize!=sizeof(DBEVENTINFO)) return 0;
+ if(dbei->timestamp==0) return 0;
+ if (NotifyEventHooks(hEventFilterAddedEvent,wParam,lParam)) {
+ return 0;
+ }
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+ }
+ ofsNew=CreateNewSpace(offsetof(struct DBEvent,blob)+dbei->cbBlob);
+ ofsModuleName=GetModuleNameOfs(dbei->szModule);
+
+ dbe.signature=DBEVENT_SIGNATURE;
+ dbe.ofsModuleName=ofsModuleName;
+ dbe.timestamp=dbei->timestamp;
+ dbe.flags=dbei->flags;
+ dbe.eventType=dbei->eventType;
+ dbe.cbBlob=dbei->cbBlob;
+ //find where to put it - sort by timestamp
+ if(dbc.eventCount==0) {
+ dbe.ofsPrev=wParam;
+ dbe.ofsNext=0;
+ dbe.flags|=DBEF_FIRST;
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=ofsNew;
+ }
+ else {
+ dbeTest=(struct DBEvent*)DBRead(dbc.ofsFirstEvent,sizeof(struct DBEvent),NULL);
+ // Should new event be placed before first event in chain?
+ if (dbei->timestamp < dbeTest->timestamp) {
+ dbe.ofsPrev=wParam;
+ dbe.ofsNext=dbc.ofsFirstEvent;
+ dbe.flags|=DBEF_FIRST;
+ dbc.ofsFirstEvent=ofsNew;
+ dbeTest=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeTest->flags&=~DBEF_FIRST;
+ dbeTest->ofsPrev=ofsNew;
+ DBWrite(dbe.ofsNext,dbeTest,sizeof(struct DBEvent));
+ }
+ else {
+ // Loop through the chain, starting at the end
+ ofsThis = dbc.ofsLastEvent;
+ dbeTest = (struct DBEvent*)DBRead(ofsThis, sizeof(struct DBEvent), NULL);
+ for (;;) {
+ // If the new event's timesstamp is equal to or greater than the
+ // current dbevent, it will be inserted after. If not, continue
+ // with the previous dbevent in chain.
+ if (dbe.timestamp >= dbeTest->timestamp) {
+ dbe.ofsPrev = ofsThis;
+ dbe.ofsNext = dbeTest->ofsNext;
+ dbeTest->ofsNext = ofsNew;
+ DBWrite(ofsThis, dbeTest, sizeof(struct DBEvent));
+ if (dbe.ofsNext == 0)
+ dbc.ofsLastEvent = ofsNew;
+ else {
+ dbeTest = (struct DBEvent*)DBRead(dbe.ofsNext, sizeof(struct DBEvent), NULL);
+ dbeTest->ofsPrev = ofsNew;
+ DBWrite(dbe.ofsNext, dbeTest, sizeof(struct DBEvent));
+ }
+ break;
+ }
+ ofsThis = dbeTest->ofsPrev;
+ dbeTest = (struct DBEvent*)DBRead(ofsThis, sizeof(struct DBEvent), NULL);
+ }
+ }
+ }
+ dbc.eventCount++;
+ if (!(dbe.flags&(DBEF_READ|DBEF_SENT))) {
+ if(dbe.timestamp<dbc.timestampFirstUnread || dbc.timestampFirstUnread==0) {
+ dbc.timestampFirstUnread=dbe.timestamp;
+ dbc.ofsFirstUnreadEvent=ofsNew;
+ }
+ }
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBWrite(ofsNew,&dbe,offsetof(struct DBEvent,blob));
+ DBWrite(ofsNew+offsetof(struct DBEvent,blob),dbei->pBlob,dbei->cbBlob);
+ DBFlush(0);
+ LeaveCriticalSection(&csDbAccess);
+ log1("add event @ %08x",ofsNew);
+ NotifyEventHooks(hEventAddedEvent,wParam,(LPARAM)ofsNew);
+ return (INT_PTR)ofsNew;
+}
+
+static INT_PTR DeleteEvent(WPARAM wParam,LPARAM lParam)
+{
+ struct DBContact dbc;
+ DWORD ofsContact,ofsThis;
+ struct DBEvent dbe,*dbeNext,*dbePrev;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ dbe=*(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE || dbe.signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ log1("delete event @ %08x",wParam);
+ LeaveCriticalSection(&csDbAccess);
+ //call notifier while outside mutex
+ NotifyEventHooks(hEventDeletedEvent,wParam,lParam);
+ //get back in
+ EnterCriticalSection(&csDbAccess);
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ dbe=*(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ //check if this was the first unread, if so, recalc the first unread
+ if(dbc.ofsFirstUnreadEvent==(DWORD)lParam) {
+ dbeNext=&dbe;
+ for (;;) {
+ if(dbeNext->ofsNext==0) {
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ break;
+ }
+ ofsThis=dbeNext->ofsNext;
+ dbeNext=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ if (!(dbeNext->flags&(DBEF_READ|DBEF_SENT))) {
+ dbc.ofsFirstUnreadEvent=ofsThis;
+ dbc.timestampFirstUnread=dbeNext->timestamp;
+ break;
+ }
+ }
+ }
+ //get previous and next events in chain and change offsets
+ if(dbe.flags&DBEF_FIRST) {
+ if(dbe.ofsNext==0) {
+ dbc.ofsFirstEvent=dbc.ofsLastEvent=0;
+ }
+ else {
+ dbeNext=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeNext->flags|=DBEF_FIRST;
+ dbeNext->ofsPrev=dbe.ofsPrev;
+ DBWrite(dbe.ofsNext,dbeNext,sizeof(struct DBEvent));
+ dbc.ofsFirstEvent=dbe.ofsNext;
+ }
+ }
+ else {
+ if(dbe.ofsNext==0) {
+ dbePrev=(struct DBEvent*)DBRead(dbe.ofsPrev,sizeof(struct DBEvent),NULL);
+ dbePrev->ofsNext=0;
+ DBWrite(dbe.ofsPrev,dbePrev,sizeof(struct DBEvent));
+ dbc.ofsLastEvent=dbe.ofsPrev;
+ }
+ else {
+ dbePrev=(struct DBEvent*)DBRead(dbe.ofsPrev,sizeof(struct DBEvent),NULL);
+ dbePrev->ofsNext=dbe.ofsNext;
+ DBWrite(dbe.ofsPrev,dbePrev,sizeof(struct DBEvent));
+ dbeNext=(struct DBEvent*)DBRead(dbe.ofsNext,sizeof(struct DBEvent),NULL);
+ dbeNext->ofsPrev=dbe.ofsPrev;
+ DBWrite(dbe.ofsNext,dbeNext,sizeof(struct DBEvent));
+ }
+ }
+ //delete event
+ DeleteSpace(lParam,offsetof(struct DBEvent,blob)+dbe.cbBlob);
+ //decrement event count
+ dbc.eventCount--;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBFlush(0);
+ //quit
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static INT_PTR GetBlobSize(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=-1;
+ else ret=dbe->cbBlob;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR GetEvent(WPARAM wParam,LPARAM lParam)
+{
+ struct DBEvent *dbe;
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ int bytesToCopy,i;
+
+ if(dbei==NULL||dbei->cbSize!=sizeof(DBEVENTINFO)) return 1;
+ if(dbei->cbBlob > 0 && dbei->pBlob == NULL) {
+ dbei->cbBlob = 0;
+ return 1;
+ }
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbei->szModule=GetModuleNameByOfs(dbe->ofsModuleName);
+ dbei->timestamp=dbe->timestamp;
+ dbei->flags=dbe->flags;
+ dbei->eventType=dbe->eventType;
+ if(dbei->cbBlob<dbe->cbBlob) bytesToCopy=dbei->cbBlob;
+ else bytesToCopy=dbe->cbBlob;
+ dbei->cbBlob=dbe->cbBlob;
+ for(i=0;;i+=MAXCACHEDREADSIZE) {
+ if(bytesToCopy-i<=MAXCACHEDREADSIZE) {
+ CopyMemory(dbei->pBlob+i,DBRead(wParam+offsetof(struct DBEvent,blob)+i,bytesToCopy-i,NULL),bytesToCopy-i);
+ break;
+ }
+ CopyMemory(dbei->pBlob+i,DBRead(wParam+offsetof(struct DBEvent,blob)+i,MAXCACHEDREADSIZE,NULL),MAXCACHEDREADSIZE);
+ }
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static INT_PTR MarkEventRead(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBEvent *dbe;
+ struct DBContact dbc;
+ DWORD ofsThis;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=*(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ dbe=(struct DBEvent*)DBRead(lParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE || dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ if(dbe->flags&DBEF_READ || dbe->flags&DBEF_SENT) {
+ ret=(INT_PTR)dbe->flags;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+ }
+ log1("mark read @ %08x",wParam);
+ dbe->flags|=DBEF_READ;
+ DBWrite(lParam,dbe,sizeof(struct DBEvent));
+ ret=(INT_PTR)dbe->flags;
+ if(dbc.ofsFirstUnreadEvent==(DWORD)lParam) {
+ for (;;) {
+ if(dbe->ofsNext==0) {
+ dbc.ofsFirstUnreadEvent=0;
+ dbc.timestampFirstUnread=0;
+ break;
+ }
+ ofsThis=dbe->ofsNext;
+ dbe=(struct DBEvent*)DBRead(ofsThis,sizeof(struct DBEvent),NULL);
+ if (!(dbe->flags&(DBEF_READ|DBEF_SENT))) {
+ dbc.ofsFirstUnreadEvent=ofsThis;
+ dbc.timestampFirstUnread=dbe->timestamp;
+ break;
+ }
+ }
+ }
+ DBWrite(wParam,&dbc,sizeof(struct DBContact));
+ DBFlush(0);
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR GetEventContact(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ while(!(dbe->flags&DBEF_FIRST))
+ dbe=(struct DBEvent*)DBRead(dbe->ofsPrev,sizeof(struct DBEvent),NULL);
+ ret=(INT_PTR)dbe->ofsPrev;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindFirstEvent(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=0;
+ else ret=(INT_PTR)dbc->ofsFirstEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindFirstUnreadEvent(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=0;
+ else ret=(INT_PTR)dbc->ofsFirstUnreadEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindLastEvent(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBContact *dbc;
+
+ EnterCriticalSection(&csDbAccess);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) ret=0;
+ else ret=(INT_PTR)dbc->ofsLastEvent;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindNextEvent(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=0;
+ else ret=(INT_PTR)dbe->ofsNext;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+static INT_PTR FindPrevEvent(WPARAM wParam,LPARAM lParam)
+{
+ INT_PTR ret;
+ struct DBEvent *dbe;
+
+ EnterCriticalSection(&csDbAccess);
+ dbe=(struct DBEvent*)DBRead(wParam,sizeof(struct DBEvent),NULL);
+ if(dbe->signature!=DBEVENT_SIGNATURE) ret=0;
+ else if(dbe->flags&DBEF_FIRST) ret=0;
+ else ret=(INT_PTR)dbe->ofsPrev;
+ LeaveCriticalSection(&csDbAccess);
+ return ret;
+}
+
+int InitEvents(void)
+{
+ CreateServiceFunction(MS_DB_EVENT_GETCOUNT,GetEventCount);
+ CreateServiceFunction(MS_DB_EVENT_ADD,AddEvent);
+ CreateServiceFunction(MS_DB_EVENT_DELETE,DeleteEvent);
+ CreateServiceFunction(MS_DB_EVENT_GETBLOBSIZE,GetBlobSize);
+ CreateServiceFunction(MS_DB_EVENT_GET,GetEvent);
+ CreateServiceFunction(MS_DB_EVENT_MARKREAD,MarkEventRead);
+ CreateServiceFunction(MS_DB_EVENT_GETCONTACT,GetEventContact);
+ CreateServiceFunction(MS_DB_EVENT_FINDFIRST,FindFirstEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDFIRSTUNREAD,FindFirstUnreadEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDLAST,FindLastEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDNEXT,FindNextEvent);
+ CreateServiceFunction(MS_DB_EVENT_FINDPREV,FindPrevEvent);
+ hEventDeletedEvent=CreateHookableEvent(ME_DB_EVENT_DELETED);
+ hEventAddedEvent=CreateHookableEvent(ME_DB_EVENT_ADDED);
+ hEventFilterAddedEvent=CreateHookableEvent(ME_DB_EVENT_FILTER_ADD);
+ return 0;
+}
+
+void UninitEvents(void)
+{
+ DestroyHookableEvent(hEventAddedEvent); hEventAddedEvent = 0;
+ DestroyHookableEvent(hEventDeletedEvent); hEventDeletedEvent = 0;
+ DestroyHookableEvent(hEventFilterAddedEvent); hEventFilterAddedEvent = 0;
+}
diff --git a/plugins/Db3x/src/dbheaders.cpp b/plugins/Db3x/src/dbheaders.cpp
new file mode 100644
index 0000000000..8320102888
--- /dev/null
+++ b/plugins/Db3x/src/dbheaders.cpp
@@ -0,0 +1,74 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+struct DBSignature {
+ char name[15];
+ BYTE eof;
+};
+static struct DBSignature dbSignature={"Miranda ICQ DB",0x1A};
+
+//the cache has not been loaded when these functions are used
+
+int CreateDbHeaders(HANDLE hFile)
+{
+ struct DBContact user;
+ DWORD bytesWritten;
+
+ CopyMemory(dbHeader.signature,&dbSignature,sizeof(dbHeader.signature));
+ dbHeader.version=DB_THIS_VERSION;
+ dbHeader.ofsFileEnd=sizeof(struct DBHeader);
+ dbHeader.slackSpace=0;
+ dbHeader.contactCount=0;
+ dbHeader.ofsFirstContact=0;
+ dbHeader.ofsFirstModuleName=0;
+ dbHeader.ofsUser=0;
+ //create user
+ dbHeader.ofsUser=dbHeader.ofsFileEnd;
+ dbHeader.ofsFileEnd+=sizeof(struct DBContact);
+ SetFilePointer(hFile,0,NULL,FILE_BEGIN);
+ WriteFile(hFile,&dbHeader,sizeof(dbHeader),&bytesWritten,NULL);
+ user.signature=DBCONTACT_SIGNATURE;
+ user.ofsNext=0;
+ user.ofsFirstSettings=0;
+ user.eventCount=0;
+ user.ofsFirstEvent=user.ofsLastEvent=0;
+ SetFilePointer(hFile,dbHeader.ofsUser,NULL,FILE_BEGIN);
+ WriteFile(hFile,&user,sizeof(struct DBContact),&bytesWritten,NULL);
+ FlushFileBuffers(hFile);
+ return 0;
+}
+
+int CheckDbHeaders(struct DBHeader * hdr)
+{
+ if(memcmp(hdr->signature,&dbSignature,sizeof(hdr->signature))) return 1;
+ if(hdr->version!=DB_THIS_VERSION) return 2;
+ if(hdr->ofsUser==0) return 3;
+ return 0;
+}
+
+int InitialiseDbHeaders(void)
+{
+ return 0;
+}
diff --git a/plugins/Db3x/src/dbmodulechain.cpp b/plugins/Db3x/src/dbmodulechain.cpp
new file mode 100644
index 0000000000..f130937af2
--- /dev/null
+++ b/plugins/Db3x/src/dbmodulechain.cpp
@@ -0,0 +1,129 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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 INT_PTR EnumModuleNames(WPARAM wParam,LPARAM lParam);
+
+struct ModuleName {
+ char *name;
+ DWORD hash;
+ DWORD ofs;
+};
+static struct ModuleName *moduleName;
+static int moduleNameCount;
+
+int InitModuleNames(void)
+{
+ struct DBModuleName *dbmn;
+ DWORD ofsThis,ofsNext;
+ int nameLen;
+
+ moduleNameCount=0;
+ moduleName=NULL;
+ ofsThis=dbHeader.ofsFirstModuleName;
+ dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL);
+ while(ofsThis) {
+ if(dbmn->signature!=DBMODULENAME_SIGNATURE) DatabaseCorruption();
+ moduleName=(struct ModuleName*)mir_realloc(moduleName,sizeof(struct ModuleName)*(moduleNameCount+1));
+ moduleName[moduleNameCount].ofs=ofsThis;
+ moduleName[moduleNameCount].hash=dbmn->cbName; //very very simple hash so far
+ moduleName[moduleNameCount].name=(char*)mir_alloc(dbmn->cbName+1);
+ ofsNext=dbmn->ofsNext;
+ nameLen=dbmn->cbName;
+ CopyMemory(moduleName[moduleNameCount].name,DBRead(ofsThis+offsetof(struct DBModuleName,name),nameLen,NULL),nameLen);
+ moduleName[moduleNameCount].name[nameLen]=0;
+ moduleNameCount++;
+ ofsThis=ofsNext;
+ dbmn=(struct DBModuleName*)DBRead(ofsThis,sizeof(struct DBModuleName),NULL);
+ }
+ CreateServiceFunction(MS_DB_MODULES_ENUM,EnumModuleNames);
+ return 0;
+}
+
+void UninitModuleNames(void)
+{
+ int i;
+ for(i=0;i<moduleNameCount;i++) mir_free(moduleName[i].name);
+ if(moduleNameCount) mir_free(moduleName);
+}
+
+static DWORD FindExistingModuleNameOfs(const char *szName,int nameLen)
+{
+ int i;
+ for(i=0;i<moduleNameCount;i++)
+ if(moduleName[i].hash==(DWORD)nameLen && !strcmp(moduleName[i].name,szName)) return moduleName[i].ofs;
+ return 0;
+}
+
+//will create the offset if it needs to
+DWORD GetModuleNameOfs(const char *szName)
+{
+ struct DBModuleName dbmn;
+ int nameLen=(int)strlen(szName);
+ DWORD ofsNew,ofsExisting;
+
+ ofsExisting=FindExistingModuleNameOfs(szName,nameLen);
+ if(ofsExisting) return ofsExisting;
+ //need to create the module name
+ ofsNew=CreateNewSpace(nameLen+offsetof(struct DBModuleName,name));
+ dbmn.signature=DBMODULENAME_SIGNATURE;
+ dbmn.cbName=nameLen;
+ dbmn.ofsNext=dbHeader.ofsFirstModuleName;
+ dbHeader.ofsFirstModuleName=ofsNew;
+ DBWrite(0,&dbHeader,sizeof(dbHeader));
+ DBWrite(ofsNew,&dbmn,offsetof(struct DBModuleName,name));
+ DBWrite(ofsNew+offsetof(struct DBModuleName,name),(PVOID)szName,nameLen);
+ DBFlush(0);
+ //add to cache
+ moduleName=(struct ModuleName*)mir_realloc(moduleName,sizeof(struct ModuleName)*(moduleNameCount+1));
+ moduleName[moduleNameCount].ofs=ofsNew;
+ moduleName[moduleNameCount].hash=nameLen; //very very simple hash so far
+ moduleName[moduleNameCount].name=(char*)mir_alloc(nameLen+1);
+ strcpy(moduleName[moduleNameCount].name,szName);
+ moduleNameCount++;
+ //quit
+ return ofsNew;
+}
+
+//it's OK that this is a bit slow - it's rarely used
+char *GetModuleNameByOfs(DWORD ofs)
+{
+ int i;
+
+ for(i=0;i<moduleNameCount;i++)
+ if(moduleName[i].ofs==ofs) return moduleName[i].name;
+ DatabaseCorruption();
+ return NULL;
+}
+
+static INT_PTR EnumModuleNames(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ INT_PTR ret;
+ for(i=0;i<moduleNameCount;i++) {
+ ret=((DBMODULEENUMPROC)lParam)(moduleName[i].name,moduleName[i].ofs,wParam);
+ if (ret) return ret;
+ }
+ return 0;
+}
diff --git a/plugins/Db3x/src/dbsettings.cpp b/plugins/Db3x/src/dbsettings.cpp
new file mode 100644
index 0000000000..209b7a13ab
--- /dev/null
+++ b/plugins/Db3x/src/dbsettings.cpp
@@ -0,0 +1,975 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+DWORD GetModuleNameOfs(const char *szName);
+
+HANDLE hCacheHeap = NULL;
+SortedList lContacts;
+
+static SortedList lSettings, lGlobalSettings;
+static HANDLE hSettingChangeEvent = NULL;
+
+#define SETTINGSGROUPOFSCOUNT 32
+struct SettingsGroupOfsCacheEntry {
+ DWORD ofsContact;
+ DWORD ofsModuleName;
+ DWORD ofsSettingsGroup;
+};
+static struct SettingsGroupOfsCacheEntry settingsGroupOfsCache[SETTINGSGROUPOFSCOUNT];
+static int nextSGOCacheEntry;
+static int mirCp = CP_ACP;
+
+//this function caches results
+static DWORD GetSettingsGroupOfsByModuleNameOfs(struct DBContact *dbc,DWORD ofsContact,DWORD ofsModuleName)
+{
+ struct DBContactSettings *dbcs;
+ DWORD ofsThis;
+ int i;
+
+ for(i=0;i<SETTINGSGROUPOFSCOUNT;i++) {
+ if(settingsGroupOfsCache[i].ofsContact==ofsContact && settingsGroupOfsCache[i].ofsModuleName==ofsModuleName)
+ return settingsGroupOfsCache[i].ofsSettingsGroup;
+ }
+ ofsThis=dbc->ofsFirstSettings;
+ while(ofsThis) {
+ dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL);
+ if(dbcs->signature!=DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption();
+ if(dbcs->ofsModuleName==ofsModuleName) {
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsContact=ofsContact;
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsModuleName=ofsModuleName;
+ settingsGroupOfsCache[nextSGOCacheEntry].ofsSettingsGroup=ofsThis;
+ if (++nextSGOCacheEntry==SETTINGSGROUPOFSCOUNT) nextSGOCacheEntry=0;
+ return ofsThis;
+ }
+ ofsThis=dbcs->ofsNext;
+ }
+ return 0;
+}
+
+static void InvalidateSettingsGroupOfsCacheEntry(DWORD ofsSettingsGroup)
+{
+ int i;
+
+ for(i=0;i<SETTINGSGROUPOFSCOUNT;i++) {
+ if(settingsGroupOfsCache[i].ofsSettingsGroup==ofsSettingsGroup) {
+ settingsGroupOfsCache[i].ofsContact=0;
+ settingsGroupOfsCache[i].ofsModuleName=0;
+ settingsGroupOfsCache[i].ofsSettingsGroup=0;
+ break;
+} } }
+
+static DWORD __inline GetSettingValueLength(PBYTE pSetting)
+{
+ if(pSetting[0]&DBVTF_VARIABLELENGTH) return 2+*(PWORD)(pSetting+1);
+ return pSetting[0];
+}
+
+static char* InsertCachedSetting( const char* szName, size_t cbNameLen, int index )
+{
+ char* newValue = (char*)HeapAlloc( hCacheHeap, 0, cbNameLen );
+ *newValue = 0;
+ strcpy(newValue+1,szName+1);
+ List_Insert(&lSettings,newValue,index);
+ return newValue;
+}
+
+static char* GetCachedSetting(const char *szModuleName,const char *szSettingName,int settingNameLen)
+{
+ static char *lastsetting = NULL;
+ int moduleNameLen = (int)strlen(szModuleName),index;
+ char *szFullName = (char*)alloca(moduleNameLen+settingNameLen+3);
+
+ strcpy(szFullName+1,szModuleName);
+ szFullName[moduleNameLen+1]='/';
+ strcpy(szFullName+moduleNameLen+2,szSettingName);
+
+ if (lastsetting && strcmp(szFullName+1,lastsetting) == 0)
+ return lastsetting;
+
+ if ( List_GetIndex(&lSettings, szFullName, &index))
+ lastsetting = (char*)lSettings.items[index] + 1;
+ else
+ lastsetting = InsertCachedSetting( szFullName, moduleNameLen+settingNameLen+3, index )+1;
+ return lastsetting;
+}
+
+static void SetCachedVariant( DBVARIANT* s /* new */, DBVARIANT* d /* cached */ )
+{
+ char* szSave = ( d->type == DBVT_UTF8 || d->type == DBVT_ASCIIZ ) ? d->pszVal : NULL;
+
+ memcpy( d, s, sizeof( DBVARIANT ));
+ if (( s->type == DBVT_UTF8 || s->type == DBVT_ASCIIZ ) && s->pszVal != NULL ) {
+ if ( szSave != NULL )
+ d->pszVal = (char*)HeapReAlloc(hCacheHeap,0,szSave,strlen(s->pszVal)+1);
+ else
+ d->pszVal = (char*)HeapAlloc(hCacheHeap,0,strlen(s->pszVal)+1);
+ strcpy(d->pszVal,s->pszVal);
+ }
+
+ switch( d->type ) {
+ case DBVT_BYTE: log1( "set cached byte: %d", d->bVal ); break;
+ case DBVT_WORD: log1( "set cached word: %d", d->wVal ); break;
+ case DBVT_DWORD: log1( "set cached dword: %d", d->dVal ); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: log1( "set cached string: '%s'", d->pszVal ); break;
+ default: log1( "set cached crap: %d", d->type ); break;
+} }
+
+static void FreeCachedVariant( DBVARIANT* V )
+{
+ if (( V->type == DBVT_ASCIIZ || V->type == DBVT_UTF8 ) && V->pszVal != NULL )
+ HeapFree(hCacheHeap,0,V->pszVal);
+}
+
+static DBVARIANT* GetCachedValuePtr( HANDLE hContact, char* szSetting, int bAllocate )
+{
+ int index;
+
+ if ( hContact == 0 ) {
+ DBCachedGlobalValue Vtemp, *V;
+ Vtemp.name = szSetting;
+ if ( List_GetIndex(&lGlobalSettings,&Vtemp,&index)) {
+ V = (DBCachedGlobalValue*)lGlobalSettings.items[index];
+ if ( bAllocate == -1 ) {
+ FreeCachedVariant( &V->value );
+ List_Remove(&lGlobalSettings,index);
+ HeapFree(hCacheHeap,0,V);
+ return NULL;
+ } }
+ else {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ V = (DBCachedGlobalValue*)HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedGlobalValue));
+ V->name = szSetting;
+ List_Insert(&lGlobalSettings,V,index);
+ }
+
+ return &V->value;
+ }
+ else {
+ DBCachedContactValue *V, *V1;
+ DBCachedContactValueList VLtemp,*VL;
+
+ VLtemp.hContact=hContact;
+ if ( List_GetIndex(&lContacts,&VLtemp,&index)) {
+ VL = (DBCachedContactValueList*)lContacts.items[index];
+ }
+ else {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ VL = (DBCachedContactValueList*)HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValueList));
+ VL->hContact = hContact;
+ List_Insert(&lContacts,VL,index);
+ }
+
+ for ( V = VL->first; V != NULL; V = V->next)
+ if (strcmp(V->name,szSetting)==0)
+ break;
+
+ if ( V == NULL ) {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ V = (DBCachedContactValue *)HeapAlloc(hCacheHeap, HEAP_ZERO_MEMORY, sizeof(DBCachedContactValue));
+ V->next = VL->first;
+ VL->first = V;
+ V->name = szSetting;
+ }
+ else if ( bAllocate == -1 ) {
+ FreeCachedVariant(&V->value);
+ if ( VL->first == V )
+ VL->first = V->next;
+ for ( V1=VL->first; V1 != NULL; V1 = V1->next )
+ if ( V1->next == V ) {
+ V1->next = V->next;
+ break;
+ }
+ HeapFree(hCacheHeap,0,V);
+ return NULL;
+ }
+
+ return &V->value;
+} }
+
+#define NeedBytes(n) if(bytesRemaining<(n)) pBlob=(PBYTE)DBRead(ofsBlobPtr,(n),&bytesRemaining)
+#define MoveAlong(n) {int x=n; pBlob+=(x); ofsBlobPtr+=(x); bytesRemaining-=(x);}
+#define VLT(n) ((n==DBVT_UTF8)?DBVT_ASCIIZ:n)
+static __inline int GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs,int isStatic)
+{
+ struct DBContact dbc;
+ struct DBContactSettings dbcs;
+ DWORD ofsModuleName,ofsContact,ofsSettingsGroup,ofsBlobPtr;
+ int settingNameLen;
+ int bytesRemaining;
+ PBYTE pBlob;
+ char* szCachedSettingName;
+
+ if ((!dbcgs->szSetting) || (!dbcgs->szModule))
+ return 1;
+ settingNameLen=(int)strlen(dbcgs->szSetting);
+
+ EnterCriticalSection(&csDbAccess);
+
+ log3("get [%08p] %s/%s",hContact,dbcgs->szModule,dbcgs->szSetting);
+
+ szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,settingNameLen);
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 0 );
+ if ( pCachedValue != NULL ) {
+ if ( pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8 ) {
+ int cbOrigLen = dbcgs->pValue->cchVal;
+ char* cbOrigPtr = dbcgs->pValue->pszVal;
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+ if ( isStatic ) {
+ int cbLen = 0;
+ if ( pCachedValue->pszVal != NULL )
+ cbLen = (int)strlen( pCachedValue->pszVal );
+
+ cbOrigLen--;
+ dbcgs->pValue->pszVal = cbOrigPtr;
+ if(cbLen<cbOrigLen) cbOrigLen=cbLen;
+ CopyMemory(dbcgs->pValue->pszVal,pCachedValue->pszVal,cbOrigLen);
+ dbcgs->pValue->pszVal[cbOrigLen]=0;
+ dbcgs->pValue->cchVal=cbLen;
+ }
+ else {
+ dbcgs->pValue->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal)+1);
+ strcpy(dbcgs->pValue->pszVal,pCachedValue->pszVal);
+ }
+ }
+ else
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+
+ switch( dbcgs->pValue->type ) {
+ case DBVT_BYTE: log1( "get cached byte: %d", dbcgs->pValue->bVal ); break;
+ case DBVT_WORD: log1( "get cached word: %d", dbcgs->pValue->wVal ); break;
+ case DBVT_DWORD: log1( "get cached dword: %d", dbcgs->pValue->dVal ); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: log1( "get cached string: '%s'", dbcgs->pValue->pszVal); break;
+ default: log1( "get cached crap: %d", dbcgs->pValue->type ); break;
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ return ( pCachedValue->type == DBVT_DELETED ) ? 1 : 0;
+ } }
+
+ ofsModuleName=GetModuleNameOfs(dbcgs->szModule);
+ if(hContact==NULL) ofsContact=dbHeader.ofsUser;
+ else ofsContact=(DWORD)hContact;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if(ofsSettingsGroup) {
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),&bytesRemaining);
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(1+settingNameLen);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcgs->szSetting,settingNameLen)) {
+ MoveAlong(1+settingNameLen);
+ NeedBytes(5);
+ if(isStatic && pBlob[0]&DBVTF_VARIABLELENGTH && VLT(dbcgs->pValue->type) != VLT(pBlob[0])) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbcgs->pValue->type=pBlob[0];
+ switch(pBlob[0]) {
+ case DBVT_DELETED: { /* this setting is deleted */
+ dbcgs->pValue->type=DBVT_DELETED;
+ LeaveCriticalSection(&csDbAccess);
+ return 2;
+ }
+ case DBVT_BYTE: dbcgs->pValue->bVal=pBlob[1]; break;
+ case DBVT_WORD: dbcgs->pValue->wVal=*(PWORD)(pBlob+1); break;
+ case DBVT_DWORD: dbcgs->pValue->dVal=*(PDWORD)(pBlob+1); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ dbcgs->pValue->cchVal--;
+ if (*(PWORD)(pBlob+1)<dbcgs->pValue->cchVal) dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[dbcgs->pValue->cchVal]=0;
+ dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ }
+ else {
+ dbcgs->pValue->pszVal=(char*)mir_alloc(1+*(PWORD)(pBlob+1));
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,*(PWORD)(pBlob+1));
+ dbcgs->pValue->pszVal[*(PWORD)(pBlob+1)]=0;
+ }
+ break;
+ case DBVT_BLOB:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ if (*(PWORD)(pBlob+1)<dbcgs->pValue->cpbVal) dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pbVal,pBlob+3,dbcgs->pValue->cpbVal);
+ }
+ else {
+ dbcgs->pValue->pbVal = (BYTE *)mir_alloc(*(PWORD)(pBlob + 1));
+ CopyMemory(dbcgs->pValue->pbVal,pBlob+3,*(PWORD)(pBlob+1));
+ }
+ dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1);
+ break;
+ }
+
+ /**** add to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB )
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ SetCachedVariant(dbcgs->pValue,pCachedValue);
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ logg();
+ return 0;
+ }
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ } }
+
+ /**** add missing setting to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB )
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ pCachedValue->type = DBVT_DELETED;
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ logg();
+ return 1;
+}
+
+static INT_PTR GetContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = ( DBCONTACTGETSETTING* )lParam;
+ dgs->pValue->type = 0;
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 0 ))
+ return 1;
+
+ if ( dgs->pValue->type == DBVT_UTF8 ) {
+ WCHAR* tmp = NULL;
+ char* p = NEWSTR_ALLOCA(dgs->pValue->pszVal);
+ if ( mir_utf8decode( p, &tmp ) != NULL ) {
+ BOOL bUsed = FALSE;
+ int result = WideCharToMultiByte( mirCp, WC_NO_BEST_FIT_CHARS, tmp, -1, NULL, 0, NULL, &bUsed );
+
+ mir_free( dgs->pValue->pszVal );
+
+ if ( bUsed || result == 0 ) {
+ dgs->pValue->type = DBVT_WCHAR;
+ dgs->pValue->pwszVal = tmp;
+ }
+ else {
+ dgs->pValue->type = DBVT_ASCIIZ;
+ dgs->pValue->pszVal = (char *)mir_alloc(result);
+ WideCharToMultiByte( mirCp, WC_NO_BEST_FIT_CHARS, tmp, -1, dgs->pValue->pszVal, result, NULL, NULL );
+ mir_free( tmp );
+ }
+ }
+ else {
+ dgs->pValue->type = DBVT_ASCIIZ;
+ mir_free( tmp );
+ } }
+
+ return 0;
+}
+
+static INT_PTR GetContactSettingStr(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = (DBCONTACTGETSETTING*)lParam;
+ int iSaveType = dgs->pValue->type;
+
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 0 ))
+ return 1;
+
+ if ( iSaveType == 0 || iSaveType == dgs->pValue->type )
+ return 0;
+
+ if ( dgs->pValue->type != DBVT_ASCIIZ && dgs->pValue->type != DBVT_UTF8 )
+ return 1;
+
+ if ( iSaveType == DBVT_WCHAR ) {
+ if ( dgs->pValue->type != DBVT_UTF8 ) {
+ int len = MultiByteToWideChar( CP_ACP, 0, dgs->pValue->pszVal, -1, NULL, 0 );
+ wchar_t* wszResult = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ if ( wszResult == NULL )
+ return 1;
+
+ MultiByteToWideChar( CP_ACP, 0, dgs->pValue->pszVal, -1, wszResult, len );
+ wszResult[ len ] = 0;
+ mir_free( dgs->pValue->pszVal );
+ dgs->pValue->pwszVal = wszResult;
+ }
+ else {
+ char* savePtr = NEWSTR_ALLOCA(dgs->pValue->pszVal);
+ mir_free( dgs->pValue->pszVal );
+ if ( !mir_utf8decode( savePtr, &dgs->pValue->pwszVal ))
+ return 1;
+ }
+ }
+ else if ( iSaveType == DBVT_UTF8 ) {
+ char* tmpBuf = mir_utf8encode( dgs->pValue->pszVal );
+ if ( tmpBuf == NULL )
+ return 1;
+
+ mir_free( dgs->pValue->pszVal );
+ dgs->pValue->pszVal = tmpBuf;
+ }
+ else if ( iSaveType == DBVT_ASCIIZ )
+ mir_utf8decode( dgs->pValue->pszVal, NULL );
+
+ dgs->pValue->type = iSaveType;
+ return 0;
+}
+
+INT_PTR GetContactSettingStatic(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING* dgs = (DBCONTACTGETSETTING*)lParam;
+ if ( GetContactSettingWorker(( HANDLE )wParam, dgs, 1 ))
+ return 1;
+
+ if ( dgs->pValue->type == DBVT_UTF8 ) {
+ mir_utf8decode( dgs->pValue->pszVal, NULL );
+ dgs->pValue->type = DBVT_ASCIIZ;
+ }
+
+ return 0;
+}
+
+static INT_PTR FreeVariant(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT *dbv=(DBVARIANT*)lParam;
+ if ( dbv == 0 ) return 1;
+ switch ( dbv->type ) {
+ case DBVT_ASCIIZ:
+ case DBVT_UTF8:
+ case DBVT_WCHAR:
+ {
+ if ( dbv->pszVal ) mir_free(dbv->pszVal);
+ dbv->pszVal=0;
+ break;
+ }
+ case DBVT_BLOB:
+ {
+ if ( dbv->pbVal ) mir_free(dbv->pbVal);
+ dbv->pbVal=0;
+ break;
+ }
+ }
+ dbv->type=0;
+ return 0;
+}
+
+static INT_PTR SetSettingResident(WPARAM wParam,LPARAM lParam)
+{
+ char* szSetting;
+ size_t cbSettingNameLen = strlen(( char* )lParam );
+ int idx;
+ char* szTemp = ( char* )alloca( cbSettingNameLen+2 );
+ strcpy( szTemp+1, ( char* )lParam );
+
+ EnterCriticalSection(&csDbAccess);
+ if ( !List_GetIndex( &lSettings, szTemp, &idx ))
+ szSetting = InsertCachedSetting( szTemp, cbSettingNameLen+2, idx );
+ else
+ szSetting = (char *)lSettings.items[idx];
+
+ *szSetting = (char)wParam;
+
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+}
+
+static INT_PTR WriteContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *dbcws=(DBCONTACTWRITESETTING*)lParam;
+ DBCONTACTWRITESETTING tmp;
+ struct DBContact dbc;
+ DWORD ofsModuleName;
+ struct DBContactSettings dbcs;
+ PBYTE pBlob;
+ int settingNameLen=0;
+ int moduleNameLen=0;
+ int settingDataLen=0;
+ int bytesRequired,bytesRemaining;
+ DWORD ofsContact,ofsSettingsGroup,ofsBlobPtr;
+
+ if (dbcws == NULL || dbcws->szSetting==NULL || dbcws->szModule==NULL )
+ return 1;
+
+ tmp = *dbcws;
+ if (tmp.value.type == DBVT_WCHAR) {
+ if (tmp.value.pszVal != NULL) {
+ char* val = mir_utf8encodeW(tmp.value.pwszVal);
+ if ( val == NULL )
+ return 1;
+
+ tmp.value.pszVal = ( char* )alloca( strlen( val )+1 );
+ strcpy( tmp.value.pszVal, val );
+ mir_free(val);
+ tmp.value.type = DBVT_UTF8;
+ }
+ else return 1;
+ }
+
+ if(tmp.value.type!=DBVT_BYTE && tmp.value.type!=DBVT_WORD && tmp.value.type!=DBVT_DWORD && tmp.value.type!=DBVT_ASCIIZ && tmp.value.type!=DBVT_UTF8 && tmp.value.type!=DBVT_BLOB)
+ return 1;
+ if ((!tmp.szModule) || (!tmp.szSetting) || ((tmp.value.type == DBVT_ASCIIZ || tmp.value.type == DBVT_UTF8 )&& tmp.value.pszVal == NULL) || (tmp.value.type == DBVT_BLOB && tmp.value.pbVal == NULL))
+ return 1;
+ // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
+ settingNameLen=(int)strlen(tmp.szSetting);
+ moduleNameLen=(int)strlen(tmp.szModule);
+ if ( settingNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugString(_T("WriteContactSetting() got a > 255 setting name length. \n"));
+ #endif
+ return 1;
+ }
+ if ( moduleNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugString(_T("WriteContactSetting() got a > 255 module name length. \n"));
+ #endif
+ return 1;
+ }
+
+ // the db can not tolerate strings/blobs longer than 0xFFFF since the format writes 2 lengths
+ switch( tmp.value.type ) {
+ case DBVT_ASCIIZ: case DBVT_BLOB: case DBVT_UTF8:
+ { int len = ( tmp.value.type != DBVT_BLOB ) ? (int)strlen(tmp.value.pszVal) : tmp.value.cpbVal;
+ if ( len >= 0xFFFF ) {
+ #ifdef _DEBUG
+ OutputDebugString(_T("WriteContactSetting() writing huge string/blob, rejecting ( >= 0xFFFF ) \n"));
+ #endif
+ return 1;
+ }
+ }
+ }
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ char* szCachedSettingName = GetCachedSetting(tmp.szModule, tmp.szSetting, settingNameLen);
+ if ( tmp.value.type != DBVT_BLOB ) {
+ DBVARIANT* pCachedValue = GetCachedValuePtr((HANDLE)wParam, szCachedSettingName, 1);
+ if ( pCachedValue != NULL ) {
+ BOOL bIsIdentical = FALSE;
+ if ( pCachedValue->type == tmp.value.type ) {
+ switch(tmp.value.type) {
+ case DBVT_BYTE: bIsIdentical = pCachedValue->bVal == tmp.value.bVal; break;
+ case DBVT_WORD: bIsIdentical = pCachedValue->wVal == tmp.value.wVal; break;
+ case DBVT_DWORD: bIsIdentical = pCachedValue->dVal == tmp.value.dVal; break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: bIsIdentical = strcmp( pCachedValue->pszVal, tmp.value.pszVal ) == 0; break;
+ }
+ if ( bIsIdentical ) {
+ LeaveCriticalSection(&csDbAccess);
+ return 0;
+ }
+ }
+ SetCachedVariant(&tmp.value, pCachedValue);
+ }
+ if ( szCachedSettingName[-1] != 0 ) {
+ LeaveCriticalSection(&csDbAccess);
+ NotifyEventHooks(hSettingChangeEvent,wParam,(LPARAM)&tmp);
+ return 0;
+ }
+ }
+ else GetCachedValuePtr((HANDLE)wParam, szCachedSettingName, -1);
+ }
+
+ ofsModuleName=GetModuleNameOfs(tmp.szModule);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ log0("write setting");
+ //make sure the module group exists
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if(ofsSettingsGroup==0) { //module group didn't exist - make it
+ if(tmp.value.type&DBVTF_VARIABLELENGTH) {
+ if(tmp.value.type==DBVT_ASCIIZ || tmp.value.type==DBVT_UTF8) bytesRequired=(int)strlen(tmp.value.pszVal)+2;
+ else if(tmp.value.type==DBVT_BLOB) bytesRequired=tmp.value.cpbVal+2;
+ }
+ else bytesRequired=tmp.value.type;
+ bytesRequired+=2+settingNameLen;
+ bytesRequired+=(DB_SETTINGS_RESIZE_GRANULARITY-(bytesRequired%DB_SETTINGS_RESIZE_GRANULARITY))%DB_SETTINGS_RESIZE_GRANULARITY;
+ ofsSettingsGroup=CreateNewSpace(bytesRequired+offsetof(struct DBContactSettings,blob));
+ dbcs.signature=DBCONTACTSETTINGS_SIGNATURE;
+ dbcs.ofsNext=dbc.ofsFirstSettings;
+ dbcs.ofsModuleName=ofsModuleName;
+ dbcs.cbBlob=bytesRequired;
+ dbcs.blob[0]=0;
+ dbc.ofsFirstSettings=ofsSettingsGroup;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ DBWrite(ofsSettingsGroup,&dbcs,sizeof(struct DBContactSettings));
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ else {
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),&bytesRemaining);
+ //find if the setting exists
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(settingNameLen+1);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,tmp.szSetting,settingNameLen))
+ break;
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ if(pBlob[0]) { //setting already existed, and up to end of name is in cache
+ MoveAlong(1+settingNameLen);
+ //if different type or variable length and length is different
+ NeedBytes(3);
+ if(pBlob[0]!=tmp.value.type || ((pBlob[0]==DBVT_ASCIIZ || pBlob[0]==DBVT_UTF8) && *(PWORD)(pBlob+1)!=strlen(tmp.value.pszVal)) || (pBlob[0]==DBVT_BLOB && *(PWORD)(pBlob+1)!=tmp.value.cpbVal)) {
+ //bin it
+ int nameLen,valLen;
+ DWORD ofsSettingToCut;
+ NeedBytes(3);
+ nameLen=1+settingNameLen;
+ valLen=1+GetSettingValueLength(pBlob);
+ ofsSettingToCut=ofsBlobPtr-nameLen;
+ MoveAlong(valLen);
+ NeedBytes(1);
+ while(pBlob[0]) {
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ DBMoveChunk(ofsSettingToCut,ofsSettingToCut+nameLen+valLen,ofsBlobPtr+1-ofsSettingToCut);
+ ofsBlobPtr-=nameLen+valLen;
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ else {
+ //replace existing setting at pBlob
+ MoveAlong(1); //skip data type
+ switch(tmp.value.type) {
+ case DBVT_BYTE: DBWrite(ofsBlobPtr,&tmp.value.bVal,1); break;
+ case DBVT_WORD: DBWrite(ofsBlobPtr,&tmp.value.wVal,2); break;
+ case DBVT_DWORD: DBWrite(ofsBlobPtr,&tmp.value.dVal,4); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: DBWrite(ofsBlobPtr+2,tmp.value.pszVal,(int)strlen(tmp.value.pszVal)); break;
+ case DBVT_BLOB: DBWrite(ofsBlobPtr+2,tmp.value.pbVal,tmp.value.cpbVal); break;
+ }
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ //notify
+ NotifyEventHooks(hSettingChangeEvent,wParam,(LPARAM)&tmp);
+ return 0;
+ }
+ }
+ }
+ //cannot do a simple replace, add setting to end of list
+ //pBlob already points to end of list
+ //see if it fits
+ if(tmp.value.type&DBVTF_VARIABLELENGTH) {
+ if(tmp.value.type==DBVT_ASCIIZ || tmp.value.type==DBVT_UTF8) bytesRequired=(int)strlen(tmp.value.pszVal)+2;
+ else if(tmp.value.type==DBVT_BLOB) bytesRequired=tmp.value.cpbVal+2;
+ }
+ else bytesRequired=tmp.value.type;
+ bytesRequired+=2+settingNameLen;
+ bytesRequired+=ofsBlobPtr+1-(ofsSettingsGroup+offsetof(struct DBContactSettings,blob));
+ if ((DWORD)bytesRequired>dbcs.cbBlob) {
+ //doesn't fit: move entire group
+ struct DBContactSettings *dbcsPrev;
+ DWORD ofsDbcsPrev,oldSize,ofsNew;
+
+ InvalidateSettingsGroupOfsCacheEntry(ofsSettingsGroup);
+ bytesRequired+=(DB_SETTINGS_RESIZE_GRANULARITY-(bytesRequired%DB_SETTINGS_RESIZE_GRANULARITY))%DB_SETTINGS_RESIZE_GRANULARITY;
+ //find previous group to change its offset
+ ofsDbcsPrev=dbc.ofsFirstSettings;
+ if(ofsDbcsPrev==ofsSettingsGroup) ofsDbcsPrev=0;
+ else {
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ while(dbcsPrev->ofsNext!=ofsSettingsGroup) {
+ if(dbcsPrev->ofsNext==0) DatabaseCorruption();
+ ofsDbcsPrev=dbcsPrev->ofsNext;
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ }
+ }
+ //create the new one
+ ofsNew=CreateNewSpace(bytesRequired+offsetof(struct DBContactSettings,blob));
+ //copy across
+ DBMoveChunk(ofsNew,ofsSettingsGroup,bytesRequired+offsetof(struct DBContactSettings,blob));
+ oldSize=dbcs.cbBlob;
+ dbcs.cbBlob=bytesRequired;
+ DBWrite(ofsNew,&dbcs,offsetof(struct DBContactSettings,blob));
+ if(ofsDbcsPrev==0) {
+ dbc.ofsFirstSettings=ofsNew;
+ DBWrite(ofsContact,&dbc,sizeof(struct DBContact));
+ }
+ else {
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ dbcsPrev->ofsNext=ofsNew;
+ DBWrite(ofsDbcsPrev,dbcsPrev,offsetof(struct DBContactSettings,blob));
+ }
+ DeleteSpace(ofsSettingsGroup,oldSize+offsetof(struct DBContactSettings,blob));
+ ofsBlobPtr+=ofsNew-ofsSettingsGroup;
+ ofsSettingsGroup=ofsNew;
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ //we now have a place to put it and enough space: make it
+ DBWrite(ofsBlobPtr,&settingNameLen,1);
+ DBWrite(ofsBlobPtr+1,(PVOID)tmp.szSetting,settingNameLen);
+ MoveAlong(1+settingNameLen);
+ DBWrite(ofsBlobPtr,&tmp.value.type,1);
+ MoveAlong(1);
+ switch(tmp.value.type) {
+ case DBVT_BYTE: DBWrite(ofsBlobPtr,&tmp.value.bVal,1); MoveAlong(1); break;
+ case DBVT_WORD: DBWrite(ofsBlobPtr,&tmp.value.wVal,2); MoveAlong(2); break;
+ case DBVT_DWORD: DBWrite(ofsBlobPtr,&tmp.value.dVal,4); MoveAlong(4); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ:
+ { int len=(int)strlen(tmp.value.pszVal);
+ DBWrite(ofsBlobPtr,&len,2);
+ DBWrite(ofsBlobPtr+2,tmp.value.pszVal,len);
+ MoveAlong(2+len);
+ }
+ break;
+ case DBVT_BLOB:
+ DBWrite(ofsBlobPtr,&tmp.value.cpbVal,2);
+ DBWrite(ofsBlobPtr+2,tmp.value.pbVal,tmp.value.cpbVal);
+ MoveAlong(2+tmp.value.cpbVal);
+ break;
+ }
+ { BYTE zero=0;
+ DBWrite(ofsBlobPtr,&zero,1);
+ }
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ //notify
+ NotifyEventHooks(hSettingChangeEvent, wParam, (LPARAM)&tmp);
+ return 0;
+}
+
+static INT_PTR DeleteContactSetting(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTGETSETTING *dbcgs=(DBCONTACTGETSETTING*)lParam;
+ struct DBContact *dbc;
+ DWORD ofsModuleName,ofsSettingsGroup,ofsBlobPtr;
+ struct DBContactSettings dbcs;
+ PBYTE pBlob;
+ int settingNameLen=(int)strlen(dbcgs->szSetting),bytesRemaining;
+ char* szCachedSettingName;
+ WPARAM saveWparam = wParam;
+
+ if ((!dbcgs->szModule) || (!dbcgs->szSetting))
+ return 1;
+
+ EnterCriticalSection(&csDbAccess);
+ ofsModuleName=GetModuleNameOfs(dbcgs->szModule);
+ if(wParam==0) wParam=dbHeader.ofsUser;
+
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ //make sure the module group exists
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(dbc,wParam,ofsModuleName);
+ if(ofsSettingsGroup==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbc=(struct DBContact*)DBRead(wParam,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(dbc,wParam,ofsModuleName);
+ if(ofsSettingsGroup==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbcs=*(struct DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(struct DBContactSettings),NULL);
+ //find if the setting exists
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(settingNameLen+1);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcgs->szSetting,settingNameLen))
+ break;
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ if (!pBlob[0]) { //setting didn't exist
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ { //bin it
+ int nameLen,valLen;
+ DWORD ofsSettingToCut;
+ MoveAlong(1+settingNameLen);
+ NeedBytes(3);
+ nameLen=1+settingNameLen;
+ valLen=1+GetSettingValueLength(pBlob);
+ ofsSettingToCut=ofsBlobPtr-nameLen;
+ MoveAlong(valLen);
+ NeedBytes(1);
+ while(pBlob[0]) {
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ DBMoveChunk(ofsSettingToCut,ofsSettingToCut+nameLen+valLen,ofsBlobPtr+1-ofsSettingToCut);
+ }
+
+ szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,settingNameLen);
+ GetCachedValuePtr((HANDLE)saveWparam, szCachedSettingName, -1 );
+
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ { //notify
+ DBCONTACTWRITESETTING dbcws;
+ dbcws.szModule=dbcgs->szModule;
+ dbcws.szSetting=dbcgs->szSetting;
+ dbcws.value.type=DBVT_DELETED;
+ NotifyEventHooks(hSettingChangeEvent,saveWparam,(LPARAM)&dbcws);
+ }
+ return 0;
+}
+
+static INT_PTR EnumContactSettings(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTENUMSETTINGS *dbces=(DBCONTACTENUMSETTINGS*)lParam;
+ struct DBContact dbc;
+ struct DBContactSettings dbcs;
+ DWORD ofsModuleName,ofsContact,ofsBlobPtr;
+ int bytesRemaining, result;
+ PBYTE pBlob;
+ char szSetting[256];
+
+ if (!dbces->szModule)
+ return -1;
+
+ EnterCriticalSection(&csDbAccess);
+
+ ofsModuleName=GetModuleNameOfs(dbces->szModule);
+ if(wParam==0) ofsContact=dbHeader.ofsUser;
+ else ofsContact=wParam;
+ dbc=*(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc.signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ dbces->ofsSettings=GetSettingsGroupOfsByModuleNameOfs(&dbc,ofsContact,ofsModuleName);
+ if (!dbces->ofsSettings) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ dbcs=*(struct DBContactSettings*)DBRead(dbces->ofsSettings,sizeof(struct DBContactSettings),&bytesRemaining);
+ ofsBlobPtr=dbces->ofsSettings+offsetof(struct DBContactSettings,blob);
+ pBlob=(PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ if(pBlob[0]==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ result = 0;
+ while(pBlob[0]) {
+ NeedBytes(1);
+ NeedBytes(1+pBlob[0]);
+ CopyMemory(szSetting,pBlob+1,pBlob[0]); szSetting[pBlob[0]]=0;
+ result = (dbces->pfnEnumProc)(szSetting,dbces->lParam);
+ MoveAlong(1+pBlob[0]);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ }
+ LeaveCriticalSection(&csDbAccess);
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Module initialization procedure
+
+static int stringCompare( DBCachedSettingName* p1, DBCachedSettingName* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static int stringCompare2( DBCachedGlobalValue* p1, DBCachedGlobalValue* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+int InitSettings(void)
+{
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTING,GetContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTING_STR,GetContactSettingStr);
+ CreateServiceFunction(MS_DB_CONTACT_GETSETTINGSTATIC,GetContactSettingStatic);
+ CreateServiceFunction(MS_DB_CONTACT_FREEVARIANT,FreeVariant);
+ CreateServiceFunction(MS_DB_CONTACT_WRITESETTING,WriteContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_DELETESETTING,DeleteContactSetting);
+ CreateServiceFunction(MS_DB_CONTACT_ENUMSETTINGS,EnumContactSettings);
+ CreateServiceFunction(MS_DB_SETSETTINGRESIDENT,SetSettingResident);
+
+ hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED);
+
+ mirCp = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ hCacheHeap = HeapCreate(0, 0, 0);
+ lSettings.sortFunc = (FSortFunc)stringCompare;
+ lSettings.increment = 50;
+ lContacts.sortFunc = HandleKeySort;
+ lContacts.increment = 100;
+ lGlobalSettings.sortFunc = (FSortFunc)stringCompare2;
+ lGlobalSettings.increment = 100;
+ return 0;
+}
+
+void UninitSettings(void)
+{
+ HeapDestroy(hCacheHeap);
+ List_Destroy(&lContacts);
+ List_Destroy(&lSettings);
+ List_Destroy(&lGlobalSettings);
+}
diff --git a/plugins/Db3x/src/encrypt.cpp b/plugins/Db3x/src/encrypt.cpp
new file mode 100644
index 0000000000..7426a50cd7
--- /dev/null
+++ b/plugins/Db3x/src/encrypt.cpp
@@ -0,0 +1,66 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+//VERY VERY VERY BASIC ENCRYPTION FUNCTION
+
+
+void Encrypt(char*msg,BOOL up)
+{
+ int i;
+ int jump;
+ if (up)
+ {
+ jump=5;
+ }
+ else
+ {
+ jump=-5;
+ }
+
+ for (i=0;msg[i];i++)
+ {
+ msg[i]=msg[i]+jump;
+ }
+
+}
+
+static INT_PTR EncodeString(WPARAM wParam,LPARAM lParam)
+{
+ Encrypt((char*)lParam,TRUE);
+ return 0;
+}
+
+static INT_PTR DecodeString(WPARAM wParam,LPARAM lParam)
+{
+ Encrypt((char*)lParam,FALSE);
+ return 0;
+}
+
+int InitCrypt(void)
+{
+ CreateServiceFunction(MS_DB_CRYPT_ENCODESTRING,EncodeString);
+ CreateServiceFunction(MS_DB_CRYPT_DECODESTRING,DecodeString);
+ return 0;
+}
diff --git a/plugins/Db3x/src/init.cpp b/plugins/Db3x/src/init.cpp
new file mode 100644
index 0000000000..f9b1269bda
--- /dev/null
+++ b/plugins/Db3x/src/init.cpp
@@ -0,0 +1,176 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 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"
+
+int hLangpack;
+
+HINSTANCE g_hInst=NULL;
+
+static PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+ "Miranda database driver",
+ __VERSION_DWORD,
+ "Provides Miranda database support: global settings, contacts, history, settings per contact.",
+ "Miranda-IM project",
+ "ghazan@miranda-im.org",
+ "Copyright 2000-2011 Miranda IM project",
+ "",
+ UNICODE_AWARE,
+ {0x1394a3ab, 0x2585, 0x4196, { 0x8f, 0x72, 0xe, 0xae, 0xc2, 0x45, 0xe, 0x11 }} //{1394A3AB-2585-4196-8F72-0EAEC2450E11}
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int getCapability( int flag )
+{
+ return 0;
+}
+
+// returns 0 if the profile is created, EMKPRF*
+static int makeDatabase(char * profile, int * error)
+{
+ HANDLE hFile=CreateFileA(profile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ if ( hFile != INVALID_HANDLE_VALUE ) {
+ CreateDbHeaders(hFile);
+ CloseHandle(hFile);
+ return 0;
+ }
+ if ( error != NULL ) *error=EMKPRF_CREATEFAILED;
+ return 1;
+}
+
+// returns 0 if the given profile has a valid header
+static int grokHeader( char * profile, int * error )
+{
+ int rc=1;
+ int chk=0;
+ struct DBHeader hdr;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ DWORD dummy=0;
+
+ hFile = CreateFileA(profile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if ( hFile == INVALID_HANDLE_VALUE ) {
+ if ( error != NULL ) *error=EGROKPRF_CANTREAD;
+ return 1;
+ }
+ // read the header, which can fail (for various reasons)
+ if ( !ReadFile(hFile, &hdr, sizeof(struct DBHeader), &dummy, NULL)) {
+ if ( error != NULL) *error=EGROKPRF_CANTREAD;
+ CloseHandle(hFile);
+ return 1;
+ }
+ chk=CheckDbHeaders(&hdr);
+ if ( chk == 0 ) {
+ // all the internal tests passed, hurrah
+ rc=0;
+ if ( error != NULL ) *error=0;
+ } else {
+ // didn't pass at all, or some did.
+ switch ( chk ) {
+ case 1:
+ {
+ // "Miranda ICQ DB" wasn't present
+ if ( error != NULL ) *error = EGROKPRF_UNKHEADER;
+ break;
+ }
+ case 2:
+ {
+ // header was present, but version information newer
+ if ( error != NULL ) *error= EGROKPRF_VERNEWER;
+ break;
+ }
+ case 3:
+ {
+ // header/version OK, internal data missing
+ if ( error != NULL ) *error=EGROKPRF_DAMAGED;
+ break;
+ }
+ } // switch
+ } //if
+ CloseHandle(hFile);
+ return rc;
+}
+
+// returns 0 if all the APIs are injected otherwise, 1
+static int LoadDatabase( char* profile )
+{
+ // don't need thread notifications
+ strncpy(szDbPath, profile, sizeof(szDbPath));
+
+ mir_getLP(&pluginInfo);
+
+ // inject all APIs and hooks into the core
+ return LoadDatabaseModule();
+}
+
+static int UnloadDatabase(int wasLoaded)
+{
+ if ( !wasLoaded) return 0;
+ UnloadDatabaseModule();
+ return 0;
+}
+
+static int getFriendlyName( char * buf, size_t cch, int shortName )
+{
+ strncpy(buf,shortName ? "db3x driver" : "db3x database support",cch);
+ return 0;
+}
+
+static DATABASELINK dblink = {
+ sizeof(DATABASELINK),
+ getCapability,
+ getFriendlyName,
+ makeDatabase,
+ grokHeader,
+ LoadDatabase,
+ UnloadDatabase,
+};
+
+BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD dwReason, LPVOID reserved)
+{
+ g_hInst = hInstDLL;
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) DATABASELINK* DatabasePluginInfo(void * reserved)
+{
+ return &dblink;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX * MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_DATABASE, MIID_LAST};
+
+extern "C" __declspec(dllexport) int Load(void)
+{
+ return 1;
+}
+
+extern "C" __declspec(dllexport) int Unload(void)
+{
+ return 0;
+}
diff --git a/plugins/Db3x/src/resource.h b/plugins/Db3x/src/resource.h
new file mode 100644
index 0000000000..96abbfff99
--- /dev/null
+++ b/plugins/Db3x/src/resource.h
@@ -0,0 +1,30 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by resource.rc
+//
+#define IDC_NOTOALL 3
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 269
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1657
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/Db3x/src/version.h b/plugins/Db3x/src/version.h
new file mode 100644
index 0000000000..2d10138fcf
--- /dev/null
+++ b/plugins/Db3x/src/version.h
@@ -0,0 +1,5 @@
+#include "m_version.h"
+
+#define __FILEVERSION_STRING MIRANDA_VERSION_FILEVERSION
+#define __VERSION_STRING MIRANDA_VERSION_STRING
+#define __VERSION_DWORD MIRANDA_VERSION_DWORD