Exemplo n.º 1
0
int CIcqProto::setSettingDouble(HANDLE hContact, const char *szSetting, double dValue)
{
  return setSettingBlob(hContact, szSetting, (BYTE*)&dValue, sizeof(double));
}
Exemplo n.º 2
0
// handle Owner's avatar hash changes
void CIcqProto::handleAvatarOwnerHash(BYTE bFlags, BYTE *pData, size_t nDataLen)
{
	if (nDataLen < 0x14 || !m_bAvatarsEnabled)
		return;

	switch (bFlags) {
	case 1: // our avatar is on the server
		setSettingBlob(NULL, "AvatarHash", pData, 0x14); /// TODO: properly handle multiple avatar items (more formats)
		setUserInfo();
		{
			// here we need to find a file, check its hash, if invalid get avatar from server
			TCHAR *file = GetOwnAvatarFileName();
			if (!file) { // we have no avatar file, download from server
				debugLogA("We have no avatar, requesting from server.");

				TCHAR szFile[MAX_PATH * 2 + 4];
				GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2);
				GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile);
			}
			else { // we know avatar filename
				BYTE *hash = calcMD5HashOfFile(file);

				if (!hash) { // hash could not be calculated - probably missing file, get avatar from server
					debugLogA("We have no avatar, requesting from server.");

					TCHAR szFile[MAX_PATH * 2 + 4];
					GetAvatarFileName(0, NULL, szFile, MAX_PATH * 2);
					GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, szFile);
				}
				// check if we had set any avatar if yes set our, if not download from server
				else if (memcmp(hash, pData + 4, 0x10)) { // we have different avatar, sync that
					if (m_bSsiEnabled && getByte("ForceOurAvatar", 1)) { // we want our avatar, update hash
						DWORD dwPaFormat = ::ProtoGetAvatarFileFormat(file);
						BYTE pHash[0x14];

						debugLogA("Our avatar is different, setting our new hash.");

						pHash[0] = 0;
						pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC;
						pHash[2] = 1; // state of the hash
						pHash[3] = 0x10; // len of the hash
						memcpy((pHash + 4), hash, 0x10);
						updateServAvatarHash(pHash, 0x14);
					}
					else { // get avatar from server
						debugLogA("We have different avatar, requesting new from server.");

						TCHAR tszFile[MAX_PATH * 2 + 4];
						GetAvatarFileName(0, NULL, tszFile, MAX_PATH * 2);
						GetAvatarData(NULL, m_dwLocalUIN, NULL, pData, 0x14, tszFile);
					}
				}
				SAFE_FREE((void**)&hash);
				SAFE_FREE(&file);
			}
		}
		break;

	case 0x41: // request to upload avatar data
	case 0x81:
		// request to re-upload avatar data
		if (m_bSsiEnabled) { // we could not change serv-list if it is disabled...
			TCHAR *file = GetOwnAvatarFileName();
			if (!file) { // we have no file to upload, remove hash from server
				debugLogA("We do not have avatar, removing hash.");
				SetMyAvatar(0, 0);
				break;
			}

			DWORD dwPaFormat = ::ProtoGetAvatarFileFormat(file);
			BYTE *hash = calcMD5HashOfFile(file);
			if (!hash) { // the hash could not be calculated, remove from server
				debugLogA("We could not obtain hash, removing hash.");
				SetMyAvatar(0, 0);
			}
			else if (!memcmp(hash, pData + 4, 0x10)) { // we have the right file
				HANDLE hFile = NULL, hMap = NULL;
				BYTE *ppMap = NULL;
				long cbFileSize = 0;

				debugLogA("Uploading our avatar data.");

				if ((hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE)
					if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
						if ((ppMap = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
							cbFileSize = GetFileSize(hFile, NULL);

				if (cbFileSize != 0)
					SetAvatarData(NULL, (WORD)(dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC), ppMap, cbFileSize);

				if (ppMap != NULL) UnmapViewOfFile(ppMap);
				if (hMap != NULL)  CloseHandle(hMap);
				if (hFile != NULL) CloseHandle(hFile);
				SAFE_FREE((void**)&hash);
			}
			else {
				BYTE pHash[0x14];

				debugLogA("Our file is different, set our new hash.");

				pHash[0] = 0;
				pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC;
				pHash[2] = 1; // state of the hash
				pHash[3] = 0x10; // len of the hash
				memcpy((pHash + 4), hash, 0x10);
				updateServAvatarHash(pHash, 0x14);

				SAFE_FREE((void**)&hash);
			}

			SAFE_FREE(&file);
		}
		break;

	default:
		debugLogA("Received UNKNOWN Avatar Status.");
	}
}
Exemplo n.º 3
0
// handle Contact's avatar hash
void CIcqProto::handleAvatarContactHash(DWORD dwUIN, char *szUID, MCONTACT hContact, BYTE *pHash, size_t nHashLen)
{
	int bJob = FALSE;
	BOOL avatarInfoPresent = FALSE;
	int avatarType = -1;
	BYTE *pAvatarHash = NULL;
	size_t cbAvatarHash = 0;
	BYTE emptyItem[0x10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

	if (!m_bAvatarsEnabled || nHashLen < 4)
		return; // only if enabled

	while (nHashLen >= 4) { // parse online message items one by one
		WORD itemType = pHash[0] << 8 | pHash[1];
		size_t itemLen = pHash[3];

		// just some validity check
		if (itemLen + 4 > nHashLen)
			itemLen = nHashLen - 4;

		if (itemLen && memcmp(pHash + 4, emptyItem, itemLen > 0x10 ? 0x10 : itemLen)) {
			// Item types
			// 0000: AIM mini avatar
			// 0001: AIM/ICQ avatar ID/hash (len 5 or 16 bytes)
			// 0002: iChat online message
			// 0008: ICQ Flash avatar hash (16 bytes)
			// 0009: iTunes music store link
			// 000C: ICQ contact photo (16 bytes)
			// 000D: Last update time of online message
			// 000E: Status mood
			if (itemType == AVATAR_HASH_MINI && itemLen == 0x05 && avatarType == -1) { // mini avatar
				pAvatarHash = pHash;
				cbAvatarHash = itemLen + 4;
				avatarType = itemType;
			}
			else if (itemType == AVATAR_HASH_STATIC && (itemLen == 0x05 || itemLen == 0x10) && (avatarType == -1 || avatarType == AVATAR_HASH_MINI)) { // normal avatar
				pAvatarHash = pHash;
				cbAvatarHash = itemLen + 4;
				avatarType = itemType;
			}
			else if (itemType == AVATAR_HASH_FLASH && itemLen == 0x10 && (avatarType == -1 || avatarType == AVATAR_HASH_MINI || avatarType == AVATAR_HASH_STATIC)) { // flash avatar
				pAvatarHash = pHash;
				cbAvatarHash = itemLen + 4;
				avatarType = itemType;
			}
			else if (itemType == AVATAR_HASH_PHOTO && itemLen == 0x10) { // big avatar (ICQ 6+)
				pAvatarHash = pHash;
				cbAvatarHash = itemLen + 4;
				avatarType = itemType;
			}
		}
		else if ((itemLen == 0) && (itemType == AVATAR_HASH_MINI || itemType == AVATAR_HASH_STATIC || itemType == AVATAR_HASH_FLASH || itemType == AVATAR_HASH_PHOTO))
			// empty item - indicating that avatar of that type was removed
			avatarInfoPresent = TRUE;

		pHash += itemLen + 4;
		nHashLen -= itemLen + 4;
	}

	if (avatarType != -1) { // check settings, should we request avatar immediatelly?
		DBVARIANT dbv = { DBVT_DELETED };
		TCHAR tszAvatar[MAX_PATH * 2 + 4];
		BYTE bAutoLoad = getByte("AvatarsAutoLoad", DEFAULT_LOAD_AVATARS);

		if ((avatarType == AVATAR_HASH_STATIC || avatarType == AVATAR_HASH_MINI) && cbAvatarHash == 0x09 && !memcmp(pAvatarHash + 4, hashEmptyAvatar + 4, 0x05)) { // empty avatar - unlink image, clear hash
			if (!getSetting(hContact, "AvatarHash", &dbv)) { // contact had avatar, clear hash, notify UI
				db_free(&dbv);
				debugLogA("%s has removed Avatar.", strUID(dwUIN, szUID));

				delSetting(hContact, "AvatarHash");
				ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
			}
			else debugLogA("%s has empty Avatar.", strUID(dwUIN, szUID));
			return;
		}

		if (getSetting(hContact, "AvatarHash", &dbv)) { // we did not find old avatar hash, i.e. get new avatar
			int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash);

			// check saved hash and file, if equal only store hash
			if (!avatarState) { // hashes are the same
				int dwPaFormat = getByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN);

				GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2);
				if (_taccess(tszAvatar, 0) == 0) { // the file is there, link to contactphoto, save hash
					debugLogA("%s has published Avatar. Image was found in the cache.", strUID(dwUIN, szUID));

					setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash);
					ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
				}
				else { // the file was lost, request avatar again
					debugLogA("%s has published Avatar.", strUID(dwUIN, szUID));
					bJob = TRUE;
				}
			}
			else { // the hash is not the one we want, request avatar
				debugLogA("%s has published a new Avatar.", strUID(dwUIN, szUID));
				bJob = TRUE;
			}
		}
		else { // we found hash check if it changed or not
			if ((dbv.cpbVal != cbAvatarHash) || memcmp(dbv.pbVal, pAvatarHash, cbAvatarHash)) { // the hash is different, request new avatar
				debugLogA("%s has changed Avatar.", strUID(dwUIN, szUID));
				bJob = TRUE;
			}
			else { // the hash was not changed, check if we have the correct file
				int avatarState = IsAvatarChanged(hContact, pAvatarHash, cbAvatarHash);

				// we should have file, check if the file really exists
				if (!avatarState) {
					int dwPaFormat = getByte(hContact, "AvatarType", PA_FORMAT_UNKNOWN);
					if (dwPaFormat == PA_FORMAT_UNKNOWN) { // we do not know the format, get avatar again
						debugLogA("%s has Avatar. Image is missing.", strUID(dwUIN, szUID));
						bJob = 2;
					}
					else {
						GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, tszAvatar, MAX_PATH * 2);
						if (_taccess(tszAvatar, 0) != 0) { // the file was lost, get it again
							debugLogA("%s has Avatar. Image is missing.", strUID(dwUIN, szUID));
							bJob = 2;
						}
						else debugLogA("%s has Avatar. Image was found in the cache.", strUID(dwUIN, szUID));
					}
				}
				else { // the hash is not the one we want, request avatar
					debugLogA("%s has Avatar. Image was not retrieved yet.", strUID(dwUIN, szUID));
					bJob = 2;
				}
			}
			db_free(&dbv);
		}

		if (bJob) {
			if (bJob == TRUE) { // Remove possible block - hash changed, try again.
				mir_cslock l(m_avatarsMutex);

				for (int i = 0; i < m_arAvatars.getCount(); i++) {
					avatars_request *ar = m_arAvatars[i];
					if (ar->hContact == hContact && ar->type == ART_BLOCK) { // found one, remove
						m_arAvatars.remove(i);
						delete ar;
						break;
					}
				}
			}

			setSettingBlob(hContact, "AvatarHash", pAvatarHash, cbAvatarHash);

			ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);

			if (bAutoLoad) { // auto-load is on, so request the avatar now, otherwise we are done
				GetAvatarFileName(dwUIN, szUID, tszAvatar, MAX_PATH * 2);
				GetAvatarData(hContact, dwUIN, szUID, pAvatarHash, cbAvatarHash, tszAvatar);
			} // avatar request sent or added to queue
		}
	}
	else if (avatarInfoPresent) { // hash was not found, clear the hash
		DBVARIANT dbv = { DBVT_DELETED };
		if (!getSetting(hContact, "AvatarHash", &dbv)) { // contact had avatar, clear hash, notify UI
			db_free(&dbv);
			debugLogA("%s has removed Avatar.", strUID(dwUIN, szUID));

			delSetting(hContact, "AvatarHash");
			ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, 0);
		}
		else debugLogA("%s has no Avatar.", strUID(dwUIN, szUID));
	}
}
Exemplo n.º 4
0
void CIcqProto::handleDirectoryUpdateResponse(BYTE *databuf, WORD wPacketLen, WORD wCookie, WORD wReplySubtype)
{
	WORD wBytesRemaining = 0;
	snac_header requestSnac = {0};
	BYTE requestResult;

#ifdef _DEBUG
	debugLogA("Received directory update response");
#endif
	if (wPacketLen >= 2)
		unpackLEWord(&databuf, &wBytesRemaining);
	wPacketLen -= 2;
	_ASSERTE(wPacketLen == wBytesRemaining);

	if (!unpackSnacHeader(&requestSnac, &databuf, &wPacketLen) || !requestSnac.bValid)
	{
		debugLogA("Error: Failed to parse directory response");
		return;
	}

	cookie_directory_data *pCookieData;
	MCONTACT hContact;
	// check request cookie
	if (!FindCookie(wCookie, &hContact, (void**)&pCookieData) || !pCookieData)
	{
		debugLogA("Warning: Ignoring unrequested directory reply type (x%x, x%x)", requestSnac.wFamily, requestSnac.wSubtype);
		return;
	}
	/// FIXME: we should really check the snac contents according to cookie data here ?? 

	if (wPacketLen >= 3)
		unpackByte(&databuf, &requestResult);
	else
	{
		debugLogA("Error: Malformed directory response");
		ReleaseCookie(wCookie);
		return;
	}
	if (requestResult != 1 && requestResult != 4)
	{
		debugLogA("Error: Directory request failed, status %u", requestResult);

		if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER)
			ProtoBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_FAILED, (HANDLE)wCookie, 0);

		ReleaseCookie(wCookie);
		return;
	}
	WORD wLen;

	unpackWord(&databuf, &wLen);
	wPacketLen -= 3;
	if (wLen)
		debugLogA("Warning: Data in error message present!");

	if (pCookieData->bRequestType == DIRECTORYREQUEST_UPDATEOWNER)
		ProtoBroadcastAck(NULL, ACKTYPE_SETINFO, ACKRESULT_SUCCESS, (HANDLE)wCookie, 0);
	if (wPacketLen == 0x18)
	{
		DWORD64 qwMetaTime;
		BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

		unpackQWord(&databuf, &qwMetaTime);
		setSettingBlob(NULL, DBSETTING_METAINFO_TIME, (BYTE*)&qwMetaTime, 8);

		if (memcmp(databuf, pbEmptyMetaToken, 0x10))
			setSettingBlob(NULL, DBSETTING_METAINFO_TOKEN, databuf, 0x10);
	}
	ReleaseCookie(wCookie);
}