From f920ef497f3299ae24fe783ce03bdd93b419f764 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 18 May 2012 22:02:50 +0000 Subject: plugins folders renaming git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Db3x/Makefile | 53 ++ plugins/Db3x/commonheaders.c | 1 + plugins/Db3x/commonheaders.h | 58 ++ plugins/Db3x/database.c | 159 ++++++ plugins/Db3x/database.h | 214 +++++++ plugins/Db3x/db3x_10.vcxproj | 302 ++++++++++ plugins/Db3x/db3x_10.vcxproj.filters | 62 +++ plugins/Db3x/dbcache.c | 229 ++++++++ plugins/Db3x/dbcontacts.c | 300 ++++++++++ plugins/Db3x/dbevents.c | 440 +++++++++++++++ plugins/Db3x/dbheaders.c | 78 +++ plugins/Db3x/dbmodulechain.c | 132 +++++ plugins/Db3x/dbsettings.c | 979 +++++++++++++++++++++++++++++++++ plugins/Db3x/docs/db3x-license.txt | 340 ++++++++++++ plugins/Db3x/docs/db3x-readme.txt | 38 ++ plugins/Db3x/docs/db3x-translation.txt | 43 ++ plugins/Db3x/encrypt.c | 67 +++ plugins/Db3x/encryption.h | 23 + plugins/Db3x/init.c | 205 +++++++ plugins/Db3x/resource.h | 30 + plugins/Db3x/resource.rc | 169 ++++++ plugins/Db3x/version.h | 5 + 22 files changed, 3927 insertions(+) create mode 100644 plugins/Db3x/Makefile create mode 100644 plugins/Db3x/commonheaders.c create mode 100644 plugins/Db3x/commonheaders.h create mode 100644 plugins/Db3x/database.c create mode 100644 plugins/Db3x/database.h create mode 100644 plugins/Db3x/db3x_10.vcxproj create mode 100644 plugins/Db3x/db3x_10.vcxproj.filters create mode 100644 plugins/Db3x/dbcache.c create mode 100644 plugins/Db3x/dbcontacts.c create mode 100644 plugins/Db3x/dbevents.c create mode 100644 plugins/Db3x/dbheaders.c create mode 100644 plugins/Db3x/dbmodulechain.c create mode 100644 plugins/Db3x/dbsettings.c create mode 100644 plugins/Db3x/docs/db3x-license.txt create mode 100644 plugins/Db3x/docs/db3x-readme.txt create mode 100644 plugins/Db3x/docs/db3x-translation.txt create mode 100644 plugins/Db3x/encrypt.c create mode 100644 plugins/Db3x/encryption.h create mode 100644 plugins/Db3x/init.c create mode 100644 plugins/Db3x/resource.h create mode 100644 plugins/Db3x/resource.rc create mode 100644 plugins/Db3x/version.h (limited to 'plugins/Db3x') diff --git a/plugins/Db3x/Makefile b/plugins/Db3x/Makefile new file mode 100644 index 0000000000..5a7563001f --- /dev/null +++ b/plugins/Db3x/Makefile @@ -0,0 +1,53 @@ +SRC = commonheaders.c \ + database.c \ + dbcache.c \ + dbcontacts.c \ + dbevents.c \ + dbheaders.c \ + dbini.c \ + dblists.c \ + dbmodulechain.c \ + dbsettings.c \ + dbtime.c \ + encrypt.c \ + init.c +OBJ = $(SRC:.c=.o) +RES = resource.res +LIB = -lgdi32 -lversion -lcomctl32 -lcomdlg32 -lole32 + +CC = gcc +RC = windres +RM = rm + +# Install location +ifdef DEBUG +BIN = ..\..\bin\debug\plugins\dbx_3x.dll +else +BIN = ..\..\bin\release\plugins\dbx_3x.dll +endif + +# Defines +DEFINES = -DWIN32 -D__SEH_NOOP +ifdef DEBUG +DEFINES := $(DEFINES) -D_DEBUG +endif + +# Flags +LFLAGS = -shared +RCFLAGS = --input-format rc --output-format coff +ifdef DEBUG +CFLAGS = -g $(DEFINES) -I../../include +else +CFLAGS = -O1 $(DEFINES) -I../../include +endif + +# Targets +all : $(OBJ) $(RES) + $(CC) $(LFLAGS) $(CFLAGS) -o $(BIN) $(OBJ) $(RES) $(LIB) -Wl + +$(RES) : $(RES:.res=.rc) $(RES:.res=.h) Makefile + $(RC) $(RCFLAGS) -o $(RES) -i $(RES:.res=.rc) + +clean : + $(RM) -f $(OBJ) $(RES) + diff --git a/plugins/Db3x/commonheaders.c b/plugins/Db3x/commonheaders.c new file mode 100644 index 0000000000..14f99f7d71 --- /dev/null +++ b/plugins/Db3x/commonheaders.c @@ -0,0 +1 @@ +#include "commonheaders.h" diff --git a/plugins/Db3x/commonheaders.h b/plugins/Db3x/commonheaders.h new file mode 100644 index 0000000000..cd82b02679 --- /dev/null +++ b/plugins/Db3x/commonheaders.h @@ -0,0 +1,58 @@ +/* + +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 MIRANDA_VER 0x0A00 + +#define _WIN32_WINNT 0x0501 + +#include "m_stdhdr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "resource.h" +#include +#include +#include +#include +#include +#include "version.h" + +extern PLUGINLINK *pluginLink; + +extern struct LIST_INTERFACE li; + +#ifdef __GNUC__ +#define mir_i64(x) (x##LL) +#else +#define mir_i64(x) (x##i64) +#endif + +#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A) diff --git a/plugins/Db3x/database.c b/plugins/Db3x/database.c new file mode 100644 index 0000000000..23d5e93723 --- /dev/null +++ b/plugins/Db3x/database.c @@ -0,0 +1,159 @@ +/* + +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" +#include "database.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/database.h b/plugins/Db3x/database.h new file mode 100644 index 0000000000..334e47002d --- /dev/null +++ b/plugins/Db3x/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 +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 + +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/db3x_10.vcxproj b/plugins/Db3x/db3x_10.vcxproj new file mode 100644 index 0000000000..51cdc684bd --- /dev/null +++ b/plugins/Db3x/db3x_10.vcxproj @@ -0,0 +1,302 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + db3x + {8B778B6A-F5EF-49A4-8437-424832F2B280} + db3x + + + + DynamicLibrary + false + Unicode + true + + + DynamicLibrary + false + Unicode + + + DynamicLibrary + false + Unicode + true + + + DynamicLibrary + false + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + true + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + dbx_3x + dbx_3x + dbx_3x + dbx_3x + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/db3x.tlb + + + + + Disabled + ../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;DB3X_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + true + Fast + Use + commonheaders.h + Level3 + EditAndContinue + 4996;%(DisableSpecificWarnings) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + ./../../include/msapi/ + + + true + true + $(TargetDir)$(TargetName).pdb + false + $(IntDir)$(TargetName).lib + MachineX86 + + + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + .\Debug/db3x.tlb + + + + + Disabled + ../../include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;DB3X_EXPORTS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDebugDLL + true + Fast + Use + commonheaders.h + Level3 + ProgramDatabase + 4996;%(DisableSpecificWarnings) + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + ./../../include/msapi/ + + + + + true + $(TargetDir)$(TargetName).pdb + false + $(IntDir)$(TargetName).lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/db3x.tlb + + + + + Full + OnlyExplicitInline + Size + true + ../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;DB3X_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + false + true + false + Use + commonheaders.h + Level3 + ProgramDatabase + 4996;%(DisableSpecificWarnings) + true + Fast + false + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + ./../../include/msapi/ + + + + + true + true + true + UseLinkTimeCodeGeneration + 0x5130000 + false + $(IntDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + .\Release/db3x.tlb + + + + + Full + OnlyExplicitInline + Size + true + ../../include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;DB3X_EXPORTS;%(PreprocessorDefinitions) + true + false + MultiThreadedDLL + false + true + false + Use + commonheaders.h + Level3 + ProgramDatabase + 4996;%(DisableSpecificWarnings) + true + Fast + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + ./../../include/msapi/ + + + + + true + true + true + UseLinkTimeCodeGeneration + 0x5130000 + false + $(IntDir)$(TargetName).lib + MachineX64 + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/Db3x/db3x_10.vcxproj.filters b/plugins/Db3x/db3x_10.vcxproj.filters new file mode 100644 index 0000000000..cb5137171a --- /dev/null +++ b/plugins/Db3x/db3x_10.vcxproj.filters @@ -0,0 +1,62 @@ + + + + + {0102a88b-21e4-49ca-a6fd-fe4978f36faf} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {ec7c1ebb-62dd-4af2-b531-4d1a46abc680} + h;hpp;hxx;hm;inl + + + {fbaceae7-3e4a-4853-96f3-eec77981b2c9} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/plugins/Db3x/dbcache.c b/plugins/Db3x/dbcache.c new file mode 100644 index 0000000000..4cf338bfb9 --- /dev/null +++ b/plugins/Db3x/dbcache.c @@ -0,0 +1,229 @@ +/* + +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" +#include "database.h" + + +#define CACHESECTIONSIZE 4096 +#define CACHESECTIONCOUNT 32 + +extern HANDLE hDbFile; +extern CRITICAL_SECTION csDbAccess; + +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=cacheSectionInfo[i].ofsBase && ofs=cacheSectionInfo[i].ofsBase && ofs=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;ihNext != 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; + li.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 ( li.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 ); + + li.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 ( li.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; + + li.List_GetIndex(&lContacts,VL,&index); + li.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 ( li.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; + li.List_Insert(&lContacts,VL,index); + } } } + + LeaveCriticalSection(&csDbAccess); + return ret; +} diff --git a/plugins/Db3x/dbevents.c b/plugins/Db3x/dbevents.c new file mode 100644 index 0000000000..39de07d187 --- /dev/null +++ b/plugins/Db3x/dbevents.c @@ -0,0 +1,440 @@ +/* + +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" +#include "database.h" + + +DWORD GetModuleNameOfs(const char *szName); +char *GetModuleNameByOfs(DWORD ofs); + +static INT_PTR GetEventCount(WPARAM wParam,LPARAM lParam); +static INT_PTR AddEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR DeleteEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR GetBlobSize(WPARAM wParam,LPARAM lParam); +static INT_PTR GetEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR MarkEventRead(WPARAM wParam,LPARAM lParam); +static INT_PTR GetEventContact(WPARAM wParam,LPARAM lParam); +static INT_PTR FindFirstEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR FindFirstUnreadEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR FindLastEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR FindNextEvent(WPARAM wParam,LPARAM lParam); +static INT_PTR FindPrevEvent(WPARAM wParam,LPARAM lParam); + +extern CRITICAL_SECTION csDbAccess; +extern struct DBHeader dbHeader; + +static HANDLE hEventDeletedEvent,hEventAddedEvent,hEventFilterAddedEvent; + +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) +{ +} + +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.timestamppBlob,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->cbBlobcbBlob) 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; +} diff --git a/plugins/Db3x/dbheaders.c b/plugins/Db3x/dbheaders.c new file mode 100644 index 0000000000..da7cb6eb6d --- /dev/null +++ b/plugins/Db3x/dbheaders.c @@ -0,0 +1,78 @@ +/* + +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" +#include "database.h" + +extern struct DBHeader dbHeader; +extern HANDLE hDbFile; + +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/dbmodulechain.c b/plugins/Db3x/dbmodulechain.c new file mode 100644 index 0000000000..8b78b4dffa --- /dev/null +++ b/plugins/Db3x/dbmodulechain.c @@ -0,0 +1,132 @@ +/* + +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" +#include "database.h" + +extern struct DBHeader dbHeader; + +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;iofsFirstSettings; + 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;itype == 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 ( li.List_GetIndex(&lGlobalSettings,&Vtemp,&index)) { + V = (DBCachedGlobalValue*)lGlobalSettings.items[index]; + if ( bAllocate == -1 ) { + FreeCachedVariant( &V->value ); + li.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; + li.List_Insert(&lGlobalSettings,V,index); + } + + return &V->value; + } + else { + DBCachedContactValue *V, *V1; + DBCachedContactValueList VLtemp,*VL; + + VLtemp.hContact=hContact; + if ( li.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; + li.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 = 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(cbLenpValue->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)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)pValue->cpbVal) dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1); + CopyMemory(dbcgs->pValue->pbVal,pBlob+3,dbcgs->pValue->cpbVal); + } + else { + dbcgs->pValue->pbVal=(char*)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 = 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 ( !li.List_GetIndex( &lSettings, szTemp, &idx )) + szSetting = InsertCachedSetting( szTemp, cbSettingNameLen+2, idx ); + else + szSetting = 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=stringCompare; + lSettings.increment=50; + lContacts.sortFunc=HandleKeySort; + lContacts.increment=100; + lGlobalSettings.sortFunc=stringCompare2; + lGlobalSettings.increment=100; + return 0; +} + +void UninitSettings(void) +{ + HeapDestroy(hCacheHeap); + li.List_Destroy(&lContacts); + li.List_Destroy(&lSettings); + li.List_Destroy(&lGlobalSettings); +} diff --git a/plugins/Db3x/docs/db3x-license.txt b/plugins/Db3x/docs/db3x-license.txt new file mode 100644 index 0000000000..7f1161073d --- /dev/null +++ b/plugins/Db3x/docs/db3x-license.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/plugins/Db3x/docs/db3x-readme.txt b/plugins/Db3x/docs/db3x-readme.txt new file mode 100644 index 0000000000..eb5707c048 --- /dev/null +++ b/plugins/Db3x/docs/db3x-readme.txt @@ -0,0 +1,38 @@ +################################################################ +# Classic Database Driver for Miranda IM +################################################################ + +About +----- +The Classic Database Driver is used to store all contacts and +events in Miranda IM. + + +Requirements +------------ + - Miranda IM 0.4 + + +History +------- +0.4.0.0 + - DB driver separated from core (initial release) + + +Copyright +--------- +Copyright (C) 2003-2005 Miranda IM Development Team + +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. diff --git a/plugins/Db3x/docs/db3x-translation.txt b/plugins/Db3x/docs/db3x-translation.txt new file mode 100644 index 0000000000..fc265cc194 --- /dev/null +++ b/plugins/Db3x/docs/db3x-translation.txt @@ -0,0 +1,43 @@ +Miranda Language Pack Version 1 +Locale: 0809 +Authors: Miranda IM Development Team +Author-email: info@miranda-im.org +Last-Modified-Using: Miranda IM 0.4 +Plugins-included: + +; Generated by lpgen on Wed Apr 6 12:41:12 2005 +; Translations: 27 + +; database.c +;[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.] +;[Database Panic] + +; dbini.c +;[Invalid setting type. The first character of every value must be b, w, d, l, s or n.] +;[Install Database Settings] + +; resource.rc +;[&Allow all further changes to this section] +;[Yes] +;[&Yes] +;[No] +;[No to all] +;[&View contents] +;[&No] +;[Cancel Import] +;[&Recycle] +;[&Delete] +;[&Move/Rename] +;[&Leave] +;[A file containing new database settings has been placed in the Miranda IM directory.] +;[Do you want to import the settings now?] +;[Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.] +;[Database settings are being imported from] +;[This file wishes to change the setting] +;[to the value] +;[Do you want to allow this change?] +;[The import has completed from] +;[What do you want to do with the file now?] +;[Database Setting Change] +;[Database Import Complete] + diff --git a/plugins/Db3x/encrypt.c b/plugins/Db3x/encrypt.c new file mode 100644 index 0000000000..6e025337e5 --- /dev/null +++ b/plugins/Db3x/encrypt.c @@ -0,0 +1,67 @@ +/* + +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" +#include "database.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/encryption.h b/plugins/Db3x/encryption.h new file mode 100644 index 0000000000..73c2d7e13a --- /dev/null +++ b/plugins/Db3x/encryption.h @@ -0,0 +1,23 @@ +/* +Miranda ICQ: the free icq client for MS Windows +Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede + +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. +*/ +#ifndef MODULAR +#include + +void Encrypt(char*msg,BOOL up); +#endif \ No newline at end of file diff --git a/plugins/Db3x/init.c b/plugins/Db3x/init.c new file mode 100644 index 0000000000..ca574224f5 --- /dev/null +++ b/plugins/Db3x/init.c @@ -0,0 +1,205 @@ +/* + +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" +#include "database.h" +#include + +struct MM_INTERFACE mmi; +struct LIST_INTERFACE li; +struct UTF8_INTERFACE utfi; +int hLangpack; + +extern char szDbPath[MAX_PATH]; + +HINSTANCE g_hInst=NULL; +PLUGINLINK *pluginLink; + +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, + DEFMOD_DB, + {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, void * plink ) +{ + PLUGINLINK *link = plink; +#ifdef _DEBUG + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); +#endif + // don't need thread notifications + strncpy(szDbPath, profile, sizeof(szDbPath)); + + // this is like Load()'s pluginLink + pluginLink=link; + + // set the memory, lists & UTF8 manager + mir_getLI( &li ); + mir_getMMI( &mmi ); + mir_getUTFI( &utfi ); + 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; +} + +__declspec(dllexport) DATABASELINK* DatabasePluginInfo(void * reserved) +{ + return &dblink; +} + +__declspec(dllexport) PLUGININFOEX * MirandaPluginInfoEx(DWORD mirandaVersion) +{ + if ( mirandaVersion < MIRANDA_VERSION_CORE ) { + MessageBox( NULL, _T("The db3x plugin cannot be loaded. It requires Miranda IM 0.7.0.0 or later."), _T("db3x Plugin"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST ); + return NULL; + } + return &pluginInfo; +} + +static const MUUID interfaces[] = {MIID_DATABASE, MIID_LAST}; +__declspec(dllexport) const MUUID * MirandaPluginInterfaces(void) +{ + return interfaces; +} + +int __declspec(dllexport) Load(PLUGINLINK * link) +{ + return 1; +} + +int __declspec(dllexport) Unload(void) +{ + return 0; +} diff --git a/plugins/Db3x/resource.h b/plugins/Db3x/resource.h new file mode 100644 index 0000000000..96abbfff99 --- /dev/null +++ b/plugins/Db3x/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/resource.rc b/plugins/Db3x/resource.rc new file mode 100644 index 0000000000..daa99f340d --- /dev/null +++ b/plugins/Db3x/resource.rc @@ -0,0 +1,169 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_INSTALLINI DIALOGEX 0, 0, 212, 102 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Install Database Settings" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Yes",IDOK,26,83,50,14 + PUSHBUTTON "No",IDCANCEL,81,83,50,14 + LTEXT "A file containing new database settings has been placed in the Miranda IM directory.", + IDC_STATIC,5,5,202,16 + LTEXT "Do you want to import the settings now?",IDC_STATIC,5, + 69,202,8 + PUSHBUTTON "No to all",IDC_NOTOALL,136,83,50,14 + LTEXT "",IDC_ININAME,5,24,143,16,SS_NOPREFIX | SS_CENTERIMAGE + PUSHBUTTON "&View contents",IDC_VIEWINI,149,25,58,14 + LTEXT "Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.", + IDC_SECURITYINFO,5,43,202,24 +END + +IDD_WARNINICHANGE DIALOGEX 0, 0, 187, 113 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Database Setting Change" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "Database settings are being imported from",IDC_STATIC,5, + 5,177,8 + CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX | + WS_GROUP,5,13,177,8 + LTEXT "This file wishes to change the setting",IDC_STATIC,5,24, + 177,8 + CONTROL "",IDC_SETTINGNAME,"Static",SS_SIMPLE | SS_NOPREFIX | + WS_GROUP,12,33,170,8 + LTEXT "to the value",IDC_STATIC,5,42,177,8 + CONTROL "",IDC_NEWVALUE,"Static",SS_SIMPLE | SS_NOPREFIX | + WS_GROUP,12,51,170,8 + LTEXT "",IDC_SECURITYINFO,5,60,177,8 + LTEXT "Do you want to allow this change?",IDC_STATIC,5,71,177, + 8 + CONTROL "&Allow all further changes to this section", + IDC_WARNNOMORE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13, + 80,169,10 + DEFPUSHBUTTON "&Yes",IDYES,5,94,50,14 + PUSHBUTTON "&No",IDNO,59,94,50,14 + PUSHBUTTON "Cancel Import",IDCANCEL,123,94,59,14 +END + +IDD_INIIMPORTDONE DIALOGEX 0, 0, 186, 73 +STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | + WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Database Import Complete" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "The import has completed from",IDC_STATIC,5,5,176,8 + CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX | + WS_GROUP,5,13,176,8 + LTEXT "What do you want to do with the file now?",IDC_STATIC,5, + 24,176,8 + PUSHBUTTON "&Recycle",IDC_RECYCLE,5,36,50,14 + PUSHBUTTON "&Delete",IDC_DELETE,68,36,50,14 + EDITTEXT IDC_NEWNAME,5,55,117,12,ES_AUTOHSCROLL + PUSHBUTTON "&Move/Rename",IDC_MOVE,124,54,57,14 + PUSHBUTTON "&Leave",IDC_LEAVE,131,36,50,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_INSTALLINI, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 207 + TOPMARGIN, 5 + BOTTOMMARGIN, 97 + END + + IDD_WARNINICHANGE, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 182 + TOPMARGIN, 5 + BOTTOMMARGIN, 108 + END + + IDD_INIIMPORTDONE, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 181 + TOPMARGIN, 5 + BOTTOMMARGIN, 68 + END +END +#endif // APSTUDIO_INVOKED + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include \0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/plugins/Db3x/version.h b/plugins/Db3x/version.h new file mode 100644 index 0000000000..826d9fdefb --- /dev/null +++ b/plugins/Db3x/version.h @@ -0,0 +1,5 @@ +#include "../../include/m_version.h" + +#define __FILEVERSION_STRING MIRANDA_VERSION_FILEVERSION +#define __VERSION_STRING MIRANDA_VERSION_STRING +#define __VERSION_DWORD MIRANDA_VERSION_DWORD -- cgit v1.2.3