コード例 #1
0
void CYahooProto::ext_got_picture_checksum(const char *me, const char *who, int cksum)
{
	LOG(("ext_yahoo_got_picture_checksum for %s checksum: %d", who, cksum));

	MCONTACT hContact = getbuddyH(who);
	if (hContact == NULL) {
		LOG(("Buddy Not Found. Skipping avatar update"));
		return;
	}

	/* Last thing check the checksum and request new one if we need to */
	if (!cksum || cksum == -1) {
		setDword(hContact, "PictCK", 0);
		reset_avatar(hContact);
	}
	else {
		if (getDword(hContact, "PictCK", 0) != cksum) {
			// Now save the new checksum. No rush requesting new avatar yet.
			setDword(hContact, "PictCK", cksum);

			// Need to delete the Avatar File!!
			TCHAR szFile[MAX_PATH];
			GetAvatarFileName(hContact, szFile, _countof(szFile) - 1, 0);
			DeleteFile(szFile);

			// Reset the avatar and cleanup.
			reset_avatar(hContact);

			// Request new avatar here... (might also want to check the sharing status?)

			if (getByte("ShareAvatar", 0) == 2)
				request_avatar(who);
		}
	}
}
コード例 #2
0
ファイル: steam_login.cpp プロジェクト: kxepal/miranda-ng
void CSteamProto::OnLoggedOn(const HttpResponse *response)
{
	if (!CheckResponse(response))
	{
		if (response && response->resultCode == HTTP_CODE_UNAUTHORIZED)
		{
			// Probably expired TokenSecret
			HandleTokenExpired();
			return;
		}

		// Probably timeout or no connection, we can do nothing here
		ShowNotification(_T("Steam"), TranslateT("Unknown login error."));

		SetStatus(ID_STATUS_OFFLINE);
		return;
	}

	JSONROOT root(response->pData);

	JSONNode *node = json_get(root, "error");
	ptrT error(json_as_string(node));
	if (mir_tstrcmpi(error, _T("OK")))
	{
		// Probably expired TokenSecret
		HandleTokenExpired();
		return;
	}

	node = json_get(root, "umqid");
	setString("UMQID", ptrA(mir_u2a(ptrT(json_as_string(node)))));

	node = json_get(root, "message");
	setDword("MessageID", json_as_int(node));
	
	if (m_lastMessageTS <= 0) {
		node = json_get(root, "utc_timestamp");
		time_t timestamp = _ttoi64(ptrT(json_as_string(node)));
		setDword("LastMessageTS", timestamp);
	}

	// load contact list
	ptrA token(getStringA("TokenSecret"));
	ptrA steamId(getStringA("SteamID"));

	PushRequest(
		new GetFriendListRequest(token, steamId),
		&CSteamProto::OnGotFriendList);

	// start polling thread
	m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, 0, NULL);

	// go to online now
	ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus);
}
コード例 #3
0
ファイル: services.cpp プロジェクト: ybznek/miranda-ng
void CYahooProto::logoff_buddies()
{
	//set all contacts to 'offline'
	for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
		setWord(hContact, "Status", ID_STATUS_OFFLINE);
		setDword(hContact, "IdleTS", 0);
		setDword(hContact, "PictLastCheck", 0);
		setDword(hContact, "PictLoading", 0);
		db_unset(hContact, "CList", "StatusMsg");
		delSetting(hContact, "YMsg");
		delSetting(hContact, "YGMsg");
	}
}
コード例 #4
0
void CVkProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveMyInfo %d", reply->resultCode);
	if (reply->resultCode != 200) {
		ConnectionFailed(LOGINERR_WRONGPASSWORD);
		return;
	}

	JSONNode jnRoot;
	const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
	if (!jnResponse)
		return;
	
	const JSONNode &jnUser = *(jnResponse.begin());


	m_myUserId = jnUser["id"].as_int();
	setDword("ID", m_myUserId);
		
	OnLoggedIn();
	RetrieveUserInfo(m_myUserId);
	RetrieveUnreadMessages();
	RetrieveFriends();
	RetrievePollingInfo();
}
コード例 #5
0
ファイル: capabilities.cpp プロジェクト: 0xmono/miranda-ng
// Scans a binary buffer for oscar capabilities and adds them to the contact.
// You probably want to call ClearAllContactCapabilities() first.
void CIcqProto::SetCapabilitiesFromBuffer(MCONTACT hContact, BYTE *pBuffer, int nLength, BOOL bReset)
{
	// Get current capability flags
	DWORD fdwContactCaps = bReset ? 0 : getDword(hContact, DBSETTING_CAPABILITIES, 0);
	// Get capability flags from buffer
	DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength);

#ifdef _DEBUG
	if (bReset)
		NetLog_CapabilityChange(this, "Set", fdwCapabilities);
	else {
		NetLog_CapabilityChange(this, "Removed", fdwContactCaps & ~fdwCapabilities & CapabilityFlagsMask);
		NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps);
	}
#endif

	if (fdwCapabilities != (fdwContactCaps & ~CapabilityFlagsMask)) {
		// Get current unmanaged capability flags
		fdwContactCaps &= ~CapabilityFlagsMask;

		// Add capability flags from buffer
		fdwContactCaps |= fdwCapabilities;

		// And write them back to database
		setDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
	}
}
コード例 #6
0
ファイル: vk_thread.cpp プロジェクト: Ganster41/miranda-ng
void CVkProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	debugLogA("CVkProto::OnReceiveMyInfo %d", reply->resultCode);
	if (reply->resultCode != 200) {
		ConnectionFailed(LOGINERR_WRONGPASSWORD);
		return;
	}

	JSONROOT pRoot;
	JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot);
	if (pResponse == NULL)
		return;

	for (size_t i = 0; i < json_size(pResponse); i++) {
		JSONNODE *it = json_at(pResponse, i);
		LPCSTR id = json_name(it);
		if (!_stricmp(id, "user_id")) {
			m_myUserId = json_as_int(it);
			setDword("ID", m_myUserId);
		}
	}

	OnLoggedIn();
	RetrieveUserInfo(m_myUserId);
	RetrieveFriends();
	RetrieveUnreadMessages();
	RetrievePollingInfo();
}
コード例 #7
0
void CYahooProto::request_avatar(const char* who)
{
	if (!getByte("ShowAvatars", 1)) {
		LOG(("Avatars disabled, but available for: %s", who));
		return;
	}

	MCONTACT hContact = getbuddyH(who);

	if (!hContact)
		return;

	time_t cur_time;
	time(&cur_time);
	time_t last_chk = getDword(hContact, "PictLastCheck", 0);

	/*
	* time() - in seconds ( 60*60 = 1 hour)
	*/
	if (getDword(hContact, "PictCK", 0) == 0 || last_chk == 0 || (cur_time - last_chk) > 60) {
		setDword(hContact, "PictLastCheck", (DWORD)cur_time);
		LOG(("Requesting Avatar for: %s", who));
		yahoo_request_buddy_avatar(m_id, who);
	}
	else LOG(("Avatar Not Available for: %s Last Check: %ld Current: %ld (Flood Check in Effect)", who, last_chk, cur_time));
}
コード例 #8
0
int CAimProto::aim_set_away(HANDLE hServerConn, unsigned short &seqno, const char *amsg, bool set)//user info
{
	unsigned short offset=0;
	char* html_msg = NULL;
	size_t msg_size = 0;
	if (set)
	{
		if (!amsg) return -1;
		setDword(AIM_KEY_LA, (DWORD)time(NULL));
		html_msg = html_encode(amsg && amsg[0] ? amsg : DEFAULT_AWAY_MSG);
		msg_size = strlen(html_msg);
	}

	aimString str(html_msg);
	const char *charset = str.isUnicode() ? AIM_MSG_TYPE_UNICODE : AIM_MSG_TYPE;
	const unsigned short charset_len = (unsigned short)strlen(charset);

	const char* msg = str.getBuf();
	const unsigned short msg_len = str.getSize();

	char* buf=(char*)alloca(SNAC_SIZE+TLV_HEADER_SIZE*3+charset_len+msg_len+1);

	aim_writesnac(0x02,0x04,offset,buf);
	aim_writetlv(0x03,charset_len,charset,offset,buf);
	aim_writetlv(0x04,(unsigned short)msg_len,msg,offset,buf);

//	aim_writetlvchar(0x0f,2,offset,buf);
	
	mir_free(html_msg);

	return aim_sendflap(hServerConn,0x02,offset,buf,seqno);
}
コード例 #9
0
void TranslatedBootMedia::updateBootsectorConfig(void)
{
	DWORD tsize, dsize, bsize, totalSize;
	
    int driverOffset = 1024;
    
	tsize = Utils::getDword(imageBuffer + driverOffset + 2);        // get size of text
	dsize = Utils::getDword(imageBuffer + driverOffset + 6);        // get size of data
	bsize = Utils::getDword(imageBuffer + driverOffset + 10);       // get size of bss
	
	totalSize = tsize + dsize + bsize;					// total size of driver in RAM = size of text + data + bss
	totalSize = ((totalSize / 1024) + 2) * 1024;		// round the size to the nearest biggest kB 
	
	int pos = getConfigPosition();
	
	if(pos == -1) {
		Debug::out(LOG_ERROR, "TranslatedBootMedia - didn't find the config position in bootsector.");
		return;
	}
	
	imageBuffer[pos + 7] = SCapacity - 1;				// store how many sectors we should read (without boot sector)
	setDword(&imageBuffer[pos + 2], totalSize);			// store how many RAM we need to reserve for driver in ST
	
	updateBootsectorChecksum();							// update the checksum at the end
	
    Debug::out(LOG_DEBUG, "TranslatedBootMedia - bootsector will read %d sectors, the driver will take %d kB of RAM.", (int) imageBuffer[pos + 7], (int) (totalSize / 1024));
    
    updateBootsectorConfigWithACSIid(lastUsedAcsiId);
}
コード例 #10
0
ファイル: steam_login.cpp プロジェクト: kxepal/miranda-ng
bool CSteamProto::Relogin()
{
	ptrA token(getStringA("TokenSecret"));
	if (mir_strlen(token) <= 0)
		return false;

	HttpRequest *request = new LogonRequest(token);
	HttpResponse *response = request->Send(m_hNetlibUser);

	bool success = false;
	if (CheckResponse(response))
	{
		JSONROOT root(response->pData);
		if (root != NULL) {
			JSONNode *node = json_get(root, "error");

			ptrT error(json_as_string(node));
			if (!mir_tstrcmpi(error, _T("OK")))
			{
				node = json_get(root, "umqid");
				setString("UMQID", ptrA(mir_u2a(ptrT(json_as_string(node)))));

				node = json_get(root, "message");
				setDword("MessageID", json_as_int(node));

				success = true;
			}
		}
	}

	delete request;
	delete response;

	return success;
}
コード例 #11
0
ファイル: gg_proto.cpp プロジェクト: MrtsComputers/miranda-ng
GGPROTO::GGPROTO(const char* pszProtoName, const TCHAR* tszUserName) :
	PROTO<GGPROTO>(pszProtoName, tszUserName),
	avatar_requests(1, HandleKeySortT),
	avatar_transfers(1, HandleKeySortT)
{
#ifdef DEBUGMODE
	extendedLogging = 0;
#endif

	// Init mutexes
	InitializeCriticalSection(&sess_mutex);
	InitializeCriticalSection(&ft_mutex);
	InitializeCriticalSection(&img_mutex);
	InitializeCriticalSection(&modemsg_mutex);
	InitializeCriticalSection(&avatar_mutex);
	InitializeCriticalSection(&sessions_mutex);

	// Register m_hNetlibUser user
	TCHAR name[128];
	mir_sntprintf(name, SIZEOF(name), TranslateT("%s connection"), m_tszUserName);

	NETLIBUSER nlu = { 0 };
	nlu.cbSize = sizeof(nlu);
	nlu.flags = NUF_TCHAR | NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS;
	nlu.szSettingsModule = m_szModuleName;
	nlu.ptszDescriptiveName = name;

	m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);

	// Register services
	CreateProtoService(PS_GETAVATARCAPS, &GGPROTO::getavatarcaps);
	CreateProtoService(PS_GETAVATARINFOT, &GGPROTO::getavatarinfo);
	CreateProtoService(PS_GETMYAVATART, &GGPROTO::getmyavatar);
	CreateProtoService(PS_SETMYAVATART, &GGPROTO::setmyavatar);

	CreateProtoService(PS_GETMYAWAYMSG, &GGPROTO::getmyawaymsg);
	CreateProtoService(PS_SETAWAYMSGT, (MyServiceFunc)&GGPROTO::SetAwayMsg);
	CreateProtoService(PS_CREATEACCMGRUI, &GGPROTO::get_acc_mgr_gui);

	CreateProtoService(PS_LEAVECHAT, &GGPROTO::leavechat);

	// Offline contacts and clear logon time
	setalloffline();
	setDword(GG_KEY_LOGONTIME, 0);

	db_set_resident(m_szModuleName, GG_KEY_AVATARREQUESTED);

	TCHAR szPath[MAX_PATH];
	mir_sntprintf(szPath, MAX_PATH, _T("%s\\%s\\ImageCache"), (TCHAR*)VARST( _T("%miranda_userdata%")), m_tszUserName);
	hImagesFolder = FoldersRegisterCustomPathT(LPGEN("Images"), m_szModuleName, szPath, m_tszUserName);

	DWORD dwVersion;
	if ((dwVersion = getDword(GG_PLUGINVERSION, 0)) < pluginInfo.version)
		cleanuplastplugin(dwVersion);

	links_instance_init();
	initavatarrequestthread();
}
コード例 #12
0
void CVkProto::RetrieveUnreadNews(time_t tLastNewsTime)
{
	debugLogA("CVkProto::RetrieveUnreadNews");
	if (!IsOnline())
		return;

	time_t tLastNewsReqTime = getDword("LastNewsReqTime", time(NULL) - 24 * 60 * 60);
	if (time(NULL) - tLastNewsReqTime < 3 * 60)
		return;
		
	CMStringA szFilter;
	szFilter = m_bNewsFilterPosts ? "post" : "";

	szFilter += szFilter.IsEmpty() ? "" : ",";
	szFilter += m_bNewsFilterPhotos ? "photo" : "";

	szFilter += szFilter.IsEmpty() ? "" : ",";
	szFilter += m_bNewsFilterTags ? "photo_tag" : "";

	szFilter += szFilter.IsEmpty() ? "" : ",";
	szFilter += m_bNewsFilterWallPhotos ? "wall_photo" : "";

	if (szFilter.IsEmpty()) {
		debugLogA("CVkProto::RetrieveUnreadNews szFilter empty");
		return;
	}

	CMStringA szSource;
	szSource = m_bNewsSourceFriends ? "friends" : "";

	szSource += szSource.IsEmpty() ? "" : ",";
	szSource += m_bNewsSourceGroups ? "groups" : "";

	szSource += szSource.IsEmpty() ? "" : ",";
	szSource += m_bNewsSourcePages ? "pages" : "";

	szSource += szSource.IsEmpty() ? "" : ",";
	szSource += m_bNewsSourceFollowing ? "following" : "";

	if (szSource.IsEmpty()) {
		debugLogA("CVkProto::RetrieveUnreadNews szSource empty");
		return;
	}
			
	Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/newsfeed.get.json", true, &CVkProto::OnReceiveUnreadNews))
		<< INT_PARAM("count", 100)
		<< INT_PARAM("return_banned", m_bNewsSourceIncludeBanned ? 1 : 0)
		<< INT_PARAM("max_photos", m_iMaxLoadNewsPhoto)
		<< INT_PARAM("start_time", tLastNewsTime + 1)
		<< CHAR_PARAM("filters", szFilter)
		<< CHAR_PARAM("source_ids", szSource)
		<< VER_API;

	setDword("LastNewsReqTime", (DWORD)time(NULL));
}
コード例 #13
0
ファイル: vk_feed.cpp プロジェクト: kxepal/miranda-ng
void CVkProto::OnReceiveUnreadNews(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
    debugLogA("CVkProto::OnReceiveUnreadNews %d", reply->resultCode);
    db_unset(NULL, m_szModuleName, "LastNewsReqTime");
    if (reply->resultCode != 200)
        return;

    JSONNode jnRoot;
    const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
    if (!jnResponse)
        return;

    OBJLIST<CVkUserInfo> vkUsers(5, NumericKeySortT);
    CreateVkUserInfoList(vkUsers, jnResponse);

    const JSONNode &jnItems = jnResponse["items"];

    OBJLIST<CVKNewsItem> vkNews(5, sttCompareVKNewsItems);
    if (jnItems)
        for (auto it = jnItems.begin(); it != jnItems.end(); ++it) {
            CVKNewsItem *vkNewsItem = GetVkNewsItem((*it), vkUsers);
            if (!vkNewsItem)
                continue;
            CVKNewsItem *vkNewsFoundItem = vkNews.find(vkNewsItem);
            if (vkNewsFoundItem == NULL)
                vkNews.insert(vkNewsItem);
            else if (vkNewsFoundItem->tszType == _T("wall_photo") && vkNewsItem->tszType == _T("post")) {
                vkNews.remove(vkNewsFoundItem);
                vkNews.insert(vkNewsItem);
            }
            else
                delete vkNewsItem;
        }

    bool bNewsAdded = false;
    for (int i = 0; i < vkNews.getCount(); i++)
        if (!(m_bNewsSourceNoReposts && vkNews[i].bIsRepost)) {
            AddFeedEvent(vkNews[i]);
            bNewsAdded = true;
        }

    if (bNewsAdded)
        AddCListEvent(true);

    setDword("LastNewsTime", time(NULL));

    vkNews.destroy();
    vkUsers.destroy();
}
コード例 #14
0
ファイル: capabilities.cpp プロジェクト: 0xmono/miranda-ng
// Sets one or many oscar capabilities for a given contact
void CIcqProto::SetContactCapabilities(MCONTACT hContact, DWORD fdwCapabilities)
{
	// Get current capability flags
	DWORD fdwContactCaps = getDword(hContact, DBSETTING_CAPABILITIES, 0);
	if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) {
#ifdef _DEBUG
		NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps);
#endif
		// Update them
		fdwContactCaps |= fdwCapabilities;

		// And write it back to disk
		setDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
	}
}
コード例 #15
0
ファイル: capabilities.cpp プロジェクト: 0xmono/miranda-ng
// Deletes one or many oscar capabilities for a given contact
void CIcqProto::ClearContactCapabilities(MCONTACT hContact, DWORD fdwCapabilities)
{
	// Get current capability flags
	DWORD fdwContactCaps = getDword(hContact, DBSETTING_CAPABILITIES, 0);
	if (fdwContactCaps != (fdwContactCaps & ~fdwCapabilities)) {
#ifdef _DEBUG
		NetLog_CapabilityChange(this, "Removed", fdwCapabilities & fdwContactCaps);
#endif
		// Clear unwanted capabilities
		fdwContactCaps &= ~fdwCapabilities;

		// And write it back to disk
		setDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
	}
}
コード例 #16
0
ファイル: vk_messages.cpp プロジェクト: ybznek/miranda-ng
void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
{
	int iResult = ACKRESULT_FAILED;
	if (pReq->pUserInfo == NULL) {
		debugLogA("CVkProto::OnSendMessage failed! (pUserInfo == NULL)");
		return;
	}
	CVkSendMsgParam *param = (CVkSendMsgParam *)pReq->pUserInfo;

	debugLogA("CVkProto::OnSendMessage %d", reply->resultCode);
	if (reply->resultCode == 200) {
		JSONNode jnRoot;
		const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot);
		if (jnResponse) {
			UINT mid;
			if (jnResponse.type() != JSON_STRING) 
				mid = jnResponse.as_int();
			else if (_stscanf(jnResponse.as_mstring(), _T("%d"), &mid) != 1)
				mid = 0;

			if (param->iMsgID != -1)
				m_sendIds.insert((HANDLE)mid);

			if (mid > getDword(param->hContact, "lastmsgid"))
				setDword(param->hContact, "lastmsgid", mid);

			if (m_vkOptions.iMarkMessageReadOn >= MarkMsgReadOn::markOnReply)
				MarkMessagesRead(param->hContact);

			iResult = ACKRESULT_SUCCESS;
		}
	}

	if (param->pFUP) {
		ProtoBroadcastAck(param->hContact, ACKTYPE_FILE, iResult, (HANDLE)(param->pFUP));
		if (!pReq->bNeedsRestart || m_bTerminated) 
			delete param->pFUP;
	}
	else if (m_bServerDelivery)
		ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, (HANDLE)(param->iMsgID));

	if (!pReq->bNeedsRestart || m_bTerminated) {
		delete param;
		pReq->pUserInfo = NULL;
	}
}
コード例 #17
0
ファイル: capabilities.cpp プロジェクト: 0xmono/miranda-ng
// Scans a binary buffer for oscar capabilities and adds them to the contact.
// You probably want to call ClearAllContactCapabilities() first.
void CIcqProto::AddCapabilitiesFromBuffer(MCONTACT hContact, BYTE *pBuffer, int nLength)
{
	// Get current capability flags
	DWORD fdwContactCaps = getDword(hContact, DBSETTING_CAPABILITIES, 0);
	// Get capability flags from buffer
	DWORD fdwCapabilities = GetCapabilitiesFromBuffer(pBuffer, nLength);

	if (fdwContactCaps != (fdwContactCaps | fdwCapabilities)) {
#ifdef _DEBUG
		NetLog_CapabilityChange(this, "Added", fdwCapabilities & ~fdwContactCaps);
#endif
		// Add capability flags from buffer
		fdwContactCaps |= fdwCapabilities;

		// And write them back to database
		setDword(hContact, DBSETTING_CAPABILITIES, fdwContactCaps);
	}
}
コード例 #18
0
ファイル: communication.cpp プロジェクト: kxepal/miranda-ng
void MinecraftDynmapProto::SignOnWorker(void*)
{
	SYSTEMTIME t;
	GetLocalTime(&t);
	debugLogA("[%d.%d.%d] Using Omegle Protocol %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING_DOTS);

	ScopedLock s(signon_lock_);

	int old_status = m_iStatus;

	// Load server from database
	ptrA str(db_get_sa(NULL, m_szModuleName, MINECRAFTDYNMAP_KEY_SERVER));
	if (!str || !str[0]) {
		MessageBox(NULL, TranslateT("Set server address to connect."), m_tszUserName, MB_OK);
		SetStatus(ID_STATUS_OFFLINE);
		return;
	}
	m_server = str;

	// Fix format of given server
	if (m_server.substr(0, 7) != "http://" && m_server.substr(0, 8) != "https://")
		m_server = "http://" + m_server;
	if (m_server.substr(m_server.length() - 1, 1) == "/")
		m_server = m_server.substr(0, m_server.length() -1);

	if (doSignOn()) {
		// Signed in, switch to online, create chatroom and start events loop
		m_iStatus = m_iDesiredStatus;
		ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);

		setDword("LogonTS", (DWORD)time(NULL));
		ClearChat();
		OnJoinChat(0, false);

		ResetEvent(events_loop_event_);

		ForkThread(&MinecraftDynmapProto::EventsLoop, this);
	}
	else {
		// Some error
		ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)old_status, m_iStatus);
	}

}
コード例 #19
0
void CYahooProto::ext_got_picture_upload(const char *me, const char *url, unsigned int ts)
{
	int cksum = 0;
	DBVARIANT dbv;

	LOG(("[ext_yahoo_got_picture_upload] url: %s timestamp: %d", url, ts));

	if (!url) {
		LOG(("[ext_yahoo_got_picture_upload] Problem with upload?"));
		return;
	}


	cksum = getDword("TMPAvatarHash", 0);
	if (cksum != 0) {
		LOG(("[ext_yahoo_got_picture_upload] Updating Checksum to: %d", cksum));
		setDword("AvatarHash", cksum);
		delSetting("TMPAvatarHash");

		// This is only meant for message sessions, but we don't got those in miranda yet
		//YAHOO_bcast_picture_checksum(cksum);
		yahoo_send_picture_checksum(m_id, NULL, cksum);

		// need to tell the stupid Yahoo that our icon updated
		//YAHOO_bcast_picture_update(2);
	}
	else
		cksum = getDword("AvatarHash", 0);

	setString("AvatarURL", url);
	//YAHOO_SetDword("AvatarExpires", ts);

	if (!getString("AvatarInv", &dbv)) {
		LOG(("[ext_yahoo_got_picture_upload] Buddy: %s told us this is bad??", dbv.pszVal));

		LOG(("[ext_yahoo_got_picture] Sending url: %s checksum: %d to '%s'!", url, cksum, dbv.pszVal));
		//void yahoo_send_picture_info(int id, const char *me, const char *who, const char *pic_url, int cksum)
		yahoo_send_picture_info(m_id, dbv.pszVal, 2, url, cksum);

		delSetting("AvatarInv");
		db_free(&dbv);
	}
}
コード例 #20
0
ファイル: vk_feed.cpp プロジェクト: truefriend-cz/miranda-ng
void CVkProto::RetrieveUnreadNotifications(time_t tLastNotificationsTime)
{
	debugLogA("CVkProto::RetrieveUnreadNotifications");
	if (!IsOnline())
		return;

	time_t tLastNotificationsReqTime = getDword("LastNotificationsReqTime", time(NULL) - 24 * 60 * 60);
	if (time(NULL) - tLastNotificationsReqTime < 3 * 60)
		return;

	CMString code(FORMAT, _T("return{\"notifications\":API.notifications.get({\"count\": 100, \"start_time\":%d})%s"),
		(LONG)(tLastNotificationsTime + 1),
		m_bNotificationFilterInvites ? _T(",\"groupinvates\":API.groups.getInvites({\"extended\":1})};") : _T("};"));

	Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveUnreadNotifications)
		<< TCHAR_PARAM("code", code)		
		<< VER_API);

	setDword("LastNotificationsReqTime", (DWORD)time(NULL));
}
コード例 #21
0
ファイル: steam_events.cpp プロジェクト: kxepal/miranda-ng
int CSteamProto::OnIdleChanged(WPARAM, LPARAM lParam)
{
	bool idle = (lParam & IDF_ISIDLE) != 0;
	bool privacy = (lParam & IDF_PRIVACY) != 0;

	// Respect user choice about (not) notifying idle to protocols
	if (privacy)
	{
		// Reset it to 0 if there is some time already
		if (m_idleTS)
		{
			m_idleTS = 0;
			delSetting("IdleTS");
		}

		return 0;
	}

	// We don't want to reset idle time when we're already in idle state
	if (idle && m_idleTS > 0)
		return 0;

	if (idle)
	{
		// User started being idle
		MIRANDA_IDLE_INFO mii = { sizeof(mii) };
		CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);

		// Compute time when user really became idle
		m_idleTS = time(0) - mii.idleTime * 60;
		setDword("IdleTS", m_idleTS);
	}
	else
	{
		// User stopped being idle
		m_idleTS = 0;
		delSetting("IdleTS");
	}

	return 0;
}
コード例 #22
0
ファイル: jabber_archive.cpp プロジェクト: martok/miranda-ng
void CJabberProto::OnIqResultGetCollectionList(HXML iqNode, CJabberIqInfo*)
{
	const TCHAR *to = xmlGetAttrValue(iqNode, _T("to"));
	if (to == NULL || mir_tstrcmp( xmlGetAttrValue(iqNode, _T("type")), _T("result")))
		return;

	HXML list = xmlGetChild(iqNode, "list");
	if (!list || mir_tstrcmp( xmlGetAttrValue(list, _T("xmlns")), JABBER_FEAT_ARCHIVE))
		return;

	MCONTACT hContact = NULL;
	time_t tmLast = 0;

	for (int nodeIdx = 1; ; nodeIdx++) {
		HXML itemNode = xmlGetNthChild(list, _T("chat"), nodeIdx);
		if (!itemNode)
			break;

		const TCHAR* start = xmlGetAttrValue(itemNode, _T("start"));
		const TCHAR* with  = xmlGetAttrValue(itemNode, _T("with"));
		if (!start || !with)
			continue;

		if (hContact == NULL) {
			if ((hContact = HContactFromJID(with)) == NULL)
				continue;

			tmLast = getDword(hContact, "LastCollection", 0);
		}

		m_ThreadInfo->send(
			XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetCollection, JABBER_IQ_TYPE_GET))
				<< XCHILDNS( _T("retrieve"), JABBER_FEAT_ARCHIVE) << XATTR(_T("with"), with) << XATTR(_T("start"), start));

		time_t tmThis = str2time(start);
		if ( tmThis > tmLast) {
			tmLast = tmThis;
			setDword(hContact, "LastCollection", tmLast+1);
		}
	}
}
コード例 #23
0
ファイル: connection.cpp プロジェクト: kxepal/miranda-ng
void OmegleProto::SignOn(void*)
{
	SYSTEMTIME t;
	GetLocalTime(&t);
	debugLogA("[%d.%d.%d] Using Omegle Protocol %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING_DOTS);

	ScopedLock s(signon_lock_);

	int old_status = m_iStatus;
	m_iStatus = m_iDesiredStatus;
	ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);

	setDword("LogonTS", (DWORD)time(NULL));
	ClearChat();
	OnJoinChat(0, false);

	if (getByte(OMEGLE_KEY_AUTO_CONNECT, 0))
		NewChat();

	//ToggleStatusMenuItems(true);
}
コード例 #24
0
void CVkProto::GetHistoryDlg(MCONTACT hContact, int iLastMsg)
{
	debugLogA("CVkProto::GetHistoryDlg %d", iLastMsg);
	int lastmsgid = -1;
	switch (m_iSyncHistoryMetod) {
	case syncAuto:
		lastmsgid = getDword(hContact, "lastmsgid", -1);
		if (lastmsgid == -1 || !IsOnline()) {
			setDword(hContact, "lastmsgid", iLastMsg);
			return;
		}
		GetServerHistory(hContact, 0, MAXHISTORYMIDSPERONE, 0, lastmsgid);
		break;
	case sync1Days:
		GetServerHistoryLastNDay(hContact, 1);
		break;
	case sync3Days:
		GetServerHistoryLastNDay(hContact, 3);
		break;
	}
	
}
コード例 #25
0
ファイル: msn_misc.cpp プロジェクト: 0xmono/miranda-ng
void CMsnProto::MSN_GoOffline(void)
{
	if (m_iStatus == ID_STATUS_OFFLINE) return;

	msnLoggedIn = false;

	if (mStatusMsgTS)
		ForkThread(&CMsnProto::msn_storeProfileThread, NULL);

	mir_free(msnPreviousUUX);
	msnPreviousUUX = NULL;
	msnSearchId = NULL;

	if (!Miranda_Terminated())
		MSN_EnableMenuItems(false);

	MSN_FreeGroups();
	MsgQueue_Clear();
	clearCachedMsg();

	if (!Miranda_Terminated()) {
		int msnOldStatus = m_iStatus; m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
		ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)msnOldStatus, ID_STATUS_OFFLINE);
		isIdle = false;

		int count = -1;
		for (;;) {
			MsnContact *msc = Lists_GetNext(count);
			if (msc == NULL) break;

			if (ID_STATUS_OFFLINE != getWord(msc->hContact, "Status", ID_STATUS_OFFLINE)) {
				setWord(msc->hContact, "Status", ID_STATUS_OFFLINE);
				setDword(msc->hContact, "IdleTS", 0);
			}
		}
	}
}
コード例 #26
0
ファイル: vk_pollserver.cpp プロジェクト: kxepal/miranda-ng
void CVkProto::PollUpdates(const JSONNode &jnUpdates)
{
	debugLogA("CVkProto::PollUpdates");
	CMStringA mids;
	int msgid, uid, flags, platform;
	MCONTACT hContact;

	
	for (auto it = jnUpdates.begin(); it != jnUpdates.end(); ++it) {
		const JSONNode &jnChild = (*it).as_array();
		switch (jnChild[json_index_t(0)].as_int()) {
		case VKPOLL_MSG_DELFLAGS:
			if (jnChild.size() < 4)
				break;
			msgid = jnChild[1].as_int();
			flags = jnChild[2].as_int();
			uid = jnChild[3].as_int();
			hContact = FindUser(uid);

			if (hContact != NULL && (flags & VKFLAG_MSGUNREAD) && !CheckMid(m_incIds, msgid)) {
				setDword(hContact, "LastMsgReadTime", time(NULL));
				if (ServiceExists(MS_MESSAGESTATE_UPDATE)) {
					MessageReadData data(time(NULL), MRD_TYPE_READTIME);
					CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data);
				}
				else 
					SetSrmmReadStatus(hContact);
				if (m_bUserForceOnlineOnActivity)
					SetInvisible(hContact);
				if (m_bSyncReadMessageStatusFromServer)
					MarkDialogAsRead(hContact);
			}
			break;

		case VKPOLL_MSG_ADDED: // new message
			msgid = jnChild[1].as_int();

			// skip outgoing messages sent from a client
			flags = jnChild[2].as_int();
			if (flags & VKFLAG_MSGOUTBOX && !(flags & VKFLAG_MSGCHAT) && CheckMid(m_sendIds, msgid))
				break;

			if (!mids.IsEmpty())
				mids.AppendChar(',');
			mids.AppendFormat("%d", msgid);
			break;

		case VKPOLL_READ_ALL_OUT:
			uid = jnChild[1].as_int();
			hContact = FindUser(uid);
			if (hContact != NULL) {
				setDword(hContact, "LastMsgReadTime", time(NULL));
				if (ServiceExists(MS_MESSAGESTATE_UPDATE)) {
					MessageReadData data(time(NULL), MRD_TYPE_READTIME);
					CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data);
				}
				else
					SetSrmmReadStatus(hContact);
				if (m_bUserForceOnlineOnActivity)
					SetInvisible(hContact);
			}
			break;
		case VKPOLL_READ_ALL_IN:
			uid = jnChild[1].as_int();
			hContact = FindUser(uid);
			if (hContact != NULL && m_bSyncReadMessageStatusFromServer)
				MarkDialogAsRead(hContact);
			break;

		case VKPOLL_USR_ONLINE:
			uid = -jnChild[1].as_int();
			if ((hContact = FindUser(uid)) != NULL) {
				setWord(hContact, "Status", ID_STATUS_ONLINE);
				platform = jnChild[2].as_int();
				SetMirVer(hContact, platform);
			}
			break;

		case VKPOLL_USR_OFFLINE:
			uid = -jnChild[1].as_int();
			if ((hContact = FindUser(uid)) != NULL) {
				setWord(hContact, "Status", ID_STATUS_OFFLINE);
				db_unset(hContact, m_szModuleName, "ListeningTo");
				SetMirVer(hContact, -1);
			}
			break;

		case VKPOLL_USR_UTN:
			uid = jnChild[1].as_int();
			hContact = FindUser(uid);
			if (hContact != NULL) {
				ForkThread(&CVkProto::ContactTypingThread, (void *)hContact);
				if (m_bUserForceOnlineOnActivity)
					SetInvisible(hContact);
			}
			break;

		case VKPOLL_CHAT_UTN:
			ForkThread(&CVkProto::ChatContactTypingThread, new CVKChatContactTypingParam(jnChild[2].as_int(), jnChild[1].as_int()));
			break;

		case VKPOLL_CHAT_CHANGED:
			int chat_id = jnChild[1].as_int();
			CVkChatInfo *cc = m_chats.find((CVkChatInfo*)&chat_id);
			if (cc)
				RetrieveChatInfo(cc);
			break;
		}
	}

	RetrieveMessagesByIds(mids);
}
コード例 #27
0
void CSteamProto::PollingThread(void*)
{
	debugLog(_T("CSteamProto::PollingThread: entering"));

	ptrA token(getStringA("TokenSecret"));
	ptrA umqId(getStringA("UMQID"));
	UINT32 messageId = getDword("MessageID", 0);

	//PollApi::PollResult pollResult;
	int errors = 0;
	bool breaked = false;
	while (!isTerminated && !breaked && errors < POLLING_ERRORS_LIMIT)
	{
		PollRequest *request = new PollRequest(token, umqId, messageId, IdleSeconds());
		//request->nlc = m_pollingConnection;
		HttpResponse *response = request->Send(m_hNetlibUser);
		delete request;

		if (response == NULL || response->resultCode != HTTP_CODE_OK)
		{
			if (response != NULL)
				delete response;

			errors++;
			continue;
		}
		else
			errors = 0;

		JSONROOT root(response->pData);
		JSONNode *node = json_get(root, "error");
		ptrT error(json_as_string(node));

		if (!lstrcmpi(error, _T("OK")))
		{
			node = json_get(root, "messagelast");
			messageId = json_as_int(node);

			node = json_get(root, "messages");
			JSONNode *nroot = json_as_array(node);

			if (nroot != NULL)
			{
				ParsePollData(nroot);
				json_delete(nroot);
			}

			m_pollingConnection = response->nlc;
		}
		else if (!lstrcmpi(error, _T("Timeout")))
		{
			continue;
		}
		/*else if (!lstrcmpi(error, _T("Not Logged On"))) // 'else' below will handle this error, we don't need this particular check right now
		{
			if (!IsOnline())
			{
				// need to relogin
				debugLog(_T("CSteamProto::PollingThread: not logged on"));

				SetStatus(ID_STATUS_OFFLINE);
			}

			breaked = true;
		}*/
		else
		{
			// something wrong
			debugLog(_T("CSteamProto::PollingThread: %s (%d)"), error, response->resultCode);

			// token has expired
			if (response->resultCode == HTTP_CODE_UNAUTHORIZED)
				delSetting("TokenSecret");

			// too low timeout?
			node = json_get(root, "sectimeout");
			int timeout = json_as_int(node);
			if (timeout < STEAM_API_TIMEOUT)
				debugLog(_T("CSteamProto::PollingThread: Timeout is too low (%d)"), timeout);

			breaked = true;
		}

		delete response;
	}

	setDword("MessageID", messageId);

	m_hPollingThread = NULL;
	debugLog(_T("CSteamProto::PollingThread: leaving"));

	if (!isTerminated)
	{
		debugLog(_T("CSteamProto::PollingThread: unexpected termination; switching protocol to offline"));
		SetStatus(ID_STATUS_OFFLINE);
	}
}
コード例 #28
0
ファイル: fam_03buddy.cpp プロジェクト: martok/miranda-ng
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);
	}
}
コード例 #29
0
ファイル: fam_03buddy.cpp プロジェクト: martok/miranda-ng
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);
}
コード例 #30
0
ファイル: fam_03buddy.cpp プロジェクト: martok/miranda-ng
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);
		}
	}
}