From 1204c8ca267a83f1df6b8087bbfc5335ffb5090d Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sat, 23 Jun 2012 17:30:56 +0000 Subject: Db3x_mmap: renamed to .cpp git-svn-id: http://svn.miranda-ng.org/main/trunk@575 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Db3x_mmap/dbsettings.cpp | 1013 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1013 insertions(+) create mode 100644 plugins/Db3x_mmap/dbsettings.cpp (limited to 'plugins/Db3x_mmap/dbsettings.cpp') diff --git a/plugins/Db3x_mmap/dbsettings.cpp b/plugins/Db3x_mmap/dbsettings.cpp new file mode 100644 index 0000000000..451ea95501 --- /dev/null +++ b/plugins/Db3x_mmap/dbsettings.cpp @@ -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(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,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)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) +{ + 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); +} -- cgit v1.2.3