summaryrefslogtreecommitdiff
path: root/plugins/Db3x_mmap/dbsettings.c
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-05-18 22:02:50 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-05-18 22:02:50 +0000
commitf920ef497f3299ae24fe783ce03bdd93b419f764 (patch)
treebdaa9197c08d29ab141a6adfdd6cc0a68ddd3996 /plugins/Db3x_mmap/dbsettings.c
parent6c3b0571f0678da0512069869afaa284c054377e (diff)
plugins folders renaming
git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Db3x_mmap/dbsettings.c')
-rw-r--r--plugins/Db3x_mmap/dbsettings.c1013
1 files changed, 1013 insertions, 0 deletions
diff --git a/plugins/Db3x_mmap/dbsettings.c b/plugins/Db3x_mmap/dbsettings.c
new file mode 100644
index 0000000000..85b91b1b6c
--- /dev/null
+++ b/plugins/Db3x_mmap/dbsettings.c
@@ -0,0 +1,1013 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2003 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+DWORD GetModuleNameOfs(const char *szName);
+DBCachedContactValueList* AddToCachedContactList(HANDLE hContact, int index);
+
+static int mirCp = CP_ACP;
+
+HANDLE hCacheHeap = NULL;
+SortedList lContacts = {0};
+HANDLE hLastCachedContact = NULL;
+static DBCachedContactValueList *LastVL = NULL;
+
+static SortedList lSettings={0}, lGlobalSettings={0}, lResidentSettings={0};
+static HANDLE hSettingChangeEvent = NULL;
+
+static DWORD GetSettingsGroupOfsByModuleNameOfs(struct DBContact *dbc,DWORD ofsModuleName)
+{
+ struct DBContactSettings *dbcs;
+ DWORD ofsThis;
+
+ ofsThis=dbc->ofsFirstSettings;
+ while(ofsThis) {
+ dbcs=(struct DBContactSettings*)DBRead(ofsThis,sizeof(struct DBContactSettings),NULL);
+ if(dbcs->signature!=DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption(NULL);
+ if(dbcs->ofsModuleName==ofsModuleName)
+ return ofsThis;
+
+ ofsThis=dbcs->ofsNext;
+ }
+ return 0;
+}
+
+static DWORD __inline GetSettingValueLength(PBYTE pSetting)
+{
+ if(pSetting[0]&DBVTF_VARIABLELENGTH) return 2+*(PWORD)(pSetting+1);
+ return pSetting[0];
+}
+
+static char* InsertCachedSetting( const char* szName, size_t cbNameLen, int index )
+{
+ char* newValue = (char*)HeapAlloc( hCacheHeap, 0, cbNameLen );
+ *newValue = 0;
+ strcpy(newValue+1,szName+1);
+ li.List_Insert(&lSettings,newValue,index);
+ return newValue;
+}
+
+static char* GetCachedSetting(const char *szModuleName,const char *szSettingName, int moduleNameLen, int settingNameLen)
+{
+ static char *lastsetting = NULL;
+ int index;
+ char szFullName[512];
+
+ strcpy(szFullName+1,szModuleName);
+ szFullName[moduleNameLen+1]='/';
+ strcpy(szFullName+moduleNameLen+2,szSettingName);
+
+ if (lastsetting && strcmp(szFullName+1,lastsetting) == 0)
+ return lastsetting;
+
+ if (li.List_GetIndex(&lSettings,szFullName,&index))
+ lastsetting = (char*)lSettings.items[index]+1;
+ else
+ lastsetting = InsertCachedSetting( szFullName, settingNameLen+moduleNameLen+3, index )+1;
+
+ return lastsetting;
+}
+
+static void SetCachedVariant( DBVARIANT* s /* new */, DBVARIANT* d /* cached */ )
+{
+ char* szSave = ( d->type == DBVT_UTF8 || d->type == DBVT_ASCIIZ ) ? d->pszVal : NULL;
+
+ memcpy( d, s, sizeof( DBVARIANT ));
+ if (( s->type == DBVT_UTF8 || s->type == DBVT_ASCIIZ ) && s->pszVal != NULL ) {
+ if ( szSave != NULL )
+ d->pszVal = (char*)HeapReAlloc(hCacheHeap,0,szSave,strlen(s->pszVal)+1);
+ else
+ d->pszVal = (char*)HeapAlloc(hCacheHeap,0,strlen(s->pszVal)+1);
+ strcpy(d->pszVal,s->pszVal);
+ }
+ else if ( szSave != NULL )
+ HeapFree(hCacheHeap,0,szSave);
+
+#ifdef DBLOGGING
+ 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;
+ }
+#endif
+}
+
+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;
+
+ if (hLastCachedContact==hContact && LastVL) {
+ VL = LastVL;
+ }
+ else {
+ VLtemp.hContact=hContact;
+
+ if ( !li.List_GetIndex(&lContacts,&VLtemp,&index))
+ {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ VL = AddToCachedContactList(hContact,index);
+ }
+ else VL = (DBCachedContactValueList*)lContacts.items[index];
+
+ LastVL = VL;
+ hLastCachedContact = hContact;
+ }
+
+ for ( V = VL->first; V != NULL; V = V->next)
+ if (V->name == szSetting)
+ break;
+
+ if ( V == NULL ) {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ V = HeapAlloc(hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedContactValue));
+ if (VL->last)
+ VL->last->next = V;
+ else
+ VL->first = V;
+ VL->last = V;
+ V->name = szSetting;
+ }
+ else if ( bAllocate == -1 ) {
+ LastVL = NULL;
+ FreeCachedVariant(&V->value);
+ if ( VL->first == V ) {
+ VL->first = V->next;
+ if (VL->last == V)
+ VL->last = V->next; // NULL
+ }
+ else
+ for ( V1 = VL->first; V1 != NULL; V1 = V1->next )
+ if ( V1->next == V ) {
+ V1->next = V->next;
+ if (VL->last == V)
+ VL->last = V1;
+ 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;
+ DWORD ofsModuleName,ofsContact,ofsSettingsGroup,ofsBlobPtr;
+ int settingNameLen,moduleNameLen;
+ int bytesRemaining;
+ PBYTE pBlob;
+ char* szCachedSettingName;
+
+ if ((!dbcgs->szSetting) || (!dbcgs->szModule))
+ return 1;
+ // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
+ settingNameLen=(int)strlen(dbcgs->szSetting);
+ moduleNameLen=(int)strlen(dbcgs->szModule);
+ if ( settingNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("GetContactSettingWorker() got a > 255 setting name length. \n");
+ #endif
+ return 1;
+ }
+ if ( moduleNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("GetContactSettingWorker() got a > 255 module name length. \n");
+ #endif
+ return 1;
+ }
+
+ EnterCriticalSection(&csDbAccess);
+
+ log3("get [%08p] %s/%s",hContact,dbcgs->szModule,dbcgs->szSetting);
+
+ szCachedSettingName = GetCachedSetting(dbcgs->szModule,dbcgs->szSetting,moduleNameLen,settingNameLen);
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 0 );
+ if ( pCachedValue != NULL ) {
+ if ( pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8 ) {
+ int cbOrigLen = dbcgs->pValue->cchVal;
+ char* cbOrigPtr = dbcgs->pValue->pszVal;
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+ if ( isStatic ) {
+ int cbLen = 0;
+ if ( pCachedValue->pszVal != NULL )
+ cbLen = (int)strlen( pCachedValue->pszVal );
+
+ cbOrigLen--;
+ dbcgs->pValue->pszVal = cbOrigPtr;
+ if(cbLen<cbOrigLen) cbOrigLen=cbLen;
+ CopyMemory(dbcgs->pValue->pszVal,pCachedValue->pszVal,cbOrigLen);
+ dbcgs->pValue->pszVal[cbOrigLen]=0;
+ dbcgs->pValue->cchVal=cbLen;
+ }
+ else {
+ dbcgs->pValue->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal)+1);
+ strcpy(dbcgs->pValue->pszVal,pCachedValue->pszVal);
+ }
+ }
+ else
+ memcpy( dbcgs->pValue, pCachedValue, sizeof( DBVARIANT ));
+
+ switch( dbcgs->pValue->type ) {
+ case DBVT_BYTE: log1( "get cached byte: %d", dbcgs->pValue->bVal ); break;
+ case DBVT_WORD: log1( "get cached word: %d", dbcgs->pValue->wVal ); break;
+ case DBVT_DWORD: log1( "get cached dword: %d", dbcgs->pValue->dVal ); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: log1( "get cached string: '%s'", dbcgs->pValue->pszVal); break;
+ default: log1( "get cached crap: %d", dbcgs->pValue->type ); break;
+ }
+
+ LeaveCriticalSection(&csDbAccess);
+ return ( pCachedValue->type == DBVT_DELETED ) ? 1 : 0;
+ } }
+
+ ofsModuleName=GetModuleNameOfs(dbcgs->szModule);
+ if(hContact==NULL) ofsContact=dbHeader.ofsUser;
+ else ofsContact=(DWORD)hContact;
+ dbc=(struct DBContact*)DBRead(ofsContact,sizeof(struct DBContact),NULL);
+ if(dbc->signature!=DBCONTACT_SIGNATURE) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ ofsSettingsGroup=GetSettingsGroupOfsByModuleNameOfs(dbc,ofsModuleName);
+ if(ofsSettingsGroup) {
+ ofsBlobPtr=ofsSettingsGroup+offsetof(struct DBContactSettings,blob);
+ pBlob = DBRead(ofsBlobPtr,sizeof(struct DBContactSettings),&bytesRemaining);
+ while(pBlob[0]) {
+ NeedBytes(1+settingNameLen);
+ if(pBlob[0]==settingNameLen && !memcmp(pBlob+1,dbcgs->szSetting,settingNameLen)) {
+ MoveAlong(1+settingNameLen);
+ NeedBytes(5);
+ if(isStatic && pBlob[0]&DBVTF_VARIABLELENGTH && VLT(dbcgs->pValue->type) != VLT(pBlob[0])) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ dbcgs->pValue->type=pBlob[0];
+ switch(pBlob[0]) {
+ case DBVT_DELETED: { /* this setting is deleted */
+ dbcgs->pValue->type=DBVT_DELETED;
+ LeaveCriticalSection(&csDbAccess);
+ return 2;
+ }
+ case DBVT_BYTE: dbcgs->pValue->bVal=pBlob[1]; break;
+ case DBVT_WORD: dbcgs->pValue->wVal=*(PWORD)(pBlob+1); break;
+ case DBVT_DWORD: dbcgs->pValue->dVal=*(PDWORD)(pBlob+1); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ dbcgs->pValue->cchVal--;
+ if(*(PWORD)(pBlob+1)<dbcgs->pValue->cchVal) dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,dbcgs->pValue->cchVal);
+ dbcgs->pValue->pszVal[dbcgs->pValue->cchVal]=0;
+ dbcgs->pValue->cchVal=*(PWORD)(pBlob+1);
+ }
+ else {
+ dbcgs->pValue->pszVal=(char*)mir_alloc(1+*(PWORD)(pBlob+1));
+ CopyMemory(dbcgs->pValue->pszVal,pBlob+3,*(PWORD)(pBlob+1));
+ dbcgs->pValue->pszVal[*(PWORD)(pBlob+1)]=0;
+ }
+ break;
+ case DBVT_BLOB:
+ NeedBytes(3+*(PWORD)(pBlob+1));
+ if(isStatic) {
+ if(*(PWORD)(pBlob+1)<dbcgs->pValue->cpbVal) dbcgs->pValue->cpbVal=*(PWORD)(pBlob+1);
+ CopyMemory(dbcgs->pValue->pbVal,pBlob+3,dbcgs->pValue->cpbVal);
+ }
+ else {
+ dbcgs->pValue->pbVal=(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)
+{
+ size_t cbSettingNameLen = strlen(( char* )lParam) + 2;
+ if (cbSettingNameLen < 512)
+ {
+ char* szSetting;
+ int idx;
+ char szTemp[512];
+ strcpy( szTemp+1, ( char* )lParam );
+
+ EnterCriticalSection(&csDbAccess);
+ if ( !li.List_GetIndex( &lSettings, szTemp, &idx ))
+ szSetting = InsertCachedSetting( szTemp, cbSettingNameLen, idx );
+ else
+ szSetting = lSettings.items[ idx ];
+
+ *szSetting = (char)wParam;
+
+ if ( !li.List_GetIndex( &lResidentSettings, szSetting+1, &idx ))
+ {
+ if (wParam)
+ li.List_Insert(&lResidentSettings,szSetting+1,idx);
+ }
+ else if (!wParam)
+ li.List_Remove(&lResidentSettings,idx);
+
+ 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;
+
+ // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
+ settingNameLen=(int)strlen(dbcws->szSetting);
+ moduleNameLen=(int)strlen(dbcws->szModule);
+ if ( settingNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("WriteContactSetting() got a > 255 setting name length. \n");
+ #endif
+ return 1;
+ }
+ if ( moduleNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("WriteContactSetting() got a > 255 module name length. \n");
+ #endif
+ 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 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:
+ { size_t len = ( tmp.value.type != DBVT_BLOB ) ? strlen(tmp.value.pszVal) : tmp.value.cpbVal;
+ if ( len >= 0xFFFF ) {
+ #ifdef _DEBUG
+ OutputDebugStringA("WriteContactSetting() writing huge string/blob, rejecting ( >= 0xFFFF ) \n");
+ #endif
+ return 1;
+ }
+ }
+ }
+
+ EnterCriticalSection(&csDbAccess);
+ {
+ char* szCachedSettingName = GetCachedSetting(tmp.szModule, tmp.szSetting, moduleNameLen, 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,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,ofsNew;
+
+ 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(NULL);
+ ofsDbcsPrev=dbcsPrev->ofsNext;
+ dbcsPrev=(struct DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(struct DBContactSettings),NULL);
+ }
+ }
+
+ //create the new one
+ ofsNew=ReallocSpace(ofsSettingsGroup, dbcs.cbBlob+offsetof(struct DBContactSettings,blob), bytesRequired+offsetof(struct DBContactSettings,blob));
+
+ 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));
+ }
+ 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;
+ PBYTE pBlob;
+ int settingNameLen,moduleNameLen,bytesRemaining;
+ char* szCachedSettingName;
+ WPARAM saveWparam = wParam;
+
+ if ((!dbcgs->szModule) || (!dbcgs->szSetting))
+ return 1;
+ // the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
+ settingNameLen=(int)strlen(dbcgs->szSetting);
+ moduleNameLen=(int)strlen(dbcgs->szModule);
+ if ( settingNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("DeleteContactSetting() got a > 255 setting name length. \n");
+ #endif
+ return 1;
+ }
+ if ( moduleNameLen > 0xFE )
+ {
+ #ifdef _DEBUG
+ OutputDebugStringA("DeleteContactSetting() got a > 255 module name length. \n");
+ #endif
+ 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,ofsModuleName);
+ if(ofsSettingsGroup==0) {
+ LeaveCriticalSection(&csDbAccess);
+ return 1;
+ }
+ //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,moduleNameLen,settingNameLen);
+ GetCachedValuePtr((HANDLE)saveWparam, szCachedSettingName, -1 );
+
+ //quit
+ DBFlush(1);
+ LeaveCriticalSection(&csDbAccess);
+ { //notify
+ DBCONTACTWRITESETTING dbcws={0};
+ 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;
+ 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,ofsModuleName);
+ if(!dbces->ofsSettings) {
+ LeaveCriticalSection(&csDbAccess);
+ return -1;
+ }
+ 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;
+}
+
+static INT_PTR EnumResidentSettings(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ int ret;
+ for(i = 0; i < lResidentSettings.realCount; i++) {
+ ret=((DBMODULEENUMPROC)lParam)(lResidentSettings.items[i],0,wParam);
+ if(ret) return ret;
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Module initialization procedure
+
+static int stringCompare( DBCachedSettingName* p1, DBCachedSettingName* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static int stringCompare2( char* p1, char* p2 )
+{
+ return strcmp( p1, p2);
+}
+
+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);
+ CreateServiceFunction("DB/ResidentSettings/Enum",EnumResidentSettings);
+
+ hSettingChangeEvent=CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED);
+
+ hCacheHeap=HeapCreate(0,0,0);
+ lSettings.sortFunc=stringCompare;
+ lSettings.increment=100;
+ lContacts.sortFunc=HandleKeySort;
+ lContacts.increment=50;
+ lGlobalSettings.sortFunc=HandleKeySort;
+ lGlobalSettings.increment=50;
+ lResidentSettings.sortFunc=stringCompare2;
+ lResidentSettings.increment=50;
+
+ mirCp = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+ return 0;
+}
+
+void UninitSettings(void)
+{
+ HeapDestroy(hCacheHeap);
+ li.List_Destroy(&lContacts);
+ li.List_Destroy(&lSettings);
+ li.List_Destroy(&lGlobalSettings);
+ li.List_Destroy(&lResidentSettings);
+}