summaryrefslogtreecommitdiff
path: root/plugins/Db3x_mmap/src/dbsettings.cpp
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-07-23 06:41:38 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-07-23 06:41:38 +0000
commit9126d2b133d00b836fca640f847a0948f7579e02 (patch)
tree7e915c08cc0e52aaa6244e709acffa91a31715a3 /plugins/Db3x_mmap/src/dbsettings.cpp
parent33e535df429971555b212f4abaff1b6adb8e7c23 (diff)
Db3x_mmap,Db_autobackups: changed folder structure
git-svn-id: http://svn.miranda-ng.org/main/trunk@1107 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/Db3x_mmap/src/dbsettings.cpp')
-rw-r--r--plugins/Db3x_mmap/src/dbsettings.cpp933
1 files changed, 933 insertions, 0 deletions
diff --git a/plugins/Db3x_mmap/src/dbsettings.cpp b/plugins/Db3x_mmap/src/dbsettings.cpp
new file mode 100644
index 0000000000..49ac018047
--- /dev/null
+++ b/plugins/Db3x_mmap/src/dbsettings.cpp
@@ -0,0 +1,933 @@
+/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright 2012 Miranda NG 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);
+
+int DBPreset_QuerySetting(const char *szModule, const char *szSetting, DBVARIANT *dbv, BOOL isStatic);
+
+DWORD CDdxMmap::GetSettingsGroupOfsByModuleNameOfs(DBContact *dbc,DWORD ofsModuleName)
+{
+ DWORD ofsThis = dbc->ofsFirstSettings;
+ while (ofsThis) {
+ DBContactSettings *dbcs = (DBContactSettings*)DBRead(ofsThis,sizeof(DBContactSettings),NULL);
+ if (dbcs->signature != DBCONTACTSETTINGS_SIGNATURE) DatabaseCorruption(NULL);
+ if (dbcs->ofsModuleName == ofsModuleName)
+ return ofsThis;
+
+ ofsThis = dbcs->ofsNext;
+ }
+ return 0;
+}
+
+DWORD __forceinline GetSettingValueLength(PBYTE pSetting)
+{
+ if (pSetting[0] & DBVTF_VARIABLELENGTH)
+ return 2+*(PWORD)(pSetting+1);
+ return pSetting[0];
+}
+
+char* CDdxMmap::InsertCachedSetting(const char* szName, size_t cbNameLen)
+{
+ char* newValue = (char*)HeapAlloc(m_hCacheHeap, 0, cbNameLen);
+ *newValue = 0;
+ strcpy(newValue+1, szName+1);
+ m_lSettings.insert(newValue);
+ return newValue;
+}
+
+char* CDdxMmap::GetCachedSetting(const char *szModuleName,const char *szSettingName, int moduleNameLen, int settingNameLen)
+{
+ char szFullName[512];
+ strcpy(szFullName+1,szModuleName);
+ szFullName[moduleNameLen+1] = '/';
+ strcpy(szFullName+moduleNameLen+2,szSettingName);
+
+ if (m_lastSetting && strcmp(szFullName+1, m_lastSetting) == 0)
+ return m_lastSetting;
+
+ int index = m_lSettings.getIndex(szFullName);
+ if (index != -1)
+ m_lastSetting = m_lSettings[index]+1;
+ else
+ m_lastSetting = InsertCachedSetting( szFullName, settingNameLen+moduleNameLen+3)+1;
+
+ return m_lastSetting;
+}
+
+void CDdxMmap::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(m_hCacheHeap,0,szSave,strlen(s->pszVal)+1);
+ else
+ d->pszVal = (char*)HeapAlloc(m_hCacheHeap,0,strlen(s->pszVal)+1);
+ strcpy(d->pszVal,s->pszVal);
+ }
+ else if ( szSave != NULL )
+ HeapFree(m_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 CDdxMmap::FreeCachedVariant( DBVARIANT* V )
+{
+ if (( V->type == DBVT_ASCIIZ || V->type == DBVT_UTF8 ) && V->pszVal != NULL )
+ HeapFree(m_hCacheHeap,0,V->pszVal);
+}
+
+DBVARIANT* CDdxMmap::GetCachedValuePtr( HANDLE hContact, char* szSetting, int bAllocate )
+{
+ if ( hContact == 0 ) {
+ DBCachedGlobalValue Vtemp, *V;
+ Vtemp.name = szSetting;
+ int index = m_lGlobalSettings.getIndex(&Vtemp);
+ if (index != -1) {
+ V = m_lGlobalSettings[index];
+ if ( bAllocate == -1 ) {
+ FreeCachedVariant( &V->value );
+ m_lGlobalSettings.remove(index);
+ HeapFree(m_hCacheHeap,0,V);
+ return NULL;
+ }
+ }
+ else {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ V = (DBCachedGlobalValue*)HeapAlloc(m_hCacheHeap,HEAP_ZERO_MEMORY,sizeof(DBCachedGlobalValue));
+ V->name = szSetting;
+ m_lGlobalSettings.insert(V);
+ }
+
+ return &V->value;
+ }
+ else {
+ DBCachedContactValue *V, *V1;
+ DBCachedContactValueList VLtemp,*VL;
+
+ if (m_hLastCachedContact == hContact && m_lastVL)
+ VL = m_lastVL;
+ else {
+ VLtemp.hContact = hContact;
+
+ int index = m_lContacts.getIndex(&VLtemp);
+ if (index == -1) {
+ if ( bAllocate != 1 )
+ return NULL;
+
+ VL = AddToCachedContactList(hContact, index);
+ }
+ else VL = m_lContacts[index];
+
+ m_lastVL = VL;
+ m_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 = (DBCachedContactValue *)HeapAlloc(m_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 ) {
+ m_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(m_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)
+
+int CDdxMmap::GetContactSettingWorker(HANDLE hContact,DBCONTACTGETSETTING *dbcgs,int isStatic)
+{
+ 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;
+ }
+
+ mir_cslock lck(m_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;
+ }
+
+ return ( pCachedValue->type == DBVT_DELETED ) ? 1 : 0;
+ } }
+
+ ofsModuleName = GetModuleNameOfs(dbcgs->szModule);
+ if (hContact == NULL) ofsContact = m_dbHeader.ofsUser;
+ else ofsContact = (DWORD)hContact;
+ dbc = (DBContact*)DBRead(ofsContact,sizeof(DBContact),NULL);
+ if (dbc->signature != DBCONTACT_SIGNATURE)
+ return 1;
+
+ ofsSettingsGroup = GetSettingsGroupOfsByModuleNameOfs(dbc,ofsModuleName);
+ if (ofsSettingsGroup) {
+ ofsBlobPtr = ofsSettingsGroup+offsetof(DBContactSettings,blob);
+ pBlob = DBRead(ofsBlobPtr,sizeof(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]))
+ return 1;
+
+ dbcgs->pValue->type = pBlob[0];
+ switch(pBlob[0]) {
+ case DBVT_DELETED: /* this setting is deleted */
+ dbcgs->pValue->type = DBVT_DELETED;
+ return 2;
+
+ case DBVT_BYTE: dbcgs->pValue->bVal = pBlob[1]; break;
+ case DBVT_WORD: DecodeCopyMemory(&(dbcgs->pValue->wVal), (PWORD)(pBlob+1), 2); break;
+ case DBVT_DWORD: DecodeCopyMemory(&(dbcgs->pValue->dVal), (PDWORD)(pBlob+1), 4); 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);
+ DecodeCopyMemory(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));
+ DecodeCopyMemory(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);
+ DecodeCopyMemory(dbcgs->pValue->pbVal,pBlob+3,dbcgs->pValue->cpbVal);
+ }
+ else {
+ dbcgs->pValue->pbVal = (BYTE *)mir_alloc(*(PWORD)(pBlob+1));
+ DecodeCopyMemory(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);
+ }
+
+ logg();
+ return 0;
+ }
+ NeedBytes(1);
+ MoveAlong(pBlob[0]+1);
+ NeedBytes(3);
+ MoveAlong(1+GetSettingValueLength(pBlob));
+ NeedBytes(1);
+ } }
+
+ #ifndef DB3X_EXPORTS
+ /**** nullbie: query info from preset **********************/
+ if (!hContact && DBPreset_QuerySetting(dbcgs->szModule, dbcgs->szSetting, dbcgs->pValue, isStatic)) {
+ /**** add to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB ) {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ SetCachedVariant(dbcgs->pValue,pCachedValue);
+ }
+ return 0;
+ }
+ #endif
+
+ /**** add missing setting to cache **********************/
+ if ( dbcgs->pValue->type != DBVT_BLOB )
+ {
+ DBVARIANT* pCachedValue = GetCachedValuePtr( hContact, szCachedSettingName, 1 );
+ if ( pCachedValue != NULL )
+ pCachedValue->type = DBVT_DELETED;
+ }
+
+ logg();
+ return 1;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::GetContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dgs)
+{
+ dgs->pValue->type = 0;
+ if ( GetContactSettingWorker(hContact, 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( m_codePage, WC_NO_BEST_FIT_CHARS, tmp, -1, NULL, 0, NULL, &bUsed );
+
+ mir_free( dgs->pValue->pszVal );
+
+ if ( bUsed || result == 0 ) {
+ dgs->pValue->type = DBVT_WCHAR;
+ dgs->pValue->pwszVal = tmp;
+ }
+ else {
+ dgs->pValue->type = DBVT_ASCIIZ;
+ dgs->pValue->pszVal = (char *)mir_alloc(result);
+ WideCharToMultiByte( m_codePage, 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;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::GetContactSettingStr(HANDLE hContact, DBCONTACTGETSETTING *dgs)
+{
+ int iSaveType = dgs->pValue->type;
+
+ if ( GetContactSettingWorker(hContact, 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;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::GetContactSettingStatic(HANDLE hContact, DBCONTACTGETSETTING *dgs)
+{
+ if ( GetContactSettingWorker(hContact, dgs, 1 ))
+ return 1;
+
+ if ( dgs->pValue->type == DBVT_UTF8 ) {
+ mir_utf8decode( dgs->pValue->pszVal, NULL );
+ dgs->pValue->type = DBVT_ASCIIZ;
+ }
+
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::FreeVariant(DBVARIANT *dbv)
+{
+ 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;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::SetSettingResident(BOOL bIsResident, const char *pszSettingName)
+{
+ size_t cbSettingNameLen = strlen(pszSettingName) + 2;
+ if (cbSettingNameLen < 512) {
+ char* szSetting;
+ char szTemp[512];
+ strcpy( szTemp+1, pszSettingName);
+
+ mir_cslock lck(m_csDbAccess);
+ int idx = m_lSettings.getIndex(szTemp);
+ if (idx == -1)
+ szSetting = InsertCachedSetting( szTemp, cbSettingNameLen);
+ else
+ szSetting = m_lSettings[idx];
+
+ *szSetting = (char)bIsResident;
+
+ idx = m_lResidentSettings.getIndex(szSetting+1);
+ if (idx == -1) {
+ if (bIsResident)
+ m_lResidentSettings.insert(szSetting+1);
+ }
+ else if (!bIsResident)
+ m_lResidentSettings.remove(idx);
+ }
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::WriteContactSetting(HANDLE hContact, DBCONTACTWRITESETTING *dbcws)
+{
+ DBCONTACTWRITESETTING tmp;
+ DWORD ofsModuleName;
+ 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;
+ }
+ }
+ }
+
+ mir_cslockfull lck(m_csDbAccess);
+
+ char* szCachedSettingName = GetCachedSetting(tmp.szModule, tmp.szSetting, moduleNameLen, settingNameLen);
+ if ( tmp.value.type != DBVT_BLOB ) {
+ DBVARIANT* pCachedValue = GetCachedValuePtr(hContact, 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 )
+ return 0;
+ }
+ SetCachedVariant(&tmp.value, pCachedValue);
+ }
+ if ( szCachedSettingName[-1] != 0 ) {
+ lck.unlock();
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (LPARAM)&tmp);
+ return 0;
+ }
+ }
+ else GetCachedValuePtr(hContact, szCachedSettingName, -1);
+
+ ofsModuleName = GetModuleNameOfs(tmp.szModule);
+ if (hContact == 0) ofsContact = m_dbHeader.ofsUser;
+ else ofsContact = (DWORD)hContact;
+
+ DBContact dbc = *(DBContact*)DBRead(ofsContact,sizeof(DBContact),NULL);
+ if (dbc.signature != DBCONTACT_SIGNATURE)
+ 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(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(DBContact));
+ DBWrite(ofsSettingsGroup,&dbcs,sizeof(DBContactSettings));
+ ofsBlobPtr = ofsSettingsGroup+offsetof(DBContactSettings,blob);
+ pBlob = (PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ }
+ else {
+ dbcs = *(DBContactSettings*)DBRead(ofsSettingsGroup,sizeof(DBContactSettings),&bytesRemaining);
+ //find if the setting exists
+ ofsBlobPtr = ofsSettingsGroup+offsetof(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: EncodeDBWrite(ofsBlobPtr,&tmp.value.wVal,2); break;
+ case DBVT_DWORD: EncodeDBWrite(ofsBlobPtr,&tmp.value.dVal,4); break;
+ case DBVT_UTF8:
+ case DBVT_ASCIIZ: EncodeDBWrite(ofsBlobPtr+2,tmp.value.pszVal,(int)strlen(tmp.value.pszVal)); break;
+ case DBVT_BLOB: EncodeDBWrite(ofsBlobPtr+2,tmp.value.pbVal,tmp.value.cpbVal); break;
+ }
+ //quit
+ DBFlush(1);
+ lck.unlock();
+ //notify
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (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(DBContactSettings,blob));
+ if ((DWORD)bytesRequired > dbcs.cbBlob) {
+ //doesn't fit: move entire group
+ 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 = (DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(DBContactSettings),NULL);
+ while (dbcsPrev->ofsNext != ofsSettingsGroup) {
+ if (dbcsPrev->ofsNext == 0) DatabaseCorruption(NULL);
+ ofsDbcsPrev = dbcsPrev->ofsNext;
+ dbcsPrev = (DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(DBContactSettings),NULL);
+ }
+ }
+
+ //create the new one
+ ofsNew = ReallocSpace(ofsSettingsGroup, dbcs.cbBlob+offsetof(DBContactSettings,blob), bytesRequired+offsetof(DBContactSettings,blob));
+
+ dbcs.cbBlob = bytesRequired;
+
+ DBWrite(ofsNew,&dbcs,offsetof(DBContactSettings,blob));
+ if (ofsDbcsPrev == 0) {
+ dbc.ofsFirstSettings = ofsNew;
+ DBWrite(ofsContact,&dbc,sizeof(DBContact));
+ }
+ else {
+ dbcsPrev = (DBContactSettings*)DBRead(ofsDbcsPrev,sizeof(DBContactSettings),NULL);
+ dbcsPrev->ofsNext = ofsNew;
+ DBWrite(ofsDbcsPrev,dbcsPrev,offsetof(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: EncodeDBWrite(ofsBlobPtr,&tmp.value.wVal,2); MoveAlong(2); break;
+ case DBVT_DWORD: EncodeDBWrite(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);
+ EncodeDBWrite(ofsBlobPtr+2,tmp.value.pszVal,len);
+ MoveAlong(2+len);
+ }
+ break;
+ case DBVT_BLOB:
+ DBWrite(ofsBlobPtr,&tmp.value.cpbVal,2) ;
+ EncodeDBWrite(ofsBlobPtr+2,tmp.value.pbVal,tmp.value.cpbVal);
+ MoveAlong(2+tmp.value.cpbVal);
+ break;
+ }
+
+ BYTE zero = 0;
+ DBWrite(ofsBlobPtr,&zero,1);
+
+ //quit
+ DBFlush(1);
+ lck.unlock();
+
+ //notify
+ NotifyEventHooks(hSettingChangeEvent, (WPARAM)hContact, (LPARAM)&tmp );
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::DeleteContactSetting(HANDLE hContact, DBCONTACTGETSETTING *dbcgs)
+{
+ DBContact *dbc;
+ DWORD ofsModuleName,ofsSettingsGroup,ofsBlobPtr;
+ PBYTE pBlob;
+ int settingNameLen,moduleNameLen,bytesRemaining;
+ char* szCachedSettingName;
+ WPARAM saveWparam = (WPARAM)hContact;
+
+ 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;
+ }
+
+ mir_cslockfull lck(m_csDbAccess);
+ ofsModuleName = GetModuleNameOfs(dbcgs->szModule);
+ if (hContact == 0)
+ hContact = (HANDLE)m_dbHeader.ofsUser;
+
+ dbc = (DBContact*)DBRead(hContact,sizeof(DBContact),NULL);
+ if (dbc->signature != DBCONTACT_SIGNATURE)
+ return 1;
+
+ //make sure the module group exists
+ ofsSettingsGroup = GetSettingsGroupOfsByModuleNameOfs(dbc,ofsModuleName);
+ if (ofsSettingsGroup == 0)
+ return 1;
+
+ //find if the setting exists
+ ofsBlobPtr = ofsSettingsGroup+offsetof(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
+ 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);
+ lck.unlock();
+
+ //notify
+ DBCONTACTWRITESETTING dbcws = {0};
+ dbcws.szModule = dbcgs->szModule;
+ dbcws.szSetting = dbcgs->szSetting;
+ dbcws.value.type = DBVT_DELETED;
+ NotifyEventHooks(hSettingChangeEvent,saveWparam,(LPARAM)&dbcws);
+ return 0;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::EnumContactSettings(HANDLE hContact, DBCONTACTENUMSETTINGS* dbces)
+{
+ DBContact *dbc;
+ DWORD ofsModuleName,ofsContact,ofsBlobPtr;
+ int bytesRemaining, result;
+ PBYTE pBlob;
+ char szSetting[256];
+
+ if (!dbces->szModule)
+ return -1;
+
+ mir_cslock lck(m_csDbAccess);
+
+ ofsModuleName = GetModuleNameOfs(dbces->szModule);
+ if (hContact == 0) ofsContact = m_dbHeader.ofsUser;
+ else ofsContact = (DWORD)hContact;
+ dbc = (DBContact*)DBRead(ofsContact,sizeof(DBContact),NULL);
+ if (dbc->signature != DBCONTACT_SIGNATURE)
+ return -1;
+
+ dbces->ofsSettings = GetSettingsGroupOfsByModuleNameOfs(dbc,ofsModuleName);
+ if ( !dbces->ofsSettings)
+ return -1;
+
+ ofsBlobPtr = dbces->ofsSettings+offsetof(DBContactSettings,blob);
+ pBlob = (PBYTE)DBRead(ofsBlobPtr,1,&bytesRemaining);
+ if (pBlob[0] == 0)
+ 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);
+ }
+ return result;
+}
+
+STDMETHODIMP_(BOOL) CDdxMmap::EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam)
+{
+ for(int i = 0; i < m_lResidentSettings.getCount(); i++) {
+ int ret = pFunc(m_lResidentSettings[i], 0, (LPARAM)pParam);
+ if (ret) return ret;
+ }
+ return 0;
+}