예제 #1
0
void CIcqProto::handleNotifyRejected(BYTE *buf, size_t wPackLen)
{
	DWORD dwUIN;
	uid_str szUID;

	while (wPackLen)
		if (unpackUID(&buf, &wPackLen, &dwUIN, &szUID))
			debugLogA("%s status notification rejected.", strUID(dwUIN, szUID));
}
예제 #2
0
void CIcqProto::makeContactTemporaryVisible(MCONTACT hContact)
{
	if (getByte(hContact, "TemporaryVisible", 0))
		return; // already there

	DWORD dwUin;
	uid_str szUid;
	if (getContactUid(hContact, &dwUin, &szUid))
		return; // Invalid contact

	icq_sendGenericContact(dwUin, szUid, ICQ_BOS_FAMILY, ICQ_CLI_ADDTEMPVISIBLE);

	setByte(hContact, "TemporaryVisible", 1);

	debugLogA("Added contact %s to temporary visible list", strUID(dwUin, szUid));
}
예제 #3
0
void CIcqProto::sendClientAuth(const char *szKey, size_t wKeyLen, BOOL bSecure)
{
	char szUin[UINMAXLEN];
	icq_packet packet;

	size_t wUinLen = mir_strlen(strUID(m_dwLocalUIN, szUin));

	packet.wLen = WORD((m_bLegacyFix ? 65 : 70) + sizeof(CLIENT_ID_STRING) + wUinLen + wKeyLen + (m_bSecureConnection ? 4 : 0));

	if (bSecure) {
		serverPacketInit(&packet, packet.wLen + 10);
		packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_LOGIN_REQUEST, 0, 0);
	}
	else {
		write_flap(&packet, ICQ_LOGIN_CHAN);
		packDWord(&packet, 0x00000001);
	}
	packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin);

	if (bSecure) { // Pack MD5 auth digest
		packTLV(&packet, 0x0025, wKeyLen, (BYTE*)szKey);
		packDWord(&packet, 0x004C0000); // empty TLV(0x4C): unknown
	}
	else { // Pack old style password hash
		BYTE hash[20];

		icq_encryptPassword(szKey, hash);
		packTLV(&packet, 0x0002, wKeyLen, hash);
	}

	// Pack client identification details.
	packTLV(&packet, 0x0003, (WORD)sizeof(CLIENT_ID_STRING)-1, (LPBYTE)CLIENT_ID_STRING);
	packTLVWord(&packet, 0x0017, CLIENT_VERSION_MAJOR);
	packTLVWord(&packet, 0x0018, CLIENT_VERSION_MINOR);
	packTLVWord(&packet, 0x0019, CLIENT_VERSION_LESSER);
	packTLVWord(&packet, 0x001a, CLIENT_VERSION_BUILD);
	packTLVWord(&packet, 0x0016, CLIENT_ID_CODE);
	packTLVDWord(&packet, 0x0014, CLIENT_DISTRIBUTION);
	packTLV(&packet, 0x000f, 0x0002, (LPBYTE)CLIENT_LANGUAGE);
	packTLV(&packet, 0x000e, 0x0002, (LPBYTE)CLIENT_COUNTRY);
	if (!m_bLegacyFix)
		packTLV(&packet, 0x0094, 0x0001, &m_bConnectionLost); // CLIENT_RECONNECT flag
	if (m_bSecureConnection)
		packDWord(&packet, 0x008C0000); // empty TLV(0x8C): use SSL

	sendServPacket(&packet);
}
예제 #4
0
void CIcqProto::makeContactTemporaryVisible(HANDLE hContact)
{
	DWORD dwUin;
	uid_str szUid;

	if (getSettingByte(hContact, "TemporaryVisible", 0))
		return; // already there

	if (getContactUid(hContact, &dwUin, &szUid))
		return; // Invalid contact

	icq_sendGenericContact(dwUin, szUid, ICQ_BOS_FAMILY, ICQ_CLI_ADDTEMPVISIBLE);

	setSettingByte(hContact, "TemporaryVisible", 1);

#ifdef _DEBUG
	NetLog_Server("Added contact %s to temporary visible list", strUID(dwUin, szUid));
#endif
}
예제 #5
0
void CIcqProto::handleLocationUserInfoReply(BYTE* buf, WORD wLen, DWORD dwCookie)
{
	HANDLE hContact;
	DWORD dwUIN;
	uid_str szUID;
	WORD wTLVCount;
	WORD wWarningLevel;
	HANDLE hCookieContact;
	WORD status;
	cookie_message_data *pCookieData;

	// Unpack the sender's user ID
	if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return;

	// Syntax check
	if (wLen < 4)
		return;

	// Warning level?
	unpackWord(&buf, &wWarningLevel);
	wLen -= 2;

	// TLV count
	unpackWord(&buf, &wTLVCount);
	wLen -= 2;

	// Determine contact
	hContact = HContactFromUID(dwUIN, szUID, NULL);

	// Ignore away status if the user is not already on our list
	if (hContact == INVALID_HANDLE_VALUE)
	{
#ifdef _DEBUG
		NetLog_Server("Ignoring away reply (%s)", strUID(dwUIN, szUID));
#endif
		return;
	}

	if (!FindCookie(dwCookie, &hCookieContact, (void**)&pCookieData))
	{
		NetLog_Server("Error: Received unexpected away reply from %s", strUID(dwUIN, szUID));
		return;
	}

	if (hContact != hCookieContact)
	{
		NetLog_Server("Error: Away reply Contact does not match Cookie Contact(0x%x != 0x%x)", hContact, hCookieContact);

		ReleaseCookie(dwCookie); // This could be a bad idea, but I think it is safe
		return;
	}

	switch (GetCookieType(dwCookie))
	{
	case CKT_FAMILYSPECIAL:
		{
			ReleaseCookie(dwCookie);

			// Read user info TLVs
			{
				oscar_tlv_chain* pChain;
				BYTE *tmp;
				char *szMsg = NULL;

				// Syntax check
				if (wLen < 4)
					return;

				tmp = buf;
				// Get general chain
				if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount)))
					return;

				disposeChain(&pChain);

				wLen -= (buf - tmp);

				// Get extra chain
				if (pChain = readIntoTLVChain(&buf, wLen, 2))
				{
					oscar_tlv *pTLV;
					char *szEncoding = NULL;

					// Get Profile encoding TLV
					pTLV = pChain->getTLV(0x01, 1);
					if (pTLV && (pTLV->wLen >= 1))
					{
						szEncoding = (char*)_alloca(pTLV->wLen + 1);
						memcpy(szEncoding, pTLV->pData, pTLV->wLen);
						szEncoding[pTLV->wLen] = '\0';
					}
					// Get Profile info TLV
					pTLV = pChain->getTLV(0x02, 1);
					if (pTLV && (pTLV->wLen >= 1))
					{
						szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2);
						memcpy(szMsg, pTLV->pData, pTLV->wLen);
						szMsg[pTLV->wLen] = '\0';
						szMsg[pTLV->wLen + 1] = '\0';
						szMsg = AimApplyEncoding(szMsg, szEncoding);
						szMsg = EliminateHtml(szMsg, pTLV->wLen);
					}
					// Free TLV chain
					disposeChain(&pChain);
				}

				setSettingString(hContact, "About", szMsg);
				BroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0);

				SAFE_FREE((void**)&szMsg);
			}
			break;
		}

	default: // away message
		{
			status = AwayMsgTypeToStatus(pCookieData->nAckType);
			if (status == ID_STATUS_OFFLINE)
			{
				NetLog_Server("SNAC(2.6) Ignoring unknown status message from %s", strUID(dwUIN, szUID));

				ReleaseCookie(dwCookie);
				return;
			}

			ReleaseCookie(dwCookie);

			// Read user info TLVs
			{
				oscar_tlv_chain* pChain;
				oscar_tlv* pTLV;
				BYTE *tmp;
				char *szMsg = NULL;
				CCSDATA ccs;
				PROTORECVEVENT pre;

				// Syntax check
				if (wLen < 4)
					return;

				tmp = buf;
				// Get general chain
				if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount)))
					return;

				disposeChain(&pChain);

				wLen -= (buf - tmp);

				// Get extra chain
				if (pChain = readIntoTLVChain(&buf, wLen, 2))
				{
					char* szEncoding = NULL;

					// Get Away encoding TLV
					pTLV = pChain->getTLV(0x03, 1);
					if (pTLV && (pTLV->wLen >= 1))
					{
						szEncoding = (char*)_alloca(pTLV->wLen + 1);
						memcpy(szEncoding, pTLV->pData, pTLV->wLen);
						szEncoding[pTLV->wLen] = '\0';
					}
					// Get Away info TLV
					pTLV = pChain->getTLV(0x04, 1);
					if (pTLV && (pTLV->wLen >= 1))
					{
						szMsg = (char*)SAFE_MALLOC(pTLV->wLen + 2);
						memcpy(szMsg, pTLV->pData, pTLV->wLen);
						szMsg[pTLV->wLen] = '\0';
						szMsg[pTLV->wLen + 1] = '\0';
						szMsg = AimApplyEncoding(szMsg, szEncoding);
						szMsg = EliminateHtml(szMsg, pTLV->wLen);
					}
					// Free TLV chain
					disposeChain(&pChain);
				}

				ccs.szProtoService = PSR_AWAYMSG;
				ccs.hContact = hContact;
				ccs.wParam = status;
				ccs.lParam = (LPARAM)&pre;
				pre.flags = 0;
				pre.szMessage = szMsg?szMsg:(char *)"";
				pre.timestamp = time(NULL);
				pre.lParam = dwCookie;

				CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs);

				SAFE_FREE((void**)&szMsg);
			}
			break;
		}
	}
}
예제 #6
0
DWORD avatars_server_connection::sendGetAvatarRequest(MCONTACT hContact, DWORD dwUin, char *szUid, const BYTE *hash, size_t hashlen, const TCHAR *file)
{
	int i;
	DWORD dwNow = GetTickCount();

	mir_cslockfull alck(ppro->m_avatarsMutex);

	for (i = 0; i < runCount;) { // look for timeouted requests
		if (runTime[i] < dwNow) { // found outdated, remove
			runContact[i] = runContact[runCount - 1];
			runTime[i] = runTime[runCount - 1];
			runCount--;
		}
		else i++;
	}

	for (i = 0; i < runCount; i++) {
		if (runContact[i] == hContact) {
			ppro->debugLogA("Ignoring duplicate get %s image request.", strUID(dwUin, szUid));
			return -1; // Success: request ignored
		}
	}

	if (runCount < 4) { // 4 concurent requests at most
		int bSendNow = TRUE;
		{
			// rate management
			mir_cslock l(m_ratesMutex);
			WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST);

			if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT)) { // we will be over quota if we send the request now, add to queue instead
				bSendNow = FALSE;
				ppro->debugLogA("Rates: Delay avatar request.");
			}
		}

		if (bSendNow) {
			runContact[runCount] = hContact;
			runTime[runCount] = GetTickCount() + 30000; // 30sec to complete request
			runCount++;

			alck.unlock();

			int nUinLen = getUIDLen(dwUin, szUid);

			cookie_avatar *ack = (cookie_avatar*)SAFE_MALLOC(sizeof(cookie_avatar));
			if (!ack)
				return 0; // Failure: out of memory

			ack->dwUin = 1; //dwUin; // I should be damned for this - only to identify get request
			ack->hContact = hContact;
			ack->hash = (BYTE*)SAFE_MALLOC(hashlen);
			memcpy(ack->hash, hash, hashlen); // copy the data
			ack->hashlen = hashlen;
			ack->szFile = null_strdup(file); // duplicate the string

			DWORD dwCookie = ppro->AllocateCookie(CKT_AVATAR, ICQ_AVATAR_GET_REQUEST, hContact, ack);
			icq_packet packet;

			serverPacketInit(&packet, 12 + nUinLen + hashlen);
			packFNACHeader(&packet, ICQ_AVATAR_FAMILY, ICQ_AVATAR_GET_REQUEST, 0, dwCookie);
			packUID(&packet, dwUin, szUid);
			packByte(&packet, 1); // unknown, probably type of request: 1 = get icon :)
			packBuffer(&packet, hash, hashlen);

			if (sendServerPacket(&packet)) {
				ppro->debugLogA("Request to get %s image sent.", strUID(dwUin, szUid));
				return dwCookie;
			}
			ppro->FreeCookie(dwCookie); // sending failed, free resources
			SAFE_FREE(&ack->szFile);
			SAFE_FREE((void**)&ack->hash);
			SAFE_FREE((void**)&ack);
		}
	}

	return 0; // Failure
}
예제 #7
0
// request avatar data from server
int CIcqProto::GetAvatarData(MCONTACT hContact, DWORD dwUin, const char *szUid, const BYTE *hash, size_t hashlen, const TCHAR *file)
{
	uid_str szUidData;
	char *pszUid = NULL;
	if (!dwUin && szUid) { // create a copy in local writable buffer
		mir_strcpy(szUidData, szUid);
		pszUid = szUidData;
	}

	mir_cslockfull alck(m_avatarsMutex);

	if (m_avatarsConnection && m_avatarsConnection->isReady()) { // check if we are ready
		// check if requests for this user are not blocked
		for (int i = 0; i < m_arAvatars.getCount();) {
			avatars_request *ar = m_arAvatars[i];
			if (ar->hContact == hContact && ar->type == ART_BLOCK) { // found a block item
				if (GetTickCount() > ar->timeOut) { // remove timeouted block
					m_arAvatars.remove(i);
					delete ar;
					continue;
				}
				debugLogA("Avatars: Requests for %s avatar are blocked.", strUID(dwUin, pszUid));
				return 0;
			}
			i++;
		}

		mir_cslock l(m_avatarsConnection->getLock());
		alck.unlock();

		DWORD dwCookie = m_avatarsConnection->sendGetAvatarRequest(hContact, dwUin, pszUid, hash, hashlen, file);
		if (dwCookie) // return now if the request was sent successfully
			return dwCookie;

		alck.lock();
	}
	// we failed to send request, or avatar thread not ready

	// check if any request for this user is not already in the queue
	for (int i = 0; i < m_arAvatars.getCount();) {
		avatars_request *ar = m_arAvatars[i];
		if (ar->hContact == hContact) { // we found it, return error
			if (ar->type == ART_BLOCK && GetTickCount() > ar->timeOut) { // remove timeouted block
				m_arAvatars.remove(i);
				delete ar;
				continue;
			}
			alck.unlock();
			debugLogA("Avatars: Ignoring duplicate get %s avatar request.", strUID(dwUin, pszUid));

			// make sure avatar connection is in progress
			requestAvatarConnection();
			return 0;
		}
		i++;
	}

	// add request to queue, processed after successful login
	avatars_request *ar = new avatars_request(ART_GET); // get avatar
	ar->hContact = hContact;
	ar->dwUin = dwUin;
	if (!dwUin)
		mir_strcpy(ar->szUid, szUid);
	ar->hash = (BYTE*)SAFE_MALLOC(hashlen);
	if (!ar->hash) { // alloc failed
		delete ar;
		return 0;
	}
	memcpy(ar->hash, hash, hashlen); // copy the data
	ar->hashlen = hashlen;
	ar->szFile = null_strdup(file); // duplicate the string
	m_arAvatars.insert(ar);
	alck.unlock();

	debugLogA("Avatars: Request to get %s image added to queue.", strUID(dwUin, pszUid));

	// make sure avatar connection is in progress
	requestAvatarConnection();
	return -1; // we added to queue
}
예제 #8
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));
	}
}
예제 #9
0
void CIcqProto::parseStatusNote(DWORD dwUin, char *szUid, MCONTACT hContact, oscar_tlv_chain *pChain)
{
	DWORD dwStatusNoteTS = time(NULL);
	BYTE *pStatusNoteTS, *pStatusNote;
	WORD wStatusNoteTSLen, wStatusNoteLen;
	BYTE bStatusNoteFlags;

	if (unpackSessionDataItem(pChain, 0x0D, &pStatusNoteTS, &wStatusNoteTSLen, NULL) && wStatusNoteTSLen == sizeof(DWORD))
		unpackDWord(&pStatusNoteTS, &dwStatusNoteTS);

	// Get Status Note session item
	if (unpackSessionDataItem(pChain, 0x02, &pStatusNote, &wStatusNoteLen, &bStatusNoteFlags)) {
		char *szStatusNote = NULL;

		if ((bStatusNoteFlags & 4) == 4 && wStatusNoteLen >= 4) {
			BYTE *buf = pStatusNote;
			WORD buflen = wStatusNoteLen - 2;
			WORD wTextLen;

			unpackWord(&buf, &wTextLen);
			if (wTextLen > buflen)
				wTextLen = buflen;

			if (wTextLen > 0) {
				szStatusNote = (char*)_alloca(wStatusNoteLen + 1);
				unpackString(&buf, szStatusNote, wTextLen);
				szStatusNote[wTextLen] = '\0';
				buflen -= wTextLen;

				WORD wEncodingType = 0;
				char *szEncoding = NULL;

				if (buflen >= 2)
					unpackWord(&buf, &wEncodingType);

				if (wEncodingType == 1 && buflen > 6) {
					// Encoding specified
					buf += 2;
					buflen -= 2;
					unpackWord(&buf, &wTextLen);
					if (wTextLen > buflen)
						wTextLen = buflen;
					szEncoding = (char*)_alloca(wTextLen + 1);
					unpackString(&buf, szEncoding, wTextLen);
					szEncoding[wTextLen] = '\0';
				}
				else if (UTF8_IsValid(szStatusNote))
					szEncoding = "utf-8";

				szStatusNote = ApplyEncoding(szStatusNote, szEncoding);
			}
		}
		// Check if the status note was changed
		if (dwStatusNoteTS > getDword(hContact, DBSETTING_STATUS_NOTE_TIME, 0)) {
			DBVARIANT dbv = {DBVT_DELETED};

			if (mir_strlen(szStatusNote) || (!getString(hContact, DBSETTING_STATUS_NOTE, &dbv) && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_UTF8) && mir_strlen(dbv.pszVal)))
				debugLogA("%s changed status note to \"%s\"", strUID(dwUin, szUid), szStatusNote ? szStatusNote : "");

			db_free(&dbv);

			if (szStatusNote)
				db_set_utf(hContact, m_szModuleName, DBSETTING_STATUS_NOTE, szStatusNote);
			else
				delSetting(hContact, DBSETTING_STATUS_NOTE);
			setDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS);

			if (getContactXStatus(hContact) != 0 || !CheckContactCapabilities(hContact, CAPF_STATUS_MESSAGES)) {
				setStatusMsgVar(hContact, szStatusNote, false);

				TCHAR *tszNote = mir_utf8decodeT(szStatusNote);
				ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, NULL, (LPARAM)tszNote);
				mir_free(tszNote);
			}
		}
		SAFE_FREE(&szStatusNote);
	}
	else if (getContactStatus(hContact) == ID_STATUS_OFFLINE) {
		setStatusMsgVar(hContact, NULL, false);
		delSetting(hContact, DBSETTING_STATUS_NOTE);
		setDword(hContact, DBSETTING_STATUS_NOTE_TIME, dwStatusNoteTS);
	}
}
예제 #10
0
void CIcqProto::handleUserOffline(BYTE *buf, size_t wLen)
{
	DWORD dwUIN;
	uid_str szUID;

	do {
		oscar_tlv_chain *pChain = NULL;
		// Unpack the sender's user ID
		if (!unpackUID(&buf, &wLen, &dwUIN, &szUID)) return;

		// Warning level?
		buf += 2;

		// TLV Count
		WORD wTLVCount;
		unpackWord(&buf, &wTLVCount);
		wLen -= 4;

		// Skip the TLV chain
		DWORD dwAwaySince = 0;
		while (wTLVCount && wLen >= 4) {
			WORD wTLVType;
			WORD wTLVLen;

			unpackWord(&buf, &wTLVType);
			unpackWord(&buf, &wTLVLen);
			wLen -= 4;

			// stop parsing overflowed packet
			if (wTLVLen > wLen) {
				disposeChain(&pChain);
				return;
			}

			if (wTLVType == 0x1D) {
				// read only TLV with Session data into chain
				BYTE *pTLV = buf - 4;
				disposeChain(&pChain);
				pChain = readIntoTLVChain(&pTLV, wLen + 4, 1);
			}
			else if (wTLVType == 0x29 && wTLVLen == sizeof(DWORD)) {
				// get Away Since value
				BYTE *pData = buf;
				unpackDWord(&pData, &dwAwaySince);
			}

			buf += wTLVLen;
			wLen -= wTLVLen;
			wTLVCount--;
		}

		// Determine contact
		MCONTACT hContact = HContactFromUID(dwUIN, szUID, NULL);

		// Skip contacts that are not already on our list or are already offline
		if (hContact != INVALID_CONTACT_ID) {
			WORD wOldStatus = getContactStatus(hContact);

			// Process Avatar Hash
			oscar_tlv *pAvatarTLV = pChain ? pChain->getTLV(0x1D, 1) : NULL;
			if (pAvatarTLV)
				handleAvatarContactHash(dwUIN, szUID, hContact, pAvatarTLV->pData, pAvatarTLV->wLen);
			else
				handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0);

			// Process Status Note (offline status note)
			parseStatusNote(dwUIN, szUID, hContact, pChain);

			// Update status times
			setDword(hContact, "IdleTS", 0);
			setDword(hContact, "AwayTS", dwAwaySince);

			// Clear custom status & mood
			char tmp = NULL;
			handleXStatusCaps(dwUIN, szUID, hContact, (BYTE*)&tmp, 0, &tmp, 0);

			if (wOldStatus != ID_STATUS_OFFLINE) {
				debugLogA("%s went offline.", strUID(dwUIN, szUID));

				setWord(hContact, "Status", ID_STATUS_OFFLINE);
				// close Direct Connections to that user
				CloseContactDirectConns(hContact);
				// Reset DC status
				setByte(hContact, "DCStatus", 0);
			}
			else debugLogA("%s is offline.", strUID(dwUIN, szUID));
		}

		// Release memory
		disposeChain(&pChain);
	}
	while (wLen >= 1);
}
예제 #11
0
void CIcqProto::handleUserOnline(BYTE *buf, size_t wLen, serverthread_info*)
{
	DWORD dwPort = 0;
	DWORD dwRealIP = 0;
	DWORD dwUIN;
	uid_str szUID;
	DWORD dwDirectConnCookie = 0;
	DWORD dwWebPort = 0;
	DWORD dwFT1 = 0, dwFT2 = 0, dwFT3 = 0;
	const char *szClient = NULL;
	BYTE bClientId = 0;
	WORD wVersion = 0;
	WORD wTLVCount;
	WORD wWarningLevel;
	WORD wStatusFlags;
	WORD wStatus = 0, wOldStatus = 0;
	BYTE nTCPFlag = 0;
	char szStrBuf[MAX_PATH];

	// Unpack the sender's user ID
	if (!unpackUID(&buf, &wLen, &dwUIN, &szUID))
		return;

	// Syntax check
	if (wLen < 4)
		return;

	// Warning level?
	unpackWord(&buf, &wWarningLevel);
	wLen -= 2;

	// TLV count
	unpackWord(&buf, &wTLVCount);
	wLen -= 2;

	// Ignore status notification if the user is not already on our list
	MCONTACT hContact = HContactFromUID(dwUIN, szUID, NULL);
	if (hContact == INVALID_CONTACT_ID) {
		debugLogA("Ignoring user online (%s)", strUID(dwUIN, szUID));
		return;
	}

	// Read user info TLVs
	oscar_tlv_chain *pChain;
	oscar_tlv *pTLV;

	// Syntax check
	if (wLen < 4)
		return;

	// Get chain
	if (!(pChain = readIntoTLVChain(&buf, wLen, wTLVCount)))
		return;

	// Get Class word
	WORD wClass = pChain->getWord(0x01, 1);
	int nIsICQ = wClass & CLASS_ICQ;

	if (dwUIN) {
		// Get DC info TLV
		pTLV = pChain->getTLV(0x0C, 1);
		if (pTLV && (pTLV->wLen >= 15)) {
			BYTE *pBuffer = pTLV->pData;

			nIsICQ = TRUE;

			unpackDWord(&pBuffer, &dwRealIP);
			unpackDWord(&pBuffer, &dwPort);
			unpackByte(&pBuffer,  &nTCPFlag);
			unpackWord(&pBuffer,  &wVersion);
			unpackDWord(&pBuffer, &dwDirectConnCookie);
			unpackDWord(&pBuffer, &dwWebPort); // Web front port
			pBuffer += 4; // Client features

			// Get faked time signatures, used to identify clients
			if (pTLV->wLen >= 0x23) {
				unpackDWord(&pBuffer, &dwFT1);
				unpackDWord(&pBuffer, &dwFT2);
				unpackDWord(&pBuffer, &dwFT3);
			}
		}

		// Get Status info TLV
		pTLV = pChain->getTLV(0x06, 1);
		if (pTLV && (pTLV->wLen >= 4)) {
			BYTE *pBuffer = pTLV->pData;
			unpackWord(&pBuffer, &wStatusFlags);
			unpackWord(&pBuffer, &wStatus);
		}
		else if (!nIsICQ) {
			// Connected thru AIM client, guess by user class
			if (wClass & CLASS_AWAY)
				wStatus = ID_STATUS_AWAY;
			else if (wClass & CLASS_WIRELESS)
				wStatus = ID_STATUS_ONTHEPHONE;
			else
				wStatus = ID_STATUS_ONLINE;

			wStatusFlags = 0;
		}
		else {
			// Huh? No status TLV? Lets guess then...
			wStatusFlags = 0;
			wStatus = ICQ_STATUS_ONLINE;
		}
	}
	else {
		nIsICQ = FALSE;

		if (wClass & CLASS_AWAY)
			wStatus = ID_STATUS_AWAY;
		else if (wClass & CLASS_WIRELESS)
			wStatus = ID_STATUS_ONTHEPHONE;
		else
			wStatus = ID_STATUS_ONLINE;

		wStatusFlags = 0;
	}

	debugLogA("Flags are %x", wStatusFlags);
	debugLogA("Status is %x", wStatus);

	// Get IP TLV
	DWORD dwIP = pChain->getDWord(0x0A, 1);

	// Get Online Since TLV
	DWORD dwOnlineSince = pChain->getDWord(0x03, 1);

	// Get Away Since TLV
	DWORD dwAwaySince = pChain->getDWord(0x29, 1);

	// Get Member Since TLV
	DWORD dwMemberSince = pChain->getDWord(0x05, 1);

	// Get Idle timer TLV
	WORD wIdleTimer = pChain->getWord(0x04, 1);
	time_t tIdleTS = 0;
	if (wIdleTimer) {
		time(&tIdleTS);
		tIdleTS -= (wIdleTimer*60);
	}

	if (wIdleTimer)
		debugLogA("Idle timer is %u.", wIdleTimer);
	debugLogA("Online since %s", time2text(dwOnlineSince));
	if (dwAwaySince)
		debugLogA("Status was set on %s", time2text(dwAwaySince));

	// Check client capabilities
	if (hContact != NULL) {
		wOldStatus = getContactStatus(hContact);

		// Collect all Capability info from TLV chain
		BYTE *capBuf = NULL;
		WORD capLen = 0;

		// Get Location Capability Info TLVs
		oscar_tlv *pFullTLV = pChain->getTLV(0x0D, 1);
		oscar_tlv *pShortTLV = pChain->getTLV(0x19, 1);

		if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE))
			capLen += pFullTLV->wLen;

		if (pShortTLV && (pShortTLV->wLen >= 2))
			capLen += (pShortTLV->wLen * 8);

		capBuf = (BYTE*)_alloca(capLen + BINARY_CAP_SIZE);

		if (capLen) {
			BYTE *pCapability = capBuf;

			capLen = 0; // we need to recount that

			if (pFullTLV && (pFullTLV->wLen >= BINARY_CAP_SIZE)) {
				// copy classic Capabilities
				BYTE *cData = pFullTLV->pData;
				int cLen = pFullTLV->wLen;

				while (cLen) {
					// be impervious to duplicates (AOL sends them sometimes)
					if (!capLen || !MatchCapability(capBuf, capLen, (capstr*)cData, BINARY_CAP_SIZE)) {
						// not present, add
						memcpy(pCapability, cData, BINARY_CAP_SIZE);
						capLen += BINARY_CAP_SIZE;
						pCapability += BINARY_CAP_SIZE;
					}
					cData += BINARY_CAP_SIZE;
					cLen -= BINARY_CAP_SIZE;
				}
			}

			if (pShortTLV && (pShortTLV->wLen >= 2)) {
				// copy short Capabilities
				capstr tmp;
				BYTE *cData = pShortTLV->pData;
				int cLen = pShortTLV->wLen;

				memcpy(tmp, capShortCaps, BINARY_CAP_SIZE);
				while (cLen) {
					// be impervious to duplicates (AOL sends them sometimes)
					tmp[2] = cData[0];
					tmp[3] = cData[1];

					if (!capLen || !MatchCapability(capBuf, capLen, &tmp, BINARY_CAP_SIZE)) {
						// not present, add
						memcpy(pCapability, tmp, BINARY_CAP_SIZE);
						capLen += BINARY_CAP_SIZE;
						pCapability += BINARY_CAP_SIZE;
					}
					cData += 2;
					cLen -= 2;
				}
			}
			debugLogA("Detected %d capability items.", capLen / BINARY_CAP_SIZE);
		}

		if (capLen) {
			// Update the contact's capabilies if present in packet
			SetCapabilitiesFromBuffer(hContact, capBuf, capLen, wOldStatus == ID_STATUS_OFFLINE);

			char *szCurrentClient = wOldStatus == ID_STATUS_OFFLINE ? NULL : getSettingStringUtf(hContact, "MirVer", NULL);

			szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, szCurrentClient, wVersion, dwFT1, dwFT2, dwFT3, dwDirectConnCookie, dwWebPort, capBuf, capLen, &bClientId, szStrBuf);
			// Check if the client changed, if not do not change
			if (szCurrentClient && !strcmpnull(szCurrentClient, szClient))
				szClient = (const char*)-1;
			SAFE_FREE(&szCurrentClient);
		}
		else if (wOldStatus == ID_STATUS_OFFLINE) {
			// Remove the contact's capabilities if coming from offline
			ClearAllContactCapabilities(hContact);

			// no capability
			debugLogA("No capability info TLVs");

			szClient = detectUserClient(hContact, nIsICQ, wClass, dwOnlineSince, NULL, wVersion, dwFT1, dwFT2, dwFT3, dwDirectConnCookie, dwWebPort, NULL, capLen, &bClientId, szStrBuf);
		}
		else  // Capabilities not present in update packet, do not touch
			szClient = (const char*)-1; // we don't want to client be overwritten

		// handle Xtraz status
		char *moodData = NULL;
		WORD moodSize = 0;

		unpackSessionDataItem(pChain, 0x0E, (BYTE**)&moodData, &moodSize, NULL);
		if (capLen || wOldStatus == ID_STATUS_OFFLINE)
			handleXStatusCaps(dwUIN, szUID, hContact, capBuf, capLen, moodData, moodSize);
		else
			handleXStatusCaps(dwUIN, szUID, hContact, NULL, 0, moodData, moodSize);

		// Determine support for extended status messages
		if (pChain->getWord(0x08, 1) == 0x0A06)
			SetContactCapabilities(hContact, CAPF_STATUS_MESSAGES);
		else if (wOldStatus == ID_STATUS_OFFLINE)
			ClearContactCapabilities(hContact, CAPF_STATUS_MESSAGES);

		if (wOldStatus == ID_STATUS_OFFLINE) {
			if (CheckContactCapabilities(hContact, CAPF_SRV_RELAY))
				debugLogA("Supports advanced messages");
			else
				debugLogA("Does NOT support advanced messages");
		}

		if (!nIsICQ) {
			// AIM clients does not advertise these, but do support them
			SetContactCapabilities(hContact, CAPF_UTF | CAPF_TYPING);
			// Server relayed messages are only supported by ICQ clients
			ClearContactCapabilities(hContact, CAPF_SRV_RELAY);

			if (dwUIN && wOldStatus == ID_STATUS_OFFLINE)
				debugLogA("Logged in with AIM client");
		}

		if (nIsICQ && wVersion < 8) {
			ClearContactCapabilities(hContact, CAPF_SRV_RELAY);
			if (wOldStatus == ID_STATUS_OFFLINE)
				debugLogA("Forcing simple messages due to compability issues");
		}

		// Process Avatar Hash
		pTLV = pChain->getTLV(0x1D, 1);
		if (pTLV)
			handleAvatarContactHash(dwUIN, szUID, hContact, pTLV->pData, pTLV->wLen);
		else
			handleAvatarContactHash(dwUIN, szUID, hContact, NULL, 0);

		// Process Status Note
		parseStatusNote(dwUIN, szUID, hContact, pChain);
	}
	// Free TLV chain
	disposeChain(&pChain);

	// Save contacts details in database
	if (hContact != NULL) {
		setDword(hContact, "LogonTS", dwOnlineSince);
		setDword(hContact, "AwayTS", dwAwaySince);
		setDword(hContact, "IdleTS", tIdleTS);

		if (dwMemberSince)
			setDword(hContact, "MemberTS", dwMemberSince);

		if (nIsICQ) {
			// on AIM these are not used
			setDword(hContact, "DirectCookie", dwDirectConnCookie);
			setByte(hContact, "DCType", (BYTE)nTCPFlag);
			setWord(hContact, "UserPort", (WORD)(dwPort & 0xffff));
			setWord(hContact, "Version", wVersion);
		}
		else {
			delSetting(hContact, "DirectCookie");
			delSetting(hContact, "DCType");
			delSetting(hContact, "UserPort");
			delSetting(hContact, "Version");
		}

		// if no detection, set uknown
		if (!szClient)
			szClient = (nIsICQ ? "Unknown" : "Unknown AIM");		

		if (szClient != (char*)-1) {
			db_set_utf(hContact, m_szModuleName, "MirVer", szClient);
			setByte(hContact, "ClientID", bClientId);
		}

		if (wOldStatus == ID_STATUS_OFFLINE) {
			setDword(hContact, "IP", dwIP);
			setDword(hContact, "RealIP", dwRealIP);
		}
		else {
			// if not first notification only write significant information
			if (dwIP)
				setDword(hContact, "IP", dwIP);
			if (dwRealIP)
				setDword(hContact, "RealIP", dwRealIP);
		}
		setWord(hContact,  "Status", (WORD)IcqStatusToMiranda(wStatus));

		// Update info?
		if (dwUIN) {
			// check if the local copy of user details is up-to-date
			if (IsMetaInfoChanged(hContact))
				icq_QueueUser(hContact);
		}
	}

	LPCTSTR ptszStatus = pcli->pfnGetStatusModeDescription(IcqStatusToMiranda(wStatus), 0);
	if (wOldStatus != IcqStatusToMiranda(wStatus)) {
		// And a small log notice... if status was changed
		if (nIsICQ)
			debugLogA("%u changed status to %S (v%d).", dwUIN, ptszStatus, wVersion);
		else
			debugLogA("%s changed status to %S.", strUID(dwUIN, szUID), ptszStatus);
	}

	if (szClient == cliSpamBot) {
		if (getByte("KillSpambots", DEFAULT_KILLSPAM_ENABLED) && db_get_b(hContact, "CList", "NotOnList", 0)) {
			// kill spammer
			icq_DequeueUser(dwUIN);
			icq_sendRemoveContact(dwUIN, NULL);
			AddToSpammerList(dwUIN);
			if (getByte("PopupsSpamEnabled", DEFAULT_SPAM_POPUPS_ENABLED))
				ShowPopupMsg(hContact, LPGEN("Spambot Detected"), LPGEN("Contact deleted & further events blocked."), POPTYPE_SPAM);
			CallService(MS_DB_CONTACT_DELETE, hContact, 0);

			debugLogA("Contact %u deleted", dwUIN);
		}
	}
}
예제 #12
0
// request avatar data from server
int CIcqProto::GetAvatarData(HANDLE hContact, DWORD dwUin, const char *szUid, const BYTE *hash, unsigned int hashlen, const TCHAR *file)
{
	uid_str szUidData;
	char *pszUid = NULL;
	if (!dwUin && szUid)
	{ // create a copy in local writable buffer
		strcpy(szUidData, szUid);
		pszUid = szUidData;
	}

	m_avatarsMutex->Enter();

	if (m_avatarsConnection && m_avatarsConnection->isReady()) // check if we are ready
	{	// check if requests for this user are not blocked
		DWORD dwNow = GetTickCount();
		avatars_request *ar = m_avatarsQueue;

		while (ar)
		{
			if (ar->hContact == hContact && ar->type == ART_BLOCK)
			{ // found a block item
				if (GetTickCount() > ar->timeOut)
				{ // remove timeouted block
					ar = ReleaseAvatarRequestInQueue(ar);
					continue;
				}
				m_avatarsMutex->Leave();
				debugLogA("Avatars: Requests for %s avatar are blocked.", strUID(dwUin, pszUid));
				return 0;
			}
			ar = ar->pNext;
		}

		avatars_server_connection *pConnection = m_avatarsConnection;

		pConnection->_Lock();
		m_avatarsMutex->Leave();

		DWORD dwCookie = pConnection->sendGetAvatarRequest(hContact, dwUin, pszUid, hash, hashlen, file);

		m_avatarsMutex->Enter();
		pConnection->_Release();

		if (dwCookie)
		{ // return now if the request was sent successfully
			m_avatarsMutex->Leave();
			return dwCookie;
		}
	}
	// we failed to send request, or avatar thread not ready

	// check if any request for this user is not already in the queue
	avatars_request *ar = m_avatarsQueue;

	while (ar)
	{
		if (ar->hContact == hContact)
		{ // we found it, return error
			if (ar->type == ART_BLOCK && GetTickCount() > ar->timeOut)
			{ // remove timeouted block
				ar = ReleaseAvatarRequestInQueue(ar);
				continue;
			}
			m_avatarsMutex->Leave();
			debugLogA("Avatars: Ignoring duplicate get %s avatar request.", strUID(dwUin, pszUid));

			// make sure avatar connection is in progress
			requestAvatarConnection();
			return 0;
		}
		ar = ar->pNext;
	}
	// add request to queue, processed after successful login
	ar = new avatars_request(ART_GET); // get avatar
	if (!ar)
	{ // out of memory, go away
		m_avatarsMutex->Leave();
		return 0;
	}
	ar->hContact = hContact;
	ar->dwUin = dwUin;
	if (!dwUin)
		strcpy(ar->szUid, szUid);
	ar->hash = (BYTE*)SAFE_MALLOC(hashlen);
	if (!ar->hash)
	{ // alloc failed
		m_avatarsMutex->Leave();
		delete ar;
		return 0;
	}
	memcpy(ar->hash, hash, hashlen); // copy the data
	ar->hashlen = hashlen;
	ar->szFile = null_strdup(file); // duplicate the string
	ar->pNext = m_avatarsQueue;
	m_avatarsQueue = ar;
	m_avatarsMutex->Leave();

	debugLogA("Avatars: Request to get %s image added to queue.", strUID(dwUin, pszUid));

	// make sure avatar connection is in progress
	requestAvatarConnection();

	return -1; // we added to queue
}
예제 #13
0
void avatars_server_connection::checkRequestQueue()
{
#ifdef _DEBUG
	ppro->debugLogA("Checking request queue...");
#endif

	ppro->m_avatarsMutex->Enter();

	while (ppro->m_avatarsQueue && runCount < 3) // pick up an request and send it - happens immediatelly after login
	{ // do not fill queue to top, leave one place free
		avatars_request *pRequest = ppro->m_avatarsQueue;

		{ // rate management
			icq_lock l(m_ratesMutex);
			WORD wGroup = m_rates->getGroupFromSNAC(ICQ_AVATAR_FAMILY, (WORD)(pRequest->type == ART_UPLOAD ? ICQ_AVATAR_GET_REQUEST : ICQ_AVATAR_UPLOAD_REQUEST));

			if (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_ALERT))
			{ // we are over rate, leave queue and wait
#ifdef _DEBUG
				ppro->debugLogA("Rates: Leaving avatar queue processing");
#endif
				break;
			}
		}

		if (pRequest->type == ART_BLOCK)
		{ // block contact processing
			avatars_request **ppRequest = &ppro->m_avatarsQueue;

			while (pRequest)
			{
				if (GetTickCount() > pRequest->timeOut)
				{ // expired contact block, remove
					*ppRequest = pRequest->pNext;
					delete pRequest;
				}
				else // it is not time, move to next request
					ppRequest = &pRequest->pNext;

				pRequest = *ppRequest;
			}
			// end queue processing (only block requests follows)
			break;
		}
		else
			ppro->m_avatarsQueue = pRequest->pNext;

		ppro->m_avatarsMutex->Leave();

#ifdef _DEBUG
		ppro->debugLogA("Picked up the %s request from queue.", strUID(pRequest->dwUin, pRequest->szUid));
#endif
		switch (pRequest->type)
		{
		case ART_GET: // get avatar
			sendGetAvatarRequest(pRequest->hContact, pRequest->dwUin, pRequest->szUid, pRequest->hash, pRequest->hashlen, pRequest->szFile);
			break;

		case ART_UPLOAD: // set avatar
			sendUploadAvatarRequest(pRequest->hContact, pRequest->wRef, pRequest->pData, pRequest->cbData);
			break;
		}
		delete pRequest;

		ppro->m_avatarsMutex->Enter();
	}

	ppro->m_avatarsMutex->Leave();
}
예제 #14
0
char* CIcqProto::buildUinList(int subtype, size_t wMaxLen, MCONTACT *hContactResume)
{
	MCONTACT hContact;
	WORD wCurrentLen = 0;
	int add;

	char *szList = (char*)SAFE_MALLOC(CallService(MS_DB_CONTACT_GETCOUNT, 0, 0) * UINMAXLEN);

	char szLen[2];
	szLen[1] = '\0';

	if (*hContactResume)
		hContact = *hContactResume;
	else
		hContact = db_find_first(m_szModuleName);

	while (hContact != NULL) {
		DWORD dwUIN;
		uid_str szUID;
		if (!getContactUid(hContact, &dwUIN, &szUID)) {
			szLen[0] = (char)mir_strlen(strUID(dwUIN, szUID));

			switch (subtype) {
			case BUL_VISIBLE:
				add = ID_STATUS_ONLINE == getWord(hContact, "ApparentMode", 0);
				break;

			case BUL_INVISIBLE:
				add = ID_STATUS_OFFLINE == getWord(hContact, "ApparentMode", 0);
				break;

			case BUL_TEMPVISIBLE:
				add = getByte(hContact, "TemporaryVisible", 0);
				// clear temporary flag
				// Here we assume that all temporary contacts will be in one packet
				setByte(hContact, "TemporaryVisible", 0);
				break;

			default:
				add = 1;

				// If we are in SS mode, we only add those contacts that are
				// not in our SS list, or are awaiting authorization, to our
				// client side list
				if (m_bSsiEnabled && getWord(hContact, DBSETTING_SERVLIST_ID, 0) &&
					 !getByte(hContact, "Auth", 0))
					 add = 0;

				// Never add hidden contacts to CS list
				if (db_get_b(hContact, "CList", "Hidden", 0))
					add = 0;

				break;
			}

			if (add) {
				wCurrentLen += szLen[0] + 1;
				if (wCurrentLen > wMaxLen) {
					*hContactResume = hContact;
					return szList;
				}

				mir_strcat(szList, szLen);
				mir_strcat(szList, szUID);
			}
		}

		hContact = db_find_next(hContact, m_szModuleName);
	}
	*hContactResume = NULL;

	return szList;
}
예제 #15
0
void CIcqProto::handleLoginChannel(BYTE *buf, WORD datalen, serverthread_info *info)
{
	icq_packet packet;

#ifdef _DEBUG
  NetLog_Server("Received SRV_HELLO from %s", info->isLoginServer ? "login server" : "communication server");
#endif

	// isLoginServer is "1" if we just received SRV_HELLO
	if (info->isLoginServer)
	{
		if (m_bSecureLogin)
		{
			char szUin[UINMAXLEN];
			WORD wUinLen;

#ifdef _DEBUG
			NetLog_Server("Sending %s to %s", "CLI_HELLO", "login server");
#endif
			packet.wLen = 12;
			write_flap(&packet, ICQ_LOGIN_CHAN);
			packDWord(&packet, 0x00000001);
			packTLVDWord(&packet, 0x8003, 0x00100000); // unknown
			sendServPacket(&packet);  // greet login server

			wUinLen = strlennull(strUID(m_dwLocalUIN, szUin));
#ifdef _DEBUG
			NetLog_Server("Sending %s to %s", "ICQ_SIGNON_AUTH_REQUEST", "login server");
#endif

			serverPacketInit(&packet, (WORD)(14 + wUinLen));
			packFNACHeader(&packet, ICQ_AUTHORIZATION_FAMILY, ICQ_SIGNON_AUTH_REQUEST, 0, 0);
			packTLV(&packet, 0x0001, wUinLen, (LPBYTE)szUin);
			sendServPacket(&packet);  // request login digest
		}
		else
		{
			sendClientAuth((char*)info->szAuthKey, info->wAuthKeyLen, FALSE);
#ifdef _DEBUG
			NetLog_Server("Sent CLI_IDENT to %s", "login server");
#endif
		}

		info->isLoginServer = 0;
		if (info->cookieDataLen)
		{
			SAFE_FREE((void**)&info->cookieData);
			info->cookieDataLen = 0;
		}
	}
	else 
	{
		if (info->cookieDataLen)
		{
			wLocalSequence = generate_flap_sequence();

			serverCookieInit(&packet, info->cookieData, (WORD)info->cookieDataLen);
			sendServPacket(&packet);

#ifdef _DEBUG
			NetLog_Server("Sent CLI_IDENT to %s", "communication server");
#endif

			SAFE_FREE((void**)&info->cookieData);
			info->cookieDataLen = 0;
		}
		else
		{
			// We need a cookie to identify us to the communication server
      NetLog_Server("Error: Connected to %s without a cookie!", "communication server");
		}
	}
}