Ejemplo n.º 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, SIZEOF(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;
		icq_lock l(m_modeMsgsMutex);

		szAwayMsg = MirandaStatusToAwayMsg(m_iStatus);
		if (szAwayMsg)
			icq_sendSetAimAwayMsgServ(*szAwayMsg);
	}
}
Ejemplo n.º 2
0
void CIcqProto::parseDirectoryUserDetailsData(MCONTACT hContact, oscar_tlv_chain *cDetails, DWORD dwCookie, cookie_directory_data *pCookieData, WORD wReplySubType)
{
	oscar_tlv *pTLV;
	WORD wRecordCount;

	if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOMULTI && !hContact)
	{
		DWORD dwUin = 0;
		char *szUid = cDetails->getString(0x32, 1);
		if (!szUid) 
		{
			debugLogA("Error: Received unrecognized data from the directory");
			return;
		}

		if (IsStringUIN(szUid))
			dwUin = atoi(szUid);

		hContact = HContactFromUID(dwUin, szUid, NULL);
		if (hContact == INVALID_CONTACT_ID)
		{
			debugLogA("Error: Received details for unknown contact \"%s\"", szUid);
			SAFE_FREE(&szUid);
			return;
		}
#ifdef _DEBUG
		else
			debugLogA("Received user info for %s from directory", szUid);
#endif
		SAFE_FREE(&szUid);
	}
#ifdef _DEBUG
  else
	{
		char *szUid = cDetails->getString(0x32, 1);

    if (!hContact)
			debugLogA("Received owner user info from directory");
		else
			debugLogA("Received user info for %s from directory", szUid);
		SAFE_FREE(&szUid);
	}
#endif

	pTLV = cDetails->getTLV(0x50, 1);
	if (pTLV && pTLV->wLen > 0)
		writeDbInfoSettingTLVStringUtf(hContact, "e-mail",  cDetails, 0x50); // Verified e-mail
	else
		writeDbInfoSettingTLVStringUtf(hContact, "e-mail",  cDetails, 0x55); // Pending e-mail

	writeDbInfoSettingTLVStringUtf(hContact, "FirstName", cDetails, 0x64);
	writeDbInfoSettingTLVStringUtf(hContact, "LastName",  cDetails, 0x6E);
	writeDbInfoSettingTLVStringUtf(hContact, "Nick",      cDetails, 0x78);
	// Home Address
	parseUserInfoRecord(hContact, cDetails->getTLV(0x96, 1), rAddress, SIZEOF(rAddress), 1);
	// Origin Address
	parseUserInfoRecord(hContact, cDetails->getTLV(0xA0, 1), rOriginAddress, SIZEOF(rOriginAddress), 1);
	// Phones
	pTLV = cDetails->getTLV(0xC8, 1);
	if (pTLV && pTLV->wLen >= 2)
	{
		BYTE *pRecords = pTLV->pData;
		unpackWord(&pRecords, &wRecordCount);
		oscar_tlv_record_list *cPhones = readIntoTLVRecordList(&pRecords, pTLV->wLen - 2, wRecordCount);
		if (cPhones)
		{
			oscar_tlv_chain *cPhone;
			cPhone = cPhones->getRecordByTLV(0x6E, 1);
			writeDbInfoSettingTLVStringUtf(hContact, "Phone", cPhone, 0x64);
			cPhone = cPhones->getRecordByTLV(0x6E, 2);
			writeDbInfoSettingTLVStringUtf(hContact, "CompanyPhone", cPhone, 0x64);
			cPhone = cPhones->getRecordByTLV(0x6E, 3);
			writeDbInfoSettingTLVStringUtf(hContact, "Cellular", cPhone, 0x64);
			cPhone = cPhones->getRecordByTLV(0x6E, 4);
			writeDbInfoSettingTLVStringUtf(hContact, "Fax", cPhone, 0x64);
			cPhone = cPhones->getRecordByTLV(0x6E, 5);
			writeDbInfoSettingTLVStringUtf(hContact, "CompanyFax", cPhone, 0x64);

			disposeRecordList(&cPhones);
		}
		else
		{ // Remove old data when phones not available
			delSetting(hContact, "Phone");
			delSetting(hContact, "CompanyPhone");
			delSetting(hContact, "Cellular");
			delSetting(hContact, "Fax");
			delSetting(hContact, "CompanyFax");
		}
	}
	else
	{ // Remove old data when phones not available
		delSetting(hContact, "Phone");
		delSetting(hContact, "CompanyPhone");
		delSetting(hContact, "Cellular");
		delSetting(hContact, "Fax");
		delSetting(hContact, "CompanyFax");
	}
	// Emails
	parseUserInfoRecord(hContact, cDetails->getTLV(0x8C, 1), rEmail, SIZEOF(rEmail), 4);

	writeDbInfoSettingTLVByte(hContact, "Timezone", cDetails, 0x17C);
	// Company
	parseUserInfoRecord(hContact, cDetails->getTLV(0x118, 1), rCompany, SIZEOF(rCompany), 1);
	// Education
	parseUserInfoRecord(hContact, cDetails->getTLV(0x10E, 1), rEducation, SIZEOF(rEducation), 1);

	switch (cDetails->getNumber(0x82, 1))
	{
	case 1: 
		setByte(hContact, "Gender", 'F');
		break;
	case 2:
		setByte(hContact, "Gender", 'M');
		break;
	default:
		delSetting(hContact, "Gender");
	}

	writeDbInfoSettingTLVStringUtf(hContact, "Homepage", cDetails, 0xFA);
	writeDbInfoSettingTLVDate(hContact, "BirthYear", "BirthMonth", "BirthDay", cDetails, 0x1A4);

	writeDbInfoSettingTLVByte(hContact, "Language1", cDetails, 0xAA);
	writeDbInfoSettingTLVByte(hContact, "Language2", cDetails, 0xB4);
	writeDbInfoSettingTLVByte(hContact, "Language3", cDetails, 0xBE);

	writeDbInfoSettingTLVByte(hContact, "MaritalStatus", cDetails, 0x12C);
	// Interests
	parseUserInfoRecord(hContact, cDetails->getTLV(0x122, 1), rInterest, SIZEOF(rInterest), 4);

	writeDbInfoSettingTLVStringUtf(hContact, "About", cDetails, 0x186);

//	if (hContact)
//		writeDbInfoSettingTLVStringUtf(hContact, DBSETTING_STATUS_NOTE, cDetails, 0x226);
//	else
	if (!hContact)
	{ // Owner contact needs special processing, in the database is current status note for the client
		// We just received the last status note set on directory, if it differs call SetStatusNote() to 
		// ensure the directory will be updated (it should be in process anyway)
		char *szClientStatusNote = getSettingStringUtf(hContact, DBSETTING_STATUS_NOTE, NULL);
		char *szDirectoryStatusNote = cDetails->getString(0x226, 1);

		if (strcmpnull(szClientStatusNote, szDirectoryStatusNote))
			SetStatusNote(szClientStatusNote, 1000, TRUE);

		// Release memory
		SAFE_FREE(&szDirectoryStatusNote);
		SAFE_FREE(&szClientStatusNote);
	}

	writeDbInfoSettingTLVByte(hContact, "PrivacyLevel", cDetails, 0x1F9);

	if (!hContact)
	{
		setByte(hContact, "Auth", !cDetails->getByte(0x19A, 1));
		writeDbInfoSettingTLVByte(hContact, "WebAware", cDetails, 0x212);
		writeDbInfoSettingTLVByte(hContact, "AllowSpam", cDetails, 0x1EA);
	}

	writeDbInfoSettingTLVWord(hContact, "InfoCP", cDetails, 0x1C2);

	if (hContact)
	{ // Handle deprecated setting (Age & Birthdate are not separate fields anymore)
		int nAge = calcAgeFromBirthDate(cDetails->getDouble(0x1A4, 1));

		if (nAge)
			setWord(hContact, "Age", nAge);
		else
			delSetting(hContact, "Age");
	}
	else // we do not need to calculate age for owner
		delSetting(hContact, "Age");

	{ // Save user info last update time and privacy token
		double dInfoTime;
		BYTE pbEmptyMetaToken[0x10] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
		int bHasMetaToken = FALSE;

		// Check if the details arrived with privacy token!
		if ((pTLV = cDetails->getTLV(0x3C, 1)) && pTLV->wLen == 0x10 && memcmp(pTLV->pData, pbEmptyMetaToken, 0x10))
			bHasMetaToken = TRUE;

		// !Important, we need to save the MDir server-item time - it can be newer than the one from the directory
		if ((dInfoTime = getSettingDouble(hContact, DBSETTING_METAINFO_TIME, 0)) > 0)
			setSettingDouble(hContact, DBSETTING_METAINFO_SAVED, dInfoTime);
		else if (bHasMetaToken || !hContact)
			writeDbInfoSettingTLVDouble(hContact, DBSETTING_METAINFO_SAVED, cDetails, 0x1CC);
		else
			setDword(hContact, DBSETTING_METAINFO_SAVED, time(NULL));
	}

	if (wReplySubType == META_DIRECTORY_RESPONSE)
		if (pCookieData->bRequestType == DIRECTORYREQUEST_INFOUSER)
			ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1 ,0);

	// Remove user from info update queue. Removing is fast so we always call this
	// even if it is likely that the user is not queued at all.
	if (hContact)
		icq_DequeueUser(getContactUin(hContact));
}