summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2018-01-14 22:02:44 +0300
committeraunsane <aunsane@gmail.com>2018-01-14 22:03:16 +0300
commit7cb1539b0dbcf585472dd2341129adf174bb0bb5 (patch)
tree6879adfdd3ebf5f64557525df118e0753969fd95 /protocols
parenta6b0d0df4854ffda2577e2b61844467253eb9e0f (diff)
Steam: refactoring pt.2
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Steam/src/api/app_info.h12
-rw-r--r--protocols/Steam/src/api/authorization.h2
-rw-r--r--protocols/Steam/src/api/enums.h38
-rw-r--r--protocols/Steam/src/api/friend.h26
-rw-r--r--protocols/Steam/src/api/friend_list.h39
-rw-r--r--protocols/Steam/src/api/history.h15
-rw-r--r--protocols/Steam/src/api/login.h15
-rw-r--r--protocols/Steam/src/api/pending.h18
-rw-r--r--protocols/Steam/src/api/poll.h56
-rw-r--r--protocols/Steam/src/api/rsa_key.h5
-rw-r--r--protocols/Steam/src/api/search.h16
-rw-r--r--protocols/Steam/src/api/session.h11
-rw-r--r--protocols/Steam/src/http_request.h4
-rw-r--r--protocols/Steam/src/main.cpp6
-rw-r--r--protocols/Steam/src/stdafx.h3
-rw-r--r--protocols/Steam/src/steam_accounts.cpp35
-rw-r--r--protocols/Steam/src/steam_contacts.cpp573
-rw-r--r--protocols/Steam/src/steam_crypt.cpp114
-rw-r--r--protocols/Steam/src/steam_dialogs.cpp6
-rw-r--r--protocols/Steam/src/steam_events.cpp2
-rw-r--r--protocols/Steam/src/steam_history.cpp8
-rw-r--r--protocols/Steam/src/steam_instances.cpp44
-rw-r--r--protocols/Steam/src/steam_login.cpp259
-rw-r--r--protocols/Steam/src/steam_menus.cpp88
-rw-r--r--protocols/Steam/src/steam_messages.cpp17
-rw-r--r--protocols/Steam/src/steam_options.cpp6
-rw-r--r--protocols/Steam/src/steam_polling.cpp111
-rw-r--r--protocols/Steam/src/steam_proto.cpp144
-rw-r--r--protocols/Steam/src/steam_proto.h99
-rw-r--r--protocols/Steam/src/steam_request.cpp107
-rw-r--r--protocols/Steam/src/steam_utils.cpp161
31 files changed, 1101 insertions, 939 deletions
diff --git a/protocols/Steam/src/api/app_info.h b/protocols/Steam/src/api/app_info.h
index b08a3f38d6..7aeb26f9d4 100644
--- a/protocols/Steam/src/api/app_info.h
+++ b/protocols/Steam/src/api/app_info.h
@@ -11,6 +11,18 @@ public:
<< CHAR_PARAM("access_token", token)
<< CHAR_PARAM("appIds", appIds);
}
+
+ //{
+ // "apps": [
+ // {
+ // "appid": 271590,
+ // "name" : "Grand Theft Auto V",
+ // "iconurl" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/271590/1e72f87eb927fa1485e68aefaff23c7fd7178251.jpg",
+ // "logourl" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/271590/e447e82f8b0c67f9e001498503c62f2a187bc609.jpg",
+ // "logosmallurl" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/271590/e447e82f8b0c67f9e001498503c62f2a187bc609_thumb.jpg"
+ // }
+ // ]
+ //}
};
#endif //_STEAM_REQUEST_APP_INFO_H_
diff --git a/protocols/Steam/src/api/authorization.h b/protocols/Steam/src/api/authorization.h
index 3d02c5deb5..b2ba2639c0 100644
--- a/protocols/Steam/src/api/authorization.h
+++ b/protocols/Steam/src/api/authorization.h
@@ -25,7 +25,7 @@ public:
<< CHAR_PARAM("captcha_text", captchaText)
<< CHAR_PARAM("rsatimestamp", timestamp)
<< BOOL_PARAM("rememberlogin", false)
- << INT64_PARAM("donotcache", time(NULL));
+ << INT64_PARAM("donotcache", now());
}
};
diff --git a/protocols/Steam/src/api/enums.h b/protocols/Steam/src/api/enums.h
index a24ce48b34..1a1643a15d 100644
--- a/protocols/Steam/src/api/enums.h
+++ b/protocols/Steam/src/api/enums.h
@@ -1,6 +1,15 @@
#ifndef _STEAM_ENUMS_H_
#define _STEAM_ENUMS_H_
+enum VisibilityState
+{
+ Private = 1,
+ FriendsOnly = 2,
+ FriendsOfFriends = 3,
+ UsersOnly = 4,
+ Public = 5,
+};
+
enum PersonaState
{
Offline = 0,
@@ -10,10 +19,19 @@ enum PersonaState
Snooze = 4,
LookingToTrade = 5,
LookingToPlay = 6,
- Max = 7,
};
-enum StatusFlags
+enum PersonaStateFlag
+{
+ None = 0,
+ HasRichPresence = 1,
+ InJoinableGame = 2,
+ OnlineUsingWeb = 256,
+ OnlineUsingMobile = 512,
+ OnlineUsingBigPicture = 1024,
+};
+
+enum PersonaStatusFlag
{
Status = 1,
PlayerName = 2,
@@ -27,6 +45,20 @@ enum StatusFlags
GameDataBlob = 512,
ClanTag = 1024,
Facebook = 2048,
-}
+};
+
+enum PersonaRelationshipAction
+{
+ // friend removed from contact list
+ Remove = 0,
+ // friend added you to ignore list
+ Ignore = 1,
+ // friend requested auth
+ AuthRequest = 2,
+ // friend added you to contact list
+ AddToList = 3,
+ // friend got (or approved?) your auth request
+ AuthRequested = 4,
+};
#endif //_STEAM_ENUMS_H_
diff --git a/protocols/Steam/src/api/friend.h b/protocols/Steam/src/api/friend.h
index 191e0b93fa..0997d42b0f 100644
--- a/protocols/Steam/src/api/friend.h
+++ b/protocols/Steam/src/api/friend.h
@@ -5,12 +5,36 @@ class GetUserSummariesRequest : public HttpRequest
{
public:
GetUserSummariesRequest(const char *token, const char *steamIds) :
- HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0002")
{
Uri
<< CHAR_PARAM("access_token", token)
<< CHAR_PARAM("steamids", steamIds);
}
+
+ //{
+ // "players": [
+ // {
+ // "steamid": "76561197960435530",
+ // "communityvisibilitystate" : 3,
+ // "profilestate" : 1,
+ // "personaname" : "Robin",
+ // "lastlogoff" : 1514966746,
+ // "profileurl" : "http://steamcommunity.com/id/robinwalker/",
+ // "avatar" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/f1/f1dd60a188883caf82d0cbfccfe6aba0af1732d4.jpg",
+ // "avatarmedium" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/f1/f1dd60a188883caf82d0cbfccfe6aba0af1732d4_medium.jpg",
+ // "avatarfull" : "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/f1/f1dd60a188883caf82d0cbfccfe6aba0af1732d4_full.jpg",
+ // "personastate" : 0,
+ // "realname" : "Robin Walker",
+ // "primaryclanid" : "103582791429521412",
+ // "timecreated" : 1063407589,
+ // "personastateflags" : 0,
+ // "loccountrycode" : "US",
+ // "locstatecode" : "WA",
+ // "loccityid" : 3961
+ // }
+ // ]
+ //}
};
#endif //_STEAM_REQUEST_FRIEND_H_
diff --git a/protocols/Steam/src/api/friend_list.h b/protocols/Steam/src/api/friend_list.h
index 604e797a2d..50c9a7b5bc 100644
--- a/protocols/Steam/src/api/friend_list.h
+++ b/protocols/Steam/src/api/friend_list.h
@@ -12,6 +12,17 @@ public:
<< CHAR_PARAM("steamid", steamId)
<< CHAR_PARAM("relationship", relationship);
}
+
+ //{
+ // "friends": [
+ // {
+ // "steamid": "XXXXXXXXXXXXXXXXX",
+ // "relationship" : "friend",
+ // "friend_since" : 1514314629
+ // }
+ // ]
+ //}
+
};
class AddFriendRequest : public HttpRequest
@@ -32,6 +43,12 @@ public:
<< CHAR_PARAM("sessionID", sessionId)
<< CHAR_PARAM("steamid", who);
}
+
+ // "true"
+
+ // {"invited":["XXXXXXXXXXXXXXXXX"], "success" : 1}
+
+ // {"failed_invites":["XXXXXXXXXXXXXXXXX"], "failed_invites_result" : [24], "success" : 1}
};
class BlockFriendRequest : public HttpRequest
@@ -55,6 +72,28 @@ public:
}
};
+class UnblockFriendRequest : public HttpRequest
+{
+public:
+ UnblockFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
+ HttpRequest(HttpPost, STEAM_WEB_URL "/actions/BlockUserAjax")
+ {
+ char login[MAX_PATH];
+ mir_snprintf(login, "%s||oauth:%s", steamId, token);
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
+
+ Headers << CHAR_PARAM("Cookie", cookie);
+
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("steamid", who)
+ << CHAR_PARAM("action", "unignore")
+ << INT_PARAM("block", 0);
+ }
+};
+
class RemoveFriendRequest : public HttpRequest
{
public:
diff --git a/protocols/Steam/src/api/history.h b/protocols/Steam/src/api/history.h
index f825622953..0eaea38fb1 100644
--- a/protocols/Steam/src/api/history.h
+++ b/protocols/Steam/src/api/history.h
@@ -9,6 +9,21 @@ public:
{
Uri << CHAR_PARAM("access_token", token);
}
+
+ //{
+ // "response": {
+ // "message_sessions": [
+ // {
+ // "accountid_friend": XXXXXXXXX,
+ // "last_message" : 1514975719,
+ // "last_view" : 1514975719,
+ // "unread_message_count" : 0
+ // }
+ // ]
+ // ,
+ // "timestamp": 1515007542
+ // }
+ //}
};
class GetHistoryMessagesRequest : public HttpRequest
diff --git a/protocols/Steam/src/api/login.h b/protocols/Steam/src/api/login.h
index 3479ae75ff..e061d4236c 100644
--- a/protocols/Steam/src/api/login.h
+++ b/protocols/Steam/src/api/login.h
@@ -14,6 +14,17 @@ public:
<< CHAR_PARAM("access_token", token)
<< CHAR_PARAM("ui_mode", "web");
}
+
+ //{
+ // "steamid": "XXXXXXXXXXXXXXXXX",
+ // "error" : "OK",
+ // "umqid" : "XXXXXXXXXXXXXXXXXXX",
+ // "timestamp" : 16955891,
+ // "utc_timestamp" : 1514974537,
+ // "message" : 1,
+ // "push" : 0
+ //}
+
};
class LogoffRequest : public HttpRequest
@@ -26,6 +37,10 @@ public:
<< CHAR_PARAM("access_token", token)
<< CHAR_PARAM("umqid", umqId);
}
+
+ //{
+ // "error": "OK"
+ //}
};
#endif //_STEAM_REQUEST_LOGIN_H_
diff --git a/protocols/Steam/src/api/pending.h b/protocols/Steam/src/api/pending.h
index a808fd172c..9aeed4e182 100644
--- a/protocols/Steam/src/api/pending.h
+++ b/protocols/Steam/src/api/pending.h
@@ -7,11 +7,9 @@ public:
ApprovePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
- char login[MAX_PATH];
- mir_snprintf(login, "%s||oauth:%s", steamId, token);
-
char cookie[MAX_PATH];
- mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
+ mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
+ steamId, token, sessionId);
Headers << CHAR_PARAM("Cookie", cookie);
@@ -32,11 +30,9 @@ public:
IgnorePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
- char login[MAX_PATH];
- mir_snprintf(login, "%s||oauth:%s", steamId, token);
-
char cookie[MAX_PATH];
- mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
+ mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
+ steamId, token, sessionId);
Headers << CHAR_PARAM("Cookie", cookie);
@@ -57,11 +53,9 @@ public:
BlockPendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
- char login[MAX_PATH];
- mir_snprintf(login, "%s||oauth:%s", steamId, token);
-
char cookie[MAX_PATH];
- mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
+ mir_snprintf(cookie, "steamLogin=%s||oauth:%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios",
+ steamId, token, sessionId);
Headers << CHAR_PARAM("Cookie", cookie);
diff --git a/protocols/Steam/src/api/poll.h b/protocols/Steam/src/api/poll.h
index 278dfb0439..6336b212e9 100644
--- a/protocols/Steam/src/api/poll.h
+++ b/protocols/Steam/src/api/poll.h
@@ -19,6 +19,62 @@ public:
<< INT_PARAM("secidletime", idleSeconds)
<< INT_PARAM("sectimeout", STEAM_API_TIMEOUT);
}
+
+ //{
+ // "pollid": 0,
+ // "sectimeout" : 30,
+ // "error" : "Timeout"
+ //}
+
+ //{
+ // "pollid": 0,
+ // "messages": [
+ // {
+ // "type": "typing",
+ // "timestamp": 17276041,
+ // "utc_timestamp": 1514974857,
+ // "steamid_from": "XXXXXXXXXXXXXXXXX",
+ // "text": ""
+ // },
+ // {
+ // "type": "saytext",
+ // "timestamp" : 17380133,
+ // "utc_timestamp" : 1514974961,
+ // "steamid_from" : "XXXXXXXXXXXXXXXXX",
+ // "text" : "message"
+ // },
+ // {
+ // "type": "personarelationship",
+ // "timestamp" : 7732750,
+ // "utc_timestamp" : 1515187192,
+ // "steamid_from" : "XXXXXXXXXXXXXXXXX",
+ // "status_flags" : 1,
+ // "persona_state" : 2
+ // },
+ // {
+ // "type": "personastate",
+ // "timestamp" : 366860,
+ // "utc_timestamp" : 1515007523,
+ // "steamid_from" : "XXXXXXXXXXXXXXXXX",
+ // "status_flags" : 9055,
+ // "persona_state" : 1,
+ // "persona_name" : "nickname"
+ // },
+ // {
+ // "type": "notificationcountupdate",
+ // "timestamp" : 11605105,
+ // "utc_timestamp" : 1515191064
+ // }
+ // ]
+ // ,
+ // "messagelast": 4,
+ // "timestamp": 17276041,
+ // "utc_timestamp": 1514974857,
+ // "messagebase": 3,
+ // "sectimeout": 14,
+ // "error": "OK"
+ //}
+
};
#endif //_STEAM_REQUEST_POLL_H_
diff --git a/protocols/Steam/src/api/rsa_key.h b/protocols/Steam/src/api/rsa_key.h
index 27a002b717..a0369f4db4 100644
--- a/protocols/Steam/src/api/rsa_key.h
+++ b/protocols/Steam/src/api/rsa_key.h
@@ -9,12 +9,9 @@ public:
{
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
- CMStringA data;
- data.AppendFormat("username=%s&donotcache=%lld", ptrA(mir_urlEncode(username)), time(NULL));
-
Content = new FormUrlEncodedContent(this)
<< CHAR_PARAM("username", username)
- << INT64_PARAM("donotcache", time(NULL));
+ << INT64_PARAM("donotcache", now());
}
};
diff --git a/protocols/Steam/src/api/search.h b/protocols/Steam/src/api/search.h
index a34c2e8398..4484af4ba8 100644
--- a/protocols/Steam/src/api/search.h
+++ b/protocols/Steam/src/api/search.h
@@ -10,11 +10,23 @@ public:
Uri
<< CHAR_PARAM("access_token", token)
<< CHAR_PARAM("keywords", text)
- << INT_PARAM("offset=%d", offset)
- << INT_PARAM("count=%d", count)
+ << INT_PARAM("offset", offset)
+ << INT_PARAM("count", count)
<< CHAR_PARAM("targets", "users")
<< CHAR_PARAM("fields", "all");
}
+
+ //{
+ // "count": 1,
+ // "total" : 336,
+ // "success" : true,
+ // "results" : [
+ // {
+ // "steamid": "XXXXXXXXXXXXXXXXX",
+ // "type" : "user"
+ // }
+ // ]
+ //}
};
#endif //_STEAM_REQUEST_SEARCH_H_
diff --git a/protocols/Steam/src/api/session.h b/protocols/Steam/src/api/session.h
index d4e91721cb..dec2e0aa0a 100644
--- a/protocols/Steam/src/api/session.h
+++ b/protocols/Steam/src/api/session.h
@@ -26,10 +26,15 @@ public:
class GetSessionRequest2 : public HttpRequest
{
public:
- GetSessionRequest2() :
- HttpRequest(HttpGet, STEAM_WEB_URL)
+ GetSessionRequest2(const char *token, const char *steamId) :
+ HttpRequest(HttpGet, STEAM_WEB_URL "/mobilesettings/GetManifest/v0001")
{
- flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPHEADERS;
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, "steamLogin=%s||oauth:%s", steamId, token);
+
+ Headers << CHAR_PARAM("Cookie", cookie);
}
};
diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h
index 43bb68d464..696b04f2a8 100644
--- a/protocols/Steam/src/http_request.h
+++ b/protocols/Steam/src/http_request.h
@@ -35,7 +35,7 @@ private:
void FormatV(const char *urlFormat, va_list args)
{
- m_uri.AppendFormatV(urlFormat, args);
+ m_uri.FormatV(urlFormat, args);
if (m_request)
m_request->szUrl = m_uri.GetBuffer();
}
@@ -125,7 +125,7 @@ public:
{
return m_request
? &m_request->headers[idx]
- : NULL;
+ : nullptr;
}
size_t GetSize() const
diff --git a/protocols/Steam/src/main.cpp b/protocols/Steam/src/main.cpp
index 0f14e6ec0e..eefe4967c6 100644
--- a/protocols/Steam/src/main.cpp
+++ b/protocols/Steam/src/main.cpp
@@ -41,8 +41,8 @@ extern "C" int __declspec(dllexport) Load(void)
pd.cbSize = sizeof(pd);
pd.szName = "STEAM";
pd.type = PROTOTYPE_PROTOCOL;
- pd.fnInit = (pfnInitProto)CSteamProto::InitProtoInstance;
- pd.fnUninit = (pfnUninitProto)CSteamProto::UninitProtoInstance;
+ pd.fnInit = (pfnInitProto)CSteamProto::InitAccount;
+ pd.fnUninit = (pfnUninitProto)CSteamProto::UninitAccount;
Proto_RegisterModule(&pd);
char iconName[100];
@@ -58,7 +58,5 @@ extern "C" int __declspec(dllexport) Load(void)
extern "C" int __declspec(dllexport) Unload(void)
{
- CSteamProto::UninitProtoInstances();
- CSteamProto::UninitMenus();
return 0;
}
diff --git a/protocols/Steam/src/stdafx.h b/protocols/Steam/src/stdafx.h
index 7b2a070da4..a8aa969ca3 100644
--- a/protocols/Steam/src/stdafx.h
+++ b/protocols/Steam/src/stdafx.h
@@ -59,9 +59,12 @@ extern HANDLE hExtraXStatus;
#define STEAM_DB_GETEVENTTEXT_CHATSTATES "/GetEventText2000"
#define STEAM_DB_EVENT_CHATSTATES_GONE 1
+#define now() time(NULL)
+
#include "steam_dialogs.h"
#include "steam_options.h"
#include "http_request.h"
+#include "api/enums.h"
#include "api/app_info.h"
#include "api/authorization.h"
#include "api/authorization.h"
diff --git a/protocols/Steam/src/steam_accounts.cpp b/protocols/Steam/src/steam_accounts.cpp
new file mode 100644
index 0000000000..43ec787c5f
--- /dev/null
+++ b/protocols/Steam/src/steam_accounts.cpp
@@ -0,0 +1,35 @@
+#include "stdafx.h"
+
+LIST<CSteamProto> CSteamProto::Accounts(1, CSteamProto::CompareProtos);
+
+int CSteamProto::CompareProtos(const CSteamProto *p1, const CSteamProto *p2)
+{
+ return mir_wstrcmp(p1->m_tszUserName, p2->m_tszUserName);
+}
+
+CSteamProto* CSteamProto::InitAccount(const char* protoName, const wchar_t* userName)
+{
+ CSteamProto *ppro = new CSteamProto(protoName, userName);
+ Accounts.insert(ppro);
+ return ppro;
+}
+
+int CSteamProto::UninitAccount(CSteamProto* ppro)
+{
+ Accounts.remove(ppro);
+ delete ppro;
+ return 0;
+}
+
+CSteamProto* CSteamProto::GetContactAccount(MCONTACT hContact)
+{
+ char *proto = GetContactProto(hContact);
+ if (proto == nullptr)
+ return nullptr;
+
+ for (int i = 0; i < Accounts.getCount(); i++)
+ if (!mir_strcmp(proto, Accounts[i]->m_szModuleName))
+ return Accounts[i];
+
+ return nullptr;
+} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index 98f06662de..894853f46b 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -2,6 +2,9 @@
void CSteamProto::SetContactStatus(MCONTACT hContact, WORD status)
{
+ if (!hContact)
+ return;
+
WORD oldStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE);
if (oldStatus != status)
{
@@ -11,19 +14,13 @@ void CSteamProto::SetContactStatus(MCONTACT hContact, WORD status)
switch (status)
{
case ID_STATUS_FREECHAT:
- {
- // Contact is looking to play, save it to as status message
- if (hContact)
- db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Looking to play"));
- }
+ // Contact is looking to play, save it to as status message
+ db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Looking to play"));
break;
case ID_STATUS_OUTTOLUNCH:
- {
- // Contact is looking to trade, save it to as status message
- if (hContact)
- db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Looking to trade"));
- }
+ // Contact is looking to trade, save it to as status message
+ db_set_ws(hContact, "CList", "StatusMsg", TranslateT("Looking to trade"));
break;
case ID_STATUS_OFFLINE:
@@ -33,16 +30,12 @@ void CSteamProto::SetContactStatus(MCONTACT hContact, WORD status)
delSetting(hContact, "XStatusName");
delSetting(hContact, "XStatusMsg");
- if (hContact)
- SetContactExtraIcon(hContact, NULL);
+ SetContactExtraIcon(hContact, NULL);
}
// no break intentionally
default:
- {
- if (hContact)
- db_unset(hContact, "CList", "StatusMsg");
- }
+ db_unset(hContact, "CList", "StatusMsg");
break;
}
}
@@ -67,20 +60,14 @@ MCONTACT CSteamProto::GetContactFromAuthEvent(MEVENT hEvent)
return DbGetAuthEventContact(&dbei);
}
-MCONTACT CSteamProto::FindContact(const char *steamId)
+MCONTACT CSteamProto::GetContact(const char *steamId)
{
- MCONTACT hContact = NULL;
-
- mir_cslock lck(this->contact_search_lock);
-
- for (hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
- {
- ptrA cSteamId(db_get_sa(hContact, this->m_szModuleName, "SteamID"));
- if (!lstrcmpA(cSteamId, steamId))
- break;
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ ptrA cSteamId(getStringA(hContact, "SteamID"));
+ if (!mir_strcmp(cSteamId, steamId))
+ return hContact;
}
-
- return hContact;
+ return NULL;
}
void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
@@ -97,26 +84,21 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
// set name
JSONNode node = data["realname"];
- if (!node.isnull())
- {
+ if (!node.isnull()) {
CMStringW realName = node.as_mstring();
- if (!realName.IsEmpty())
- {
+ if (!realName.IsEmpty()) {
int pos = realName.Find(L' ', 1);
- if (pos != -1)
- {
+ if (pos != -1) {
setWString(hContact, "FirstName", realName.Mid(0, pos));
setWString(hContact, "LastName", realName.Mid(pos + 1));
}
- else
- {
+ else {
setWString(hContact, "FirstName", realName);
delSetting(hContact, "LastName");
}
}
}
- else
- {
+ else {
delSetting(hContact, "FirstName");
delSetting(hContact, "LastName");
}
@@ -128,8 +110,7 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
// set country
node = data["loccountrycode"];
- if (!node.isnull())
- {
+ if (!node.isnull()) {
json_string countryCode = node.as_string();
char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)countryCode.c_str(), 0);
setString(hContact, "Country", country);
@@ -138,17 +119,25 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
delSetting(hContact, "Country");
// state code
- node = data["locstatecode"];
- if (!node.isnull())
- setDword(hContact, "StateCode", node.as_int());
- else
+ // 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
- node = data["loccityid"];
- if (!node.isnull())
- setDword(hContact, "CityID", node.as_int());
- else
+ // 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
@@ -160,34 +149,38 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
setDword(hContact, "LogoffTS", node.as_int());
// status
- // NOTE: this here is wrong info, probably depending on publicity of steam profile, but we don't need this at all, we get status updates by polling
- /*node = json_get(data, "personastate");
- status = SteamToMirandaStatus(json_as_int(node));
- SetContactStatus(hContact, status);
- */
+ node = data["lastlogoff"];
+ // note: this here is often wrong info, probably depending on publicity of steam profile
+ // but sometimes polling does not get status at all
+ WORD oldStatus = getWord(hContact, "Status", ID_STATUS_OFFLINE);
+ // so, set status only if contact offline
+ if (oldStatus == ID_STATUS_OFFLINE) {
+ WORD status = SteamToMirandaStatus((PersonaState)node.as_int());
+ SetContactStatus(hContact, status);
+ }
// client
node = data["personastateflags"];
- int stateflags = !node.isnull() ? node.as_int() : -1;
+ long stateflags = !node.isnull() ? node.as_int() : -1;
if (stateflags == 0) {
// nothing special, either standard client or in different status (only online, I want to play, I want to trade statuses support this flags)
WORD status = getWord(hContact, "Status", ID_STATUS_OFFLINE);
if (status == ID_STATUS_ONLINE || status == ID_STATUS_OUTTOLUNCH || status == ID_STATUS_FREECHAT)
setWString(hContact, "MirVer", L"Steam");
}
- else if (stateflags & 2) {
+ else if (stateflags & PersonaStateFlag::InJoinableGame) {
// game
setWString(hContact, "MirVer", L"Steam (in game)");
}
- else if (stateflags & 256) {
+ else if (stateflags & PersonaStateFlag::OnlineUsingWeb) {
// on website
setWString(hContact, "MirVer", L"Steam (website)");
}
- else if (stateflags & 512) {
+ else if (stateflags & PersonaStateFlag::OnlineUsingMobile) {
// on mobile
setWString(hContact, "MirVer", L"Steam (mobile)");
}
- else if (stateflags & 1024) {
+ else if (stateflags & PersonaStateFlag::OnlineUsingBigPicture) {
// big picture mode
setWString(hContact, "MirVer", L"Steam (Big Picture)");
}
@@ -199,8 +192,7 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
// playing game
json_string appId = data["gameid"].as_string();
CMStringW gameInfo = data["gameextrainfo"].as_mstring();
- if (!appId.empty() || !gameInfo.IsEmpty())
- {
+ if (!appId.empty() || !gameInfo.IsEmpty()) {
DWORD gameId = atol(appId.c_str());
json_string serverIP = data["gameserverip"].as_string();
json_string serverID = data["gameserversteamid"].as_string();
@@ -210,16 +202,14 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
setString(hContact, "ServerID", serverID.c_str());
CMStringW message(gameInfo);
- if (gameId && message.IsEmpty())
- {
+ if (gameId && message.IsEmpty()) {
ptrA token(getStringA("TokenSecret"));
PushRequest(
new GetAppInfoRequest(token, appId.c_str()),
&CSteamProto::OnGotAppInfo,
(void*)hContact);
}
- else
- {
+ else {
if (!gameId)
message.Append(TranslateT(" (Non-Steam)"));
if (!serverIP.empty())
@@ -232,8 +222,7 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
SetContactExtraIcon(hContact, gameId);
}
- else
- {
+ else {
delSetting(hContact, "GameID");
delSetting(hContact, "ServerIP");
delSetting(hContact, "ServerID");
@@ -246,136 +235,125 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
}
}
-void CSteamProto::ContactIsRemoved(MCONTACT hContact)
+void CSteamProto::ContactIsFriend(MCONTACT hContact)
{
delSetting(hContact, "AuthAsked");
+ delSetting(hContact, "Auth");
+ delSetting(hContact, "Grant");
+ db_unset(hContact, "CList", "NotOnList");
- // If this contact was authorized and now is not (and isn't filled time of deletion), notify it
- if (!getDword(hContact, "DeletedTS", 0) && getByte(hContact, "Auth", 0) == 0)
- {
- setDword(hContact, "DeletedTS", ::time(nullptr));
+ // Check if this contact was removed someday and if so, notify he's back
+ if (getDword(hContact, "DeletedTS", 0) && !getByte(hContact, "Auth", 0)) {
+ delSetting(hContact, "DeletedTS");
ptrW nick(getWStringA(hContact, "Nick"));
wchar_t message[MAX_PATH];
- mir_snwprintf(message, MAX_PATH, TranslateT("%s has been removed from your contact list"), nick);
+ mir_snwprintf(message, MAX_PATH, TranslateT("%s is back in your contact list"), nick);
- ShowNotification(L"Steam", message);
+ ShowNotification(message);
}
+}
- if (getByte(hContact, "Auth", 0) != 1)
- {
- setByte(hContact, "Auth", 1);
- }
+void CSteamProto::ContactIsBlocked(MCONTACT hContact)
+{
+ // todo
+ setByte(hContact, "Block", 1);
+}
- SetContactStatus(hContact, ID_STATUS_OFFLINE);
+void CSteamProto::ContactIsUnblocked(MCONTACT hContact)
+{
+ delSetting(hContact, "Block");
}
-void CSteamProto::ContactIsFriend(MCONTACT hContact)
+void CSteamProto::ContactIsRemoved(MCONTACT hContact)
{
delSetting(hContact, "AuthAsked");
- // Check if this contact was removed someday and if so, notify he's back
- if (getDword(hContact, "DeletedTS", 0) && getByte(hContact, "Auth", 0) != 0)
- {
- delSetting(hContact, "DeletedTS");
+ // If this contact was authorized and now is not (and isn't filled time of deletion), notify it
+ if (!getDword(hContact, "DeletedTS", 0) && !getByte(hContact, "Auth", 0)) {
+ setDword(hContact, "DeletedTS", now());
ptrW nick(getWStringA(hContact, "Nick"));
wchar_t message[MAX_PATH];
- mir_snwprintf(message, MAX_PATH, TranslateT("%s is back in your contact list"), nick);
-
- ShowNotification(L"Steam", message);
- }
+ mir_snwprintf(message, MAX_PATH, TranslateT("%s has been removed from your contact list"), nick);
- if (getByte(hContact, "Auth", 0) != 0 || getByte(hContact, "Grant", 0) != 0)
- {
- delSetting(hContact, "Auth");
- delSetting(hContact, "Grant");
+ ShowNotification(message);
}
-}
-void CSteamProto::ContactIsIgnored(MCONTACT hContact)
-{
- // todo
- setByte(hContact, "Block", 1);
+ setByte(hContact, "Auth", 1);
+ SetContactStatus(hContact, ID_STATUS_OFFLINE);
}
void CSteamProto::ContactIsAskingAuth(MCONTACT hContact)
{
- if (getByte(hContact, "AuthAsked", 0) != 0) {
+ //if (getByte(hContact, "AuthAsked", 0))
// auth request was already showed, do nothing here
- return;
- }
+ //return;
- if (getByte(hContact, "Auth", 0) == 0) {
+ /*if (getByte(hContact, "Auth", 0) == 0) {
// user was just added or he already has authorization, but because we've just got auth request, he was probably deleted and requested again
ContactIsRemoved(hContact);
- }
+ }*/
// create auth request event
ptrA steamId(getStringA(hContact, "SteamID"));
ptrA nickName(getStringA(hContact, "Nick"));
+ if (nickName == nullptr)
+ nickName = mir_strdup(steamId);
ptrA firstName(getStringA(hContact, "FirstName"));
- if (firstName == NULL)
+ if (firstName == nullptr)
firstName = mir_strdup("");
ptrA lastName(getStringA(hContact, "LastName"));
- if (lastName == NULL)
+ if (lastName == nullptr)
lastName = mir_strdup("");
char reason[MAX_PATH];
- mir_snprintf(reason, Translate("%s has added you to his or her Friend List"), nickName);
+ mir_snprintf(reason, Translate("%s has added you to contact list"), nickName);
DB_AUTH_BLOB blob(hContact, nickName, firstName, lastName, steamId, reason);
PROTORECVEVENT recv = { 0 };
- recv.timestamp = time(nullptr);
+ recv.timestamp = now();
recv.szMessage = blob;
recv.lParam = blob.size();
ProtoChainRecv(hContact, PSR_AUTH, 0, (LPARAM)&recv);
-
- // remember to not create this event again, unless authorization status changes again
- setByte(hContact, "AuthAsked", 1);
}
-MCONTACT CSteamProto::AddContact(const char *steamId, bool isTemporary)
+MCONTACT CSteamProto::AddContact(const char *steamId, const wchar_t *nick, bool isTemporary)
{
- MCONTACT hContact = NULL;
-
- mir_cslock lck(this->contact_search_lock);
+ mir_cslock lock(m_addContactLock);
- for (hContact = db_find_first(this->m_szModuleName); hContact; hContact = db_find_next(hContact, this->m_szModuleName))
- {
- ptrA cSteamId(db_get_sa(hContact, this->m_szModuleName, "SteamID"));
- if (!lstrcmpA(cSteamId, steamId))
- break;
+ if (!steamId || !mir_strlen(steamId)) {
+ debugLogA(__FUNCTION__ ": empty steam id");
+ return NULL;
}
- if (!hContact)
- {
- // create contact
- hContact = db_add_contact();
- Proto_AddToContact(hContact, this->m_szModuleName);
+ MCONTACT hContact = GetContact(steamId);
+ if (hContact)
+ return hContact;
- setString(hContact, "SteamID", steamId);
+ // create contact
+ hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
- // update info
- //UpdateContact(hContact, contact);
+ setString(hContact, "SteamID", steamId);
+ if (mir_wstrlen(nick)) {
+ setWString(hContact, "Nick", nick);
+ db_set_ws(hContact, "CList", "MyHandle", nick);
+ }
- if (isTemporary)
- {
- setByte(hContact, "Auth", 1);
- //setByte(hContact, "Grant", 1);
- db_set_b(hContact, "CList", "NotOnList", 1);
- }
+ // update info
+ //UpdateContact(hContact, contact);
- // move to default group
- DBVARIANT dbv;
- if (!getWString("DefaultGroup", &dbv))
- {
- if(Clist_GroupExists(dbv.ptszVal))
- db_set_ws(hContact, "CList", "Group", dbv.ptszVal);
- db_free(&dbv);
- }
- }
+ if (isTemporary)
+ db_set_b(hContact, "CList", "NotOnList", 1);
+
+ setByte(hContact, "Auth", 1);
+ //setByte(hContact, "Grant", 1);
+
+ // move to default group
+ if (m_defaultGroup)
+ db_set_ws(hContact, "CList", "Group", m_defaultGroup);
return hContact;
}
@@ -391,11 +369,11 @@ void CSteamProto::UpdateContactRelationship(MCONTACT hContact, const JSONNode &d
return;
json_string relationship = node.as_string();
- if (!lstrcmpiA(relationship.c_str(), "friend"))
+ if (!mir_strcmp(relationship.c_str(), "friend"))
ContactIsFriend(hContact);
- else if (!lstrcmpiA(relationship.c_str(), "ignoredfriend"))
- ContactIsIgnored(hContact);
- else if (!lstrcmpiA(relationship.c_str(), "requestrecipient"))
+ else if (!mir_strcmp(relationship.c_str(), "ignoredfriend"))
+ ContactIsBlocked(hContact);
+ else if (!mir_strcmp(relationship.c_str(), "requestrecipient"))
ContactIsAskingAuth(hContact);
}
@@ -404,8 +382,7 @@ void CSteamProto::OnGotAppInfo(const JSONNode &root, void *arg)
MCONTACT hContact = (UINT_PTR)arg;
JSONNode apps = root["apps"].as_array();
- for (const JSONNode &app : apps)
- {
+ for (const JSONNode &app : apps) {
DWORD gameId = app["appid"].as_int();
CMStringW message = app["name"].as_mstring();
@@ -424,67 +401,69 @@ void CSteamProto::OnGotFriendList(const JSONNode &root, void*)
std::string steamIds = (char*)ptrA(getStringA("SteamID"));
// Remember contacts on server
- std::map<json_string, JSONNode*> friendsMap;
+ std::map<json_string, JSONNode*> friendsMap;
JSONNode friends = root["friends"].as_array();
- for (const JSONNode &_friend : friends)
- {
+ for (const JSONNode &_friend : friends) {
json_string steamId = _friend["steamid"].as_string();
friendsMap.insert(std::make_pair(steamId, json_copy(&_friend)));
}
- { // Check and update contacts in database
- mir_cslock lck(this->contact_search_lock);
-
- for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
- {
- ptrA steamId(getStringA(hContact, "SteamID"));
- if (steamId == nullptr)
- continue;
+ // Check and update contacts in database
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) {
+ ptrA steamId(getStringA(hContact, "SteamID"));
+ if (steamId == nullptr)
+ continue;
- auto it = friendsMap.find((char*)steamId);
- if (it != friendsMap.end())
- {
- // Contact is on server-list, update (and eventually notify) it
- UpdateContactRelationship(hContact, *it->second);
- steamIds.append(",").append(it->first);
- json_delete(it->second);
- friendsMap.erase(it);
- }
- else
- {
- // Contact was removed from server-list, notify it
- ContactIsRemoved(hContact);
- }
+ auto it = friendsMap.find((char*)steamId);
+ if (it == friendsMap.end()) {
+ // Contact was removed from server-list, notify it
+ ContactIsRemoved(hContact);
+ continue;
}
+
+ JSONNode _friend = *it->second;
+
+ // Contact is on server-list, update (and eventually notify) it
+ UpdateContactRelationship(hContact, _friend);
+
+ // Do not update summary for non friends
+ json_string relationship = _friend["relationship"].as_string();
+ if (relationship == "friend")
+ steamIds.append(",").append(it->first);
+
+ json_delete(it->second);
+ friendsMap.erase(it);
}
// Check remaining contacts in map and add them to contact list
- for (auto it : friendsMap)
- {
+ for (auto it : friendsMap) {
// Contact is on server-list, but not in database, add (but not notify) it
- MCONTACT hContact = AddContact(it.first.c_str());
- UpdateContactRelationship(hContact, *it.second);
-
- steamIds.append(",").append(it.first);
+ JSONNode _friend = *it.second;
+
+ json_string relationship = _friend["relationship"].as_string();
+
+ MCONTACT hContact = AddContact(it.first.c_str(), nullptr, relationship != "friend");
+ UpdateContactRelationship(hContact, _friend);
+
+ if (relationship == "friend")
+ steamIds.append(",").append(it.first);
+
json_delete(it.second);
}
friendsMap.clear();
- // We need to delete nroot here at the end, because we had references to JSONNode objects stored in friends map
- // json_delete(nroot);
-
ptrA token(getStringA("TokenSecret"));
if (!steamIds.empty())
{
- //steamIds.pop_back();
+ steamIds.pop_back();
PushRequest(
new GetUserSummariesRequest(token, steamIds.c_str()),
&CSteamProto::OnGotUserSummaries);
}
- // Download last messages
+ // Load last conversations
PushRequest(
new GetConversationsRequest(token),
&CSteamProto::OnGotConversations);
@@ -501,11 +480,9 @@ void CSteamProto::OnGotBlockList(const JSONNode &root, void*)
if (friends.isnull())
return;
- for (size_t i = 0; i < friends.size(); i++)
+ for (const JSONNode &_friend: friends)
{
- JSONNode node = friends[i].as_node();
-
- json_string steamId = node["steamid"].as_string();
+ json_string steamId = _friend["steamid"].as_string();
/*MCONTACT hContact = FindContact(steamId);
if (!hContact)
@@ -514,8 +491,8 @@ void CSteamProto::OnGotBlockList(const JSONNode &root, void*)
steamIds.append(steamId).append(",");
}*/
- json_string relationship = node["relationship"].as_string();
- if (!lstrcmpiA(relationship.c_str(), "ignoredfriend"))
+ json_string relationship = _friend["relationship"].as_string();
+ if (!mir_strcmp(relationship.c_str(), "ignoredfriend"))
{
// todo: open block list
}
@@ -529,15 +506,12 @@ void CSteamProto::OnGotUserSummaries(const JSONNode &root, void*)
if (players.isnull())
return;
- for (size_t i = 0; i < players.size(); i++)
- {
- JSONNode player = players[i];
+ for (const JSONNode &player : players) {
json_string steamId = player["steamid"].as_string();
-
- MCONTACT hContact = NULL;
- if (!IsMe(steamId.c_str()))
- hContact = AddContact(steamId.c_str());
-
+ CMStringW nick = player["personaname"].as_mstring();
+ MCONTACT hContact = !IsMe(steamId.c_str())
+ ? hContact = AddContact(steamId.c_str(), nick)
+ : NULL;
UpdateContactDetails(hContact, player);
}
}
@@ -548,8 +522,7 @@ void CSteamProto::OnGotAvatar(const HttpResponse &response, void *arg)
ai.hContact = (UINT_PTR)arg;
GetDbAvatarInfo(ai);
- if (!response.IsSuccess())
- {
+ if (!response.IsSuccess()) {
ptrA steamId(getStringA(ai.hContact, "SteamID"));
debugLogA(__FUNCTION__ ": failed to get avatar %s", steamId);
@@ -558,11 +531,10 @@ void CSteamProto::OnGotAvatar(const HttpResponse &response, void *arg)
return;
}
- FILE *fp = _wfopen(ai.filename, L"wb");
- if (fp)
- {
- fwrite(response.Content, sizeof(char), response.Content.GetSize(), fp);
- fclose(fp);
+ FILE *file = _wfopen(ai.filename, L"wb");
+ if (file) {
+ fwrite(response.Content, sizeof(char), response.Content.GetSize(), file);
+ fclose(file);
if (ai.hContact)
ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, 0);
@@ -575,21 +547,63 @@ void CSteamProto::OnFriendAdded(const HttpResponse &response, void *arg)
{
SendAuthParam *param = (SendAuthParam*)arg;
- if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
- {
- ptrA steamId(getStringA(param->hContact, "SteamID"));
- debugLogA(__FUNCTION__ ": failed to add friend %s", steamId);
+ if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+
+ ptrW steamId(getWStringA(param->hContact, "SteamID"));
+ ptrW who(getWStringA(param->hContact, "Nick"));
+ if (!who)
+ who = mir_wstrdup(steamId);
- ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_FAILED, param->hAuth, 0);
+ wchar_t message[MAX_PATH];
+ mir_snwprintf(message, L"Error adding friend %s", who);
+
+ JSONNode root = JSONNode::parse(response.Content);
+ if (root) {
+ int success = root["success"].as_int();
+ if (success == 1) {
+ JSONNode invited = root["invited"].as_array();
+ if (invited.empty()) {
+ JSONNode errors = root["failed_invites_result"].as_array();
+ if (!errors.empty()) {
+ int first = 0;
+ int errorCode = errors[first].as_int();
+ switch (errorCode)
+ {
+ case 11:
+ mir_snwprintf(message, L"All communication with %s is blocked. Communication is only possible if you have lifted the blocking. To do this, visit the user's Steam Community page.", who);
+ break;
+ case 15:
+ mir_snwprintf(message, L"Request to %s can not be sent. His/her friends list is full.", who);
+ break;
+ case 24:
+ mir_wstrcpy(message, L"Your account does not meet the requirements to use this feature. Visit Steam Support to get more information.");
+ break;
+ case 25:
+ mir_snwprintf(message, L"Request to %s can not be sent. Your friends list is full.", who);
+ break;
+ case 40:
+ mir_snwprintf(message, L"Error adding friend %s. The communication between you and the other Steam member is blocked.", who);
+ break;
+ case 84:
+ mir_wstrcpy(message, L"You've been sending too many invitations lately. Please try again in a day or two.");
+ break;
+ }
+ }
+ }
+ else {
+ ContactIsFriend(param->hContact);
+ ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_SUCCESS, param->hAuth, 0);
+ return;
+ }
+ }
+ }
+ ShowNotification(message, MB_ICONERROR);
+ ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_FAILED, param->hAuth, 0);
return;
}
- delSetting(param->hContact, "Auth");
- delSetting(param->hContact, "Grant");
- delSetting(param->hContact, "DeletedTS");
- db_unset(param->hContact, "CList", "NotOnList");
-
+ ContactIsFriend(param->hContact);
ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_SUCCESS, param->hAuth, 0);
}
@@ -597,27 +611,42 @@ void CSteamProto::OnFriendBlocked(const HttpResponse &response, void *arg)
{
ptrA steamId((char*)arg);
- if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
- {
- debugLogA(__FUNCTION__ ": failed to ignore friend %s", (char*)arg);
+ if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+ debugLogA(__FUNCTION__ ": failed to ignore friend %s", (char*)steamId);
return;
}
+
+ MCONTACT hContact = GetContact(steamId);
+ if (hContact)
+ ContactIsBlocked(hContact);
}
-void CSteamProto::OnFriendRemoved(const HttpResponse &response, void *arg)
+void CSteamProto::OnFriendUnblocked(const HttpResponse &response, void *arg)
{
- MCONTACT hContact = (UINT_PTR)arg;
+ ptrA steamId((char*)arg);
- if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
- {
- ptrA who(getStringA(hContact, "SteamID"));
+ if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+ debugLogA(__FUNCTION__ ": failed to unignore friend %s", (char*)steamId);
+ return;
+ }
+
+ MCONTACT hContact = GetContact(steamId);
+ if (hContact)
+ ContactIsUnblocked(hContact);
+}
- debugLogA(__FUNCTION__ ": failed to remove friend %s", who);
+void CSteamProto::OnFriendRemoved(const HttpResponse &response, void *arg)
+{
+ ptrA steamId((char*)arg);
+
+ if (!response.IsSuccess() || mir_strcmp(response.Content, "true")) {
+ debugLogA(__FUNCTION__ ": failed to remove friend %s", (char*)steamId);
return;
}
- setByte(hContact, "Auth", 1);
- setDword(hContact, "DeletedTS", ::time(nullptr));
+ MCONTACT hContact = GetContact(steamId);
+ if (hContact)
+ ContactIsRemoved(hContact);
}
void CSteamProto::OnAuthRequested(const JSONNode &root, void*)
@@ -628,13 +657,14 @@ void CSteamProto::OnAuthRequested(const JSONNode &root, void*)
int first = 0;
JSONNode players = root["players"].as_array();
JSONNode player = players[first];
- if (!player.isnull())
- {
- json_string steamId = player["steamid"].as_string();
- MCONTACT hContact = AddContact(steamId.c_str());
- UpdateContactDetails(hContact, player);
- ContactIsAskingAuth(hContact);
- }
+ if (player.isnull())
+ return;
+
+ 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)
@@ -645,8 +675,7 @@ void CSteamProto::OnPendingApproved(const JSONNode &root, void *arg)
return;
int success = root["success"].as_int();
- if (success == 0)
- {
+ if (success == 0) {
json_string error = root["error_text"].as_string();
debugLogA(__FUNCTION__ ": failed to approve pending from %s (%s)", steamId, ptrA(mir_utf8decodeA(error.c_str())));
}
@@ -660,8 +689,7 @@ void CSteamProto::OnPendingIgnoreded(const JSONNode &root, void *arg)
return;
int success = root["success"].as_int();
- if (success == 0)
- {
+ if (success == 0) {
json_string error = root["error_text"].as_string();
debugLogA(__FUNCTION__ ": failed to ignore pending from %s (%s)", steamId, ptrA(mir_utf8decodeA(error.c_str())));
}
@@ -671,54 +699,47 @@ void CSteamProto::OnSearchResults(const HttpResponse &response, void *arg)
{
HANDLE searchType = (HANDLE)arg;
- if (!response.IsSuccess())
- {
+ if (!response.IsSuccess()) {
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, searchType, 0);
debugLogA(__FUNCTION__ ": failed to get summaries");
return;
}
JSONNode root = JSONNode::parse(response.Content);
- if (root.isnull())
- {
+ if (root.isnull()) {
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, searchType, 0);
+ debugLogA(__FUNCTION__ ": no data");
return;
}
JSONNode players = root["players"].as_array();
- for (size_t i = 0; i < players.size(); i++)
- {
- JSONNode player = players[i];
-
+ for (const JSONNode &player : players) {
STEAM_SEARCH_RESULT ssr = { 0 };
- ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT);
- ssr.hdr.flags = PSR_UNICODE;
+ ssr.psr.cbSize = sizeof(STEAM_SEARCH_RESULT);
+ ssr.psr.flags = PSR_UNICODE;
CMStringW steamId = player["steamid"].as_mstring();
- ssr.hdr.id.w = steamId.Detach();
+ ssr.psr.id.w = steamId.Detach();
CMStringW nick = player["personaname"].as_mstring();
- ssr.hdr.nick.w = nick.Detach();
+ ssr.psr.nick.w = nick.Detach();
JSONNode node = player["realname"];
- if (!node.isnull())
- {
+ if (!node.isnull()) {
CMStringW realName = node.as_mstring();
- if (!realName.IsEmpty())
- {
+ if (!realName.IsEmpty()) {
int pos = realName.Find(' ', 1);
- if (pos != -1)
- {
- ssr.hdr.firstName.w = realName.Mid(0, pos).Detach();
- ssr.hdr.lastName.w = realName.Mid(pos + 1).Detach();
+ if (pos != -1) {
+ ssr.psr.firstName.w = realName.Mid(0, pos).Detach();
+ ssr.psr.lastName.w = realName.Mid(pos + 1).Detach();
}
else
- ssr.hdr.firstName.w = realName.Detach();
+ ssr.psr.firstName.w = realName.Detach();
}
}
- //ssr.contact = contact;
- ssr.data = json_copy(&player); // FIXME: is this needed and safe (no memleak) to be here?
+ // todo: is this needed and safe (no memleak) to be here?
+ ssr.data = json_copy(&player);
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, searchType, (LPARAM)&ssr);
}
@@ -728,17 +749,16 @@ void CSteamProto::OnSearchResults(const HttpResponse &response, void *arg)
void CSteamProto::OnSearchByNameStarted(const HttpResponse &response, void *arg)
{
- if (!response.IsSuccess())
- {
+ if (!response.IsSuccess()) {
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)arg, 0);
debugLogA(__FUNCTION__ ": failed to get results");
return;
}
JSONNode root = JSONNode::parse(response.Content);
- if (root.isnull())
- {
+ if (root.isnull()) {
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)arg, 0);
+ debugLogA(__FUNCTION__ ": no data");
return;
}
@@ -749,27 +769,22 @@ void CSteamProto::OnSearchByNameStarted(const HttpResponse &response, void *arg)
std::string steamIds;
JSONNode results = root["results"].as_array();
- for (size_t i = 0; i < results.size(); i++)
- {
- JSONNode result = results[i];
+ for (const JSONNode &result : results) {
json_string steamId = result["steamid"].as_string();
steamIds.append(steamId).append(",");
}
- if (!steamIds.empty())
- {
- // remove trailing ","
- steamIds.pop_back();
-
- ptrA token(getStringA("TokenSecret"));
-
- PushRequest(
- new GetUserSummariesRequest(token, steamIds.c_str()),
- &CSteamProto::OnSearchResults,
- (HANDLE)arg);
- }
- else
- {
+ if (steamIds.empty()) {
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)arg, 0);
+ return;
}
+
+ // remove trailing ","
+ steamIds.pop_back();
+
+ ptrA token(getStringA("TokenSecret"));
+ PushRequest(
+ new GetUserSummariesRequest(token, steamIds.c_str()),
+ &CSteamProto::OnSearchResults,
+ (HANDLE)arg);
}
diff --git a/protocols/Steam/src/steam_crypt.cpp b/protocols/Steam/src/steam_crypt.cpp
new file mode 100644
index 0000000000..7c7fa07312
--- /dev/null
+++ b/protocols/Steam/src/steam_crypt.cpp
@@ -0,0 +1,114 @@
+#include "stdafx.h"
+
+#pragma comment(lib, "crypt32.lib")
+
+int CSteamProto::RsaEncrypt(const char *pszModulus, DWORD &exponent, const char *data, BYTE *encryptedData, DWORD &encryptedSize)
+{
+ DWORD cchModulus = (DWORD)mir_strlen(pszModulus);
+ int result = 0;
+ BYTE *pbBuffer = nullptr;
+ BYTE *pKeyBlob = nullptr;
+ HCRYPTKEY phKey = 0;
+ HCRYPTPROV hCSP = 0;
+
+ // convert hex string to byte array
+ DWORD cbLen = 0, dwSkip = 0, dwFlags = 0;
+ if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, nullptr, &cbLen, &dwSkip, &dwFlags))
+ {
+ result = GetLastError();
+ goto exit;
+ }
+
+ // allocate a new buffer.
+ pbBuffer = (BYTE*)malloc(cbLen);
+ if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, pbBuffer, &cbLen, &dwSkip, &dwFlags))
+ {
+ result = GetLastError();
+ goto exit;
+ }
+
+ // reverse byte array, because of microsoft
+ for (int i = 0; i < (int)(cbLen / 2); ++i)
+ {
+ BYTE temp = pbBuffer[cbLen - i - 1];
+ pbBuffer[cbLen - i - 1] = pbBuffer[i];
+ pbBuffer[i] = temp;
+ }
+
+ if (!CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT) &&
+ !CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT | CRYPT_NEWKEYSET))
+ {
+ result = GetLastError();
+ goto exit;
+ }
+
+ // Move the key into the key container.
+ DWORD cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbLen;
+ pKeyBlob = (BYTE*)malloc(cbKeyBlob);
+
+ // Fill in the data.
+ PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pKeyBlob;
+ pPublicKey->bType = PUBLICKEYBLOB;
+ pPublicKey->bVersion = CUR_BLOB_VERSION; // Always use this value.
+ pPublicKey->reserved = 0; // Must be zero.
+ pPublicKey->aiKeyAlg = CALG_RSA_KEYX; // RSA public-key key exchange.
+
+ // The next block of data is the RSAPUBKEY structure.
+ RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pKeyBlob + sizeof(PUBLICKEYSTRUC));
+ pRsaPubKey->magic = 0x31415352; // RSA1 // Use public key
+ pRsaPubKey->bitlen = cbLen * 8; // Number of bits in the modulus.
+ pRsaPubKey->pubexp = exponent; // Exponent.
+
+ // Copy the modulus into the blob. Put the modulus directly after the
+ // RSAPUBKEY structure in the blob.
+ BYTE *pKey = (BYTE*)(((BYTE *)pRsaPubKey) + sizeof(RSAPUBKEY));
+ //pKeyBlob + sizeof(BLOBHEADER)+ sizeof(RSAPUBKEY);
+ memcpy(pKey, pbBuffer, cbLen);
+
+ // Now import public key
+ if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey))
+ {
+ result = GetLastError();
+ goto exit;
+ }
+
+ DWORD dataSize = (DWORD)mir_strlen(data);
+
+ // if data is not allocated just renurn size
+ if (encryptedData == nullptr)
+ {
+ // get length of encrypted data
+ if (!CryptEncrypt(phKey, 0, TRUE, 0, nullptr, &encryptedSize, dataSize))
+ result = GetLastError();
+ goto exit;
+ }
+
+ // encrypt password
+ memcpy(encryptedData, data, dataSize);
+ if (!CryptEncrypt(phKey, 0, TRUE, 0, encryptedData, &dataSize, encryptedSize))
+ {
+ result = GetLastError();
+ goto exit;
+ }
+
+ // reverse byte array again
+ for (int i = 0; i < (int)(encryptedSize / 2); ++i)
+ {
+ BYTE temp = encryptedData[encryptedSize - i - 1];
+ encryptedData[encryptedSize - i - 1] = encryptedData[i];
+ encryptedData[i] = temp;
+ }
+
+exit:
+ if (pKeyBlob)
+ free(pKeyBlob);
+ if (phKey)
+ CryptDestroyKey(phKey);
+
+ if (pbBuffer)
+ free(pbBuffer);
+ if (hCSP)
+ CryptReleaseContext(hCSP, 0);
+
+ return 0;
+}
diff --git a/protocols/Steam/src/steam_dialogs.cpp b/protocols/Steam/src/steam_dialogs.cpp
index 0565040d8d..b3731551b0 100644
--- a/protocols/Steam/src/steam_dialogs.cpp
+++ b/protocols/Steam/src/steam_dialogs.cpp
@@ -20,11 +20,9 @@ void CSteamPasswordEditor::OnInitDialog()
void CSteamPasswordEditor::OnOk(CCtrlButton*)
{
- if (m_proto->password != nullptr)
- mir_free(m_proto->password);
- m_proto->password = m_password.GetText();
+ m_proto->m_password = m_password.GetText();
if (m_savePermanently.Enabled())
- m_proto->setWString("Password", m_proto->password);
+ m_proto->setWString("Password", m_proto->m_password);
EndDialog(m_hwnd, DIALOG_RESULT_OK);
}
diff --git a/protocols/Steam/src/steam_events.cpp b/protocols/Steam/src/steam_events.cpp
index ef2d59ed40..0a5f7d4fde 100644
--- a/protocols/Steam/src/steam_events.cpp
+++ b/protocols/Steam/src/steam_events.cpp
@@ -69,7 +69,7 @@ int CSteamProto::OnIdleChanged(WPARAM, LPARAM lParam)
Idle_GetInfo(mii);
// Compute time when user really became idle
- m_idleTS = time(nullptr) - mii.idleTime * 60;
+ m_idleTS = now() - mii.idleTime * 60;
setDword("IdleTS", m_idleTS);
}
else
diff --git a/protocols/Steam/src/steam_history.cpp b/protocols/Steam/src/steam_history.cpp
index a897037bae..a7f0d22e61 100644
--- a/protocols/Steam/src/steam_history.cpp
+++ b/protocols/Steam/src/steam_history.cpp
@@ -54,7 +54,7 @@ void CSteamProto::OnGotHistoryMessages(const JSONNode &root, void *arg)
JSONNode message = messages[i - 1];
long long accountId = _wtoi64(message["accountid"].as_mstring());
- const char *authorSteamId = AccountIdToSteamId(accountId);
+ const char *steamId = AccountIdToSteamId(accountId);
json_string text = message["message"].as_string();
@@ -68,13 +68,11 @@ void CSteamProto::OnGotHistoryMessages(const JSONNode &root, void *arg)
recv.timestamp = timestamp;
recv.szMessage = (char*)text.c_str();
- MCONTACT hContact = FindContact(cSteamId);
+ MCONTACT hContact = GetContact(cSteamId);
if (!hContact)
return;
- // Self SteamID
- ptrA steamId(getStringA("SteamID"));
- if (strcmp(steamId, authorSteamId))
+ if (IsMe(steamId))
{
// Received message
ProtoChainRecvMsg(hContact, &recv);
diff --git a/protocols/Steam/src/steam_instances.cpp b/protocols/Steam/src/steam_instances.cpp
deleted file mode 100644
index b88ada2bb4..0000000000
--- a/protocols/Steam/src/steam_instances.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include "stdafx.h"
-
-int CSteamProto::CompareProtos(const CSteamProto *p1, const CSteamProto *p2)
-{
- return lstrcmp(p1->m_tszUserName, p2->m_tszUserName);
-}
-
-LIST<CSteamProto> CSteamProto::InstanceList(1, CSteamProto::CompareProtos);
-
-CSteamProto* CSteamProto::InitProtoInstance(const char* protoName, const wchar_t* userName)
-{
- CSteamProto *ppro = new CSteamProto(protoName, userName);
- InstanceList.insert(ppro);
-
- return ppro;
-}
-
-int CSteamProto::UninitProtoInstance(CSteamProto* ppro)
-{
- InstanceList.remove(ppro);
- delete ppro;
-
- return 0;
-}
-
-void CSteamProto::UninitProtoInstances()
-{
- for (int i = InstanceList.getCount(); i > 0; i--)
- UninitProtoInstance(InstanceList[i]);
- InstanceList.destroy();
-}
-
-CSteamProto* CSteamProto::GetContactProtoInstance(MCONTACT hContact)
-{
- char *proto = GetContactProto(hContact);
- if (proto == nullptr)
- return nullptr;
-
- for (int i = 0; i < InstanceList.getCount(); i++)
- if (!mir_strcmp(proto, InstanceList[i]->m_szModuleName))
- return InstanceList[i];
-
- return nullptr;
-} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp
index def14a9d26..773556e84b 100644
--- a/protocols/Steam/src/steam_login.cpp
+++ b/protocols/Steam/src/steam_login.cpp
@@ -8,79 +8,39 @@ bool CSteamProto::IsOnline()
bool CSteamProto::IsMe(const char *steamId)
{
ptrA mySteamId(getStringA("SteamID"));
- if (!lstrcmpA(steamId, mySteamId))
- return true;
-
- return false;
+ return mir_strcmp(steamId, mySteamId) == 0;
}
void CSteamProto::Login()
{
ptrA token(getStringA("TokenSecret"));
ptrA sessionId(getStringA("SessionID"));
- if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0)
- {
+ if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0) {
PushRequest(
new LogonRequest(token),
&CSteamProto::OnLoggedOn);
+ return;
}
- else
- {
- T2Utf username(getWStringA("Username"));
- if (username == NULL)
- {
- SetStatus(ID_STATUS_OFFLINE);
- return;
- }
-
- PushRequest(
- new GetRsaKeyRequest(username),
- &CSteamProto::OnGotRsaKey);
- }
-}
-
-bool CSteamProto::Relogin()
-{
- ptrA token(getStringA("TokenSecret"));
- if (mir_strlen(token) <= 0)
- return false;
-
- HttpRequest *request = new LogonRequest(token);
- HttpResponse *response = SendRequest(request);
-
- bool success = false;
- if (response)
- {
- JSONNode root = JSONNode::parse(response->Content);
- if (root.isnull()) {
- json_string error = root["error"].as_string();
- if (!mir_strcmpi(error.c_str(), "OK"))
- {
- json_string umqId = root["umqid"].as_string();
- setString("UMQID", umqId.c_str());
-
- long messageId = root["message"].as_int();
- setDword("MessageID", messageId);
-
- success = true;
- }
- }
+
+ T2Utf username(getWStringA("Username"));
+ if (username == NULL) {
+ SetStatus(ID_STATUS_OFFLINE);
+ return;
}
- delete response;
-
- return success;
+ PushRequest(
+ new GetRsaKeyRequest(username),
+ &CSteamProto::OnGotRsaKey);
}
-void CSteamProto::LogOut()
+void CSteamProto::Logout()
{
- isTerminated = true;
+ m_isTerminated = true;
if (m_hRequestQueueThread)
SetEvent(m_hRequestsQueueEvent);
ptrA token(getStringA("TokenSecret"));
- if (mir_strlen(token) > 0)
- {
+ if (mir_strlen(token) > 0) {
ptrA umqid(getStringA("UMQID"));
SendRequest(new LogoffRequest(token, umqid));
}
@@ -88,14 +48,12 @@ void CSteamProto::LogOut()
void CSteamProto::OnGotRsaKey(const JSONNode &root, void*)
{
- if (root.isnull())
- {
+ if (root.isnull()) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
- if (!root["success"].as_bool())
- {
+ if (!root["success"].as_bool()) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
@@ -113,16 +71,14 @@ void CSteamProto::OnGotRsaKey(const JSONNode &root, void*)
DWORD error = 0;
DWORD encryptedSize = 0;
- if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, nullptr, encryptedSize)) != 0)
- {
+ if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, nullptr, encryptedSize)) != 0) {
debugLogA(__FUNCTION__ ": encryption error (%lu)", error);
SetStatus(ID_STATUS_OFFLINE);
return;
}
BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize);
- if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, encryptedPassword, encryptedSize)) != 0)
- {
+ if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, encryptedPassword, encryptedSize)) != 0) {
debugLogA(__FUNCTION__ ": encryption error (%lu)", error);
SetStatus(ID_STATUS_OFFLINE);
return;
@@ -135,20 +91,26 @@ void CSteamProto::OnGotRsaKey(const JSONNode &root, void*)
T2Utf username(getWStringA("Username"));
ptrA twoFactorCode(getStringA("TwoFactorCode"));
- if (!twoFactorCode) twoFactorCode = mir_strdup("");
+ if (!twoFactorCode)
+ twoFactorCode = mir_strdup("");
ptrA guardId(getStringA("GuardId"));
- if (!guardId) guardId = mir_strdup("");
+ if (!guardId)
+ guardId = mir_strdup("");
ptrA guardCode(getStringA("GuardCode"));
- if (!guardCode) guardCode = mir_strdup("");
+ if (!guardCode)
+ guardCode = mir_strdup("");
ptrA captchaId(getStringA("CaptchaId"));
- if (!captchaId) captchaId = mir_strdup("-1");
+ if (!captchaId)
+ captchaId = mir_strdup("-1");
ptrA captchaText(getStringA("CaptchaText"));
- if (!captchaText) captchaText = mir_strdup("");
+ if (!captchaText)
+ captchaText = mir_strdup("");
PushRequest(
- new AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp.c_str(), twoFactorCode, guardCode, guardId, captchaId, captchaText),
+ new AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp.c_str(), twoFactorCode,
+ guardCode, guardId, captchaId, captchaText),
&CSteamProto::OnAuthorization);
}
@@ -156,15 +118,13 @@ void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg)
{
ptrA captchaId((char*)arg);
- if (!response.IsSuccess())
- {
+ if (!response.IsSuccess()) {
debugLogA(__FUNCTION__ ": failed to get captcha");
return;
}
CSteamCaptchaDialog captchaDialog(this, (BYTE*)response.Content.GetData(), response.Content.GetSize());
- if (captchaDialog.DoModal() != DIALOG_RESULT_OK)
- {
+ if (captchaDialog.DoModal() != DIALOG_RESULT_OK) {
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
return;
@@ -181,21 +141,18 @@ void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg)
void CSteamProto::OnAuthorization(const HttpResponse &response, void*)
{
- if (!response)
- {
+ if (!response) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
JSONNode root = JSONNode::parse(response.Content);
- if (root.isnull())
- {
+ if (root.isnull()) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
- if (!root["success"].as_bool())
- {
+ if (!root["success"].as_bool()) {
OnAuthorizationError(root);
return;
}
@@ -215,24 +172,33 @@ void CSteamProto::DeleteAuthSettings()
void CSteamProto::OnAuthorizationError(const JSONNode &root)
{
CMStringW message = root["message"].as_mstring();
- debugLogA(__FUNCTION__ ": %s", _T2A(message.GetBuffer()));
- if (!mir_wstrcmpi(message, L"Incorrect login."))
- {
+ if (message == L"Incorrect login.") {
// We can't continue with incorrect login/password
+ debugLogA(__FUNCTION__ ": incorrect login");
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
+ ShowNotification(message);
+ return;
+ }
+
+ if (root["clear_password_field"].as_bool()) {
+ // describes if the password field was cleared. This can also be true if the twofactor code was wrong
+ debugLogA(__FUNCTION__ ": clear password field");
+ delSetting("Passowrd"); // experiment
+ delSetting("TwoFactorCode");
+ SetStatus(ID_STATUS_OFFLINE);
+ ShowNotification(message);
return;
}
T2Utf username(getWStringA("Username"));
- if (root["requires_twofactor"].as_bool())
- {
+ if (root["requires_twofactor"].as_bool()) {
debugLogA(__FUNCTION__ ": requires twofactor");
+ delSetting("TwoFactorCode");
CSteamTwoFactorDialog twoFactorDialog(this);
- if (twoFactorDialog.DoModal() != DIALOG_RESULT_OK)
- {
+ if (twoFactorDialog.DoModal() != DIALOG_RESULT_OK) {
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
return;
@@ -246,40 +212,24 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root)
return;
}
- if (root["clear_password_field"].as_bool())
- {
- debugLogA(__FUNCTION__ ": clear password field");
- // describes if the password field was cleared. This can also be true if the twofactor code was wrong
- DeleteAuthSettings();
- SetStatus(ID_STATUS_OFFLINE);
- return;
- }
-
- if (root["emailauth_needed"].as_bool())
- {
+ if (root["emailauth_needed"].as_bool()) {
debugLogA(__FUNCTION__ ": emailauth needed");
std::string guardId = root["emailsteamid"].as_string();
ptrA oldGuardId(getStringA("GuardId"));
- if (mir_strcmp(guardId.c_str(), oldGuardId) == 0)
- {
+ if (mir_strcmp(guardId.c_str(), oldGuardId) == 0) {
delSetting("GuardId");
delSetting("GuardCode");
- PushRequest(
- new GetRsaKeyRequest(username),
- &CSteamProto::OnGotRsaKey);
- return;
}
- std::string domain = root["emaildomain"].as_string();
+ json_string domain = root["emaildomain"].as_string();
// Make absolute link
if (domain.find("://") == std::string::npos)
domain = "http://" + domain;
CSteamGuardDialog guardDialog(this, domain.c_str());
- if (guardDialog.DoModal() != DIALOG_RESULT_OK)
- {
+ if (guardDialog.DoModal() != DIALOG_RESULT_OK) {
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
return;
@@ -294,10 +244,11 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root)
return;
}
- if (root["captcha_needed"].as_bool())
- {
+ if (root["captcha_needed"].as_bool()) {
debugLogA(__FUNCTION__ ": captcha needed");
- std::string captchaId = root["captcha_gid"].as_string();
+ delSetting("CaptchaId");
+ delSetting("CaptchaText");
+ json_string captchaId = root["captcha_gid"].as_string();
PushRequest(
new GetCaptchaRequest(captchaId.c_str()),
&CSteamProto::OnGotCaptcha,
@@ -305,44 +256,36 @@ void CSteamProto::OnAuthorizationError(const JSONNode &root)
return;
}
+ // unhadled error
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
- ShowNotification(L"Steam", message);
+ ShowNotification(message);
}
void CSteamProto::OnAuthorizationSuccess(const JSONNode &root)
{
DeleteAuthSettings();
- if (!root["login_complete"].as_bool())
- {
+ if (!root["login_complete"].as_bool()) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
- std::string oauth = root["oauth"].as_string();
+ json_string oauth = root["oauth"].as_string();
JSONNode node = JSONNode::parse(oauth.c_str());
- if (node.isnull())
- {
+ if (node.isnull()) {
SetStatus(ID_STATUS_OFFLINE);
return;
}
- std::string steamId = node["steamid"].as_string();
+ json_string steamId = node["steamid"].as_string();
setString("SteamID", steamId.c_str());
- std::string token = node["oauth_token"].as_string();
+ json_string token = node["oauth_token"].as_string();
setString("TokenSecret", token.c_str());
- std::string cookie = node["webcookie"].as_string();
-
- SendRequest(
- new GetSessionRequest(token.c_str(), steamId.c_str(), cookie.c_str()),
- &CSteamProto::OnGotSession);
-
- // We need to load homepage to get sessionid cookie
SendRequest(
- new GetSessionRequest2(),
+ new GetSessionRequest2(token.c_str(), steamId.c_str()),
&CSteamProto::OnGotSession);
PushRequest(
@@ -352,12 +295,13 @@ void CSteamProto::OnAuthorizationSuccess(const JSONNode &root)
void CSteamProto::OnGotSession(const HttpResponse &response, void*)
{
- if (!response)
+ if (!response) {
+ debugLogA(__FUNCTION__ ": failed to get session id");
return;
+ }
- for (size_t i = 0; i < response.Headers.GetSize(); i++)
- {
- if (lstrcmpiA(response.Headers[i]->szName, "Set-Cookie"))
+ for (size_t i = 0; i < response.Headers.GetSize(); i++) {
+ if (mir_strcmpi(response.Headers[i]->szName, "Set-Cookie"))
continue;
std::string cookies = response.Headers[i]->szValue;
@@ -378,48 +322,38 @@ void CSteamProto::HandleTokenExpired()
if (isLoginAgain) {
// Notify error to user
debugLogA(__FUNCTION__ ": cannot obtain connection token");
- ShowNotification(L"Steam", TranslateT("Cannot obtain connection token."));
+ ShowNotification(TranslateT("Cannot obtain connection token."));
// Just go offline; it also resets the isLoginAgain to false
SetStatus(ID_STATUS_OFFLINE);
+ return;
}
- else
- {
- // Remember we are trying to relogin
- isLoginAgain = true;
-
- // Remember status user wanted
- int desiredStatus = m_iDesiredStatus;
- // Set status to offline
- SetStatus(ID_STATUS_OFFLINE);
+ // Remember we are trying to relogin
+ isLoginAgain = true;
- // Try to login again automatically
- SetStatus(desiredStatus);
- }
+ Login();
+ return;
}
void CSteamProto::OnLoggedOn(const HttpResponse &response, void*)
{
- if (!response.IsSuccess())
- {
+ if (!response.IsSuccess()) {
// Probably timeout or no connection, we can do nothing here
debugLogA(__FUNCTION__ ": unknown login error");
- ShowNotification(L"Steam", TranslateT("Unknown login error."));
+ ShowNotification(TranslateT("Unknown login error."));
SetStatus(ID_STATUS_OFFLINE);
return;
}
- if (response.GetStatusCode() == HTTP_CODE_UNAUTHORIZED)
- {
+ if (response.GetStatusCode() == HTTP_CODE_UNAUTHORIZED) {
// Probably expired TokenSecret
HandleTokenExpired();
return;
}
JSONNode root = JSONNode::parse(response.Content);
- CMStringW error = root["error"].as_mstring();
- if (mir_wstrcmpi(error, L"OK"))
- {
+ json_string error = root["error"].as_string();
+ if (error != "OK") {
// Probably expired TokenSecret
HandleTokenExpired();
return;
@@ -431,8 +365,7 @@ void CSteamProto::OnLoggedOn(const HttpResponse &response, void*)
long messageId = root["umqid"].as_int();
setDword("MessageID", messageId);
- if (m_lastMessageTS <= 0)
- {
+ if (m_lastMessageTS <= 0) {
time_t timestamp = _wtoi64(root["utc_timestamp"].as_mstring());
setDword("LastMessageTS", timestamp);
}
@@ -441,6 +374,10 @@ void CSteamProto::OnLoggedOn(const HttpResponse &response, void*)
ptrA token(getStringA("TokenSecret"));
ptrA steamId(getStringA("SteamID"));
+ SendRequest(
+ new GetSessionRequest2(token, steamId),
+ &CSteamProto::OnGotSession);
+
// send this request immediately, so we can start polling thread with already loaded all contacts
SendRequest(
new GetFriendListRequest(token, steamId),
@@ -452,3 +389,23 @@ void CSteamProto::OnLoggedOn(const HttpResponse &response, void*)
// start polling thread
m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, nullptr, nullptr);
}
+
+void CSteamProto::OnReLogin(const JSONNode &root, void*)
+{
+ if (root.isnull()) {
+ SetStatus(ID_STATUS_OFFLINE);
+ return;
+ }
+
+ json_string error = root["error"].as_string();
+ if (error != "OK") {
+ SetStatus(ID_STATUS_OFFLINE);
+ return;
+ }
+
+ json_string umqId = root["umqid"].as_string();
+ setString("UMQID", umqId.c_str());
+
+ long messageId = root["message"].as_int();
+ setDword("MessageID", messageId);
+} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_menus.cpp b/protocols/Steam/src/steam_menus.cpp
index 98b86f333c..2387f19f9d 100644
--- a/protocols/Steam/src/steam_menus.cpp
+++ b/protocols/Steam/src/steam_menus.cpp
@@ -6,21 +6,27 @@ HGENMENU CSteamProto::contactMenuItems[CMI_MAX];
template<int(__cdecl CSteamProto::*Service)(WPARAM, LPARAM)>
INT_PTR GlobalService(WPARAM wParam, LPARAM lParam)
{
- CSteamProto *ppro = CSteamProto::GetContactProtoInstance((MCONTACT)wParam);
+ CSteamProto *ppro = CSteamProto::GetContactAccount((MCONTACT)wParam);
return ppro ? (ppro->*Service)(wParam, lParam) : 0;
}
-INT_PTR CSteamProto::MenuChooseService(WPARAM wParam, LPARAM lParam)
+int CSteamProto::AuthRequestCommand(WPARAM hContact, LPARAM)
{
- if (lParam)
- *(void**)lParam = (void*)wParam;
+ ProtoChainSend(hContact, PSS_AUTHREQUEST, 0, 0);
return 0;
}
-int CSteamProto::AuthRequestCommand(WPARAM hContact, LPARAM)
+int CSteamProto::AuthRevokeCommand(WPARAM hContact, LPARAM)
{
- ProtoChainSend(hContact, PSS_AUTHREQUEST, 0, 0);
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+ PushRequest(
+ new RemoveFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendRemoved,
+ (void*)who);
return 0;
}
@@ -40,12 +46,28 @@ int CSteamProto::BlockCommand(WPARAM hContact, LPARAM)
return 0;
}
+int CSteamProto::UnblockCommand(WPARAM hContact, LPARAM)
+{
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new UnblockFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendUnblocked,
+ who);
+
+ return 0;
+}
+
int CSteamProto::JoinToGameCommand(WPARAM hContact, LPARAM)
{
char url[MAX_PATH];
DWORD gameId = getDword(hContact, "GameID", 0);
mir_snprintf(url, "steam://rungameid/%lu", gameId);
Utils_OpenUrl(url);
+
return 0;
}
@@ -53,7 +75,6 @@ INT_PTR CSteamProto::OpenBlockListCommand(WPARAM, LPARAM)
{
ptrA token(getStringA("TokenSecret"));
ptrA steamId(getStringA("SteamID"));
-
PushRequest(
new GetFriendListRequest(token, steamId, "ignoredfriend"),
&CSteamProto::OnGotBlockList);
@@ -67,29 +88,31 @@ int CSteamProto::OnPrebuildContactMenu(WPARAM wParam, LPARAM)
if (!hContact)
return 0;
- if (!this->IsOnline() || lstrcmpA(GetContactProto(hContact), m_szModuleName))
+ if (!IsOnline() || mir_strcmp(GetContactProto(hContact), m_szModuleName))
return 0;
- //bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
+ bool ctrlPressed = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
bool authNeeded = getBool(hContact, "Auth", 0);
- Menu_ShowItem(contactMenuItems[CMI_AUTH_REQUEST], authNeeded);
+ Menu_ShowItem(contactMenuItems[CMI_AUTH_REQUEST], authNeeded || ctrlPressed);
+ Menu_ShowItem(contactMenuItems[CMI_AUTH_REVOKE], !authNeeded || ctrlPressed);
bool isBlocked = getBool(hContact, "Block", 0);
- Menu_ShowItem(contactMenuItems[CMI_BLOCK], !isBlocked);
+ Menu_ShowItem(contactMenuItems[CMI_BLOCK], !isBlocked || ctrlPressed);
+ Menu_ShowItem(contactMenuItems[CMI_UNBLOCK], isBlocked || ctrlPressed);
DWORD gameId = getDword(hContact, "GameID", 0);
- Menu_ShowItem(contactMenuItems[CMI_JOIN_GAME], gameId > 0);
+ Menu_ShowItem(contactMenuItems[CMI_JOIN_GAME], gameId || ctrlPressed);
return 0;
}
int CSteamProto::PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
{
- for (int i = 0; i < _countof(CSteamProto::contactMenuItems); i++)
+ for (int i = 0; i < CMI_MAX; i++)
Menu_ShowItem(CSteamProto::contactMenuItems[i], false);
- CSteamProto* ppro = CSteamProto::GetContactProtoInstance((MCONTACT)wParam);
+ CSteamProto* ppro = CSteamProto::GetContactAccount((MCONTACT)wParam);
return (ppro) ? ppro->OnPrebuildContactMenu(wParam, lParam) : 0;
}
@@ -100,11 +123,11 @@ void CSteamProto::OnInitStatusMenu()
mi.root = Menu_GetProtocolRoot(this);
// Show block list
- mi.pszService = "/BlockList";
- CreateProtoService(mi.pszService, &CSteamProto::OpenBlockListCommand);
- mi.name.w = LPGENW("Blocked contacts");
- mi.position = 200000 + SMI_BLOCKED_LIST;
- Menu_AddProtoMenuItem(&mi, m_szModuleName);
+ //mi.pszService = "/BlockList";
+ //CreateProtoService(mi.pszService, &CSteamProto::OpenBlockListCommand);
+ //mi.name.w = LPGENW("Blocked contacts");
+ //mi.position = 200000 + SMI_BLOCKED_LIST;
+ //Menu_AddProtoMenuItem(&mi, m_szModuleName);
}
void CSteamProto::InitMenus()
@@ -125,15 +148,33 @@ void CSteamProto::InitMenus()
contactMenuItems[CMI_AUTH_REQUEST] = Menu_AddContactMenuItem(&mi);
CreateServiceFunction(mi.pszService, GlobalService<&CSteamProto::AuthRequestCommand>);
+ // "Revoke authorization"
+ SET_UID(mi, 0x619efdcb, 0x99c0, 0x44a8, 0xbf, 0x28, 0xc3, 0xe0, 0x2f, 0xb3, 0x7e, 0x77);
+ mi.pszService = MODULE "/RevokeAuth";
+ mi.name.w = LPGENW("Revoke authorization");
+ mi.position = -201001001 + CMI_AUTH_REVOKE;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_AUTH_REVOKE);
+ contactMenuItems[CMI_AUTH_REVOKE] = Menu_AddContactMenuItem(&mi);
+ CreateServiceFunction(mi.pszService, GlobalService<&CSteamProto::AuthRevokeCommand>);
+
// "Block"
SET_UID(mi, 0xc6169b8f, 0x53ab, 0x4242, 0xbe, 0x90, 0xe2, 0x4a, 0xa5, 0x73, 0x88, 0x32);
mi.pszService = MODULE "/Block";
mi.name.w = LPGENW("Block");
mi.position = -201001001 + CMI_BLOCK;
- mi.hIcolibItem = Skin_GetIconHandle(SKINICON_AUTH_REQUEST);
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_OFF);
contactMenuItems[CMI_BLOCK] = Menu_AddContactMenuItem(&mi);
CreateServiceFunction(mi.pszService, GlobalService<&CSteamProto::BlockCommand>);
+ // "Unblock"
+ SET_UID(mi, 0xc6169b8f, 0x53ab, 0x4242, 0xbe, 0x90, 0xe2, 0x4a, 0xa5, 0x73, 0x88, 0x32);
+ mi.pszService = MODULE "/Unblock";
+ mi.name.w = LPGENW("Unblock");
+ mi.position = -201001001 + CMI_UNBLOCK;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_ON);
+ contactMenuItems[CMI_UNBLOCK] = Menu_AddContactMenuItem(&mi);
+ CreateServiceFunction(mi.pszService, GlobalService<&CSteamProto::UnblockCommand>);
+
mi.flags |= CMIF_NOTOFFLINE;
// "Join to game"
@@ -145,10 +186,3 @@ void CSteamProto::InitMenus()
contactMenuItems[CMI_JOIN_GAME] = Menu_AddContactMenuItem(&mi);
CreateServiceFunction(mi.pszService, GlobalService<&CSteamProto::JoinToGameCommand>);
}
-
-void CSteamProto::UninitMenus()
-{
- Menu_RemoveItem(contactMenuItems[CMI_AUTH_REQUEST]);
- Menu_RemoveItem(contactMenuItems[CMI_BLOCK]);
- Menu_RemoveItem(contactMenuItems[CMI_JOIN_GAME]);
-}
diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp
index a4c8ebee94..e4d90643be 100644
--- a/protocols/Steam/src/steam_messages.cpp
+++ b/protocols/Steam/src/steam_messages.cpp
@@ -4,7 +4,6 @@ struct SendMessageParam
{
MCONTACT hContact;
HANDLE hMessage;
- char *message;
};
int CSteamProto::OnSendMessage(MCONTACT hContact, const char *message)
@@ -14,7 +13,6 @@ int CSteamProto::OnSendMessage(MCONTACT hContact, const char *message)
SendMessageParam *param = (SendMessageParam*)mir_calloc(sizeof(SendMessageParam));
param->hContact = hContact;
param->hMessage = (HANDLE)hMessage;
- param->message = mir_strdup(message);
ptrA token(getStringA("TokenSecret"));
ptrA umqid(getStringA("UMQID"));
@@ -66,7 +64,6 @@ void CSteamProto::OnMessageSent(const HttpResponse &response, void *arg)
ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hMessage, 0);
}
- mir_free(param->message);
mir_free(param);
}
@@ -89,13 +86,13 @@ int CSteamProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
int CSteamProto::UserIsTyping(MCONTACT hContact, int type)
{
// NOTE: Steam doesn't support sending "user stopped typing" so we're sending only positive info
- if (hContact && IsOnline() && type == PROTOTYPE_SELFTYPING_ON)
- {
- ptrA token(getStringA("TokenSecret"));
- ptrA umqid(getStringA("UMQID"));
- ptrA steamId(getStringA(hContact, "SteamID"));
- PushRequest(new SendTypingRequest(token, umqid, steamId));
- }
+ if (type == PROTOTYPE_SELFTYPING_OFF)
+ return 0;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA umqid(getStringA("UMQID"));
+ ptrA steamId(getStringA(hContact, "SteamID"));
+ PushRequest(new SendTypingRequest(token, umqid, steamId));
return 0;
}
diff --git a/protocols/Steam/src/steam_options.cpp b/protocols/Steam/src/steam_options.cpp
index ea55af1147..c5898bea86 100644
--- a/protocols/Steam/src/steam_options.cpp
+++ b/protocols/Steam/src/steam_options.cpp
@@ -25,9 +25,11 @@ void CSteamOptionsMain::OnInitDialog()
void CSteamOptionsMain::OnApply()
{
- wchar_t *group = m_group.GetText();
- if (mir_wstrlen(group) > 0 && !Clist_GroupExists(group))
+ ptrW group(m_group.GetText());
+ if (mir_wstrcmp(group, m_proto->m_defaultGroup)) {
+ m_proto->m_defaultGroup = mir_wstrdup(group);
Clist_GroupCreate(0, group);
+ }
if (m_proto->IsOnline())
{
diff --git a/protocols/Steam/src/steam_polling.cpp b/protocols/Steam/src/steam_polling.cpp
index 182f9df783..26c5c63e88 100644
--- a/protocols/Steam/src/steam_polling.cpp
+++ b/protocols/Steam/src/steam_polling.cpp
@@ -4,21 +4,17 @@
void CSteamProto::ParsePollData(const JSONNode &data)
{
- std::string steamIds;
- for (const JSONNode &item : data)
- {
+ for (const JSONNode &item : data) {
json_string steamId = item["steamid_from"].as_string();
time_t timestamp = _wtol(item["utc_timestamp"].as_mstring());
MCONTACT hContact = NULL;
- if (!IsMe(steamId.c_str()) && !(hContact = FindContact(steamId.c_str())))
+ if (!IsMe(steamId.c_str()) && !(hContact = GetContact(steamId.c_str())))
// probably this is info about random player playing on same server, so we ignore it
continue;
json_string type = item["type"].as_string();
- if (!mir_strcmpi(type.c_str(), "my_saytext") ||
- !mir_strcmpi(type.c_str(), "my_emote"))
- {
+ if (type == "my_saytext" || type =="my_emote") {
json_string text = item["text"].as_string();
PROTORECVEVENT recv = { 0 };
@@ -27,9 +23,7 @@ void CSteamProto::ParsePollData(const JSONNode &data)
recv.flags = PREF_SENT;
Proto_RecvMessage(hContact, &recv);
}
- else if (!mir_strcmpi(type.c_str(), "saytext") ||
- !mir_strcmpi(type.c_str(), "emote"))
- {
+ else if (type == "saytext" || type =="emote") {
json_string text = item["text"].as_string();
PROTORECVEVENT recv = { 0 };
@@ -40,81 +34,70 @@ void CSteamProto::ParsePollData(const JSONNode &data)
CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
m_typingTimestamps[steamId] = 0;
}
- else if (!mir_strcmpi(type.c_str(), "typing") && hContact)
- {
+ else if (type == "typing") {
auto it = m_typingTimestamps.find(steamId);
- if (it != m_typingTimestamps.end())
- {
+ if (it != m_typingTimestamps.end()) {
if ((timestamp - it->second) < STEAM_TYPING_TIME)
continue;
}
CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)STEAM_TYPING_TIME);
m_typingTimestamps[steamId] = timestamp;
}
- else if (!mir_strcmpi(type.c_str(), "personastate"))
- {
- JSONNode node = item["persona_state"];
- int status = !node.isnull()
- ? SteamToMirandaStatus(node.as_int())
- : -1;
-
- if (IsMe(steamId.c_str()))
- {
- if (status == -1 || status == ID_STATUS_OFFLINE)
- continue;
- SetStatus(status);
- continue;
+ else if (type == "personastate") {
+ if (!IsMe(steamId.c_str())) {
+ // there no sense to change own status
+ JSONNode node = item["persona_state"];
+ if (!node.isnull()) {
+ int status = SteamToMirandaStatus((PersonaState)node.as_int());
+ SetContactStatus(hContact, status);
+ }
}
-
- if (status != -1)
- SetContactStatus(hContact, status);
- // todo: find difference between state changing and info changing
- steamIds.append(steamId).append(",");
+ int statusFlags = item["status_flags"].as_int();
+ if ((statusFlags & PersonaStatusFlag::PlayerName) == PersonaStatusFlag::PlayerName) {
+ CMStringW nick = item["persona_name"].as_mstring();
+ if (!nick.IsEmpty())
+ setWString(hContact, "Nick", nick);
+ }
}
- else if (!mir_strcmpi(type.c_str(), "personarelationship"))
- {
+ else if (type == "personarelationship") {
int state = item["persona_state"].as_int();
- switch (state)
- {
- case 0:
- hContact = FindContact(steamId.c_str());
+ switch (state) {
+ case PersonaRelationshipAction::Remove:
+ hContact = GetContact(steamId.c_str());
if (hContact)
ContactIsRemoved(hContact);
break;
- case 1:
- hContact = FindContact(steamId.c_str());
+ case PersonaRelationshipAction::Ignore:
+ hContact = GetContact(steamId.c_str());
if (hContact)
- ContactIsIgnored(hContact);
+ ContactIsBlocked(hContact);
break;
- case 2:
- // auth request
- hContact = FindContact(steamId.c_str());
+ case PersonaRelationshipAction::AuthRequest:
+ hContact = GetContact(steamId.c_str());
if (hContact)
ContactIsAskingAuth(hContact);
- else
- {
+ else {
// load info about this user from server
ptrA token(getStringA("TokenSecret"));
-
PushRequest(
new GetUserSummariesRequest(token, steamId.c_str()),
&CSteamProto::OnAuthRequested);
}
break;
- case 3:
- // todo: add to list
- break;
+ case PersonaRelationshipAction::AuthRequested:
+ hContact = GetContact(steamId.c_str());
+ if (hContact)
+ ContactIsFriend(hContact);
default:
continue;
}
}
- else if (!mir_strcmpi(type.c_str(), "leftconversation") && hContact)
- {
+ else if (type == "leftconversation") {
if (!getBool("ShowChatEvents", true))
continue;
@@ -124,26 +107,24 @@ void CSteamProto::ParsePollData(const JSONNode &data)
dbei.cbBlob = 1;
dbei.eventType = EVENTTYPE_STEAM_CHATSTATES;
dbei.flags = DBEF_READ;
- dbei.timestamp = time(nullptr);
+ dbei.timestamp = now();
dbei.szModule = m_szModuleName;
db_event_add(hContact, &dbei);
}
- else
- {
+ else {
debugLogA(__FUNCTION__ ": Unknown event type \"%s\"", type.c_str());
continue;
}
}
- if (!steamIds.empty())
- {
+ /*if (!steamIds.empty()) {
steamIds.pop_back();
- ptrA token(getStringA("TokenSecret"));
+ ptrA token(getStringA("TokenSecret"));
PushRequest(
new GetUserSummariesRequest(token, steamIds.c_str()),
&CSteamProto::OnGotUserSummaries);
- }
+ }*/
}
struct PollParam
@@ -172,8 +153,10 @@ void CSteamProto::OnGotPoll(const HttpResponse &response, void *arg)
if (!mir_strcmpi(error.c_str(), "Timeout"))
{
// Do nothing as this is not necessarily an error
+ return;
}
- else if (!mir_strcmpi(error.c_str(), "OK"))
+
+ if (!mir_strcmpi(error.c_str(), "OK"))
{
// Remember last message timestamp
time_t timestamp = _wtoi64(root["utc_timestamp"].as_mstring());
@@ -197,10 +180,12 @@ void CSteamProto::OnGotPoll(const HttpResponse &response, void *arg)
debugLogA(__FUNCTION__ ": Not Logged On");
// try to reconnect only when we're actually online (during normal logout we will still got this error anyway, but in that case our status is already offline)
- if (!IsOnline() || !Relogin())
+ if (IsOnline())
{
- // let it jump out of further processing
- param->errors = param->errorsLimit;
+ ptrA token(getStringA("TokenSecret"));
+ SendRequest(
+ new LogonRequest(token),
+ &CSteamProto::OnReLogin);
}
}
else
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index 52022b10d5..b3ba3024bc 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -2,17 +2,22 @@
CSteamProto::CSteamProto(const char* protoName, const wchar_t* userName)
: PROTO<CSteamProto>(protoName, userName),
- requestQueue(1), hAuthProcess(1), hMessageProcess(1)
+ m_requestQueue(1), hAuthProcess(1), hMessageProcess(1)
{
CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
m_idleTS = 0;
m_lastMessageTS = 0;
isLoginAgain = false;
- m_pollingConnection = nullptr;
m_hPollingThread = nullptr;
m_hRequestsQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ // default group
+ m_defaultGroup = getWStringA("DefaultGroup");
+ if (m_defaultGroup == nullptr)
+ m_defaultGroup = mir_wstrdup(L"Steam");
+ Clist_GroupCreate(0, m_defaultGroup);
+
// icons
wchar_t filePath[MAX_PATH];
GetModuleFileName(g_hInstance, filePath, MAX_PATH);
@@ -48,9 +53,6 @@ CSteamProto::CSteamProto(const char* protoName, const wchar_t* userName)
setAllContactStatuses(ID_STATUS_OFFLINE);
- // services
- CreateServiceFunction(MODULE"/MenuChoose", CSteamProto::MenuChooseService);
-
// avatar API
CreateProtoService(PS_GETAVATARINFO, &CSteamProto::GetAvatarInfo);
CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps);
@@ -91,28 +93,13 @@ CSteamProto::~CSteamProto()
}
}
-MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT* psr)
+MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr)
{
- MCONTACT hContact = NULL;
- ptrA steamId(mir_u2a(psr->id.w));
- if (psr->cbSize == sizeof(PROTOSEARCHRESULT))
- {
- if (!FindContact(steamId))
- {
- //hContact = AddContact(steamId, true);
- //ForkThread(&CSteamProto::UpdateContactsThread, (void*)mir_strdup(steamId));
+ _T2A steamId(psr->id.w);
+ MCONTACT hContact = AddContact(steamId, psr->nick.w, true);
- ptrA token(getStringA("TokenSecret"));
-
- PushRequest(
- new GetUserSummariesRequest(token, steamId),
- &CSteamProto::OnGotUserSummaries);
- }
- }
- else if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT))
- {
+ if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) {
STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr;
- hContact = AddContact(steamId, true);
UpdateContactDetails(hContact, *ssr->data);
}
@@ -121,14 +108,11 @@ MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT* psr)
int CSteamProto::Authorize(MEVENT hDbEvent)
{
- if (IsOnline() && hDbEvent)
- {
+ if (IsOnline() && hDbEvent) {
MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
if (hContact == INVALID_CONTACT_ID)
return 1;
- //ForkThread(&CSteamProto::AuthAllowThread, (void*)hContact);
-
ptrA token(getStringA("TokenSecret"));
ptrA sessionId(getStringA("SessionID"));
ptrA steamId(getStringA("SteamID"));
@@ -145,16 +129,20 @@ int CSteamProto::Authorize(MEVENT hDbEvent)
return 1;
}
+int CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT *pre)
+{
+ // remember to not create this event again, unless authorization status changes again
+ setByte(hContact, "AuthAsked", 1);
+ return Proto_AuthRecv(m_szModuleName, pre);
+}
+
int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
{
- if (IsOnline() && hDbEvent)
- {
+ if (IsOnline() && hDbEvent) {
MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
if (hContact == INVALID_CONTACT_ID)
return 1;
- //ForkThread(&CSteamProto::AuthDenyThread, (void*)hContact);
-
ptrA token(getStringA("TokenSecret"));
ptrA sessionId(getStringA("SessionID"));
ptrA steamId(getStringA("SteamID"));
@@ -173,32 +161,18 @@ int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*)
{
- if (IsOnline() && hContact)
- {
+ if (IsOnline() && hContact) {
UINT hAuth = InterlockedIncrement(&hAuthProcess);
SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam));
param->hContact = hContact;
param->hAuth = (HANDLE)hAuth;
- //ForkThread(&CSteamProto::AddContactThread, param);
-
ptrA token(getStringA("TokenSecret"));
ptrA sessionId(getStringA("SessionID"));
ptrA steamId(getStringA("SteamID"));
ptrA who(getStringA(hContact, "SteamID"));
- /*
- posilame: (kdyz my zadame)
- sessionID MjYzNDM4NDgw
- steamid 76561198166125402
- accept_invite 0
-
- pri uspesnem pozadavku vrati: {"invited":["76561198166125402"],"success":1}
- kdyz nas ignoruje: {"failed_invites":["76561198166125402"],"failed_invites_result":[41],"success":1}
-
- */
-
PushRequest(
new AddFriendRequest(token, sessionId, steamId, who),
&CSteamProto::OnFriendAdded,
@@ -212,8 +186,7 @@ int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*)
DWORD_PTR CSteamProto:: GetCaps(int type, MCONTACT)
{
- switch(type)
- {
+ switch (type) {
case PFLAGNUM_1:
return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
case PFLAGNUM_2:
@@ -249,7 +222,7 @@ HANDLE CSteamProto::SearchBasic(const wchar_t* id)
HANDLE CSteamProto::SearchByName(const wchar_t* nick, const wchar_t* firstName, const wchar_t* lastName)
{
- if (!this->IsOnline())
+ if (!IsOnline())
return nullptr;
// Combine all fields to single text
@@ -257,7 +230,7 @@ HANDLE CSteamProto::SearchByName(const wchar_t* nick, const wchar_t* firstName,
mir_snwprintf(keywordsT, L"%s %s %s", nick, firstName, lastName);
ptrA token(getStringA("TokenSecret"));
- ptrA keywords(mir_utf8encodeW(keywordsT));
+ ptrA keywords(mir_utf8encodeW(rtrimw(keywordsT)));
PushRequest(
new SearchRequest(token, keywords),
@@ -269,8 +242,7 @@ HANDLE CSteamProto::SearchByName(const wchar_t* nick, const wchar_t* firstName,
int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message)
{
- if (!IsOnline())
- {
+ if (!IsOnline()) {
ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, nullptr, (LPARAM)Translate("You cannot send messages when you are offline."));
return 0;
}
@@ -280,11 +252,10 @@ int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message)
int CSteamProto::SetStatus(int new_status)
{
- mir_cslock lock(set_status_lock);
+ mir_cslock lock(m_setStatusLock);
// Routing statuses not supported by Steam
- switch (new_status)
- {
+ switch (new_status) {
case ID_STATUS_OFFLINE:
case ID_STATUS_AWAY:
case ID_STATUS_NA:
@@ -310,8 +281,7 @@ int CSteamProto::SetStatus(int new_status)
int old_status = m_iStatus;
m_iDesiredStatus = new_status;
- if (new_status == ID_STATUS_OFFLINE)
- {
+ if (new_status == ID_STATUS_OFFLINE) {
// Reset relogin flag
isLoginAgain = false;
@@ -320,20 +290,19 @@ int CSteamProto::SetStatus(int new_status)
if (!Miranda_IsTerminated())
setAllContactStatuses(ID_STATUS_OFFLINE);
- LogOut();
+ Logout();
}
- else if (old_status == ID_STATUS_OFFLINE)
- {
+ else if (old_status == ID_STATUS_OFFLINE) {
// Load last message timestamp for correct loading of messages history
m_lastMessageTS = getDword("LastMessageTS", 0);
m_iStatus = ID_STATUS_CONNECTING;
- isTerminated = false;
+ m_isTerminated = false;
- m_hRequestQueueThread = ForkThreadEx(&CSteamProto::RequestQueueThread, NULL, NULL);
+ m_hRequestQueueThread = ForkThreadEx(&CSteamProto::RequestQueueThread, nullptr, nullptr);
-
+ Login();
}
else
m_iStatus = new_status;
@@ -343,7 +312,7 @@ int CSteamProto::SetStatus(int new_status)
return 0;
}
-void __cdecl CSteamProto::GetAwayMsgThread(void *arg)
+void CSteamProto::GetAwayMsgThread(void *arg)
{
// Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg()
Sleep(50);
@@ -352,8 +321,7 @@ void __cdecl CSteamProto::GetAwayMsgThread(void *arg)
CMStringW message(db_get_wsa(hContact, "CList", "StatusMsg"));
// if contact has no status message, get xstatus message
- if (message.IsEmpty())
- {
+ if (message.IsEmpty()) {
ptrW xStatusName(getWStringA(hContact, "XStatusName"));
ptrW xStatusMsg(getWStringA(hContact, "XStatusMsg"));
@@ -366,45 +334,37 @@ void __cdecl CSteamProto::GetAwayMsgThread(void *arg)
ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)message.c_str());
}
-HANDLE __cdecl CSteamProto::GetAwayMsg(MCONTACT hContact)
+HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact)
{
ForkThread(&CSteamProto::GetAwayMsgThread, (void*)hContact);
return (HANDLE)1;
}
-int __cdecl CSteamProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam)
+int CSteamProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam)
{
- switch (eventType)
- {
+ switch (eventType) {
case EV_PROTO_ONLOAD:
- return this->OnModulesLoaded(wParam, lParam);
-
- /*case EV_PROTO_ONOPTIONS:
- return this->OnOptionsInit(wParam, lParam);*/
+ return OnModulesLoaded(wParam, lParam);
case EV_PROTO_ONCONTACTDELETED:
- if (IsOnline())
- {
+ if (IsOnline()) {
MCONTACT hContact = (MCONTACT)wParam;
-
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- ptrA steamId(getStringA("SteamID"));
- ptrA who(getStringA(hContact, "SteamID"));
-
- // Don't request delete contact from server when we're not friends anyway
- if (getByte(hContact, "Auth", 0) != 0)
- return 0;
-
- PushRequest(
- new RemoveFriendRequest(token, sessionId, steamId, who),
- &CSteamProto::OnFriendRemoved,
- (void*)hContact);
+ // remove only authorized contacts
+ if (!getByte(hContact, "Auth", 0)) {
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+ PushRequest(
+ new RemoveFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendRemoved,
+ (void*)who);
+ }
}
return 0;
case EV_PROTO_ONMENU:
- this->OnInitStatusMenu();
+ //OnInitStatusMenu();
break;
}
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index d53e21b009..d1e5513baa 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -13,18 +13,19 @@ struct SendAuthParam
struct STEAM_SEARCH_RESULT
{
- PROTOSEARCHRESULT hdr;
- JSONNode *data;
+ PROTOSEARCHRESULT psr;
+ const JSONNode *data;
};
enum
{
CMI_AUTH_REQUEST,
//CMI_AUTH_GRANT,
- //CMI_AUTH_REVOKE,
+ CMI_AUTH_REVOKE,
CMI_BLOCK,
+ CMI_UNBLOCK,
CMI_JOIN_GAME,
- SMI_BLOCKED_LIST,
+ //SMI_BLOCKED_LIST,
CMI_MAX // this item shall be the last one
};
@@ -37,6 +38,13 @@ struct RequestQueueItem
HttpCallback httpCallback;
JsonCallback jsonCallback;
void *param;
+
+ RequestQueueItem(HttpRequest *request)
+ : request(request), httpCallback(nullptr), jsonCallback(nullptr), param(nullptr) {}
+ RequestQueueItem(HttpRequest *request, HttpCallback callback, void *param)
+ : request(request), httpCallback(callback), jsonCallback(nullptr), param(param) {}
+ RequestQueueItem(HttpRequest *request, JsonCallback callback, void *param)
+ : request(request), httpCallback(nullptr), jsonCallback(callback), param(param) {}
};
class CSteamProto : public PROTO<CSteamProto>
@@ -54,15 +62,16 @@ public:
virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr);
virtual int __cdecl Authorize(MEVENT hDbEvent);
+ virtual int __cdecl AuthRecv(MCONTACT, PROTORECVEVENT*);
virtual int __cdecl AuthDeny(MEVENT hDbEvent, const wchar_t *szReason);
- virtual int __cdecl AuthRequest(MCONTACT hContact, const wchar_t * szMessage);
+ virtual int __cdecl AuthRequest(MCONTACT hContact, const wchar_t *szMessage);
virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL);
virtual HANDLE __cdecl SearchBasic(const wchar_t *id);
- virtual HANDLE __cdecl SearchByName(const wchar_t* nick, const wchar_t* firstName, const wchar_t* lastName);
+ virtual HANDLE __cdecl SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName);
- virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg);
+ virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char *msg);
virtual int __cdecl SetStatus(int iNewStatus);
@@ -71,31 +80,31 @@ public:
virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam);
// instances
- static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName);
- static int UninitProtoInstance(CSteamProto* ppro);
+ static CSteamProto* InitAccount(const char* protoName, const wchar_t *userName);
+ static int UninitAccount(CSteamProto* ppro);
- static CSteamProto* GetContactProtoInstance(MCONTACT hContact);
- static void UninitProtoInstances();
+ static CSteamProto* GetContactAccount(MCONTACT hContact);
// menus
static void InitMenus();
- static void UninitMenus();
protected:
- wchar_t *password;
+ ptrW m_password;
+ ptrW m_defaultGroup;
bool isLoginAgain;
time_t m_idleTS;
- bool isTerminated, isConnected;
- mir_cs requestQueueLock;
+ // requests
+ bool m_isTerminated;
+ mir_cs m_requestQueueLock;
HANDLE m_hRequestsQueueEvent;
HANDLE m_hRequestQueueThread;
- LIST<RequestQueueItem> requestQueue;
- HANDLE m_pollingConnection, m_hPollingThread;
- ULONG hAuthProcess;
- ULONG hMessageProcess;
- mir_cs contact_search_lock;
- mir_cs requests_queue_lock;
- mir_cs set_status_lock;
+ LIST<RequestQueueItem> m_requestQueue;
+ // pooling
+ HANDLE m_hPollingThread;
+ ULONG hAuthProcess;
+ ULONG hMessageProcess;
+ mir_cs m_addContactLock;
+ mir_cs m_setStatusLock;
std::map<HANDLE, time_t> m_mpOutMessages;
std::map<std::string, time_t> m_typingTimestamps;
@@ -106,19 +115,22 @@ protected:
time_t m_lastMessageTS;
// instances
- static LIST<CSteamProto> InstanceList;
+ static LIST<CSteamProto> Accounts;
static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2);
// requests
- HttpResponse* SendRequest(HttpRequest *request);
- void SendRequest(HttpRequest *request, HttpCallback callback, void *param = NULL);
- void SendRequest(HttpRequest *request, JsonCallback callback, void *param = NULL);
+ void SendRequest(HttpRequest *request);
+ void SendRequest(HttpRequest *request, HttpCallback callback, void *param = nullptr);
+ void SendRequest(HttpRequest *request, JsonCallback callback, void *param = nullptr);
void PushRequest(HttpRequest *request);
- void PushRequest(HttpRequest *request, HttpCallback callback, void *param = NULL);
- void PushRequest(HttpRequest *request, JsonCallback callback, void *param = NULL);
+ void PushRequest(HttpRequest *request, HttpCallback callback, void *param = nullptr);
+ void PushRequest(HttpRequest *request, JsonCallback callback, void *param = nullptr);
+ void PushToRequestQueue(RequestQueueItem *item);
+ RequestQueueItem *PopFromRequestQueue();
+ void ProcessRequestQueue();
void __cdecl RequestQueueThread(void*);
- // pooling thread
+ // pooling
void ParsePollData(const JSONNode &data);
void OnGotPoll(const HttpResponse &response, void *arg);
void __cdecl PollingThread(void*);
@@ -128,8 +140,7 @@ protected:
bool IsMe(const char *steamId);
void Login();
- bool Relogin();
- void LogOut();
+ void Logout();
void OnGotRsaKey(const JSONNode &root, void*);
@@ -141,6 +152,7 @@ protected:
void OnGotSession(const HttpResponse &response, void*);
void OnLoggedOn(const HttpResponse &response, void*);
+ void OnReLogin(const JSONNode &root, void*);
void HandleTokenExpired();
void DeleteAuthSettings();
@@ -156,11 +168,12 @@ protected:
void ContactIsRemoved(MCONTACT hContact);
void ContactIsFriend(MCONTACT hContact);
- void ContactIsIgnored(MCONTACT hContact);
+ void ContactIsBlocked(MCONTACT hContact);
+ void ContactIsUnblocked(MCONTACT hContact);
void ContactIsAskingAuth(MCONTACT hContact);
- MCONTACT FindContact(const char *steamId);
- MCONTACT AddContact(const char *steamId, bool isTemporary = false);
+ MCONTACT GetContact(const char *steamId);
+ MCONTACT AddContact(const char *steamId, const wchar_t *nick = nullptr, bool isTemporary = false);
void OnGotFriendList(const JSONNode &root, void*);
void OnGotBlockList(const JSONNode &root, void*);
@@ -169,6 +182,7 @@ protected:
void OnFriendAdded(const HttpResponse &response, void *arg);
void OnFriendBlocked(const HttpResponse &response, void *arg);
+ void OnFriendUnblocked(const HttpResponse &response, void *arg);
void OnFriendRemoved(const HttpResponse &response, void *arg);
void OnAuthRequested(const JSONNode &root, void *arg);
@@ -193,13 +207,13 @@ protected:
static HGENMENU contactMenuItems[CMI_MAX];
int __cdecl AuthRequestCommand(WPARAM, LPARAM);
+ int __cdecl AuthRevokeCommand(WPARAM, LPARAM);
int __cdecl BlockCommand(WPARAM, LPARAM);
+ int __cdecl UnblockCommand(WPARAM, LPARAM);
int __cdecl JoinToGameCommand(WPARAM, LPARAM);
INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM);
- static INT_PTR MenuChooseService(WPARAM wParam, LPARAM lParam);
-
static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam);
int OnPrebuildContactMenu(WPARAM wParam, LPARAM);
@@ -231,8 +245,8 @@ protected:
INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam);
// utils
- static WORD SteamToMirandaStatus(int state);
- static int MirandaToSteamState(int status);
+ static WORD SteamToMirandaStatus(PersonaState state);
+ static PersonaState MirandaToSteamState(int status);
static int RsaEncrypt(const char *pszModulus, DWORD &exponent, const char *data, BYTE *encrypted, DWORD &encryptedSize);
@@ -244,7 +258,7 @@ protected:
// helpers
inline int IdleSeconds() {
// Based on idle time we report Steam server will mark us as online/away/snooze
- switch (this->m_iStatus) {
+ switch (m_iStatus) {
case ID_STATUS_AWAY:
return STEAM_API_IDLEOUT_AWAY;
case ID_STATUS_NA:
@@ -263,6 +277,13 @@ protected:
mir_snprintf(steamId, "%llu", accountId + 76561197960265728ll);
return steamId;
}
+
+ inline const char *SteamIdToAccountId(long long steamId)
+ {
+ static char accountId[10];
+ mir_snprintf(accountId, "%llu", steamId - 76561197960265728ll);
+ return accountId;
+ }
};
int OnReloadIcons(WPARAM wParam, LPARAM lParam);
diff --git a/protocols/Steam/src/steam_request.cpp b/protocols/Steam/src/steam_request.cpp
index 363f31a328..51b09ecfc3 100644
--- a/protocols/Steam/src/steam_request.cpp
+++ b/protocols/Steam/src/steam_request.cpp
@@ -1,11 +1,10 @@
#include "stdafx.h"
-HttpResponse* CSteamProto::SendRequest(HttpRequest *request)
+void CSteamProto::SendRequest(HttpRequest *request)
{
NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
- HttpResponse *response = new HttpResponse(request, pResp);
+ HttpResponse response(request, pResp);
delete request;
- return response;
}
void CSteamProto::SendRequest(HttpRequest *request, HttpCallback callback, void *param)
@@ -21,8 +20,7 @@ void CSteamProto::SendRequest(HttpRequest *request, JsonCallback callback, void
{
NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
HttpResponse response(request, pResp);
- if (callback)
- {
+ if (callback) {
JSONNode root = JSONNode::parse(response.Content);
(this->*callback)(root, param);
}
@@ -31,68 +29,75 @@ void CSteamProto::SendRequest(HttpRequest *request, JsonCallback callback, void
void CSteamProto::PushRequest(HttpRequest *request)
{
- RequestQueueItem *item = new RequestQueueItem();
- item->request = request;
- {
- mir_cslock lock(requestQueueLock);
- requestQueue.insert(item);
- }
- SetEvent(m_hRequestsQueueEvent);
+ RequestQueueItem *item = new RequestQueueItem(request);
+ PushToRequestQueue(item);
}
void CSteamProto::PushRequest(HttpRequest *request, HttpCallback callback, void *param)
{
- RequestQueueItem *item = new RequestQueueItem();
- item->request = request;
- item->httpCallback = callback;
- item->param = param;
- {
- mir_cslock lock(requestQueueLock);
- requestQueue.insert(item);
- }
- SetEvent(m_hRequestsQueueEvent);
+ RequestQueueItem *item = new RequestQueueItem(request, callback, param);
+ PushToRequestQueue(item);
}
void CSteamProto::PushRequest(HttpRequest *request, JsonCallback callback, void *param)
{
- RequestQueueItem *item = new RequestQueueItem();
- item->request = request;
- item->jsonCallback = callback;
- item->param = param;
+ RequestQueueItem *item = new RequestQueueItem(request, callback, param);
+ PushToRequestQueue(item);
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+
+void CSteamProto::PushToRequestQueue(RequestQueueItem *item)
+{
+ if (m_isTerminated)
+ return;
{
- mir_cslock lock(requestQueueLock);
- requestQueue.insert(item);
+ mir_cslock lock(m_requestQueueLock);
+ m_requestQueue.insert(item);
}
SetEvent(m_hRequestsQueueEvent);
}
-void CSteamProto::RequestQueueThread(void*)
+RequestQueueItem *CSteamProto::PopFromRequestQueue()
{
- Login();
+ mir_cslock lock(m_requestQueueLock);
+ if (!m_requestQueue.getCount())
+ return nullptr;
- do
- {
- RequestQueueItem *item;
- while (true)
- {
- {
- mir_cslock lock(requestQueueLock);
- if (!requestQueue.getCount())
- break;
+ RequestQueueItem *item = m_requestQueue[0];
+ m_requestQueue.remove(0);
+ return item;
+}
- item = requestQueue[0];
- requestQueue.remove(0);
- }
- if (item->httpCallback)
- SendRequest(item->request, item->httpCallback, item->param);
- else if (item->jsonCallback)
- SendRequest(item->request, item->jsonCallback, item->param);
- else
- SendRequest(item->request);
- delete item;
- }
+void CSteamProto::ProcessRequestQueue()
+{
+ while (true) {
+ RequestQueueItem *item = PopFromRequestQueue();
+ if (item == nullptr)
+ break;
+ if (item->httpCallback)
+ SendRequest(item->request, item->httpCallback, item->param);
+ else if (item->jsonCallback)
+ SendRequest(item->request, item->jsonCallback, item->param);
+ else
+ SendRequest(item->request);
+ delete item;
+ }
+}
+
+void CSteamProto::RequestQueueThread(void*)
+{
+ do {
+ ProcessRequestQueue();
WaitForSingleObject(m_hRequestsQueueEvent, 1000);
- } while (!isTerminated);
+ } while (!m_isTerminated);
+ {
+ mir_cslock lock(m_requestQueueLock);
+ for (int i = 0; i < m_requestQueue.getCount(); i++) {
+ delete m_requestQueue[i];
+ m_requestQueue.remove(i);
+ }
+ }
+ m_hRequestQueueThread = nullptr;
- m_hRequestQueueThread = NULL;
} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_utils.cpp b/protocols/Steam/src/steam_utils.cpp
index 409ce4276a..447a844b16 100644
--- a/protocols/Steam/src/steam_utils.cpp
+++ b/protocols/Steam/src/steam_utils.cpp
@@ -1,162 +1,49 @@
#include "stdafx.h"
-#pragma comment(lib, "crypt32.lib")
-
-WORD CSteamProto::SteamToMirandaStatus(int state)
+WORD CSteamProto::SteamToMirandaStatus(PersonaState state)
{
switch (state)
{
- case 0: //Offline
+ case PersonaState::Offline:
return ID_STATUS_OFFLINE;
- case 1: //Online
+ case PersonaState::Online:
return ID_STATUS_ONLINE;
- case 2: //Busy
+ case PersonaState::Busy:
return ID_STATUS_DND;
- case 3: //Away
+ case PersonaState::Away:
return ID_STATUS_AWAY;
- case 4: //Snoozing
+ case PersonaState::Snooze:
return ID_STATUS_NA;
- case 5: //Looking to trade
+ case PersonaState::LookingToTrade:
return ID_STATUS_OUTTOLUNCH;
- case 6: //Looking to play
+ case PersonaState::LookingToPlay:
return ID_STATUS_FREECHAT;
default:
return ID_STATUS_ONLINE;
}
}
-int CSteamProto::MirandaToSteamState(int status)
+PersonaState CSteamProto::MirandaToSteamState(int status)
{
switch (status)
{
case ID_STATUS_OFFLINE:
- return 0; //Offline
+ return PersonaState::Offline;
case ID_STATUS_ONLINE:
- return 1; //Online
+ return PersonaState::Online;
case ID_STATUS_DND:
- return 2; //Busy
+ return PersonaState::Busy;
case ID_STATUS_AWAY:
- return 3; //Away
+ return PersonaState::Away;
case ID_STATUS_NA:
- return 4; //Snoozing
+ return PersonaState::Snooze;
case ID_STATUS_OUTTOLUNCH:
- return 5; //Looking to trade
+ return PersonaState::LookingToTrade;
case ID_STATUS_FREECHAT:
- return 6; //Looking to play
+ return PersonaState::LookingToPlay;
default:
- return 1;
- }
-}
-
-int CSteamProto::RsaEncrypt(const char *pszModulus, DWORD &exponent, const char *data, BYTE *encryptedData, DWORD &encryptedSize)
-{
- DWORD cchModulus = (DWORD)mir_strlen(pszModulus);
- int result = 0;
- BYTE *pbBuffer = nullptr;
- BYTE *pKeyBlob = nullptr;
- HCRYPTKEY phKey = 0;
- HCRYPTPROV hCSP = 0;
-
- // convert hex string to byte array
- DWORD cbLen = 0, dwSkip = 0, dwFlags = 0;
- if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, nullptr, &cbLen, &dwSkip, &dwFlags))
- {
- result = GetLastError();
- goto exit;
- }
-
- // allocate a new buffer.
- pbBuffer = (BYTE*)malloc(cbLen);
- if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, pbBuffer, &cbLen, &dwSkip, &dwFlags))
- {
- result = GetLastError();
- goto exit;
- }
-
- // reverse byte array, because of microsoft
- for (int i = 0; i < (int)(cbLen / 2); ++i)
- {
- BYTE temp = pbBuffer[cbLen - i - 1];
- pbBuffer[cbLen - i - 1] = pbBuffer[i];
- pbBuffer[i] = temp;
- }
-
- if (!CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT) &&
- !CryptAcquireContext(&hCSP, nullptr, nullptr, PROV_RSA_AES, CRYPT_SILENT | CRYPT_NEWKEYSET))
- {
- result = GetLastError();
- goto exit;
- }
-
- // Move the key into the key container.
- DWORD cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbLen;
- pKeyBlob = (BYTE*)malloc(cbKeyBlob);
-
- // Fill in the data.
- PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pKeyBlob;
- pPublicKey->bType = PUBLICKEYBLOB;
- pPublicKey->bVersion = CUR_BLOB_VERSION; // Always use this value.
- pPublicKey->reserved = 0; // Must be zero.
- pPublicKey->aiKeyAlg = CALG_RSA_KEYX; // RSA public-key key exchange.
-
- // The next block of data is the RSAPUBKEY structure.
- RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pKeyBlob + sizeof(PUBLICKEYSTRUC));
- pRsaPubKey->magic = 0x31415352; // RSA1 // Use public key
- pRsaPubKey->bitlen = cbLen * 8; // Number of bits in the modulus.
- pRsaPubKey->pubexp = exponent; // Exponent.
-
- // Copy the modulus into the blob. Put the modulus directly after the
- // RSAPUBKEY structure in the blob.
- BYTE *pKey = (BYTE*)(((BYTE *)pRsaPubKey) + sizeof(RSAPUBKEY));
- //pKeyBlob + sizeof(BLOBHEADER)+ sizeof(RSAPUBKEY);
- memcpy(pKey, pbBuffer, cbLen);
-
- // Now import public key
- if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey))
- {
- result = GetLastError();
- goto exit;
- }
-
- DWORD dataSize = (DWORD)mir_strlen(data);
-
- // if data is not allocated just renurn size
- if (encryptedData == nullptr)
- {
- // get length of encrypted data
- if (!CryptEncrypt(phKey, 0, TRUE, 0, nullptr, &encryptedSize, dataSize))
- result = GetLastError();
- goto exit;
- }
-
- // encrypt password
- memcpy(encryptedData, data, dataSize);
- if (!CryptEncrypt(phKey, 0, TRUE, 0, encryptedData, &dataSize, encryptedSize))
- {
- result = GetLastError();
- goto exit;
- }
-
- // reverse byte array again
- for (int i = 0; i < (int)(encryptedSize / 2); ++i)
- {
- BYTE temp = encryptedData[encryptedSize - i - 1];
- encryptedData[encryptedSize - i - 1] = encryptedData[i];
- encryptedData[i] = temp;
+ return PersonaState::Online;
}
-
-exit:
- if (pKeyBlob)
- free(pKeyBlob);
- if (phKey)
- CryptDestroyKey(phKey);
-
- if (pbBuffer)
- free(pbBuffer);
- if (hCSP)
- CryptReleaseContext(hCSP, 0);
-
- return 0;
}
void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact)
@@ -184,18 +71,14 @@ void CSteamProto::ShowNotification(const wchar_t *message, int flags, MCONTACT h
ShowNotification(_A2W(MODULE), message, flags, hContact);
}
-INT_PTR __cdecl CSteamProto::OnGetEventTextChatStates(WPARAM pEvent, LPARAM datatype)
+INT_PTR CSteamProto::OnGetEventTextChatStates(WPARAM pEvent, LPARAM datatype)
{
// Retrieves a chat state description from an event
-
DBEVENTINFO *dbei = (DBEVENTINFO *)pEvent;
- if (dbei->cbBlob > 0) {
- if (dbei->pBlob[0] == STEAM_DB_EVENT_CHATSTATES_GONE) {
- if (datatype == DBVT_WCHAR)
- return (INT_PTR)mir_wstrdup(TranslateT("closed chat session"));
- return (INT_PTR)mir_strdup(Translate("closed chat session"));
- }
- }
+ if (dbei->cbBlob > 0 && dbei->pBlob[0] == STEAM_DB_EVENT_CHATSTATES_GONE)
+ return (datatype == DBVT_WCHAR)
+ ? (INT_PTR)mir_wstrdup(TranslateT("closed chat session"))
+ : (INT_PTR)mir_strdup(Translate("closed chat session"));
return NULL;
}