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); } }
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); }