summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2024-12-17 23:24:44 +0300
committerGeorge Hazan <george.hazan@gmail.com>2024-12-17 23:24:44 +0300
commit4c3d77032316bc8814cddc00d020ba00d4533999 (patch)
tree1862e30966a69bf94a7288b95baed5b04a040d80 /protocols
parent4b5082aef3817173bc254755c0ec352da064a440 (diff)
Steam:
- contact statuses are back; - contact info is back too; - Miranda's account status is passed to the server; - some old code removed;
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Steam/src/main.cpp2
-rw-r--r--protocols/Steam/src/protobuf-c/protobuf-c-text.cpp9
-rw-r--r--protocols/Steam/src/stdafx.h6
-rw-r--r--protocols/Steam/src/steam_avatars.cpp17
-rw-r--r--protocols/Steam/src/steam_contacts.cpp295
-rw-r--r--protocols/Steam/src/steam_login.cpp4
-rw-r--r--protocols/Steam/src/steam_messages.cpp67
-rw-r--r--protocols/Steam/src/steam_proto.cpp10
-rw-r--r--protocols/Steam/src/steam_proto.h23
-rw-r--r--protocols/Steam/src/steam_server.cpp68
-rw-r--r--protocols/Steam/src/steam_utils.cpp14
-rw-r--r--protocols/Steam/src/steam_utils.h18
-rw-r--r--protocols/Steam/src/steam_ws.cpp2
13 files changed, 264 insertions, 271 deletions
diff --git a/protocols/Steam/src/main.cpp b/protocols/Steam/src/main.cpp
index 9e69376684..fcb3b1b9d9 100644
--- a/protocols/Steam/src/main.cpp
+++ b/protocols/Steam/src/main.cpp
@@ -138,6 +138,7 @@ void CMPlugin::InitSteamServices()
messageHandlers[EMsg::ClientLoggedOff] = ServiceResponseHandler(&CSteamProto::OnClientLogoff);
messageHandlers[EMsg::ClientLogOnResponse] = ServiceResponseHandler(&CSteamProto::OnClientLogon);
messageHandlers[EMsg::ClientFriendsList] = ServiceResponseHandler(&CSteamProto::OnGotFriendList);
+ messageHandlers[EMsg::ClientPersonaState] = ServiceResponseHandler(&CSteamProto::OnGotFriendInfo);
// services from steammessages_auth.steamclient.proto
services["Authentication"] = &authentication__descriptor;
@@ -163,6 +164,7 @@ void CMPlugin::InitSteamServices()
serviceHandlers[FriendSendMessage] = ServiceResponseHandler(&CSteamProto::OnMessageSent);
serviceHandlers[FriendGetActiveSessions] = ServiceResponseHandler(&CSteamProto::OnGotConversations);
+ serviceHandlers[FriendGetIncomingMessage] = ServiceResponseHandler(&CSteamProto::OnGotIncomingMessage);
serviceHandlers[NotificationReceived] = ServiceResponseHandler(&CSteamProto::OnGotNotification);
}
diff --git a/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp b/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp
index 68e54f143e..44fa0b7232 100644
--- a/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp
+++ b/protocols/Steam/src/protobuf-c/protobuf-c-text.cpp
@@ -60,7 +60,7 @@ esc_str(const char *src, size_t len)
}
}
- char *dst = (char *)malloc((escapes * 4) + ((len - escapes) * 2) + 1);
+ char *dst = (char *)malloc((escapes * 2) + ((len - escapes) * 2) + 1);
if (!dst) {
return NULL;
}
@@ -95,12 +95,7 @@ esc_str(const char *src, size_t len)
/* Escape with octal if !isprint. */
default:
- if (!isprint(src[i])) {
- dst_len += sprintf(dst + dst_len, "\\%03o", src[i]);
- }
- else {
- dst[dst_len++] = src[i];
- }
+ dst[dst_len++] = src[i];
break;
}
}
diff --git a/protocols/Steam/src/stdafx.h b/protocols/Steam/src/stdafx.h
index 87d0bbeace..ff762f0d39 100644
--- a/protocols/Steam/src/stdafx.h
+++ b/protocols/Steam/src/stdafx.h
@@ -68,15 +68,11 @@ extern HANDLE hExtraXStatus;
#define STEAM_DB_GETEVENTTEXT_CHATSTATES "/GetEventText2000"
#define STEAM_DB_EVENT_CHATSTATES_GONE 1
-#define now() time(0)
-
-int64_t getRandomInt();
-CMStringA protobuf_c_text_to_string(const ProtobufCMessage &msg);
-
#include "steam_dialogs.h"
#include "api/enums.h"
#include "steam_proto.h"
+#include "steam_utils.h"
#include "api/app_info.h"
#include "api/avatar.h"
diff --git a/protocols/Steam/src/steam_avatars.cpp b/protocols/Steam/src/steam_avatars.cpp
index 2a7de109ca..022ec914c5 100644
--- a/protocols/Steam/src/steam_avatars.cpp
+++ b/protocols/Steam/src/steam_avatars.cpp
@@ -23,17 +23,18 @@ bool CSteamProto::GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &pai)
return true;
}
-void CSteamProto::CheckAvatarChange(MCONTACT hContact, std::string avatarUrl)
+void CSteamProto::CheckAvatarChange(MCONTACT hContact, const char *avatarHash)
{
- if (avatarUrl.empty())
- return;
-
// Check for avatar change
- ptrA oldAvatarUrl(getStringA(hContact, "AvatarUrl"));
- bool update_required = (!oldAvatarUrl || avatarUrl.compare(oldAvatarUrl));
+ ptrA oldAvatarHash(getStringA(hContact, "AvatarHash"));
+ bool update_required = mir_strcmp(oldAvatarHash, avatarHash) != 0;
- if (update_required)
- setString(hContact, "AvatarUrl", avatarUrl.c_str());
+ if (update_required) {
+ if (avatarHash)
+ setString(hContact, "AvatarHash", avatarHash);
+ else
+ delSetting(hContact, "AvatarHash");
+ }
if (!hContact) {
PROTO_AVATAR_INFORMATION ai = { 0 };
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index dddca89631..9291629968 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -81,166 +81,134 @@ MCONTACT CSteamProto::GetContact(int64_t steamId)
return NULL;
}
-void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
+void CSteamProto::OnGotFriendInfo(const CMsgClientPersonaState &reply, const CMsgProtoBufHeader &)
{
- // set common data
- CMStringW nick = data["personaname"].as_mstring();
- setWString(hContact, "Nick", nick);
-
- json_string homepage = data["profileurl"].as_string();
- setString(hContact, "Homepage", homepage.c_str());
-
- json_string primaryClanId = data["primaryclanid"].as_string();
- setString(hContact, "PrimaryClanID", primaryClanId.c_str());
-
- // set name
- const JSONNode &node = data["realname"];
- if (node) {
- CMStringW realName = node.as_mstring();
- if (!realName.IsEmpty()) {
- int pos = realName.Find(L' ', 1);
- if (pos != -1) {
- setWString(hContact, "FirstName", realName.Mid(0, pos));
- setWString(hContact, "LastName", realName.Mid(pos + 1));
- }
- else {
- setWString(hContact, "FirstName", realName);
- delSetting(hContact, "LastName");
- }
- }
- }
- else {
- delSetting(hContact, "FirstName");
- delSetting(hContact, "LastName");
- }
-
- // avatar
- bool biggerAvatars = getBool("UseBigAvatars", false);
- json_string avatarUrl = data[biggerAvatars ? "avatarfull" : "avatarmedium"].as_string();
- CheckAvatarChange(hContact, avatarUrl);
-
- // set country
- json_string countryCode = data["loccountrycode"].as_string();
- if (!countryCode.empty()) {
- char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)countryCode.c_str(), 0);
- setString(hContact, "Country", country);
- }
- else delSetting(hContact, "Country");
-
- // state code
- // note: it seems that steam sends "incorrect" state code
- //node = data["locstatecode"];
- //if (!node.isnull())
- //{
- // json_string stateCode = node.as_string();
- // setString(hContact, "State", stateCode.c_str());
- //}
- //else
- //{
- // delSetting(hContact, "State");
- delSetting(hContact, "StateCode");
- //}
-
- // city id
- // note: steam no longer sends state city id
- //node = data["loccityid"];
- //if (!node.isnull())
- // setDword(hContact, "CityID", node.as_int());
- //else
- delSetting(hContact, "CityID");
-
- // account created
- setDword(hContact, "MemberTS", data["timecreated"].as_int());
-
- // last logout time
- setDword(hContact, "LogoffTS", data["lastlogoff"].as_int());
-
- if (!IsOnline())
- return;
-
- // status
- // note: this here is often wrong info, probably depending on publicity of steam profile
- // but sometimes polling does not get status at all
- uint16_t oldStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE);
- // so, set status only if contact is offline
- if (oldStatus == ID_STATUS_OFFLINE) {
- uint16_t status = SteamToMirandaStatus((PersonaState)data["personastate"].as_int());
- SetContactStatus(hContact, status);
- }
+ for (int i = 0; i < reply.n_friends; i++) {
+ auto *F = reply.friends[i];
- // client
- const JSONNode &nFlags = data["personastateflags"];
- PersonaStateFlag stateflags = (nFlags) ? (PersonaStateFlag)nFlags.as_int() : (PersonaStateFlag)(-1);
+ auto hContact = GetContact(F->friendid);
+ if (!hContact && F->friendid != m_iSteamId)
+ hContact = AddContact(F->friendid);
- if (stateflags == PersonaStateFlag::None) {
- // nothing special, either standard client or in different status (only online, I want to play, I want to trade statuses support this flags)
- uint16_t status = getWord(hContact, "Status", ID_STATUS_OFFLINE);
- if (status == ID_STATUS_ONLINE || status == ID_STATUS_FREECHAT)
- setWString(hContact, "MirVer", L"Steam");
- }
- else if (contains_flag(stateflags, PersonaStateFlag::InJoinableGame)) {
- // game
- setWString(hContact, "MirVer", L"Steam (in game)");
- }
- else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeWeb)) {
- // on website
- setWString(hContact, "MirVer", L"Steam (website)");
- }
- else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeMobile)) {
- // on mobile
- setWString(hContact, "MirVer", L"Steam (mobile)");
- }
- else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeBigPicture)) {
- // on big picture
- setWString(hContact, "MirVer", L"Steam (Big Picture)");
- }
- else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeVR)) {
- // on VR
- setWString(hContact, "MirVer", L"Steam (VR)");
- }
- else {
- // none/unknown (e.g. when contact is offline)
- delSetting(hContact, "MirVer");
- }
+ // set name
+ if (F->player_name) {
+ CMStringW realName(Utf2T(F->player_name));
+ if (!realName.IsEmpty()) {
+ int pos = realName.Find(L' ', 1);
+ if (pos != -1) {
+ setWString(hContact, "FirstName", realName.Mid(0, pos));
+ setWString(hContact, "LastName", realName.Mid(pos + 1));
+ }
+ else {
+ setWString(hContact, "FirstName", realName);
+ delSetting(hContact, "LastName");
+ }
+ }
+ }
+ else {
+ delSetting(hContact, "FirstName");
+ delSetting(hContact, "LastName");
+ }
- // playing game
- json_string appId = data["gameid"].as_string();
- CMStringW gameInfo = data["gameextrainfo"].as_mstring();
- if (!appId.empty() || !gameInfo.IsEmpty()) {
- uint32_t gameId = atol(appId.c_str());
- json_string serverIP = data["gameserverip"].as_string();
- json_string serverID = data["gameserversteamid"].as_string();
+ // avatar
+ if (F->avatar_hash.len != 0) {
+ CMStringA szHash;
+ szHash.Truncate(int(F->avatar_hash.len) * 2 + 1);
+ bin2hex(F->avatar_hash.data, F->avatar_hash.len, szHash.GetBuffer());
+ CheckAvatarChange(hContact, szHash);
+ }
+ else CheckAvatarChange(hContact, 0);
+
+ // last logout time
+ if (F->has_last_logoff)
+ setDword(hContact, "LogoffTS", F->last_logoff);
+ if (F->has_last_logon)
+ setDword(hContact, "LogonTS", F->last_logon);
+
+ // status
+ // note: this here is often wrong info, probably depending on publicity of steam profile
+ // but sometimes polling does not get status at all
+ int oldStatus = Contact::GetStatus(hContact);
+ // so, set status only if contact is offline
+ if (oldStatus == ID_STATUS_OFFLINE) {
+ uint16_t status = SteamToMirandaStatus(PersonaState(F->persona_state));
+ SetContactStatus(hContact, status);
+ }
- setDword(hContact, "GameID", gameId);
- setString(hContact, "ServerIP", serverIP.c_str());
- setString(hContact, "ServerID", serverID.c_str());
+ // client
+ PersonaStateFlag stateflags = (F->has_persona_state_flags) ? (PersonaStateFlag)(F->persona_state_flags) : (PersonaStateFlag)(-1);
- CMStringW message(gameInfo);
- if (gameId && message.IsEmpty())
- SendRequest(new GetAppInfoRequest(m_szAccessToken, appId.c_str()), &CSteamProto::OnGotAppInfo, (void*)hContact);
+ if (stateflags == PersonaStateFlag::None) {
+ // nothing special, either standard client or in different status (only online, I want to play, I want to trade statuses support this flags)
+ uint16_t status = getWord(hContact, "Status", ID_STATUS_OFFLINE);
+ if (status == ID_STATUS_ONLINE || status == ID_STATUS_FREECHAT)
+ setWString(hContact, "MirVer", L"Steam");
+ }
+ else if (contains_flag(stateflags, PersonaStateFlag::InJoinableGame)) {
+ // game
+ setWString(hContact, "MirVer", L"Steam (in game)");
+ }
+ else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeWeb)) {
+ // on website
+ setWString(hContact, "MirVer", L"Steam (website)");
+ }
+ else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeMobile)) {
+ // on mobile
+ setWString(hContact, "MirVer", L"Steam (mobile)");
+ }
+ else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeBigPicture)) {
+ // on big picture
+ setWString(hContact, "MirVer", L"Steam (Big Picture)");
+ }
+ else if (contains_flag(stateflags, PersonaStateFlag::ClientTypeVR)) {
+ // on VR
+ setWString(hContact, "MirVer", L"Steam (VR)");
+ }
else {
- if (!gameId)
- message.Append(TranslateT(" (Non-Steam)"));
- if (!serverIP.empty())
- message.AppendFormat(TranslateT(" on server %S"), serverIP.c_str());
+ // none/unknown (e.g. when contact is offline)
+ delSetting(hContact, "MirVer");
}
- setDword(hContact, "XStatusId", gameId);
- setWString(hContact, "XStatusName", TranslateT("Playing"));
- setWString(hContact, "XStatusMsg", message);
+ // playing game
+ /*
+ json_string appId = data["gameid"].as_string();
+ CMStringW gameInfo = data["gameextrainfo"].as_mstring();
+ if (!appId.empty() || !gameInfo.IsEmpty()) {
+ uint32_t gameId = atol(appId.c_str());
+ json_string serverIP = data["gameserverip"].as_string();
+ json_string serverID = data["gameserversteamid"].as_string();
+
+ setDword(hContact, "GameID", gameId);
+ setString(hContact, "ServerIP", serverIP.c_str());
+ setString(hContact, "ServerID", serverID.c_str());
+
+ CMStringW message(gameInfo);
+ if (gameId && message.IsEmpty())
+ SendRequest(new GetAppInfoRequest(m_szAccessToken, appId.c_str()), &CSteamProto::OnGotAppInfo, (void *)hContact);
+ else {
+ if (!gameId)
+ message.Append(TranslateT(" (Non-Steam)"));
+ if (!serverIP.empty())
+ message.AppendFormat(TranslateT(" on server %S"), serverIP.c_str());
+ }
- SetContactExtraIcon(hContact, gameId);
- }
- else {
- delSetting(hContact, "GameID");
- delSetting(hContact, "ServerIP");
- delSetting(hContact, "ServerID");
+ setDword(hContact, "XStatusId", gameId);
+ setWString(hContact, "XStatusName", TranslateT("Playing"));
+ setWString(hContact, "XStatusMsg", message);
- delSetting(hContact, "XStatusId");
- delSetting(hContact, "XStatusName");
- delSetting(hContact, "XStatusMsg");
+ SetContactExtraIcon(hContact, gameId);
+ }
+ else {*/
+ delSetting(hContact, "GameID");
+ delSetting(hContact, "ServerIP");
+ delSetting(hContact, "ServerID");
- SetContactExtraIcon(hContact, NULL);
+ delSetting(hContact, "XStatusId");
+ delSetting(hContact, "XStatusName");
+ delSetting(hContact, "XStatusMsg");
+
+ SetContactExtraIcon(hContact, NULL);
+ // }
}
}
@@ -300,8 +268,11 @@ void CSteamProto::ContactIsAskingAuth(MCONTACT hContact)
return;
// create auth request event
- ptrA steamId(getUStringA(hContact, DBKEY_STEAM_ID));
- SendRequest(new GetUserSummariesRequest(m_szAccessToken, steamId), &CSteamProto::OnGotUserSummaries);
+ uint64_t id(GetId(hContact, DBKEY_STEAM_ID));
+ SendUserInfoRequest(id, true);
+
+ char steamId[100];
+ _i64toa(id, steamId, 10);
ptrA nickName(getUStringA(hContact, "Nick"));
if (nickName == nullptr)
@@ -505,16 +476,6 @@ void CSteamProto::OnGotBlockList(const JSONNode &root, void *)
}
}
-void CSteamProto::OnGotUserSummaries(const JSONNode &root, void *)
-{
- for (auto &player : root["players"]) {
- json_string steamId = player["steamid"].as_string();
- CMStringW nick = player["personaname"].as_mstring();
- MCONTACT hContact = !IsMe(steamId.c_str()) ? AddContact(steamId.c_str(), nick) : 0;
- UpdateContactDetails(hContact, player);
- }
-}
-
void CSteamProto::OnGotAvatar(const MHttpResponse &response, void *arg)
{
PROTO_AVATAR_INFORMATION ai = { 0 };
@@ -646,20 +607,6 @@ void CSteamProto::OnFriendRemoved(const MHttpResponse &response, void *arg)
ContactIsRemoved(hContact);
}
-void CSteamProto::OnAuthRequested(const JSONNode &root, void *)
-{
- if (root.isnull())
- return;
-
- for (auto &player : root["players"]) {
- json_string steamId = player["steamid"].as_string();
- CMStringW nick = player["personaname"].as_mstring();
- MCONTACT hContact = AddContact(steamId.c_str(), nick);
- UpdateContactDetails(hContact, player);
- ContactIsAskingAuth(hContact);
- }
-}
-
void CSteamProto::OnPendingApproved(const JSONNode &root, void *arg)
{
ptrA steamId((char *)arg);
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp
index e83853c7e5..702e47839a 100644
--- a/protocols/Steam/src/steam_login.cpp
+++ b/protocols/Steam/src/steam_login.cpp
@@ -17,7 +17,7 @@ bool CSteamProto::IsOnline()
bool CSteamProto::IsMe(const char *steamId)
{
- return m_iSteamId == _atoi64(steamId);
+ return m_iSteamId == (uint64_t)_atoi64(steamId);
}
void CSteamProto::Logout()
@@ -265,6 +265,8 @@ void CSteamProto::OnClientLogon(const CMsgClientLogonResponse &reply, const CMsg
// go to online now
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus);
+
+ SendPersonaStatus(m_iStatus);
}
void CSteamProto::OnClientLogoff(const CMsgClientLoggedOff &reply, const CMsgProtoBufHeader&)
diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp
index 17da66fbb7..25ccc07800 100644
--- a/protocols/Steam/src/steam_messages.cpp
+++ b/protocols/Steam/src/steam_messages.cpp
@@ -1,5 +1,72 @@
#include "stdafx.h"
+void CSteamProto::SendFriendMessage(uint32_t msgId, int64_t steamId, const char *pszMessage)
+{
+ CMStringA szId(FORMAT, "%d", msgId);
+
+ CFriendMessagesSendMessageRequest request;
+ request.chat_entry_type = (int)EChatEntryType::ChatMsg; request.has_chat_entry_type = true;
+ request.client_message_id = szId.GetBuffer();
+ request.contains_bbcode = request.has_contains_bbcode = true;
+ request.steamid = steamId; request.has_steamid = true;
+ request.message = (char *)pszMessage;
+
+ auto iSourceId = WSSendService(FriendSendMessage, request);
+ mir_cslock lck(m_csOwnMessages);
+ if (COwnMessage *pOwn = m_arOwnMessages.find((COwnMessage *)&msgId))
+ pOwn->iSourceId = iSourceId;
+}
+
+void CSteamProto::OnMessageSent(const CFriendMessagesSendMessageResponse &reply, const CMsgProtoBufHeader &hdr)
+{
+ COwnMessage tmp(0, 0);
+ {
+ mir_cslock lck(m_csOwnMessages);
+ for (auto &it : m_arOwnMessages)
+ if (it->iSourceId == hdr.jobid_target) {
+ tmp = *it;
+ m_arOwnMessages.remove(m_arOwnMessages.indexOf(&it));
+ break;
+ }
+ }
+
+ if (!tmp.hContact)
+ return;
+
+ if (hdr.failed()) {
+ CMStringW wszMessage(FORMAT, TranslateT("Message sending has failed with error %d"), hdr.eresult);
+ ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)tmp.iMessageId, (LPARAM)wszMessage.c_str());
+ }
+ else {
+ uint32_t timestamp = (reply.has_server_timestamp) ? reply.server_timestamp : 0;
+ if (timestamp > getDword(tmp.hContact, DB_KEY_LASTMSGTS))
+ setDword(tmp.hContact, DB_KEY_LASTMSGTS, timestamp);
+
+ tmp.timestamp = timestamp;
+ ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tmp.iMessageId, 0);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CSteamProto::OnGotIncomingMessage(const CFriendMessagesIncomingMessageNotification &reply, const CMsgProtoBufHeader &)
+{
+ MCONTACT hContact = GetContact(AccountIdToSteamId(reply.steamid_friend));
+ if (!hContact) {
+ debugLogA("message from unknown account %lld ignored", reply.steamid_friend);
+ return;
+ }
+
+ DB::EventInfo dbei;
+ dbei.flags = DBEF_UTF;
+ dbei.cbBlob = (int)mir_strlen(reply.message);
+ dbei.pBlob = reply.message;
+ dbei.timestamp = reply.has_rtime32_server_timestamp ? reply.rtime32_server_timestamp : time(0);
+ ProtoChainRecvMsg(hContact, dbei);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
int CSteamProto::UserIsTyping(MCONTACT hContact, int type)
{
// NOTE: Steam doesn't support sending "user stopped typing" so we're sending only positive info
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index 00f9579cdb..a6bef00d29 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -86,12 +86,10 @@ CSteamProto::~CSteamProto()
MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr)
{
- MCONTACT hContact = AddContact(_wtoi64(psr->id.w), psr->nick.w, true);
+ uint64_t id = _wtoi64(psr->id.w);
+ MCONTACT hContact = AddContact(id, psr->nick.w, true);
- if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) {
- STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT *)psr;
- UpdateContactDetails(hContact, *ssr->data);
- }
+ SendUserInfoRequest(id, true);
return hContact;
}
@@ -280,6 +278,8 @@ int CSteamProto::SetStatus(int new_status)
else if (IsOnline()) {
m_iStatus = new_status;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+
+ SendPersonaStatus(m_iStatus);
}
return 0;
}
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index 2d7f1c4b5b..cbf7d6eaba 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -24,6 +24,7 @@
#define FriendSendMessage "FriendMessages.SendMessage#1"
#define FriendGetActiveSessions "FriendMessages.GetActiveMessageSessions#1"
+#define FriendGetIncomingMessage "FriendMessagesClient.IncomingMessage#1"
#define NotificationReceived "SteamNotificationClient.NotificationsReceived#1"
@@ -115,7 +116,7 @@ class CSteamProto : public PROTO<CSteamProto>
ptrW m_password;
bool m_bTerminated;
time_t m_idleTS;
- int64_t m_iSteamId, m_iClientId, m_iSessionId;
+ uint64_t m_iSteamId, m_iClientId, m_iSessionId;
MBinBuffer m_requestId;
int64_t GetId(const char *pszSetting);
@@ -152,7 +153,9 @@ class CSteamProto : public PROTO<CSteamProto>
void SendHeartBeat();
void SendLogout();
+ void SendPersonaStatus(int iStatus);
void SendPollRequest();
+ void SendUserInfoRequest(uint64_t id, bool bRetrieveState);
void SendUserInfoRequest(const std::vector<uint64_t> &ids, bool bRetrieveState);
// login
@@ -180,7 +183,7 @@ class CSteamProto : public PROTO<CSteamProto>
// avatars
wchar_t *GetAvatarFilePath(MCONTACT hContact);
bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATION &pai);
- void CheckAvatarChange(MCONTACT hContact, std::string avatarUrl);
+ void CheckAvatarChange(MCONTACT hContact, const char *avatarHash);
INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
@@ -192,7 +195,6 @@ class CSteamProto : public PROTO<CSteamProto>
MCONTACT GetContactFromAuthEvent(MEVENT hEvent);
- void UpdateContactDetails(MCONTACT hContact, const JSONNode &data);
void UpdateContactRelationship(MCONTACT hContact, FriendRelationship);
void OnGotAppInfo(const JSONNode &root, void *arg);
@@ -203,6 +205,7 @@ class CSteamProto : public PROTO<CSteamProto>
void ContactIsAskingAuth(MCONTACT hContact);
void OnGotFriendList(const CMsgClientFriendsList &reply, const CMsgProtoBufHeader &hdr);
+ void OnGotFriendInfo(const CMsgClientPersonaState &reply, const CMsgProtoBufHeader &hdr);
MCONTACT GetContact(const char *steamId);
MCONTACT AddContact(const char *steamId, const wchar_t *nick = nullptr, bool isTemporary = false);
@@ -211,7 +214,6 @@ class CSteamProto : public PROTO<CSteamProto>
MCONTACT AddContact(int64_t steamId, const wchar_t *nick = nullptr, bool isTemporary = false);
void OnGotBlockList(const JSONNode &root, void *);
- void OnGotUserSummaries(const JSONNode &root, void *);
void OnGotAvatar(const MHttpResponse &response, void *arg);
void OnFriendAdded(const MHttpResponse &response, void *arg);
@@ -219,8 +221,6 @@ class CSteamProto : public PROTO<CSteamProto>
void OnFriendUnblocked(const MHttpResponse &response, void *arg);
void OnFriendRemoved(const MHttpResponse &response, void *arg);
- void OnAuthRequested(const JSONNode &root, void *arg);
-
void OnPendingApproved(const JSONNode &root, void *arg);
void OnPendingIgnoreded(const JSONNode &root, void *arg);
@@ -257,6 +257,7 @@ class CSteamProto : public PROTO<CSteamProto>
OBJLIST<COwnMessage> m_arOwnMessages;
void SendFriendMessage(uint32_t msgId, int64_t steamId, const char *pszMessage);
+ void OnGotIncomingMessage(const CFriendMessagesIncomingMessageNotification &reply, const CMsgProtoBufHeader &hdr);
void OnMessageSent(const CFriendMessagesSendMessageResponse &reply, const CMsgProtoBufHeader &hdr);
int __cdecl OnPreCreateMessage(WPARAM, LPARAM lParam);
@@ -275,13 +276,6 @@ class CSteamProto : public PROTO<CSteamProto>
int __cdecl OnIdleChanged(WPARAM, LPARAM);
int __cdecl OnOptionsInit(WPARAM wParam, LPARAM lParam);
- // utils
- static uint16_t SteamToMirandaStatus(PersonaState state);
- static PersonaState MirandaToSteamState(int status);
-
- static void ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
- static void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
-
INT_PTR __cdecl OnGetEventTextChatStates(WPARAM wParam, LPARAM lParam);
// helpers
@@ -372,7 +366,4 @@ struct CMPlugin : public ACCPROTOPLUGIN<CSteamProto>
int OnReloadIcons(WPARAM wParam, LPARAM lParam);
void SetContactExtraIcon(MCONTACT hContact, int status);
-MBinBuffer RsaEncrypt(const char *pszModulus, const char *exponent, const char *data);
-MBinBuffer createMachineID(const char *accName);
-
#endif //_STEAM_PROTO_H_
diff --git a/protocols/Steam/src/steam_server.cpp b/protocols/Steam/src/steam_server.cpp
index f7330dbc49..061c2ec6c2 100644
--- a/protocols/Steam/src/steam_server.cpp
+++ b/protocols/Steam/src/steam_server.cpp
@@ -17,55 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
-void CSteamProto::SendFriendMessage(uint32_t msgId, int64_t steamId, const char *pszMessage)
-{
- CMStringA szId(FORMAT, "%d", msgId);
-
- CFriendMessagesSendMessageRequest request;
- request.chat_entry_type = (int)EChatEntryType::ChatMsg; request.has_chat_entry_type = true;
- request.client_message_id = szId.GetBuffer();
- request.contains_bbcode = request.has_contains_bbcode = true;
- request.steamid = steamId; request.has_steamid = true;
- request.message = (char *)pszMessage;
-
- auto iSourceId = WSSendService(FriendSendMessage, request);
- mir_cslock lck(m_csOwnMessages);
- if (COwnMessage *pOwn = m_arOwnMessages.find((COwnMessage *)&msgId))
- pOwn->iSourceId = iSourceId;
-}
-
-void CSteamProto::OnMessageSent(const CFriendMessagesSendMessageResponse &reply, const CMsgProtoBufHeader &hdr)
-{
- COwnMessage tmp(0, 0);
- {
- mir_cslock lck(m_csOwnMessages);
- for (auto &it : m_arOwnMessages)
- if (it->iSourceId == hdr.jobid_target) {
- tmp = *it;
- m_arOwnMessages.remove(m_arOwnMessages.indexOf(&it));
- break;
- }
- }
-
- if (!tmp.hContact)
- return;
-
- if (hdr.failed()) {
- CMStringW wszMessage(FORMAT, TranslateT("Message sending has failed with error %d"), hdr.eresult);
- ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)tmp.iMessageId, (LPARAM)wszMessage.c_str());
- }
- else {
- uint32_t timestamp = (reply.has_server_timestamp) ? reply.server_timestamp : 0;
- if (timestamp > getDword(tmp.hContact, DB_KEY_LASTMSGTS))
- setDword(tmp.hContact, DB_KEY_LASTMSGTS, timestamp);
-
- tmp.timestamp = timestamp;
- ProtoBroadcastAck(tmp.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)tmp.iMessageId, 0);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
void CSteamProto::OnGotNotification(const CSteamNotificationNotificationsReceivedNotification &reply, const CMsgProtoBufHeader &hdr)
{
if (hdr.eresult != 1)
@@ -81,15 +32,32 @@ void CSteamProto::OnGotNotification(const CSteamNotificationNotificationsReceive
/////////////////////////////////////////////////////////////////////////////////////////
+void CSteamProto::SendPersonaStatus(int status)
+{
+ CMsgClientChangeStatus request;
+ request.persona_state = (int)MirandaToSteamState(status); request.has_persona_state = true;
+ WSSend(EMsg::ClientChangeStatus, request);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CSteamProto::SendFriendActiveSessions()
{
CFriendsMessagesGetActiveMessageSessionsRequest request;
- request.has_only_sessions_with_messages = request.only_sessions_with_messages = true;
+ request.has_lastmessage_since = true;
+ request.has_only_sessions_with_messages = false; request.only_sessions_with_messages = true;
WSSendService(FriendGetActiveSessions, request);
}
/////////////////////////////////////////////////////////////////////////////////////////
+void CSteamProto::SendUserInfoRequest(uint64_t id, bool bRetrieveState)
+{
+ std::vector<uint64_t> ids;
+ ids.push_back(id & 0xFFFFFFFFll);
+ SendUserInfoRequest(ids, bRetrieveState);
+}
+
void CSteamProto::SendUserInfoRequest(const std::vector<uint64_t> &ids, bool bRetrieveState)
{
CMsgClientRequestFriendData request;
diff --git a/protocols/Steam/src/steam_utils.cpp b/protocols/Steam/src/steam_utils.cpp
index ebc3c2b6f8..912f84318f 100644
--- a/protocols/Steam/src/steam_utils.cpp
+++ b/protocols/Steam/src/steam_utils.cpp
@@ -75,8 +75,9 @@ void CSteamProto::SetId(const char *pszSetting, int64_t id)
}
/////////////////////////////////////////////////////////////////////////////////////////
+// Statuses
-uint16_t CSteamProto::SteamToMirandaStatus(PersonaState state)
+int SteamToMirandaStatus(PersonaState state)
{
switch (state) {
case PersonaState::Offline:
@@ -99,7 +100,7 @@ uint16_t CSteamProto::SteamToMirandaStatus(PersonaState state)
}
}
-PersonaState CSteamProto::MirandaToSteamState(int status)
+PersonaState MirandaToSteamState(int status)
{
switch (status) {
case ID_STATUS_OFFLINE:
@@ -121,7 +122,10 @@ PersonaState CSteamProto::MirandaToSteamState(int status)
}
}
-void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact)
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popups
+
+void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact)
{
if (Miranda_IsTerminated())
return;
@@ -140,11 +144,13 @@ void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *messag
MessageBox(nullptr, message, caption, MB_OK | flags);
}
-void CSteamProto::ShowNotification(const wchar_t *message, int flags, MCONTACT hContact)
+void ShowNotification(const wchar_t *message, int flags, MCONTACT hContact)
{
ShowNotification(_A2W(MODULE), message, flags, hContact);
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
INT_PTR CSteamProto::OnGetEventTextChatStates(WPARAM pEvent, LPARAM datatype)
{
// Retrieves a chat state description from an event
diff --git a/protocols/Steam/src/steam_utils.h b/protocols/Steam/src/steam_utils.h
new file mode 100644
index 0000000000..40cdd07088
--- /dev/null
+++ b/protocols/Steam/src/steam_utils.h
@@ -0,0 +1,18 @@
+#ifndef _STEAM_UTILS_H_
+#define _STEAM_UTILS_H_
+
+int SteamToMirandaStatus(PersonaState state);
+PersonaState MirandaToSteamState(int status);
+
+void ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
+void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL);
+
+MBinBuffer RsaEncrypt(const char *pszModulus, const char *exponent, const char *data);
+MBinBuffer createMachineID(const char *accName);
+
+#define now() time(0)
+
+int64_t getRandomInt();
+CMStringA protobuf_c_text_to_string(const ProtobufCMessage &msg);
+
+#endif //_STEAM_UTILS_H_
diff --git a/protocols/Steam/src/steam_ws.cpp b/protocols/Steam/src/steam_ws.cpp
index 93e63f5606..585d995e24 100644
--- a/protocols/Steam/src/steam_ws.cpp
+++ b/protocols/Steam/src/steam_ws.cpp
@@ -221,7 +221,7 @@ void CSteamProto::ProcessServiceResponse(const uint8_t *buf, size_t cbLen, const
*p1 = 0;
if (auto *pMethod = protobuf_c_service_descriptor_get_method_by_name(it->second, p)) {
- auto *pDescr = pMethod->output;
+ auto *pDescr = (hdr.jobid_target == -1) ? pMethod->input : pMethod->output;
if (auto *pMessage = protobuf_c_message_unpack(pDescr, 0, cbLen, buf)) {
debugLogA("Processing service message: %s\n%s", hdr.target_job_name, protobuf_c_text_to_string(*pMessage).c_str());