From 4c3d77032316bc8814cddc00d020ba00d4533999 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 17 Dec 2024 23:24:44 +0300 Subject: Steam: - contact statuses are back; - contact info is back too; - Miranda's account status is passed to the server; - some old code removed; --- protocols/Steam/src/main.cpp | 2 + protocols/Steam/src/protobuf-c/protobuf-c-text.cpp | 9 +- protocols/Steam/src/stdafx.h | 6 +- protocols/Steam/src/steam_avatars.cpp | 17 +- protocols/Steam/src/steam_contacts.cpp | 295 +++++++++------------ protocols/Steam/src/steam_login.cpp | 4 +- protocols/Steam/src/steam_messages.cpp | 67 +++++ protocols/Steam/src/steam_proto.cpp | 10 +- protocols/Steam/src/steam_proto.h | 23 +- protocols/Steam/src/steam_server.cpp | 68 ++--- protocols/Steam/src/steam_utils.cpp | 14 +- protocols/Steam/src/steam_utils.h | 18 ++ protocols/Steam/src/steam_ws.cpp | 2 +- 13 files changed, 264 insertions(+), 271 deletions(-) create mode 100644 protocols/Steam/src/steam_utils.h (limited to 'protocols/Steam/src') 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 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 void SendHeartBeat(); void SendLogout(); + void SendPersonaStatus(int iStatus); void SendPollRequest(); + void SendUserInfoRequest(uint64_t id, bool bRetrieveState); void SendUserInfoRequest(const std::vector &ids, bool bRetrieveState); // login @@ -180,7 +183,7 @@ class CSteamProto : public PROTO // 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 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 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 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 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 OBJLIST 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 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 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 . #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 ids; + ids.push_back(id & 0xFFFFFFFFll); + SendUserInfoRequest(ids, bRetrieveState); +} + void CSteamProto::SendUserInfoRequest(const std::vector &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()); -- cgit v1.2.3