Example #1
0
void CIcqProto::handleServUINSettings(int nPort, serverthread_info *info)
{
	setUserInfo();

	/* SNAC 3,4: Tell server who's on our list (deprecated) */
	/* SNAC 3,15: Try to add unauthorised contacts to temporary list */
	sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOTEMPLIST, BUL_ALLCONTACTS);

	if (m_iDesiredStatus == ID_STATUS_INVISIBLE) {
		/* Tell server who's on our visible list (deprecated) */
		if (!m_bSsiEnabled)
			sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE);
		else
			updateServVisibilityCode(3);
	}

	if (m_iDesiredStatus != ID_STATUS_INVISIBLE) {
		/* Tell server who's on our invisible list (deprecated) */
		if (!m_bSsiEnabled)
			sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE);
		else
			updateServVisibilityCode(4);
	}

	// SNAC 1,1E: Set status
	icq_packet packet;
	{
		DWORD dwDirectCookie = rand() ^ (rand() << 16);

		// Get status
		WORD wStatus = MirandaStatusToIcq(m_iDesiredStatus);

		// Get status note & mood
		char *szStatusNote = PrepareStatusNote(m_iDesiredStatus);
		BYTE bXStatus = getContactXStatus(NULL);
		char szMoodData[32];

		// prepare mood id
		if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus - 1] != -1)
			mir_snprintf(szMoodData, "icqmood%d", moodXStatus[bXStatus - 1]);
		else
			szMoodData[0] = '\0';

		//! Tricky code, this ensures that the status note will be saved to the directory
		SetStatusNote(szStatusNote, m_bGatewayMode ? 5000 : 2500, TRUE);

		size_t wStatusNoteLen = mir_strlen(szStatusNote);
		size_t wStatusMoodLen = mir_strlen(szMoodData);
		size_t wSessionDataLen = (wStatusNoteLen ? wStatusNoteLen + 4 : 0) + 4 + wStatusMoodLen + 4;

		serverPacketInit(&packet, 71 + (wSessionDataLen ? wSessionDataLen + 4 : 0));
		packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS);
		packDWord(&packet, 0x00060004);             // TLV 6: Status mode and security flags
		packWord(&packet, GetMyStatusFlags());      // Status flags
		packWord(&packet, wStatus);                 // Status
		packTLVWord(&packet, 0x0008, 0x0A06);       // TLV 8: Independent Status Messages
		packDWord(&packet, 0x000c0025);             // TLV C: Direct connection info
		packDWord(&packet, getDword("RealIP", 0));
		packDWord(&packet, nPort);
		packByte(&packet, DC_TYPE);                 // TCP/FLAG firewall settings
		packWord(&packet, ICQ_VERSION);
		packDWord(&packet, dwDirectCookie);         // DC Cookie
		packDWord(&packet, WEBFRONTPORT);           // Web front port
		packDWord(&packet, CLIENTFEATURES);         // Client features
		packDWord(&packet, 0x7fffffff);             // Abused timestamp
		packDWord(&packet, ICQ_PLUG_VERSION);       // Abused timestamp
		if (ServiceExists("SecureIM/IsContactSecured"))
			packDWord(&packet, 0x5AFEC0DE);           // SecureIM Abuse
		else
			packDWord(&packet, 0x00000000);           // Timestamp
		packWord(&packet, 0x0000);                  // Unknown
		packTLVWord(&packet, 0x001F, 0x0000);

		if (wSessionDataLen) { // Pack session data
			packWord(&packet, 0x1D);                  // TLV 1D
			packWord(&packet, WORD(wSessionDataLen));       // TLV length
			packWord(&packet, 0x02);                  // Item Type
			if (wStatusNoteLen) {
				packWord(&packet, 0x400 | WORD(wStatusNoteLen + 4)); // Flags + Item Length
				packWord(&packet, WORD(wStatusNoteLen));      // Text Length
				packBuffer(&packet, (LPBYTE)szStatusNote, wStatusNoteLen);
				packWord(&packet, 0);                   // Encoding not specified (utf-8 is default)
			}
			else
				packWord(&packet, 0);                   // Flags + Item Length
			packWord(&packet, 0x0E);                  // Item Type
			packWord(&packet, WORD(wStatusMoodLen));        // Flags + Item Length
			if (wStatusMoodLen)
				packBuffer(&packet, (LPBYTE)szMoodData, wStatusMoodLen); // Mood

			// Save current status note & mood
			db_set_utf(NULL, m_szModuleName, DBSETTING_STATUS_NOTE, szStatusNote);
			setString(DBSETTING_STATUS_MOOD, szMoodData);
		}
		// Release memory
		SAFE_FREE(&szStatusNote);

		sendServPacket(&packet);
	}

	/* SNAC 1,11 */
	serverPacketInit(&packet, 14);
	packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE);
	packDWord(&packet, 0x00000000);

	sendServPacket(&packet);
	m_bIdleAllow = 0;

	// Change status
	SetCurrentStatus(m_iDesiredStatus);

	// Finish Login sequence
	serverPacketInit(&packet, 98);
	packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY);
	packDWord(&packet, 0x00220001); // imitate ICQ 6 behaviour
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00010004);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00130004);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00020001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00030001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00150001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00040001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00060001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x00090001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x000A0001);
	packDWord(&packet, 0x0110164f);
	packDWord(&packet, 0x000B0001);
	packDWord(&packet, 0x0110164f);

	sendServPacket(&packet);

	debugLogA(" *** Yeehah, login sequence complete");

	// login sequence is complete enter logged-in mode
	info->bLoggedIn = true;
	m_bConnectionLost = false;

	// enable auto info-update routine
	icq_EnableUserLookup(true);

	if (!info->isMigrating) {
		// Get Offline Messages Reqeust
		cookie_offline_messages *ack = (cookie_offline_messages*)SAFE_MALLOC(sizeof(cookie_offline_messages));
		if (ack) {
			DWORD dwCookie = AllocateCookie(CKT_OFFLINEMESSAGE, ICQ_MSG_CLI_REQ_OFFLINE, 0, ack);

			serverPacketInit(&packet, 10);
			packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQ_OFFLINE, 0, dwCookie);

			sendServPacket(&packet);
		}
		else icq_LogMessage(LOG_WARNING, LPGEN("Failed to request offline messages. They may be received next time you log in."));

		// Update our information from the server
		sendOwnerInfoRequest();

		// Request info updates on all contacts
		icq_RescanInfoUpdate();

		// Start sending Keep-Alive packets
		StartKeepAlive(info);

		if (m_bAvatarsEnabled) { // Send SNAC 1,4 - request avatar family 0x10 connection
			icq_requestnewfamily(ICQ_AVATAR_FAMILY, &CIcqProto::StartAvatarThread);

			m_avatarsConnectionPending = TRUE;
			debugLogA("Requesting Avatar family entry point.");
		}

		// Set last xstatus
		updateServerCustomStatus(TRUE);
	}
	info->isMigrating = false;

	if (m_bAimEnabled) {
		char **szAwayMsg = NULL;
		mir_cslock l(m_modeMsgsMutex);

		szAwayMsg = MirandaStatusToAwayMsg(m_iStatus);
		if (szAwayMsg)
			icq_sendSetAimAwayMsgServ(*szAwayMsg);
	}
}
Example #2
0
void __cdecl CIcqProto::InfoUpdateThread( void* )
{
	int i;
	DWORD dwWait = WAIT_OBJECT_0;

	debugLogA("%s thread starting.", "Info-Update");

	bInfoUpdateRunning = TRUE;

	while (bInfoUpdateRunning)
	{
		if (!nInfoUserCount && bInfoPendingUsers) // whole queue processed, check if more users needs updating
			icq_RescanInfoUpdate();

		if (!nInfoUserCount || !bInfoUpdateEnabled || !icqOnline())
		{
			dwWait = WAIT_TIMEOUT;
			while (bInfoUpdateRunning && dwWait == WAIT_TIMEOUT)
			{ // wait for new work or until we should end
				dwWait = ICQWaitForSingleObject(hInfoQueueEvent, 10000);
			}
		}
		if (!bInfoUpdateRunning) break;

		switch (dwWait) {
		case WAIT_IO_COMPLETION:
			// Possible shutdown in progress
			break;

		case WAIT_OBJECT_0:
		case WAIT_TIMEOUT:
			// Time to check for new users
			if (!bInfoUpdateEnabled) continue; // we can't send requests now      

			if (nInfoUserCount && icqOnline())
			{
				time_t now = time(NULL);
				BOOL bNotReady = FALSE, bTimeOuted = FALSE;

				// Check the list, take only users that were there for at least 5sec
				// wait if any user is there shorter than 5sec and not a single user is there longer than 20sec
				infoUpdateMutex->Enter();
				for (i = 0; i<LISTSIZE; i++)
				{
					if (m_infoUpdateList[i].hContact)
					{
						if (m_infoUpdateList[i].queued + 20 < now)
						{
							bTimeOuted = TRUE;
							break;
						}
						else if (m_infoUpdateList[i].queued + 5 >= now)
							bNotReady = TRUE;
					}
				}
				infoUpdateMutex->Leave();

				if (!bTimeOuted && bNotReady)
				{
					SleepEx(1000, TRUE);
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					continue;
				}

				if (FindCookie(dwInfoActiveRequest, NULL, NULL))
				{ // only send another request, when the previous is completed
#ifdef _DEBUG
					debugLogA("Info-Update: Request 0x%x still in progress.", dwInfoActiveRequest);
#endif
					SleepEx(1000, TRUE);
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					continue;
				}

#ifdef _DEBUG
				debugLogA("Info-Update: Users %u in queue.", nInfoUserCount);
#endif
				// Either some user is waiting long enough, or all users are ready (waited at least the minimum time)
				m_ratesMutex->Enter();
				if (!m_rates)
				{ // we cannot send info request - icq is offline
					m_ratesMutex->Leave();
					break;
				}
				WORD wGroup = m_rates->getGroupFromSNAC(ICQ_EXTENSIONS_FAMILY, ICQ_META_CLI_REQUEST);
				while (m_rates->getNextRateLevel(wGroup) < m_rates->getLimitLevel(wGroup, RML_IDLE_30))
				{ // we are over rate, need to wait before sending
					int nDelay = m_rates->getDelayToLimitLevel(wGroup, RML_IDLE_50);

					m_ratesMutex->Leave();
#ifdef _DEBUG
					debugLogA("Rates: InfoUpdate delayed %dms", nDelay);
#endif
					SleepEx(nDelay, TRUE); // do not keep things locked during sleep
					if (!bInfoUpdateRunning)
					{ // need to end as fast as possible
						debugLogA("%s thread ended.", "Info-Update");
						goto LBL_Exit;
					}
					m_ratesMutex->Enter();
					if (!m_rates) // we lost connection when we slept, go away
						break;
				}
				if (!m_rates)
				{ // we cannot send info request - icq is offline
					m_ratesMutex->Leave();
					break;
				}
				m_ratesMutex->Leave();

				userinfo *hContactList[LISTSIZE];
				int nListIndex = 0;
				BYTE *pRequestData = NULL;
				int nRequestSize = 0;

				infoUpdateMutex->Enter();
				for (i = 0; i<LISTSIZE; i++)
				{
					if (m_infoUpdateList[i].hContact)
					{
						// check TS again, maybe it has been updated while we slept
						if (IsMetaInfoChanged(m_infoUpdateList[i].hContact))
						{
							if (m_infoUpdateList[i].queued + 5 < now)
							{
								BYTE *pItem = NULL;
								int nItemSize = 0;
								DBVARIANT dbv = {DBVT_DELETED};

								if (!getSetting(m_infoUpdateList[i].hContact, DBSETTING_METAINFO_TOKEN, &dbv))
								{ // retrieve user details using privacy token
									ppackTLV(&pItem, &nItemSize, 0x96, dbv.cpbVal, dbv.pbVal);
									db_free(&dbv);
								}
								// last updated time
								ppackTLVDouble(&pItem, &nItemSize, 0x64, getSettingDouble(m_infoUpdateList[i].hContact, DBSETTING_METAINFO_TIME, 0));

								ppackTLVUID(&pItem, &nItemSize, 0x32, m_infoUpdateList[i].dwUin, NULL);
								ppackWord(&pRequestData, &nRequestSize, (WORD)nItemSize);
								ppackBuffer(&pRequestData, &nRequestSize, nItemSize, pItem);
								// take a reference
								SAFE_FREE((void**)&pItem);
								hContactList[nListIndex++] = &m_infoUpdateList[i];
							}
						}
						else
						{
#ifdef _DEBUG
							debugLogA("Dequeued absolete user %u", m_infoUpdateList[i].dwUin);
#endif
							// Dequeue user and find another one
							m_infoUpdateList[i].dwUin = 0;
							m_infoUpdateList[i].hContact = NULL;
							nInfoUserCount--;
							// continue for loop
						}
					}
				}

#ifdef _DEBUG
				debugLogA("Request info for %u user(s).", nListIndex);
#endif
				if (!nListIndex)
				{ // no users to request info for
					infoUpdateMutex->Leave();
					break;
				}
				if (!(dwInfoActiveRequest = sendUserInfoMultiRequest(pRequestData, nRequestSize, nListIndex)))
				{ // sending data packet failed
					SAFE_FREE((void**)&pRequestData);
					infoUpdateMutex->Leave();
					break;
				}
				SAFE_FREE((void**)&pRequestData);

				for (i = 0; i<nListIndex; i++)
				{ // Dequeue users and go back to sleep
					hContactList[i]->dwUin = 0;
					hContactList[i]->hContact = NULL;
					hContactList[i]->queued = 0;
					nInfoUserCount--;
				}
				infoUpdateMutex->Leave();
			}
			break;

		default:
			// Something strange happened. Exit
			bInfoUpdateRunning = FALSE;
			break;
		}
	}

	debugLogA("%s thread ended.", "Info-Update");

LBL_Exit:
	SAFE_DELETE(&infoUpdateMutex);
	CloseHandle(hInfoQueueEvent);
}