Пример #1
0
STDMETHODIMP_(BOOL) CDbxMdb::EnumContactSettings(MCONTACT contactID, DBCONTACTENUMSETTINGS* dbces)
{
	if (!dbces->szModule)
		return -1;

	int result = -1;

	DBSettingKey keySearch;
	keySearch.dwContactID = contactID;
	keySearch.dwOfsModule = GetModuleNameOfs(dbces->szModule);
	memset(keySearch.szSettingName, 0, _countof(keySearch.szSettingName));

	mir_cslockfull lck(m_csDbAccess);
	txn_ptr_ro trnlck(m_txn);
	cursor_ptr_ro cursor(m_curSettings);

	MDB_val key = { sizeof(keySearch), &keySearch }, data;

	if (mdb_cursor_get(cursor, &key, &data, MDB_SET_RANGE) == MDB_SUCCESS) 
	{
		do 
		{
			const DBSettingKey *pKey = (const DBSettingKey*)key.mv_data;
			if (pKey->dwContactID != contactID || pKey->dwOfsModule != keySearch.dwOfsModule)
				return result;

			char szSetting[256];
			strncpy_s(szSetting, pKey->szSettingName, key.mv_size - sizeof(DWORD) * 2);
			result = (dbces->pfnEnumProc)(szSetting, dbces->lParam);
		}
			while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == MDB_SUCCESS);
	}

	return result;
}
Пример #2
0
int CDbxMdb::Load(bool bSkipInit)
{
	if (!Remap())
		return EGROKPRF_CANTREAD;

	if (!bSkipInit) {
		txn_ptr trnlck(m_pMdbEnv);
		mdb_open(trnlck, "global", MDB_CREATE | MDB_INTEGERKEY, &m_dbGlobal);
		mdb_open(trnlck, "contacts", MDB_CREATE | MDB_INTEGERKEY, &m_dbContacts);
		mdb_open(trnlck, "modules", MDB_CREATE | MDB_INTEGERKEY, &m_dbModules);
		mdb_open(trnlck, "events", MDB_CREATE | MDB_INTEGERKEY, &m_dbEvents);
		mdb_open(trnlck, "eventsrt", MDB_CREATE | MDB_INTEGERKEY, &m_dbEventsSort);
		mdb_open(trnlck, "settings", MDB_CREATE, &m_dbSettings);

		DWORD keyVal = 1;
		MDB_val key = { sizeof(DWORD), &keyVal }, data;
		if (mdb_get(trnlck, m_dbGlobal, &key, &data) == MDB_SUCCESS) {
			DBHeader *hdr = (DBHeader*)data.mv_data;
			if (hdr->dwSignature != DBHEADER_SIGNATURE)
				DatabaseCorruption(NULL);

			memcpy(&m_header, data.mv_data, sizeof(m_header));
		}
		else {
			m_header.dwSignature = DBHEADER_SIGNATURE;
			m_header.dwVersion = 1;
			data.mv_data = &m_header; data.mv_size = sizeof(m_header);
			mdb_put(trnlck, m_dbGlobal, &key, &data, 0);

			keyVal = 0;
			DBContact dbc = { DBCONTACT_SIGNATURE, 0, 0, 0 };
			data.mv_data = &dbc; data.mv_size = sizeof(dbc);
			mdb_put(trnlck, m_dbContacts, &key, &data, 0);
		}
		trnlck.commit();

		if (InitModuleNames()) return EGROKPRF_CANTREAD;
		if (InitCrypt())       return EGROKPRF_CANTREAD;

		// everything is ok, go on
		if (!m_bReadOnly) {
			// we don't need events in the service mode
			if (ServiceExists(MS_DB_SETSAFETYMODE)) {
				hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED);
				hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED);
				hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED);
				hEventMarkedRead = CreateHookableEvent(ME_DB_EVENT_MARKED_READ);

				hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED);
				hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED);
				hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD);
			}
		}

		FillContacts();
	}

	return ERROR_SUCCESS;
}
Пример #3
0
STDMETHODIMP_(BOOL) CDbxMdb::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting)
{
	if (!szModule || !szSetting)
		return 1;

	// the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
	int settingNameLen = (int)strlen(szSetting);
	int moduleNameLen = (int)strlen(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;
	}

	MCONTACT saveContact = contactID;
	{
		mir_cslock lck(m_csDbAccess);
		char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen);
		if (szCachedSettingName[-1] == 0) { // it's not a resident variable
			DBSettingKey keySearch;
			keySearch.dwContactID = contactID;
			keySearch.dwOfsModule = GetModuleNameOfs(szModule);
			strncpy_s(keySearch.szSettingName, szSetting, _TRUNCATE);

			MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data;

			for (;; Remap()) {
				txn_ptr trnlck(m_pMdbEnv);
				if (mdb_del(trnlck, m_dbSettings, &key, &data))
					return 1;

				if (trnlck.commit())
					break;
			}
		}

		m_cache->GetCachedValuePtr(saveContact, szCachedSettingName, -1);
	}

	// notify
	DBCONTACTWRITESETTING dbcws = { 0 };
	dbcws.szModule = szModule;
	dbcws.szSetting = szSetting;
	dbcws.value.type = DBVT_DELETED;
	NotifyEventHooks(hSettingChangeEvent, saveContact, (LPARAM)&dbcws);
	return 0;
}
Пример #4
0
STDMETHODIMP_(BOOL) CDbxMdb::EnumContactSettings(MCONTACT contactID, DBCONTACTENUMSETTINGS* dbces)
{
	if (!dbces->szModule)
		return -1;

	int result = 0;
	mir_cslock lck(m_csDbAccess);

	DBSettingKey keySearch;
	keySearch.dwContactID = contactID;
	keySearch.dwOfsModule = GetModuleNameOfs(dbces->szModule);
	memset(keySearch.szSettingName, 0, SIZEOF(keySearch.szSettingName));

	LIST<char> arSettings(50);
	{
		txn_ptr trnlck(m_pMdbEnv, true);
		cursor_ptr cursor(trnlck, m_dbSettings);

		MDB_val key = { sizeof(keySearch), &keySearch }, data;
		if (mdb_cursor_get(cursor, &key, &data, MDB_SET_RANGE) == MDB_SUCCESS) {
			do {
				DBSettingKey *pKey = (DBSettingKey*)key.mv_data;
				if (pKey->dwContactID != contactID || pKey->dwOfsModule != keySearch.dwOfsModule)
					break;

				char szSetting[256];
				strncpy_s(szSetting, pKey->szSettingName, key.mv_size - sizeof(DWORD) * 2);
				arSettings.insert(mir_strdup(szSetting));
			}
				while (mdb_cursor_get(cursor, &key, &data, MDB_NEXT) == MDB_SUCCESS);
		}
	}

	if (arSettings.getCount() == 0)
		return -1;

	for (int i = 0; i < arSettings.getCount(); i++) {
		result = (dbces->pfnEnumProc)(arSettings[i], dbces->lParam);
		mir_free(arSettings[i]);
	}

	return result;
}
Пример #5
0
STDMETHODIMP_(BOOL) CDbxMdb::DeleteContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting)
{
	if (!szModule || !szSetting)
		return 1;

	int settingNameLen = (int)strlen(szSetting);
	int moduleNameLen = (int)strlen(szModule);

	MCONTACT saveContact = contactID;
	{
		mir_cslock lck(m_csDbAccess);
		char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen);
		if (szCachedSettingName[-1] == 0) { // it's not a resident variable
			DBSettingKey keySearch;
			keySearch.dwContactID = contactID;
			keySearch.dwOfsModule = GetModuleNameOfs(szModule);
			strncpy_s(keySearch.szSettingName, szSetting, _TRUNCATE);

			MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data;

			for (;; Remap()) 
			{
				txn_ptr trnlck(m_pMdbEnv);
				MDB_CHECK(mdb_del(trnlck, m_dbSettings, &key, &data), 1);
				if (trnlck.commit())
					break;
			}
		}

		m_cache->GetCachedValuePtr(saveContact, szCachedSettingName, -1);
	}

	// notify
	DBCONTACTWRITESETTING dbcws = { 0 };
	dbcws.szModule = szModule;
	dbcws.szSetting = szSetting;
	dbcws.value.type = DBVT_DELETED;
	NotifyEventHooks(hSettingChangeEvent, saveContact, (LPARAM)&dbcws);
	return 0;
}
Пример #6
0
int CDbxMdb::GetContactSettingWorker(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic)
{
	if (szSetting == NULL || szModule == NULL)
		return 1;

	// the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
	int settingNameLen = (int)strlen(szSetting);
	int moduleNameLen = (int)strlen(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);

LBL_Seek:
	char *szCachedSettingName = m_cache->GetCachedSetting(szModule, szSetting, moduleNameLen, settingNameLen);

	DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 0);
	if (pCachedValue != NULL) {
		if (pCachedValue->type == DBVT_ASCIIZ || pCachedValue->type == DBVT_UTF8) {
			int cbOrigLen = dbv->cchVal;
			char *cbOrigPtr = dbv->pszVal;
			memcpy(dbv, pCachedValue, sizeof(DBVARIANT));
			if (isStatic) {
				int cbLen = 0;
				if (pCachedValue->pszVal != NULL)
					cbLen = (int)strlen(pCachedValue->pszVal);

				cbOrigLen--;
				dbv->pszVal = cbOrigPtr;
				if (cbLen < cbOrigLen)
					cbOrigLen = cbLen;
				memcpy(dbv->pszVal, pCachedValue->pszVal, cbOrigLen);
				dbv->pszVal[cbOrigLen] = 0;
				dbv->cchVal = cbLen;
			}
			else {
				dbv->pszVal = (char*)mir_alloc(strlen(pCachedValue->pszVal) + 1);
				strcpy(dbv->pszVal, pCachedValue->pszVal);
			}
		}
		else memcpy(dbv, pCachedValue, sizeof(DBVARIANT));

		return (pCachedValue->type == DBVT_DELETED) ? 1 : 0;
	}

	// never look db for the resident variable
	if (szCachedSettingName[-1] != 0)
		return 1;

	DBCachedContact *cc = (contactID) ? m_cache->GetCachedContact(contactID) : NULL;

	txn_ptr trnlck(m_pMdbEnv);
	//mdb_open(trnlck, "settings", 0, &m_dbSettings);

	DBSettingKey keySearch;
	keySearch.dwContactID = contactID;
	keySearch.dwOfsModule = GetModuleNameOfs(szModule);
	strncpy_s(keySearch.szSettingName, szSetting, _TRUNCATE);

	MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data;
	if (mdb_get(trnlck, m_dbSettings, &key, &data)) {
		// try to get the missing mc setting from the active sub
		if (cc && cc->IsMeta() && ValidLookupName(szModule, szSetting)) {
			if (contactID = db_mc_getDefault(contactID)) {
				if (szModule = GetContactProto(contactID)) {
					moduleNameLen = (int)strlen(szModule);
					goto LBL_Seek;
				}
			}
		}
		return 1;
	}

	BYTE *pBlob = (BYTE*)data.mv_data;
	if (isStatic && (pBlob[0] & DBVTF_VARIABLELENGTH) && VLT(dbv->type) != VLT(pBlob[0]))
		return 1;

	int varLen;
	BYTE iType = dbv->type = pBlob[0]; pBlob++;
	switch (iType) {
	case DBVT_DELETED: /* this setting is deleted */
		dbv->type = DBVT_DELETED;
		return 2;

	case DBVT_BYTE:  dbv->bVal = *pBlob; break;
	case DBVT_WORD:  dbv->wVal = *(WORD*)pBlob; break;
	case DBVT_DWORD: dbv->dVal = *(DWORD*)pBlob; break;

	case DBVT_UTF8:
	case DBVT_ASCIIZ:
		varLen = *(WORD*)pBlob;
		pBlob += 2;
		if (isStatic) {
			dbv->cchVal--;
			if (varLen < dbv->cchVal)
				dbv->cchVal = varLen;
			memmove(dbv->pszVal, pBlob, dbv->cchVal); // decode
			dbv->pszVal[dbv->cchVal] = 0;
			dbv->cchVal = varLen;
		}
		else {
			dbv->pszVal = (char*)mir_alloc(1 + varLen);
			memmove(dbv->pszVal, pBlob, varLen);
			dbv->pszVal[varLen] = 0;
		}
		break;

	case DBVT_BLOB:
		varLen = *(WORD*)pBlob;
		pBlob += 2;
		if (isStatic) {
			if (varLen < dbv->cpbVal)
				dbv->cpbVal = varLen;
			memmove(dbv->pbVal, pBlob, dbv->cpbVal);
		}
		else {
			dbv->pbVal = (BYTE *)mir_alloc(varLen);
			memmove(dbv->pbVal, pBlob, varLen);
		}
		dbv->cpbVal = varLen;
		break;

	case DBVT_ENCRYPTED:
		if (m_crypto == NULL)
			return 1;

		varLen = *(WORD*)pBlob;
		pBlob += 2;
		
		size_t realLen;
		ptrA decoded(m_crypto->decodeString(pBlob, varLen, &realLen));
		if (decoded == NULL)
			return 1;

		varLen = (WORD)realLen;
		dbv->type = DBVT_UTF8;
		if (isStatic) {
			dbv->cchVal--;
			if (varLen < dbv->cchVal)
				dbv->cchVal = varLen;
			memmove(dbv->pszVal, decoded, dbv->cchVal);
			dbv->pszVal[dbv->cchVal] = 0;
			dbv->cchVal = varLen;
		}
		else {
			dbv->pszVal = (char*)mir_alloc(1 + varLen);
			memmove(dbv->pszVal, decoded, varLen);
			dbv->pszVal[varLen] = 0;
		}
		break;
	}

	/**** add to cache **********************/
	if (iType != DBVT_BLOB && iType != DBVT_ENCRYPTED) {
		DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1);
		if (pCachedValue != NULL)
			m_cache->SetCachedVariant(dbv, pCachedValue);
	}

	return 0;
}
Пример #7
0
STDMETHODIMP_(BOOL) CDbxMdb::WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws)
{
	if (dbcws == NULL || dbcws->szSetting == NULL || dbcws->szModule == NULL || m_bReadOnly)
		return 1;

	// the db format can't tolerate more than 255 bytes of space (incl. null) for settings+module name
	int settingNameLen = (int)strlen(dbcws->szSetting);
	int 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;
	}

	// used for notifications
	DBCONTACTWRITESETTING dbcwNotif = *dbcws;
	if (dbcwNotif.value.type == DBVT_WCHAR) {
		if (dbcwNotif.value.pszVal != NULL) {
			char* val = mir_utf8encodeW(dbcwNotif.value.pwszVal);
			if (val == NULL)
				return 1;

			dbcwNotif.value.pszVal = (char*)alloca(strlen(val) + 1);
			strcpy(dbcwNotif.value.pszVal, val);
			mir_free(val);
			dbcwNotif.value.type = DBVT_UTF8;
		}
		else return 1;
	}

	if (dbcwNotif.szModule == NULL || dbcwNotif.szSetting == NULL)
		return 1;

	DBCONTACTWRITESETTING dbcwWork = dbcwNotif;

	mir_ptr<BYTE> pEncoded(NULL);
	bool bIsEncrypted = false;
	switch (dbcwWork.value.type) {
	case DBVT_BYTE: case DBVT_WORD: case DBVT_DWORD:
		break;

	case DBVT_ASCIIZ: case DBVT_UTF8:
		bIsEncrypted = m_bEncrypted || IsSettingEncrypted(dbcws->szModule, dbcws->szSetting);
	LBL_WriteString:
		if (dbcwWork.value.pszVal == NULL)
			return 1;
		dbcwWork.value.cchVal = (WORD)strlen(dbcwWork.value.pszVal);
		if (bIsEncrypted) {
			size_t len;
			BYTE *pResult = m_crypto->encodeString(dbcwWork.value.pszVal, &len);
			if (pResult != NULL) {
				pEncoded = dbcwWork.value.pbVal = pResult;
				dbcwWork.value.cpbVal = (WORD)len;
				dbcwWork.value.type = DBVT_ENCRYPTED;
			}
		}
		break;

	case DBVT_UNENCRYPTED:
		dbcwNotif.value.type = dbcwWork.value.type = DBVT_UTF8;
		goto LBL_WriteString;

	case DBVT_BLOB: case DBVT_ENCRYPTED:
		if (dbcwWork.value.pbVal == NULL)
			return 1;
		break;
	default:
		return 1;
	}

	mir_cslockfull lck(m_csDbAccess);

	char *szCachedSettingName = m_cache->GetCachedSetting(dbcwWork.szModule, dbcwWork.szSetting, moduleNameLen, settingNameLen);

	// we don't cache blobs and passwords
	if (dbcwWork.value.type != DBVT_BLOB && dbcwWork.value.type != DBVT_ENCRYPTED && !bIsEncrypted) {
		DBVARIANT *pCachedValue = m_cache->GetCachedValuePtr(contactID, szCachedSettingName, 1);
		if (pCachedValue != NULL) {
			bool bIsIdentical = false;
			if (pCachedValue->type == dbcwWork.value.type) {
				switch (dbcwWork.value.type) {
				case DBVT_BYTE:   bIsIdentical = pCachedValue->bVal == dbcwWork.value.bVal;  break;
				case DBVT_WORD:   bIsIdentical = pCachedValue->wVal == dbcwWork.value.wVal;  break;
				case DBVT_DWORD:  bIsIdentical = pCachedValue->dVal == dbcwWork.value.dVal;  break;
				case DBVT_UTF8:
				case DBVT_ASCIIZ: bIsIdentical = strcmp(pCachedValue->pszVal, dbcwWork.value.pszVal) == 0; break;
				}
				if (bIsIdentical)
					return 0;
			}
			m_cache->SetCachedVariant(&dbcwWork.value, pCachedValue);
		}
		if (szCachedSettingName[-1] != 0) {
			lck.unlock();
			NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwWork);
			return 0;
		}
	}
	else m_cache->GetCachedValuePtr(contactID, szCachedSettingName, -1);

	DBSettingKey keySearch;
	keySearch.dwContactID = contactID;
	keySearch.dwOfsModule = GetModuleNameOfs(dbcws->szModule);
	strncpy_s(keySearch.szSettingName, dbcws->szSetting, _TRUNCATE);

	MDB_val key = { 2 * sizeof(DWORD) + settingNameLen, &keySearch }, data;

	switch (dbcwWork.value.type) {
	case DBVT_BYTE:  data.mv_size = 2; break;
	case DBVT_WORD:  data.mv_size = 3; break;
	case DBVT_DWORD: data.mv_size = 5; break;
	
	case DBVT_ASCIIZ: 
	case DBVT_UTF8:
		data.mv_size = 3 + dbcwWork.value.cchVal; break;

	case DBVT_BLOB:
	case DBVT_ENCRYPTED:
		data.mv_size = 3 + dbcwWork.value.cpbVal; break;
	}

	for (;; Remap()) {
		txn_ptr trnlck(m_pMdbEnv);
		MDB_CHECK(mdb_put(trnlck, m_dbSettings, &key, &data, MDB_RESERVE), 1);

		BYTE *pBlob = (BYTE*)data.mv_data;
		*pBlob++ = dbcwWork.value.type;
		switch (dbcwWork.value.type) {
		case DBVT_BYTE:  *pBlob = dbcwWork.value.bVal; break;
		case DBVT_WORD:  *(WORD*)pBlob = dbcwWork.value.wVal; break;
		case DBVT_DWORD: *(DWORD*)pBlob = dbcwWork.value.dVal; break;

		case DBVT_ASCIIZ:
		case DBVT_UTF8:
			data.mv_size = *(WORD*)pBlob = dbcwWork.value.cchVal;
			pBlob += 2;
			memcpy(pBlob, dbcwWork.value.pszVal, dbcwWork.value.cchVal);
			break;

		case DBVT_BLOB:
		case DBVT_ENCRYPTED:
			data.mv_size = *(WORD*)pBlob = dbcwWork.value.cpbVal;
			pBlob += 2;
			memcpy(pBlob, dbcwWork.value.pbVal, dbcwWork.value.cpbVal);
		}

		if (trnlck.commit())
			break;
	}
	lck.unlock();

	// notify
	NotifyEventHooks(hSettingChangeEvent, contactID, (LPARAM)&dbcwNotif);
	return 0;
}