summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2017-12-28 21:21:10 +0300
committeraunsane <aunsane@gmail.com>2017-12-28 21:21:28 +0300
commit0156ed41dceeef48f070adf67f14d4ba4c4f6d61 (patch)
treed0e1dca4c2c9c3c056ae9cb69dde10ea59316481
parentf0075f2b956969f29acd3bc9289c8a5f78faddad (diff)
Steam: refactoring
- reworking http requests - added ability to get game name by appid - another attempt to fix #633 - minor refactoring
-rw-r--r--protocols/Steam/res/Resource.rc43
-rw-r--r--protocols/Steam/src/api/app_info.h16
-rw-r--r--protocols/Steam/src/api/authorization.h34
-rw-r--r--protocols/Steam/src/api/avatar.h2
-rw-r--r--protocols/Steam/src/api/captcha.h4
-rw-r--r--protocols/Steam/src/api/enums.h32
-rw-r--r--protocols/Steam/src/api/friend.h7
-rw-r--r--protocols/Steam/src/api/friend_list.h52
-rw-r--r--protocols/Steam/src/api/history.h17
-rw-r--r--protocols/Steam/src/api/login.h17
-rw-r--r--protocols/Steam/src/api/message.h32
-rw-r--r--protocols/Steam/src/api/pending.h48
-rw-r--r--protocols/Steam/src/api/poll.h20
-rw-r--r--protocols/Steam/src/api/rsa_key.h9
-rw-r--r--protocols/Steam/src/api/search.h14
-rw-r--r--protocols/Steam/src/api/session.h12
-rw-r--r--protocols/Steam/src/http_request.h413
-rw-r--r--protocols/Steam/src/request_queue.cpp120
-rw-r--r--protocols/Steam/src/request_queue.h58
-rw-r--r--protocols/Steam/src/resource.h4
-rw-r--r--protocols/Steam/src/stdafx.h2
-rw-r--r--protocols/Steam/src/steam_contacts.cpp510
-rw-r--r--protocols/Steam/src/steam_history.cpp102
-rw-r--r--protocols/Steam/src/steam_login.cpp250
-rw-r--r--protocols/Steam/src/steam_menus.cpp3
-rw-r--r--protocols/Steam/src/steam_messages.cpp41
-rw-r--r--protocols/Steam/src/steam_polling.cpp341
-rw-r--r--protocols/Steam/src/steam_proto.cpp56
-rw-r--r--protocols/Steam/src/steam_proto.h91
-rw-r--r--protocols/Steam/src/steam_request.cpp130
30 files changed, 1242 insertions, 1238 deletions
diff --git a/protocols/Steam/res/Resource.rc b/protocols/Steam/res/Resource.rc
index 2cb5633c29..fe899696d1 100644
--- a/protocols/Steam/res/Resource.rc
+++ b/protocols/Steam/res/Resource.rc
@@ -17,7 +17,7 @@
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD)
LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
-#pragma code_page(1250)
+#pragma code_page(1251)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
@@ -63,7 +63,9 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_STEAM ICON "steam.ico"
+
IDI_GAMING ICON "gaming.ico"
+
#endif // Russian (Russia) resources
/////////////////////////////////////////////////////////////////////////////
@@ -113,7 +115,8 @@ BEGIN
END
IDD_CAPTCHA DIALOGEX 0, 0, 143, 81
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
CAPTION "Captcha"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
@@ -123,7 +126,8 @@ BEGIN
END
IDD_GUARD DIALOGEX 0, 0, 193, 93
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
CAPTION "Steam Guard"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
@@ -146,7 +150,7 @@ END
IDD_PASSWORD_EDITOR DIALOGEX 0, 0, 209, 75
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOOLWINDOW | WS_EX_APPWINDOW
+EXSTYLE WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_APPWINDOW
CAPTION "Enter password"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
@@ -158,8 +162,9 @@ BEGIN
END
IDD_TWOFACTOR DIALOGEX 0, 0, 193, 83
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Steam Guard"
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
+CAPTION "Sms code"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
EDITTEXT IDC_TEXT,7,41,179,14,ES_AUTOHSCROLL
@@ -237,6 +242,32 @@ BEGIN
END
#endif // APSTUDIO_INVOKED
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_GUARD AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_CAPTCHA AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_PASSWORD_EDITOR AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_TWOFACTOR AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
#endif // English resources
/////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/Steam/src/api/app_info.h b/protocols/Steam/src/api/app_info.h
new file mode 100644
index 0000000000..b08a3f38d6
--- /dev/null
+++ b/protocols/Steam/src/api/app_info.h
@@ -0,0 +1,16 @@
+#ifndef _STEAM_REQUEST_APP_INFO_H_
+#define _STEAM_REQUEST_APP_INFO_H_
+
+class GetAppInfoRequest : public HttpRequest
+{
+public:
+ GetAppInfoRequest(const char *token, const char *appIds) :
+ HttpRequest(HttpGet, STEAM_API_URL "/ISteamGameOAuth/GetAppInfo/v0001")
+ {
+ Uri
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("appIds", appIds);
+ }
+};
+
+#endif //_STEAM_REQUEST_APP_INFO_H_
diff --git a/protocols/Steam/src/api/authorization.h b/protocols/Steam/src/api/authorization.h
index cba8d4d274..3d02c5deb5 100644
--- a/protocols/Steam/src/api/authorization.h
+++ b/protocols/Steam/src/api/authorization.h
@@ -5,27 +5,27 @@ class AuthorizationRequest : public HttpRequest
{
public:
AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *twoFactorCode, const char *guardCode, const char *guardId = "", const char *captchaId = "-1", const char *captchaText = "") :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobilelogin/dologin/")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/mobilelogin/dologin/")
{
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
- AddHeader("Referer", STEAM_WEB_URL "/mobilelogin/dologin?oauth_client_id=3638BFB1&oauth_scope=read_profile%20write_profile%20read_client%20write_client");
- AddHeader("Cookie", "mobileClientVersion=1291812;forceMobile=1;mobileClient=ios");
+ Headers
+ << CHAR_PARAM("Referer", STEAM_WEB_URL "/mobilelogin/dologin?oauth_client_id=3638BFB1&oauth_scope=read_profile%20write_profile%20read_client%20write_client")
+ << CHAR_PARAM("Cookie", "mobileClientVersion=1291812;forceMobile=1;mobileClient=ios");
- CMStringA data;
- data.AppendFormat("password=%s&username=%s&twofactorcode=%s&emailauth=%s&loginfriendlyname=%s&oauth_client_id=3638BFB1&captchagid=%s&captcha_text=%s&emailsteamid=%s&rsatimestamp=%s&rememberlogin=false&donotcache=%lld",
- ptrA(mir_urlEncode(password)),
- ptrA(mir_urlEncode(username)),
- twoFactorCode,
- guardCode,
- "Miranda%20NG",
- captchaId,
- ptrA(mir_urlEncode(captchaText)),
- guardId,
- timestamp,
- time(NULL));
- SetData(data, data.GetLength());
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("oauth_client_id", "3638BFB1")
+ << CHAR_PARAM("loginfriendlyname", "Miranda NG")
+ << CHAR_PARAM("password", password)
+ << CHAR_PARAM("username", username)
+ << CHAR_PARAM("twofactorcode", twoFactorCode)
+ << CHAR_PARAM("emailsteamid", guardId)
+ << CHAR_PARAM("emailauth", guardCode)
+ << CHAR_PARAM("captchagid", captchaId)
+ << CHAR_PARAM("captcha_text", captchaText)
+ << CHAR_PARAM("rsatimestamp", timestamp)
+ << BOOL_PARAM("rememberlogin", false)
+ << INT64_PARAM("donotcache", time(NULL));
}
};
diff --git a/protocols/Steam/src/api/avatar.h b/protocols/Steam/src/api/avatar.h
index 28e573d9d1..521536550e 100644
--- a/protocols/Steam/src/api/avatar.h
+++ b/protocols/Steam/src/api/avatar.h
@@ -5,7 +5,7 @@ class GetAvatarRequest : public HttpRequest
{
public:
GetAvatarRequest(const char *url) :
- HttpRequest(REQUEST_GET, url)
+ HttpRequest(HttpGet, url)
{
flags = NLHRF_HTTP11 | NLHRF_NODUMP;
}
diff --git a/protocols/Steam/src/api/captcha.h b/protocols/Steam/src/api/captcha.h
index 9619a09b54..0b8ba9191a 100644
--- a/protocols/Steam/src/api/captcha.h
+++ b/protocols/Steam/src/api/captcha.h
@@ -5,9 +5,11 @@ class GetCaptchaRequest : public HttpRequest
{
public:
GetCaptchaRequest(const char *captchaId) :
- HttpRequest(REQUEST_GET, FORMAT, STEAM_WEB_URL "/public/captcha.php?gid=%s", captchaId)
+ HttpRequest(HttpGet, STEAM_WEB_URL "/public/captcha.php")
{
flags = NLHRF_HTTP11 | NLHRF_NODUMP;
+
+ Uri << CHAR_PARAM("gid", captchaId);
}
};
diff --git a/protocols/Steam/src/api/enums.h b/protocols/Steam/src/api/enums.h
new file mode 100644
index 0000000000..a24ce48b34
--- /dev/null
+++ b/protocols/Steam/src/api/enums.h
@@ -0,0 +1,32 @@
+#ifndef _STEAM_ENUMS_H_
+#define _STEAM_ENUMS_H_
+
+enum PersonaState
+{
+ Offline = 0,
+ Online = 1,
+ Busy = 2,
+ Away = 3,
+ Snooze = 4,
+ LookingToTrade = 5,
+ LookingToPlay = 6,
+ Max = 7,
+};
+
+enum StatusFlags
+{
+ Status = 1,
+ PlayerName = 2,
+ QueryPort = 4,
+ SourceID = 8,
+ Presence = 16,
+ Metadata = 32,
+ LastSeen = 64,
+ ClanInfo = 128,
+ GameExtraInfo = 256,
+ GameDataBlob = 512,
+ ClanTag = 1024,
+ Facebook = 2048,
+}
+
+#endif //_STEAM_ENUMS_H_
diff --git a/protocols/Steam/src/api/friend.h b/protocols/Steam/src/api/friend.h
index ade553f2c0..191e0b93fa 100644
--- a/protocols/Steam/src/api/friend.h
+++ b/protocols/Steam/src/api/friend.h
@@ -5,10 +5,11 @@ class GetUserSummariesRequest : public HttpRequest
{
public:
GetUserSummariesRequest(const char *token, const char *steamIds) :
- HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001")
{
- AddParameter("access_token", token);
- AddParameter("steamids", steamIds);
+ Uri
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("steamids", steamIds);
}
};
diff --git a/protocols/Steam/src/api/friend_list.h b/protocols/Steam/src/api/friend_list.h
index b6ab98402b..604e797a2d 100644
--- a/protocols/Steam/src/api/friend_list.h
+++ b/protocols/Steam/src/api/friend_list.h
@@ -5,11 +5,12 @@ class GetFriendListRequest : public HttpRequest
{
public:
GetFriendListRequest(const char *token, const char *steamId, const char *relationship = "friend,ignoredfriend,requestrecipient") :
- HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001")
{
- AddParameter("access_token", token);
- AddParameter("steamid", steamId);
- AddParameter("relationship", relationship);
+ Uri
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("steamid", steamId)
+ << CHAR_PARAM("relationship", relationship);
}
};
@@ -17,7 +18,7 @@ class AddFriendRequest : public HttpRequest
{
public:
AddFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/AddFriendAjax")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/actions/AddFriendAjax")
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -25,15 +26,11 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[128];
- mir_snprintf(data, _countof(data),
- "sessionID=%s&steamid=%s",
- sessionId,
- who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("steamid", who);
}
};
@@ -41,7 +38,7 @@ class BlockFriendRequest : public HttpRequest
{
public:
BlockFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/BlockUserAjax")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/actions/BlockUserAjax")
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -49,15 +46,12 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[128];
- mir_snprintf(data, _countof(data),
- "sessionID=%s&action=ignore&steamid=%s",
- sessionId,
- who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("steamid", who)
+ << CHAR_PARAM("action", "ignore");
}
};
@@ -65,7 +59,7 @@ class RemoveFriendRequest : public HttpRequest
{
public:
RemoveFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/actions/RemoveFriendAjax")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/actions/RemoveFriendAjax")
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -73,15 +67,11 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[128];
- mir_snprintf(data, _countof(data),
- "sessionID=%s&steamid=%s",
- sessionId,
- who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("steamid", who);
}
};
diff --git a/protocols/Steam/src/api/history.h b/protocols/Steam/src/api/history.h
index 09eed8a49c..f825622953 100644
--- a/protocols/Steam/src/api/history.h
+++ b/protocols/Steam/src/api/history.h
@@ -5,9 +5,9 @@ class GetConversationsRequest : public HttpRequest
{
public:
GetConversationsRequest(const char *token) :
- HttpRequest(REQUEST_GET, STEAM_API_URL "/IFriendMessagesService/GetActiveMessageSessions/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/IFriendMessagesService/GetActiveMessageSessions/v0001")
{
- AddParameter("access_token", token);
+ Uri << CHAR_PARAM("access_token", token);
}
};
@@ -15,13 +15,14 @@ class GetHistoryMessagesRequest : public HttpRequest
{
public:
GetHistoryMessagesRequest(const char *token, const char *steamId, const char *who, time_t since) :
- HttpRequest(REQUEST_GET, STEAM_API_URL "/IFriendMessagesService/GetRecentMessages/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/IFriendMessagesService/GetRecentMessages/v0001")
{
- AddParameter("access_token", token);
- AddParameter("steamid1", steamId);
- AddParameter("steamid2", who);
- // Steam somehow doesn't respect too precise start time parameter, so we better request older time and then do own filtering again
- AddParameter("rtime32_start_time=%d", since - 1500);
+ Uri
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("steamid1", steamId)
+ << CHAR_PARAM("steamid2", who)
+ // Steam somehow doesn't respect too precise start time parameter, so we better request older time and then do own filtering again
+ << INT64_PARAM("rtime32_start_time", since - 1500);
}
};
diff --git a/protocols/Steam/src/api/login.h b/protocols/Steam/src/api/login.h
index 35ea1d8c74..3479ae75ff 100644
--- a/protocols/Steam/src/api/login.h
+++ b/protocols/Steam/src/api/login.h
@@ -5,13 +5,14 @@ class LogonRequest : public HttpRequest
{
public:
LogonRequest(const char *token) :
- HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001")
+ HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001")
{
char data[256];
mir_snprintf(data, "access_token=%s&ui_mode=web", token);
- SetData(data, strlen(data));
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("ui_mode", "web");
}
};
@@ -19,13 +20,11 @@ class LogoffRequest : public HttpRequest
{
public:
LogoffRequest(const char *token, const char *umqId) :
- HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001")
+ HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001")
{
- char data[256];
- mir_snprintf(data, "access_token=%s&umqid=%s", token, umqId);
-
- SetData(data, strlen(data));
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("umqid", umqId);
}
};
diff --git a/protocols/Steam/src/api/message.h b/protocols/Steam/src/api/message.h
index 77adb4a240..eee4c43b28 100644
--- a/protocols/Steam/src/api/message.h
+++ b/protocols/Steam/src/api/message.h
@@ -5,17 +5,14 @@ class SendMessageRequest : public HttpRequest
{
public:
SendMessageRequest(const char *token, const char *umqId, const char *steamId, const char *text) :
- HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
+ HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
{
- CMStringA data;
- data.AppendFormat("access_token=%s&umqid=%s&steamid_dst=%s&type=saytext&text=%s",
- token,
- umqId,
- steamId,
- ptrA(mir_urlEncode(text)));
-
- SetData(data, data.GetLength());
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("umqid", umqId)
+ << CHAR_PARAM("steamid_dst", steamId)
+ << CHAR_PARAM("type", "saytext")
+ << CHAR_PARAM("text", text);
}
};
@@ -23,16 +20,13 @@ class SendTypingRequest : public HttpRequest
{
public:
SendTypingRequest(const char *token, const char *umqId, const char *steamId) :
- HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
+ HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
{
- CMStringA data;
- data.AppendFormat("access_token=%s&umqid=%s&steamid_dst=%s&type=typing",
- token,
- umqId,
- steamId);
-
- SetData(data, data.GetLength());
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("umqid", umqId)
+ << CHAR_PARAM("steamid_dst", steamId)
+ << CHAR_PARAM("type", "typing");
}
};
diff --git a/protocols/Steam/src/api/pending.h b/protocols/Steam/src/api/pending.h
index 7c1964b6c5..a808fd172c 100644
--- a/protocols/Steam/src/api/pending.h
+++ b/protocols/Steam/src/api/pending.h
@@ -5,7 +5,7 @@ class ApprovePendingRequest : public HttpRequest
{
public:
ApprovePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+ HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -13,12 +13,16 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[MAX_PATH];
- mir_snprintf(data, "sessionID=%s&id=%s&perform=accept&action=approvePending&itype=friend&json=1&xml=0", sessionId, who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("id", who)
+ << CHAR_PARAM("perform", "accept")
+ << CHAR_PARAM("action", "approvePending")
+ << CHAR_PARAM("itype", "friend")
+ << INT_PARAM("json", 1)
+ << INT_PARAM("xml", 0);
}
};
@@ -26,7 +30,7 @@ class IgnorePendingRequest : public HttpRequest
{
public:
IgnorePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+ HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -34,12 +38,16 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[MAX_PATH];
- mir_snprintf(data, "sessionID=%s&id=%s&perform=ignore&action=approvePending&itype=friend&json=1&xml=0", sessionId, who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("id", who)
+ << CHAR_PARAM("perform", "ignore")
+ << CHAR_PARAM("action", "approvePending")
+ << CHAR_PARAM("itype", "friend")
+ << INT_PARAM("json", 1)
+ << INT_PARAM("xml", 0);
}
};
@@ -47,7 +55,7 @@ class BlockPendingRequest : public HttpRequest
{
public:
BlockPendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
- HttpRequest(REQUEST_POST, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
+ HttpRequest(HttpPost, FORMAT, STEAM_WEB_URL "/profiles/%s/home_process", steamId)
{
char login[MAX_PATH];
mir_snprintf(login, "%s||oauth:%s", steamId, token);
@@ -55,12 +63,16 @@ public:
char cookie[MAX_PATH];
mir_snprintf(cookie, "steamLogin=%s;sessionid=%s;mobileClientVersion=1291812;forceMobile=1;mobileClient=ios", login, sessionId);
- char data[MAX_PATH];
- mir_snprintf(data, "sessionID=%s&id=%s&perform=block&action=approvePending&itype=friend&json=1&xml=0", sessionId, who);
+ Headers << CHAR_PARAM("Cookie", cookie);
- SetData(data, strlen(data));
- AddHeader("Cookie", cookie);
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("sessionID", sessionId)
+ << CHAR_PARAM("id", who)
+ << CHAR_PARAM("perform", "block")
+ << CHAR_PARAM("action", "approvePending")
+ << CHAR_PARAM("itype", "friend")
+ << INT_PARAM("json", 1)
+ << INT_PARAM("xml", 0);
}
};
diff --git a/protocols/Steam/src/api/poll.h b/protocols/Steam/src/api/poll.h
index 5c5da5674c..278dfb0439 100644
--- a/protocols/Steam/src/api/poll.h
+++ b/protocols/Steam/src/api/poll.h
@@ -5,23 +5,19 @@ class PollRequest : public HttpRequest
{
public:
PollRequest(const char *token, const char *umqId, UINT32 messageId, int idleSeconds) :
- HttpRequest(REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001")
+ HttpRequest(HttpPost, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001")
{
timeout = (STEAM_API_TIMEOUT + 5) * 1000;
// flags |= NLHRF_PERSISTENT;
- CMStringA data;
- data.AppendFormat("access_token=%s&umqid=%s&message=%u&secidletime=%d&sectimeout=%d",
- token,
- umqId,
- messageId,
- idleSeconds,
- STEAM_API_TIMEOUT);
+ Headers << CHAR_PARAM("Connection", "keep-alive");
- SetData(data, data.GetLength());
-
- AddHeader("Connection", "keep-alive");
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("umqid", umqId)
+ << INT64_PARAM("message", messageId)
+ << INT_PARAM("secidletime", idleSeconds)
+ << INT_PARAM("sectimeout", STEAM_API_TIMEOUT);
}
};
diff --git a/protocols/Steam/src/api/rsa_key.h b/protocols/Steam/src/api/rsa_key.h
index 9f89a70403..27a002b717 100644
--- a/protocols/Steam/src/api/rsa_key.h
+++ b/protocols/Steam/src/api/rsa_key.h
@@ -5,15 +5,16 @@ class GetRsaKeyRequest : public HttpRequest
{
public:
GetRsaKeyRequest(const char *username) :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobilelogin/getrsakey/")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/mobilelogin/getrsakey/")
{
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
-
CMStringA data;
data.AppendFormat("username=%s&donotcache=%lld", ptrA(mir_urlEncode(username)), time(NULL));
- SetData(data, data.GetLength());
+
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("username", username)
+ << INT64_PARAM("donotcache", time(NULL));
}
};
diff --git a/protocols/Steam/src/api/search.h b/protocols/Steam/src/api/search.h
index a22ed64431..a34c2e8398 100644
--- a/protocols/Steam/src/api/search.h
+++ b/protocols/Steam/src/api/search.h
@@ -5,13 +5,15 @@ class SearchRequest : public HttpRequest
{
public:
SearchRequest(const char *token, const char *text, int offset = 0, int count = 30) :
- HttpRequest(REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/Search/v0001")
+ HttpRequest(HttpGet, STEAM_API_URL "/ISteamUserOAuth/Search/v0001")
{
- AddParameter("access_token", token);
- AddParameter("keywords", ptrA(mir_urlEncode(text)));
- AddParameter("offset=%d", offset);
- AddParameter("count=%d", count);
- AddParameter("targets=users&fields=all");
+ Uri
+ << CHAR_PARAM("access_token", token)
+ << CHAR_PARAM("keywords", text)
+ << INT_PARAM("offset=%d", offset)
+ << INT_PARAM("count=%d", count)
+ << CHAR_PARAM("targets", "users")
+ << CHAR_PARAM("fields", "all");
}
};
diff --git a/protocols/Steam/src/api/session.h b/protocols/Steam/src/api/session.h
index b00e470da6..d4e91721cb 100644
--- a/protocols/Steam/src/api/session.h
+++ b/protocols/Steam/src/api/session.h
@@ -5,19 +5,21 @@ class GetSessionRequest : public HttpRequest
{
public:
GetSessionRequest(const char *token, const char *steamId, const char *cookie) :
- HttpRequest(REQUEST_POST, STEAM_WEB_URL "/mobileloginsucceeded")
+ HttpRequest(HttpPost, STEAM_WEB_URL "/mobileloginsucceeded")
{
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+ Content = new FormUrlEncodedContent(this)
+ << CHAR_PARAM("oauth_token", token)
+ << CHAR_PARAM("steamid", steamId)
+ << CHAR_PARAM("webcookie", cookie);
+
char data[512];
mir_snprintf(data, _countof(data),
"oauth_token=%s&steamid=%s&webcookie=%s",
token,
steamId,
cookie);
-
- SetData(data, strlen(data));
- AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
}
};
@@ -25,7 +27,7 @@ class GetSessionRequest2 : public HttpRequest
{
public:
GetSessionRequest2() :
- HttpRequest(REQUEST_GET, STEAM_WEB_URL)
+ HttpRequest(HttpGet, STEAM_WEB_URL)
{
flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
}
diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h
index 841910dc32..43bb68d464 100644
--- a/protocols/Steam/src/http_request.h
+++ b/protocols/Steam/src/http_request.h
@@ -1,166 +1,377 @@
#ifndef _HTTP_REQUEST_H_
#define _HTTP_REQUEST_H_
-class HttpResponse : public NETLIBHTTPREQUEST, public MZeroedObject
+class HttpRequest;
+class HttpResponse;
+
+class HttpUri
{
+ friend class HttpRequest;
+
private:
- bool isEmptyResponse;
+ CMStringA m_uri;
+ NETLIBHTTPREQUEST *m_request;
+
+ HttpUri(NETLIBHTTPREQUEST *request, const char *uri)
+ : m_request(request), m_uri(uri)
+ {
+ if (m_request)
+ m_request->szUrl = m_uri.GetBuffer();
+ }
+
+ HttpUri(NETLIBHTTPREQUEST *request, const char *urlFormat, va_list args)
+ : m_request(request)
+ {
+ m_uri.AppendFormatV(urlFormat, args);
+ if (m_request)
+ m_request->szUrl = m_uri.GetBuffer();
+ }
+
+ ~HttpUri()
+ {
+ if (m_request)
+ m_request->szUrl = NULL;
+ }
+
+ void FormatV(const char *urlFormat, va_list args)
+ {
+ m_uri.AppendFormatV(urlFormat, args);
+ if (m_request)
+ m_request->szUrl = m_uri.GetBuffer();
+ }
+
+ void AppendFormat(const char *fmt, ...)
+ {
+ va_list args;
+ va_start(args, fmt);
+ m_uri += (m_uri.Find('?') == -1) ? '?' : '&';
+ m_uri.AppendFormatV(fmt, args);
+ va_end(args);
+
+ if (m_request)
+ m_request->szUrl = m_uri.GetBuffer();
+ }
public:
- const NETLIBHTTPREQUEST* request;
+ HttpUri& operator=(const HttpUri&); // to prevent copying;
- HttpResponse(const NETLIBHTTPREQUEST* response, const NETLIBHTTPREQUEST* request = NULL)
+ operator const char*() const
{
- this->request = request;
- isEmptyResponse = (response == NULL);
- if (response)
- {
- cbSize = response->cbSize;
- requestType = response->requestType;
- flags = response->flags;
- szUrl = mir_strdup(response->szUrl);
- headers = (NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER) * response->headersCount);
- headersCount = response->headersCount;
- for (int i = 0; i < headersCount; i++)
- {
- headers[i].szName = mir_strdup(response->headers[i].szName);
- headers[i].szValue = mir_strdup(response->headers[i].szValue);
- }
- pData = (char*)mir_alloc(response->dataLength);
- dataLength = response->dataLength;
- memcpy(pData, response->pData, dataLength);
- resultCode = response->resultCode;
- szResultDescr = mir_strdup(response->szResultDescr);
- nlc = response->nlc;
- timeout = response->timeout;
- }
- else if (request != NULL)
- {
- // when response is null, we must get resultCode from the request object
- resultCode = request->resultCode;
- }
+ return m_request
+ ? m_request->szUrl
+ : NULL;
}
- bool const operator !() const
+ HttpUri &operator<<(const PARAM &param)
{
- return isEmptyResponse;
+ AppendFormat(param.szName);
+ return *this;
}
- ~HttpResponse()
+ HttpUri &operator<<(const INT_PARAM &param)
{
- for (int i = 0; i < headersCount; i++)
- {
- mir_free(headers[i].szName);
- mir_free(headers[i].szValue);
- }
- mir_free(szUrl);
- mir_free(headers);
- mir_free(pData);
- mir_free(szResultDescr);
+ AppendFormat("%s=%i", param.szName, param.iValue);
+ return *this;
+ }
+
+ HttpUri &operator<<(const INT64_PARAM &param)
+ {
+ AppendFormat("%s=%lld", param.szName, param.iValue);
+ return *this;
+ }
+
+ HttpUri &operator<<(const CHAR_PARAM &param)
+ {
+ AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(param.szValue)));
+ return *this;
}
};
-class HttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject
+class HttpHeaders
{
+ friend class HttpContent;
+ friend class HttpRequest;
+ friend class HttpResponse;
+
private:
- CMStringA m_url;
+ NETLIBHTTPREQUEST *m_request;
+
+ HttpHeaders(NETLIBHTTPREQUEST *request)
+ : m_request(request)
+ {
+ }
+
+ void Set(LPCSTR szName)
+ {
+ Set(szName, "");
+ }
+
+ void Set(LPCSTR szName, LPCSTR szValue)
+ {
+ if (!m_request)
+ return;
+
+ m_request->headers = (NETLIBHTTPHEADER*)mir_realloc(m_request->headers,
+ sizeof(NETLIBHTTPHEADER)*(m_request->headersCount + 1));
+ m_request->headers[m_request->headersCount].szName = mir_strdup(szName);
+ m_request->headers[m_request->headersCount].szValue = mir_strdup(szValue);
+ m_request->headersCount++;
+ }
+
+public:
+ HttpHeaders& operator=(const HttpHeaders&); // to prevent copying;
+
+ const NETLIBHTTPHEADER* operator[](size_t idx) const
+ {
+ return m_request
+ ? &m_request->headers[idx]
+ : NULL;
+ }
+
+ size_t GetSize() const
+ {
+ return m_request
+ ? m_request->headersCount
+ : 0;
+ }
+
+ HttpHeaders& operator<<(const PARAM &param)
+ {
+ Set(param.szName);
+ return *this;
+ }
+
+ HttpHeaders& operator<<(const CHAR_PARAM &param)
+ {
+ Set(param.szName, param.szValue);
+ return *this;
+ }
+};
+
+class HttpContent
+{
+ friend class HttpRequest;
+ friend class HttpResponse;
protected:
- enum HttpRequestUrlFormat { FORMAT };
+ HttpHeaders Headers;
+ NETLIBHTTPREQUEST *m_request;
- void Init(int type)
+ HttpContent(NETLIBHTTPREQUEST *request)
+ : Headers(request), m_request(request)
{
- cbSize = sizeof(NETLIBHTTPREQUEST);
- requestType = type;
- flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT;
- AddHeader("user-agent", "Steam 1.2.0 / iPhone");
}
- void AddHeader(LPCSTR szName, LPCSTR szValue)
+ virtual ~HttpContent()
+ {
+ if (m_request)
+ {
+ m_request->pData = nullptr;
+ m_request->dataLength = 0;
+ }
+ }
+
+public:
+ HttpContent& operator=(const HttpContent&); // to prevent copying;
+
+ operator bool() const
+ {
+ return m_request && m_request->pData && m_request->dataLength;
+ }
+
+ operator const char*() const
{
- headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1));
- headers[headersCount].szName = mir_strdup(szName);
- headers[headersCount].szValue = mir_strdup(szValue);
- headersCount++;
+ return m_request
+ ? m_request->pData
+ : nullptr;
}
- void AddParameter(const char *fmt, ...)
+ const char* GetData() const
+ {
+ return m_request
+ ? m_request->pData
+ : nullptr;
+ }
+
+ size_t GetSize() const
+ {
+ return m_request
+ ? m_request->dataLength
+ : 0;
+ }
+};
+
+class FormUrlEncodedContent : public HttpContent
+{
+ friend FormUrlEncodedContent* operator<<(FormUrlEncodedContent*, const PARAM&);
+ friend FormUrlEncodedContent* operator<<(FormUrlEncodedContent*, const BOOL_PARAM&);
+ friend FormUrlEncodedContent* operator<<(FormUrlEncodedContent*, const INT_PARAM&);
+ friend FormUrlEncodedContent* operator<<(FormUrlEncodedContent*, const INT64_PARAM&);
+ friend FormUrlEncodedContent* operator<<(FormUrlEncodedContent*, const CHAR_PARAM&);
+
+private:
+ CMStringA m_content;
+
+ void AppendFormat(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
- m_url += m_url.Find('?') == -1 ? '?' : '&';
- m_url.AppendFormatV(fmt, args);
+ if (!m_content.IsEmpty())
+ m_content += '&';
+ m_content.AppendFormatV(fmt, args);
va_end(args);
+
+ if (m_request)
+ {
+ m_request->pData = m_content.GetBuffer();
+ m_request->dataLength = m_content.GetLength();
+ }
}
- void AddParameter(LPCSTR name, LPCSTR value)
+public:
+ FormUrlEncodedContent(NETLIBHTTPREQUEST *request)
+ : HttpContent(request)
{
- AddParameter("%s=%s", name, value);
+ Headers << CHAR_PARAM("Content-Type", "application/x-www-form-urlencoded");
}
+};
+
+__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const PARAM &param)
+{
+ content->AppendFormat(param.szName);
+ return content;
+}
- void SetData(const char *data, size_t size)
+__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const BOOL_PARAM &param)
+{
+ content->AppendFormat("%s=%s", param.szName, param.bValue ? "true" : "false");
+ return content;
+}
+
+__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const INT_PARAM &param)
+{
+ content->AppendFormat("%s=%i", param.szName, param.iValue);
+ return content;
+}
+
+__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const INT64_PARAM &param)
+{
+ content->AppendFormat("%s=%lld", param.szName, param.iValue);
+ return content;
+}
+
+__forceinline FormUrlEncodedContent* operator<<(FormUrlEncodedContent *content, const CHAR_PARAM &param)
+{
+ content->AppendFormat("%s=%s", param.szName, ptrA(mir_urlEncode(param.szValue)));
+ return content;
+}
+
+enum HttpMethod
+{
+ HttpGet = 1,
+ HttpPost
+};
+
+class HttpResponse
+{
+ friend class HttpRequest;
+
+private:
+ NETLIBHTTPREQUEST *m_response;
+
+public:
+ HttpRequest *Request;
+ HttpHeaders Headers;
+ HttpContent Content;
+
+ HttpResponse(HttpRequest *request, NETLIBHTTPREQUEST *response)
+ : Request(request),
+ m_response(response),
+ Headers(response),
+ Content(response)
+ {
+ }
+
+ ~HttpResponse()
+ {
+ Netlib_FreeHttpRequest(m_response);
+ }
+
+ bool operator!() const
{
- if (pData != NULL)
- mir_free(pData);
+ return !m_response || !m_response->pData;
+ }
+
+ operator bool() const
+ {
+ return m_response && m_response->pData;
+ }
- dataLength = (int)size;
- pData = (char*)mir_alloc(size + 1);
- memcpy(pData, data, size);
- pData[size] = 0;
+ bool IsSuccess() const
+ {
+ return m_response &&
+ m_response->resultCode >= HTTP_CODE_OK &&
+ m_response->resultCode <= HTTP_CODE_MULTI_STATUS;
+ }
+
+ int GetStatusCode() const
+ {
+ return m_response->resultCode;
}
+};
+
+class HttpRequest : protected NETLIBHTTPREQUEST, public MZeroedObject
+{
+ friend class HttpUri;
+ friend class HttpHeaders;
+ friend class HttpContent;
+
+protected:
+ enum HttpRequestUrlFormat { FORMAT };
public:
- HttpRequest(int type, LPCSTR url)
+ HttpUri Uri;
+ HttpHeaders Headers;
+ HttpContent *Content;
+
+ HttpRequest(HttpMethod method, const char *url)
+ : Uri(this, url), Headers(this), Content(nullptr)
{
- Init(type);
+ cbSize = sizeof(NETLIBHTTPREQUEST);
+ requestType = method;
+ flags = NLHRF_HTTP11 | NLHRF_SSL;
- m_url = url;
+ Content = new HttpContent(this);
}
- HttpRequest(int type, HttpRequestUrlFormat, LPCSTR urlFormat, ...)
+ HttpRequest(HttpMethod method, HttpRequestUrlFormat, const char *urlFormat, ...)
+ : Uri(this, urlFormat), Headers(this), Content(nullptr)
{
- Init(type);
+ cbSize = sizeof(NETLIBHTTPREQUEST);
+ requestType = method;
+ flags = NLHRF_HTTP11 | NLHRF_SSL;
va_list formatArgs;
va_start(formatArgs, urlFormat);
- m_url.AppendFormatV(urlFormat, formatArgs);
+ Uri.FormatV(urlFormat, formatArgs);
va_end(formatArgs);
+
+ Content = new HttpContent(this);
}
~HttpRequest()
{
- for (int i = 0; i < headersCount; i++)
+ if (Content != nullptr)
{
- mir_free(headers[i].szName);
- mir_free(headers[i].szValue);
+ delete Content;
+ Content = nullptr;
}
- mir_free(headers);
-
- if (pData != NULL)
- mir_free(pData);
}
- HttpResponse* Send(HNETLIBUSER nlu)
+ operator NETLIBHTTPREQUEST*()
{
- szUrl = m_url.GetBuffer();
-
- Netlib_Logf(nlu, "Send request to %s", szUrl);
-
- NETLIBHTTPREQUEST* response = Netlib_HttpTransaction(nlu, this);
- HttpResponse* result = new HttpResponse(response, this);
- Netlib_FreeHttpRequest(response);
-
- return result;
+ return this;
}
};
-
-bool __forceinline ResponseHttpOk(const HttpResponse *response) {
- return (response && response->pData && (response->resultCode == HTTP_CODE_OK));
-}
-
-bool __forceinline CheckResponse(const HttpResponse *response) {
- return (response && response->pData);
-}
-
#endif //_HTTP_REQUEST_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/request_queue.cpp b/protocols/Steam/src/request_queue.cpp
deleted file mode 100644
index 84d6414c40..0000000000
--- a/protocols/Steam/src/request_queue.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-Copyright (c) 2015-17 Miranda NG project (https://miranda-ng.org)
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation version 2
-of the License.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "stdafx.h"
-
-RequestQueue::RequestQueue(HNETLIBUSER hConnection) :
- hConnection(hConnection), requests(1)
-{
- isTerminated = true;
- hRequestQueueThread = nullptr;
- hRequestQueueEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
-}
-
-RequestQueue::~RequestQueue()
-{
- requests.destroy();
- CloseHandle(hRequestQueueEvent);
-}
-
-void RequestQueue::Start()
-{
- if (!isTerminated)
- return;
-
- isTerminated = false;
- if (hRequestQueueThread == nullptr)
- hRequestQueueThread = mir_forkthread((pThreadFunc)&RequestQueue::WorkerThread, this);
-}
-
-void RequestQueue::Stop()
-{
- if (isTerminated)
- return;
-
- isTerminated = true;
- SetEvent(hRequestQueueEvent);
-}
-
-void RequestQueue::Push(HttpRequest *request, HttpResponseCallback response, void *arg, HttpFinallyCallback last)
-{
- if (isTerminated)
- return;
-
- RequestQueueItem *item = new RequestQueueItem(request, response, arg, last);
- {
- mir_cslock lock(requestQueueLock);
-
- requests.insert(item);
- }
- SetEvent(hRequestQueueEvent);
-}
-
-void RequestQueue::Send(HttpRequest *request, HttpResponseCallback response, void *arg, HttpFinallyCallback last)
-{
- RequestQueueItem *item = new RequestQueueItem(request, response, arg, last);
- mir_forkthreadowner((pThreadFuncOwner)&RequestQueue::AsyncSendThread, this, item, nullptr);
-}
-
-void RequestQueue::Execute(RequestQueueItem *item)
-{
- HttpResponse *response = item->request->Send(hConnection);
- if (item->responseCallback != nullptr)
- item->responseCallback(response, item->arg);
- if (item->finallyCallback != nullptr)
- item->finallyCallback(item->arg);
- delete item;
- delete response;
-}
-
-unsigned int RequestQueue::AsyncSendThread(void *owner, void *arg)
-{
- RequestQueue *queue = (RequestQueue*)owner;
- RequestQueueItem *item = (RequestQueueItem*)arg;
-
- queue->Execute(item);
-
- return 0;
-}
-
-unsigned int RequestQueue::WorkerThread(void *arg)
-{
- RequestQueue *queue = (RequestQueue*)arg;
-
- while (!queue->isTerminated)
- {
- WaitForSingleObject(queue->hRequestQueueEvent, INFINITE);
- while (true)
- {
- RequestQueueItem *item = nullptr;
- {
- mir_cslock lock(queue->requestQueueLock);
-
- if (queue->requests.getCount() == 0)
- break;
-
- item = queue->requests[0];
- queue->requests.remove(0);
- }
- if (item != nullptr)
- queue->Execute(item);
- }
- }
-
- queue->hRequestQueueThread = nullptr;
- return 0;
-} \ No newline at end of file
diff --git a/protocols/Steam/src/request_queue.h b/protocols/Steam/src/request_queue.h
deleted file mode 100644
index 6d14209fb8..0000000000
--- a/protocols/Steam/src/request_queue.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef _REQUEST_QUEUE_H_
-#define _REQUEST_QUEUE_H_
-
-typedef void(*HttpResponseCallback)(const HttpResponse *response, void *arg);
-typedef void(*HttpFinallyCallback)(void *arg);
-
-struct RequestQueueItem
-{
- void *arg;
- HttpRequest *request;
- HttpResponseCallback responseCallback;
- HttpFinallyCallback finallyCallback;
-
- RequestQueueItem(HttpRequest *request, void *arg, HttpFinallyCallback finallyCallback) :
- request(request), responseCallback(NULL), arg(arg), finallyCallback(finallyCallback)
- {
- }
-
- RequestQueueItem(HttpRequest *request, HttpResponseCallback response, void *arg, HttpFinallyCallback finallyCallback) :
- request(request), responseCallback(response), arg(arg), finallyCallback(finallyCallback)
- {
- }
-
- ~RequestQueueItem()
- {
- delete request;
- request = NULL;
- responseCallback = NULL;
- finallyCallback = NULL;
- }
-};
-
-class RequestQueue
-{
- bool isTerminated;
- HNETLIBUSER hConnection;
- mir_cs requestQueueLock;
- LIST<RequestQueueItem> requests;
- HANDLE hRequestQueueEvent, hRequestQueueThread;
-
- void Execute(RequestQueueItem *item);
-
- static unsigned int __cdecl AsyncSendThread(void*, void*);
- static unsigned int __cdecl WorkerThread(void*);
-
-public:
- RequestQueue(HNETLIBUSER hConnection);
- ~RequestQueue();
-
- void Start();
- void Stop();
-
- void Push(HttpRequest *request, HttpResponseCallback response = NULL, void *arg = NULL, HttpFinallyCallback last = NULL);
- void Send(HttpRequest *request, HttpResponseCallback response = NULL, void *arg = NULL, HttpFinallyCallback last = NULL);
-
-};
-
-#endif //_REQUEST_QUEUE_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/resource.h b/protocols/Steam/src/resource.h
index bafc927a3b..fa9145b922 100644
--- a/protocols/Steam/src/resource.h
+++ b/protocols/Steam/src/resource.h
@@ -1,6 +1,6 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
-// Used by D:\Development\Miranda NG\Miranda NG\protocols\Steam\res\Resource.rc
+// Used by D:\Projects\c++\miranda-ng\protocols\Steam\res\Resource.rc
//
#define IDD_ACCMGR 9
#define IDD_OPT_MAIN 10
@@ -39,7 +39,7 @@
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 121
+#define _APS_NEXT_RESOURCE_VALUE 125
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1085
#define _APS_NEXT_SYMED_VALUE 101
diff --git a/protocols/Steam/src/stdafx.h b/protocols/Steam/src/stdafx.h
index 3abce22f89..7b2a070da4 100644
--- a/protocols/Steam/src/stdafx.h
+++ b/protocols/Steam/src/stdafx.h
@@ -62,7 +62,7 @@ extern HANDLE hExtraXStatus;
#include "steam_dialogs.h"
#include "steam_options.h"
#include "http_request.h"
-#include "request_queue.h"
+#include "api/app_info.h"
#include "api/authorization.h"
#include "api/authorization.h"
#include "api/avatar.h"
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index 7546f33d40..fddad8a4a5 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -50,13 +50,8 @@ void CSteamProto::SetContactStatus(MCONTACT hContact, WORD status)
void CSteamProto::SetAllContactsStatus(WORD status)
{
- for (MCONTACT hContact = db_find_first(this->m_szModuleName); hContact; hContact = db_find_next(hContact, this->m_szModuleName))
- {
- if (this->isChatRoom(hContact))
- continue;
-
+ for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName))
SetContactStatus(hContact, status);
- }
}
MCONTACT CSteamProto::GetContactFromAuthEvent(MEVENT hEvent)
@@ -84,7 +79,7 @@ MCONTACT CSteamProto::FindContact(const char *steamId)
mir_cslock lck(this->contact_search_lock);
- for (hContact = db_find_first(this->m_szModuleName); hContact; hContact = db_find_next(hContact, this->m_szModuleName))
+ 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))
@@ -94,34 +89,34 @@ MCONTACT CSteamProto::FindContact(const char *steamId)
return hContact;
}
-void CSteamProto::UpdateContactDetails(MCONTACT hContact, JSONNode *data)
+void CSteamProto::UpdateContactDetails(MCONTACT hContact, const JSONNode &data)
{
// set common data
- JSONNode *node = json_get(data, "personaname");
- setWString(hContact, "Nick", ptrW(json_as_string(node)));
+ CMStringW nick = data["personaname"].as_mstring();
+ setWString(hContact, "Nick", nick);
- node = json_get(data, "profileurl");
- setString(hContact, "Homepage", _T2A(ptrW(json_as_string(node))));
+ json_string homepage = data["profileurl"].as_string();
+ setString(hContact, "Homepage", homepage.c_str());
- node = json_get(data, "primaryclanid");
- setString(hContact, "PrimaryClanID", _T2A(ptrW(json_as_string(node))));
+ json_string primaryClanId = data["primaryclanid"].as_string();
+ setString(hContact, "PrimaryClanID", primaryClanId.c_str());
// set name
- node = json_get(data, "realname");
- if (node != nullptr)
+ JSONNode node = data["realname"];
+ if (!node.isnull())
{
- std::wstring realname = (wchar_t*)ptrW(json_as_string(node));
- if (!realname.empty())
+ CMStringW realName = node.as_mstring();
+ if (!realName.IsEmpty())
{
- size_t pos = realname.find(L' ', 1);
- if (pos != std::wstring::npos)
+ int pos = realName.Find(L' ', 1);
+ if (pos != -1)
{
- setWString(hContact, "FirstName", realname.substr(0, pos).c_str());
- setWString(hContact, "LastName", realname.substr(pos + 1).c_str());
+ setWString(hContact, "FirstName", realName.Mid(0, pos));
+ setWString(hContact, "LastName", realName.Mid(pos + 1));
}
else
{
- setWString(hContact, "FirstName", realname.c_str());
+ setWString(hContact, "FirstName", realName);
delSetting(hContact, "LastName");
}
}
@@ -134,42 +129,41 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, JSONNode *data)
// avatar
bool biggerAvatars = getBool("UseBigAvatars", false);
- node = json_get(data, biggerAvatars ? "avatarfull" : "avatarmedium");
- std::string avatarUrl = (char*)_T2A(ptrW(json_as_string(node)));
+ json_string avatarUrl = data[biggerAvatars ? "avatarfull" : "avatarmedium"].as_string();
CheckAvatarChange(hContact, avatarUrl);
// set country
- node = json_get(data, "loccountrycode");
- if (node != nullptr)
+ node = data["loccountrycode"];
+ if (!node.isnull())
{
- const char *iso = ptrA(mir_u2a(ptrW(json_as_string(node))));
- char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)iso, 0);
+ json_string countryCode = node.as_string();
+ char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)countryCode.c_str(), 0);
setString(hContact, "Country", country);
}
else
delSetting(hContact, "Country");
// state code
- node = json_get(data, "locstatecode");
- if (node)
- setDword(hContact, "StateCode", json_as_int(node));
+ node = data["locstatecode"];
+ if (!node.isnull())
+ setDword(hContact, "StateCode", node.as_int());
else
delSetting(hContact, "StateCode");
// city id
- node = json_get(data, "loccityid");
- if (node)
- setDword(hContact, "CityID", json_as_int(node));
+ node = data["loccityid"];
+ if (!node.isnull())
+ setDword(hContact, "CityID", node.as_int());
else
delSetting(hContact, "CityID");
// account created
- node = json_get(data, "timecreated");
- setDword(hContact, "MemberTS", json_as_int(node));
+ node = data["timecreated"];
+ setDword(hContact, "MemberTS", node.as_int());
// last logout time
- node = json_get(data, "lastlogoff");
- setDword(hContact, "LogoffTS", json_as_int(node));
+ node = data["lastlogoff"];
+ 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
@@ -179,9 +173,8 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, JSONNode *data)
*/
// client
- node = json_get(data, "personastateflags");
- int stateflags = node ? json_as_int(node) : -1;
-
+ node = data["personastateflags"];
+ int 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);
@@ -208,31 +201,36 @@ void CSteamProto::UpdateContactDetails(MCONTACT hContact, JSONNode *data)
// none/unknown (e.g. when contact is offline)
delSetting(hContact, "MirVer");
}
-
- // playing game
- node = json_get(data, "gameid");
- DWORD gameId = node ? atol(_T2A(ptrW(json_as_string(node)))) : 0;
-
- node = json_get(data, "gameextrainfo");
- ptrW gameInfo(json_as_string(node));
- if (gameId > 0 || gameInfo[0] != '\0')
+ // playing game
+ json_string appId = data["gameid"].as_string();
+ CMStringW gameInfo = data["gameextrainfo"].as_mstring();
+ if (!appId.empty() || !gameInfo.IsEmpty())
{
- node = json_get(data, "gameserverip");
- ptrW serverIP(json_as_string(node));
-
- node = json_get(data, "gameserversteamid");
- ptrW serverID (json_as_string(node));
+ DWORD gameId = atol(appId.c_str());
+ json_string serverIP = data["gameserverip"].as_string();
+ json_string serverID = data["gameserversteamid"].as_string();
setDword(hContact, "GameID", gameId);
- setString(hContact, "ServerIP", _T2A(serverIP));
- setString(hContact, "ServerID", _T2A(serverID));
+ setString(hContact, "ServerIP", serverIP.c_str());
+ setString(hContact, "ServerID", serverID.c_str());
CMStringW message(gameInfo);
- if (!gameId)
- message.Append(TranslateT(" (Non-Steam)"));
- if (serverIP[0] != '\0')
- message.AppendFormat(TranslateT(" on server %s"), serverIP);
+ if (gameId && message.IsEmpty())
+ {
+ ptrA token(getStringA("TokenSecret"));
+ PushRequest(
+ new GetAppInfoRequest(token, appId.c_str()),
+ &CSteamProto::OnGotAppInfo,
+ (void*)hContact);
+ }
+ else
+ {
+ if (!gameId)
+ message.Append(TranslateT(" (Non-Steam)"));
+ if (!serverIP.empty())
+ message.AppendFormat(TranslateT(" on server %s"), serverIP.c_str());
+ }
setDword(hContact, "XStatusId", gameId);
setWString(hContact, "XStatusName", TranslateT("Playing"));
@@ -388,86 +386,75 @@ MCONTACT CSteamProto::AddContact(const char *steamId, bool isTemporary)
return hContact;
}
-void CSteamProto::UpdateContactRelationship(MCONTACT hContact, JSONNode *data)
+void CSteamProto::UpdateContactRelationship(MCONTACT hContact, const JSONNode &data)
{
- JSONNode *node = json_get(data, "friend_since");
- if (node)
- db_set_dw(hContact, "UserInfo", "ContactAddTime", json_as_int(node));
+ JSONNode node = data["friend_since"];
+ if (!node.isnull())
+ db_set_dw(hContact, "UserInfo", "ContactAddTime", node.as_int());
- node = json_get(data, "relationship");
- if (node == nullptr)
+ node = data["relationship"];
+ if (node.isnull())
return;
- ptrA relationship(mir_u2a(ptrW(json_as_string(node))));
- if (!lstrcmpiA(relationship, "friend"))
- {
+ json_string relationship = node.as_string();
+ if (!lstrcmpiA(relationship.c_str(), "friend"))
ContactIsFriend(hContact);
- }
- else if (!lstrcmpiA(relationship, "ignoredfriend"))
- {
+ else if (!lstrcmpiA(relationship.c_str(), "ignoredfriend"))
ContactIsIgnored(hContact);
- }
- else if (!lstrcmpiA(relationship, "requestrecipient"))
- {
+ else if (!lstrcmpiA(relationship.c_str(), "requestrecipient"))
ContactIsAskingAuth(hContact);
- }
}
-void CSteamProto::OnGotFriendList(const HttpResponse *response)
+void CSteamProto::OnGotAppInfo(const JSONNode &root, void *arg)
{
- if (!CheckResponse(response))
- return;
+ MCONTACT hContact = (UINT_PTR)arg;
- JSONROOT root(response->pData);
- if (root == nullptr)
+ JSONNode apps = root["apps"].as_array();
+ for (const JSONNode &app : apps)
+ {
+ DWORD gameId = app["appid"].as_int();
+ CMStringW message = app["name"].as_mstring();
+
+ setDword(hContact, "XStatusId", gameId);
+ setWString(hContact, "XStatusName", TranslateT("Playing"));
+ setWString(hContact, "XStatusMsg", message);
+ }
+}
+
+void CSteamProto::OnGotFriendList(const JSONNode &root, void*)
+{
+ if (root.isnull())
return;
+ // Comma-separated list of steam ids to update summaries
std::string steamIds = (char*)ptrA(getStringA("SteamID"));
- std::map<std::string, JSONNode*> friends;
-
// Remember contacts on server
- JSONNode *node = json_get(root, "friends");
- JSONNode *nroot = json_as_array(node);
- if (nroot != nullptr)
+ std::map<json_string, JSONNode*> friendsMap;
+ JSONNode friends = root["friends"].as_array();
+ for (const JSONNode &_friend : friends)
{
- for (size_t i = 0; i < json_size(nroot); i++)
- {
- JSONNode *child = json_at(nroot, i);
- if (child == nullptr)
- break;
-
- node = json_get(child, "steamid");
- if (node == nullptr)
- continue;
-
- std::string steamId = (char*)_T2A(ptrW(json_as_string(node)));
- friends.insert(std::make_pair(steamId, child));
- }
+ json_string steamId = _friend["steamid"].as_string();
+ friendsMap.insert(std::make_pair(steamId, json_copy(&_friend)));
}
- {
- // Check and update contacts in database
+ { // 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))
{
- if (isChatRoom(hContact))
- continue;
-
- ptrA id(getStringA(hContact, "SteamID"));
- if (id == NULL)
+ ptrA steamId(getStringA(hContact, "SteamID"));
+ if (steamId == nullptr)
continue;
- std::map<std::string, JSONNode*>::iterator it = friends.find(std::string(id));
-
- if (it != friends.end())
+ auto it = friendsMap.find((char*)steamId);
+ if (it != friendsMap.end())
{
// Contact is on server-list, update (and eventually notify) it
- UpdateContactRelationship(hContact, it->second);
-
+ UpdateContactRelationship(hContact, *it->second);
steamIds.append(",").append(it->first);
- friends.erase(it);
+ json_delete(it->second);
+ friendsMap.erase(it);
}
else
{
@@ -478,19 +465,19 @@ void CSteamProto::OnGotFriendList(const HttpResponse *response)
}
// Check remaining contacts in map and add them to contact list
- for (std::map<std::string, JSONNode*>::iterator it = friends.begin(); it != friends.end();)
+ 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);
+ MCONTACT hContact = AddContact(it.first.c_str());
+ UpdateContactRelationship(hContact, *it.second);
- steamIds.append(",").append(it->first);
- it = friends.erase(it);
+ steamIds.append(",").append(it.first);
+ json_delete(it.second);
}
- friends.clear();
+ 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);
+ // json_delete(nroot);
ptrA token(getStringA("TokenSecret"));
@@ -509,93 +496,68 @@ void CSteamProto::OnGotFriendList(const HttpResponse *response)
&CSteamProto::OnGotConversations);
}
-void CSteamProto::OnGotBlockList(const HttpResponse *response)
+void CSteamProto::OnGotBlockList(const JSONNode &root, void*)
{
- if (!CheckResponse(response))
- return;
-
- JSONROOT root(response->pData);
- if (root == nullptr)
+ if (root.isnull())
return;
//std::string steamIds;
- JSONNode *node = json_get(root, "friends");
- JSONNode *nroot = json_as_array(node);
- if (nroot != nullptr)
- {
- for (size_t i = 0; i < json_size(nroot); i++)
- {
- JSONNode *child = json_at(nroot, i);
- if (child == nullptr)
- break;
+ JSONNode friends = root["friends"].as_array();
+ if (friends.isnull())
+ return;
- node = json_get(child, "steamid");
- ptrA steamId(mir_u2a(ptrW(json_as_string(node))));
+ for (size_t i = 0; i < friends.size(); i++)
+ {
+ JSONNode node = friends[i].as_node();
- /*MCONTACT hContact = FindContact(steamId);
- if (!hContact)
- {
- hContact = AddContact(steamId);
- steamIds.append(steamId).append(",");
- }*/
+ json_string steamId = node["steamid"].as_string();
- node = json_get(child, "relationship");
- ptrA relationship(mir_u2a(ptrW(json_as_string(node))));
+ /*MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ {
+ hContact = AddContact(steamId);
+ steamIds.append(steamId).append(",");
+ }*/
- if (!lstrcmpiA(relationship, "ignoredfriend"))
- {
- // todo: open block list
- }
- else continue;
+ json_string relationship = node["relationship"].as_string();
+ if (!lstrcmpiA(relationship.c_str(), "ignoredfriend"))
+ {
+ // todo: open block list
}
- json_delete(nroot);
+ else continue;
}
}
-void CSteamProto::OnGotUserSummaries(const HttpResponse *response)
+void CSteamProto::OnGotUserSummaries(const JSONNode &root, void*)
{
- if (!CheckResponse(response))
+ JSONNode players = root["players"].as_array();
+ if (players.isnull())
return;
- JSONROOT root(response->pData);
- if (root == nullptr)
- return;
-
- JSONNode *node = json_get(root, "players");
- JSONNode *nroot = json_as_array(node);
- if (nroot != nullptr)
+ for (size_t i = 0; i < players.size(); i++)
{
- for (size_t i = 0; i < json_size(nroot); i++)
- {
- JSONNode *item = json_at(nroot, i);
- if (item == nullptr)
- break;
-
- node = json_get(item, "steamid");
- ptrA steamId(mir_u2a(ptrW(json_as_string(node))));
+ JSONNode player = players[i];
+ json_string steamId = player["steamid"].as_string();
- MCONTACT hContact = NULL;
- if (!IsMe(steamId)) {
- hContact = AddContact(steamId);
- }
+ MCONTACT hContact = NULL;
+ if (!IsMe(steamId.c_str()))
+ hContact = AddContact(steamId.c_str());
- UpdateContactDetails(hContact, item);
- }
- json_delete(nroot);
+ UpdateContactDetails(hContact, player);
}
}
-void CSteamProto::OnGotAvatar(const HttpResponse *response, void *arg)
+void CSteamProto::OnGotAvatar(const HttpResponse &response, void *arg)
{
PROTO_AVATAR_INFORMATION ai = { 0 };
ai.hContact = (UINT_PTR)arg;
GetDbAvatarInfo(ai);
- if (!ResponseHttpOk(response))
+ if (!response.IsSuccess())
{
ptrA steamId(getStringA(ai.hContact, "SteamID"));
- debugLogA("CSteamProto::OnGotAvatar: failed to get avatar %s", steamId);
+ debugLogA(__FUNCTION__ ": failed to get avatar %s", steamId);
if (ai.hContact)
ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, 0);
@@ -605,7 +567,7 @@ void CSteamProto::OnGotAvatar(const HttpResponse *response, void *arg)
FILE *fp = _wfopen(ai.filename, L"wb");
if (fp)
{
- fwrite(response->pData, sizeof(char), response->dataLength, fp);
+ fwrite(response.Content, sizeof(char), response.Content.GetSize(), fp);
fclose(fp);
if (ai.hContact)
@@ -615,14 +577,14 @@ void CSteamProto::OnGotAvatar(const HttpResponse *response, void *arg)
}
}
-void CSteamProto::OnFriendAdded(const HttpResponse *response, void *arg)
+void CSteamProto::OnFriendAdded(const HttpResponse &response, void *arg)
{
SendAuthParam *param = (SendAuthParam*)arg;
- if (!response || response->resultCode != HTTP_CODE_OK || lstrcmpiA(response->pData, "true"))
+ if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
{
ptrA steamId(getStringA(param->hContact, "SteamID"));
- debugLogA("CSteamProto::OnFriendAdded: failed to add friend %s", steamId);
+ debugLogA(__FUNCTION__ ": failed to add friend %s", steamId);
ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_FAILED, param->hAuth, 0);
@@ -637,24 +599,26 @@ void CSteamProto::OnFriendAdded(const HttpResponse *response, void *arg)
ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_SUCCESS, param->hAuth, 0);
}
-void CSteamProto::OnFriendBlocked(const HttpResponse *response, void *arg)
+void CSteamProto::OnFriendBlocked(const HttpResponse &response, void *arg)
{
- if (!response || response->resultCode != HTTP_CODE_OK || lstrcmpiA(response->pData, "true"))
+ ptrA steamId((char*)arg);
+
+ if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
{
- debugLogA("CSteamProto::OnFriendIgnored: failed to ignore friend %s", (char*)arg);
+ debugLogA(__FUNCTION__ ": failed to ignore friend %s", (char*)arg);
return;
}
}
-void CSteamProto::OnFriendRemoved(const HttpResponse *response, void *arg)
+void CSteamProto::OnFriendRemoved(const HttpResponse &response, void *arg)
{
MCONTACT hContact = (UINT_PTR)arg;
- if (!response || response->resultCode != HTTP_CODE_OK || lstrcmpiA(response->pData, "true"))
+ if (!response.IsSuccess() || lstrcmpiA(response.Content, "true"))
{
ptrA who(getStringA(hContact, "SteamID"));
- debugLogA("CSteamProto::OnFriendRemoved: failed to remove friend %s", who);
+ debugLogA(__FUNCTION__ ": failed to remove friend %s", who);
return;
}
@@ -662,155 +626,123 @@ void CSteamProto::OnFriendRemoved(const HttpResponse *response, void *arg)
setDword(hContact, "DeletedTS", ::time(nullptr));
}
-void CSteamProto::OnAuthRequested(const HttpResponse *response, void *arg)
+void CSteamProto::OnAuthRequested(const JSONNode &root, void*)
{
- if (!ResponseHttpOk(response))
- {
- debugLogA("CSteamProto::OnAuthRequested: failed to request info for %s", (char*)arg);
+ if (root.isnull())
return;
- }
-
- JSONROOT root(response->pData);
- if (root == nullptr)
- return;
-
- JSONNode *node = json_get(root, "players");
- JSONNode *nodes = json_as_array(node);
- JSONNode *nroot = json_at(nodes, 0);
- if (nroot != nullptr)
+ int first = 0;
+ JSONNode players = root["players"].as_array();
+ JSONNode player = players[first];
+ if (!player.isnull())
{
- node = json_get(nroot, "steamid");
- ptrA steamId(mir_u2a(ptrW(json_as_string(node))));
-
- MCONTACT hContact = AddContact(steamId);
-
- UpdateContactDetails(hContact, nroot);
-
+ json_string steamId = player["steamid"].as_string();
+ MCONTACT hContact = AddContact(steamId.c_str());
+ UpdateContactDetails(hContact, player);
ContactIsAskingAuth(hContact);
}
-
- json_delete(nodes);
}
-void CSteamProto::OnPendingApproved(const HttpResponse *response, void *arg)
+void CSteamProto::OnPendingApproved(const JSONNode &root, void *arg)
{
- if (!ResponseHttpOk(response))
- {
- debugLogA("CSteamProto::OnPendingApproved: failed to approve pending from %s", (char*)arg);
- return;
- }
+ ptrA steamId((char*)arg);
- JSONROOT root(response->pData);
- if (root == nullptr)
+ if (root.isnull())
return;
- JSONNode *node = json_get(root, "success");
- if (json_as_int(node) == 0)
+ int success = root["success"].as_int();
+ if (success == 0)
{
- node = json_get(root, "error_text");
- debugLogA("CSteamProto::OnPendingApproved: failed to approve pending from %s (%s)", (char*)arg, ptrA(mir_utf8encodeW(ptrW(json_as_string(node)))));
+ json_string error = root["error_text"].as_string();
+ debugLogA(__FUNCTION__ ": failed to approve pending from %s (%s)", steamId, ptrA(mir_utf8decodeA(error.c_str())));
}
}
-void CSteamProto::OnPendingIgnoreded(const HttpResponse *response, void *arg)
+void CSteamProto::OnPendingIgnoreded(const JSONNode &root, void *arg)
{
- if (!ResponseHttpOk(response))
- {
- debugLogA("CSteamProto::OnPendingIgnored: failed to ignore pending from %s", (char*)arg);
- return;
- }
+ ptrA steamId((char*)arg);
- JSONROOT root(response->pData);
- if (root == nullptr)
+ if (root.isnull())
return;
- JSONNode *node = json_get(root, "success");
- if (json_as_int(node) == 0)
+ int success = root["success"].as_int();
+ if (success == 0)
{
- node = json_get(root, "error_text");
- debugLogA("CSteamProto::OnPendingIgnored: failed to ignore pending from %s (%s)", (char*)arg, ptrA(mir_utf8encodeW(ptrW(json_as_string(node)))));
+ json_string error = root["error_text"].as_string();
+ debugLogA(__FUNCTION__ ": failed to ignore pending from %s (%s)", steamId, ptrA(mir_utf8decodeA(error.c_str())));
}
}
-void CSteamProto::OnSearchResults(const HttpResponse *response, void *arg)
+void CSteamProto::OnSearchResults(const HttpResponse &response, void *arg)
{
HANDLE searchType = (HANDLE)arg;
- if (!ResponseHttpOk(response))
+ if (!response.IsSuccess())
{
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, searchType, 0);
- debugLogA("CSteamProto::AddSearchResults: failed to get summaries");
+ debugLogA(__FUNCTION__ ": failed to get summaries");
return;
}
- JSONROOT root(response->pData);
- if (root == nullptr)
+ JSONNode root = JSONNode::parse(response.Content);
+ if (root.isnull())
{
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, searchType, 0);
return;
}
- JSONNode *node = json_get(root, "players");
- JSONNode *nroot = json_as_array(node);
- if (nroot != nullptr)
+ JSONNode players = root["players"].as_array();
+ for (size_t i = 0; i < players.size(); i++)
{
- for (size_t i = 0; i < json_size(nroot); i++)
- {
- JSONNode *child = json_at(nroot, i);
- if (child == nullptr)
- break;
+ JSONNode player = players[i];
- STEAM_SEARCH_RESULT ssr = { 0 };
- ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT);
- ssr.hdr.flags = PSR_UNICODE;
+ STEAM_SEARCH_RESULT ssr = { 0 };
+ ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT);
+ ssr.hdr.flags = PSR_UNICODE;
- node = json_get(child, "steamid");
- ssr.hdr.id.w = mir_wstrdup(ptrW(json_as_string(node)));
+ CMStringW steamId = player["steamid"].as_mstring();
+ ssr.hdr.id.w = steamId.Detach();
- node = json_get(child, "personaname");
- ssr.hdr.nick.w = mir_wstrdup(ptrW(json_as_string(node)));
+ CMStringW nick = player["personaname"].as_mstring();
+ ssr.hdr.nick.w = nick.Detach();
- node = json_get(child, "realname");
- if (node != nullptr)
+ JSONNode node = player["realname"];
+ if (!node.isnull())
+ {
+ CMStringW realName = node.as_mstring();
+ if (!realName.IsEmpty())
{
- std::wstring realname = (wchar_t*)ptrW(json_as_string(node));
- if (!realname.empty())
+ int pos = realName.Find(' ', 1);
+ if (pos != -1)
{
- size_t pos = realname.find(' ', 1);
- if (pos != std::wstring::npos)
- {
- ssr.hdr.firstName.w = mir_wstrdup(realname.substr(0, pos).c_str());
- ssr.hdr.lastName.w = mir_wstrdup(realname.substr(pos + 1).c_str());
- }
- else
- ssr.hdr.firstName.w = mir_wstrdup(realname.c_str());
+ ssr.hdr.firstName.w = realName.Mid(0, pos).Detach();
+ ssr.hdr.lastName.w = realName.Mid(pos + 1).Detach();
}
+ else
+ ssr.hdr.firstName.w = realName.Detach();
}
+ }
- //ssr.contact = contact;
- ssr.data = json_copy(child); // FIXME: is this needed and safe (no memleak) to be here?
+ //ssr.contact = contact;
+ ssr.data = json_copy(&player); // FIXME: is this needed and safe (no memleak) to be here?
- ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, searchType, (LPARAM)&ssr);
- }
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, searchType, (LPARAM)&ssr);
}
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, searchType, 0);
-
- json_delete(nroot);
}
-void CSteamProto::OnSearchByNameStarted(const HttpResponse *response, void *arg)
+void CSteamProto::OnSearchByNameStarted(const HttpResponse &response, void *arg)
{
- if (!ResponseHttpOk(response))
+ if (!response.IsSuccess())
{
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)arg, 0);
- debugLogA("CSteamProto::OnSearchByNameEnded: failed to get results");
+ debugLogA(__FUNCTION__ ": failed to get results");
return;
}
- JSONROOT root(response->pData);
- if (root == nullptr)
+ JSONNode root = JSONNode::parse(response.Content);
+ if (root.isnull())
{
ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)arg, 0);
return;
@@ -822,24 +754,12 @@ void CSteamProto::OnSearchByNameStarted(const HttpResponse *response, void *arg)
std::string steamIds;
- JSONNode *node = json_get(root, "results");
- JSONNode *nroot = json_as_array(node);
- if (nroot != nullptr)
+ JSONNode results = root["results"].as_array();
+ for (size_t i = 0; i < results.size(); i++)
{
- for (size_t i = 0; i < json_size(nroot); i++)
- {
- JSONNode *child = json_at(nroot, i);
- if (child == nullptr)
- break;
-
- node = json_get(child, "steamid");
- if (node == nullptr)
- continue;
-
- std::string steamId = (char*)_T2A(ptrW(json_as_string(node)));
- steamIds.append(steamId).append(",");
- }
- json_delete(nroot);
+ JSONNode result = results[i];
+ json_string steamId = result["steamid"].as_string();
+ steamIds.append(steamId).append(",");
}
if (!steamIds.empty())
diff --git a/protocols/Steam/src/steam_history.cpp b/protocols/Steam/src/steam_history.cpp
index 3b62aa21bc..a897037bae 100644
--- a/protocols/Steam/src/steam_history.cpp
+++ b/protocols/Steam/src/steam_history.cpp
@@ -1,92 +1,64 @@
#include "stdafx.h"
-void CSteamProto::OnGotConversations(const HttpResponse *response)
+void CSteamProto::OnGotConversations(const JSONNode &root, void*)
{
// Don't load any messages when we don't have lastMessageTS, as it may cause duplicates
if (m_lastMessageTS <= 0)
return;
- if (!ResponseHttpOk(response))
+ if (root.isnull())
return;
- JSONROOT root(response->pData);
- if (root == nullptr)
+ JSONNode response = root["response"];
+ JSONNode sessions = response["message_sessions"].as_array();
+ if (sessions.isnull())
return;
- JSONNode *node = json_get(root, "response");
- JSONNode *sessions = json_get(node, "message_sessions");
- JSONNode *nsessions = json_as_array(sessions);
-
- if (nsessions != nullptr)
+ for (const JSONNode &session : sessions)
{
- ptrA token(getStringA("TokenSecret"));
- ptrA steamId(getStringA("SteamID"));
-
-
- for (size_t i = 0; i < json_size(nsessions); i++)
- {
- JSONNode *session = json_at(nsessions, i);
+ long long accountId = _wtoi64(session["accountid_friend"].as_mstring());
+ const char *who = AccountIdToSteamId(accountId);
- node = json_get(session, "accountid_friend");
- const char *who = AccountIdToSteamId(_wtoi64(ptrW(json_as_string(node))));
+ time_t lastMessageTS = _wtoi64(session["last_message"].as_mstring());
- node = json_get(session, "last_message");
- time_t lastMessageTS = _wtoi64(ptrW(json_as_string(node)));
+ /*node = json_get(session, "last_view");
+ time_t last_view = _wtoi64(ptrW(json_as_string(node)));
- /*node = json_get(session, "last_view");
- time_t last_view = _wtoi64(ptrW(json_as_string(node)));
+ node = json_get(session, "unread_message_count");
+ long unread_count = json_as_int(node);*/
- node = json_get(session, "unread_message_count");
- long unread_count = json_as_int(node);*/
+ if (lastMessageTS > m_lastMessageTS)
+ {
+ ptrA token(getStringA("TokenSecret"));
+ ptrA steamId(getStringA("SteamID"));
- if (lastMessageTS > m_lastMessageTS)
- {
- PushRequest(
- new GetHistoryMessagesRequest(token, steamId, who, m_lastMessageTS),
- &CSteamProto::OnGotHistoryMessages,
- mir_strdup(who),
- MirFreeArg);
- }
+ PushRequest(
+ new GetHistoryMessagesRequest(token, steamId, who, m_lastMessageTS),
+ &CSteamProto::OnGotHistoryMessages,
+ mir_strdup(who));
}
-
- json_delete(nsessions);
}
}
-void CSteamProto::OnGotHistoryMessages(const HttpResponse *response, void *arg)
+void CSteamProto::OnGotHistoryMessages(const JSONNode &root, void *arg)
{
- MCONTACT hContact = FindContact((char*)arg);
- if (!hContact)
- return;
+ ptrA cSteamId((char*)arg);
- if (!ResponseHttpOk(response))
+ if (root.isnull())
return;
- JSONROOT root(response->pData);
- if (root == nullptr)
- return;
-
- JSONNode *node = json_get(root, "response");
-
- JSONNode *messages = json_get(node, "messages");
- JSONNode *nmessages = json_as_array(messages);
-
- // Self SteamID
- ptrA steamId(getStringA("SteamID"));
-
- for (size_t i = json_size(nmessages); i > 0; i--)
+ JSONNode response = root["response"];
+ JSONNode messages = response["messages"].as_array();
+ for (size_t i = messages.size(); i > 0; i--)
{
- JSONNode *message = json_at(nmessages, i - 1);
+ JSONNode message = messages[i - 1];
- node = json_get(message, "accountid");
- const char *authorSteamId = AccountIdToSteamId(_wtoi64(ptrW(json_as_string(node))));
+ long long accountId = _wtoi64(message["accountid"].as_mstring());
+ const char *authorSteamId = AccountIdToSteamId(accountId);
- node = json_get(message, "message");
- ptrW text(json_as_string(node));
- T2Utf szMessage(text);
+ json_string text = message["message"].as_string();
- node = json_get(message, "timestamp");
- time_t timestamp = _wtoi64(ptrW(json_as_string(node)));
+ time_t timestamp = _wtoi64(message["timestamp"].as_mstring());
// Ignore already existing messages
if (timestamp <= m_lastMessageTS)
@@ -94,8 +66,14 @@ void CSteamProto::OnGotHistoryMessages(const HttpResponse *response, void *arg)
PROTORECVEVENT recv = { 0 };
recv.timestamp = timestamp;
- recv.szMessage = szMessage;
+ recv.szMessage = (char*)text.c_str();
+ MCONTACT hContact = FindContact(cSteamId);
+ if (!hContact)
+ return;
+
+ // Self SteamID
+ ptrA steamId(getStringA("SteamID"));
if (strcmp(steamId, authorSteamId))
{
// Received message
@@ -108,6 +86,4 @@ void CSteamProto::OnGotHistoryMessages(const HttpResponse *response, void *arg)
Proto_RecvMessage(hContact, &recv);
}
}
-
- json_delete(nmessages);
}
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp
index d91acaba6d..3375a128d5 100644
--- a/protocols/Steam/src/steam_login.cpp
+++ b/protocols/Steam/src/steam_login.cpp
@@ -14,6 +14,31 @@ bool CSteamProto::IsMe(const char *steamId)
return false;
}
+void CSteamProto::Login()
+{
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0)
+ {
+ PushRequest(
+ new LogonRequest(token),
+ &CSteamProto::OnLoggedOn);
+ }
+ 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"));
@@ -21,53 +46,66 @@ bool CSteamProto::Relogin()
return false;
HttpRequest *request = new LogonRequest(token);
- HttpResponse *response = request->Send(m_hNetlibUser);
+ HttpResponse *response = SendRequest(request);
bool success = false;
- if (CheckResponse(response))
+ if (response)
{
- JSONROOT root(response->pData);
- if (root != nullptr) {
- JSONNode *node = json_get(root, "error");
-
- ptrW error(json_as_string(node));
- if (!mir_wstrcmpi(error, L"OK"))
+ JSONNode root = JSONNode::parse(response->Content);
+ if (root.isnull()) {
+ json_string error = root["error"].as_string();
+ if (!mir_strcmpi(error.c_str(), "OK"))
{
- node = json_get(root, "umqid");
- setString("UMQID", ptrA(mir_u2a(ptrW(json_as_string(node)))));
+ json_string umqId = root["umqid"].as_string();
+ setString("UMQID", umqId.c_str());
- node = json_get(root, "message");
- setDword("MessageID", json_as_int(node));
+ long messageId = root["message"].as_int();
+ setDword("MessageID", messageId);
success = true;
}
}
}
- delete request;
delete response;
return success;
}
-void CSteamProto::OnGotRsaKey(const HttpResponse *response)
+void CSteamProto::LogOut()
{
- if (!CheckResponse(response))
- return;
+ isTerminated = true;
+ if (hRequestQueueThread)
+ SetEvent(hRequestsQueueEvent);
- // load rsa key parts
- JSONNode root = JSONNode::parse(response->pData);
- if (!root)
+ ptrA token(getStringA("TokenSecret"));
+ if (mir_strlen(token) > 0)
+ {
+ ptrA umqid(getStringA("UMQID"));
+ SendRequest(new LogoffRequest(token, umqid));
+ }
+}
+
+void CSteamProto::OnGotRsaKey(const JSONNode &root, void*)
+{
+ if (root.isnull())
+ {
+ SetStatus(ID_STATUS_OFFLINE);
return;
+ }
if (!root["success"].as_bool())
+ {
+ SetStatus(ID_STATUS_OFFLINE);
return;
+ }
- std::string modulus = root["publickey_mod"].as_string();
- std::string exp = root["publickey_exp"].as_string();
+ // load rsa key parts
+ json_string modulus = root["publickey_mod"].as_string();
+ json_string exp = root["publickey_exp"].as_string();
DWORD exponent = strtoul(exp.c_str(), nullptr, 16); // default "010001" = 0x10001
- std::string timestamp = root["timestamp"].as_string();
+ json_string timestamp = root["timestamp"].as_string();
// encrcrypt password
ptrA base64RsaEncryptedPassword;
@@ -77,14 +115,16 @@ void CSteamProto::OnGotRsaKey(const HttpResponse *response)
DWORD encryptedSize = 0;
if ((error = RsaEncrypt(modulus.c_str(), exponent, szPassword, nullptr, encryptedSize)) != 0)
{
- debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error);
+ 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)
{
- debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error);
+ debugLogA(__FUNCTION__ ": encryption error (%lu)", error);
+ SetStatus(ID_STATUS_OFFLINE);
return;
}
@@ -112,16 +152,43 @@ void CSteamProto::OnGotRsaKey(const HttpResponse *response)
&CSteamProto::OnAuthorization);
}
-void CSteamProto::OnAuthorization(const HttpResponse *response)
+void CSteamProto::OnGotCaptcha(const HttpResponse &response, void *arg)
+{
+ ptrA captchaId((char*)arg);
+
+ 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)
+ {
+ DeleteAuthSettings();
+ SetStatus(ID_STATUS_OFFLINE);
+ return;
+ }
+
+ setString("CaptchaId", captchaId);
+ setString("CaptchaText", captchaDialog.GetCaptchaText());
+
+ T2Utf username(getWStringA("Username"));
+ PushRequest(
+ new GetRsaKeyRequest(username),
+ &CSteamProto::OnGotRsaKey);
+}
+
+void CSteamProto::OnAuthorization(const HttpResponse &response, void*)
{
- if (!CheckResponse(response))
+ if (!response)
{
SetStatus(ID_STATUS_OFFLINE);
return;
}
- JSONNode root = JSONNode::parse(response->pData);
- if (!root)
+ JSONNode root = JSONNode::parse(response.Content);
+ if (root.isnull())
{
SetStatus(ID_STATUS_OFFLINE);
return;
@@ -145,13 +212,11 @@ void CSteamProto::DeleteAuthSettings()
delSetting("CaptchaText");
}
-void CSteamProto::OnAuthorizationError(const JSONNode &node)
+void CSteamProto::OnAuthorizationError(const JSONNode &root)
{
- std::string message = node["message"].as_string();
- ptrW messageT(mir_utf8decodeW(message.c_str()));
- debugLogA("CSteamProto::OnAuthorizationError: %s", message.c_str());
-
- if (!mir_wstrcmpi(messageT, L"Incorrect login."))
+ CMStringW message = root["message"].as_mstring();
+ debugLogA(__FUNCTION__ ": %s", _T2A(message.GetBuffer()));
+ if (!mir_wstrcmpi(message, L"Incorrect login."))
{
// We can't continue with incorrect login/password
DeleteAuthSettings();
@@ -161,9 +226,9 @@ void CSteamProto::OnAuthorizationError(const JSONNode &node)
T2Utf username(getWStringA("Username"));
- if (node["requires_twofactor"].as_bool())
+ if (root["requires_twofactor"].as_bool())
{
- debugLogA("CSteamProto::OnAuthorizationError: requires twofactor");
+ debugLogA(__FUNCTION__ ": requires twofactor");
CSteamTwoFactorDialog twoFactorDialog(this);
if (twoFactorDialog.DoModal() != DIALOG_RESULT_OK)
@@ -181,21 +246,20 @@ void CSteamProto::OnAuthorizationError(const JSONNode &node)
return;
}
- if (node["clear_password_field"].as_bool())
+ if (root["clear_password_field"].as_bool())
{
- debugLogA("CSteamProto::OnAuthorizationError: clear password field");
-
- // Probably wrong password entered?
+ 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 (node["emailauth_needed"].as_bool())
+ if (root["emailauth_needed"].as_bool())
{
- debugLogA("CSteamProto::OnAuthorizationError: emailauth needed");
+ debugLogA(__FUNCTION__ ": emailauth needed");
- std::string guardId = node["emailsteamid"].as_string();
+ std::string guardId = root["emailsteamid"].as_string();
ptrA oldGuardId(getStringA("GuardId"));
if (mir_strcmp(guardId.c_str(), oldGuardId) == 0)
{
@@ -207,7 +271,7 @@ void CSteamProto::OnAuthorizationError(const JSONNode &node)
return;
}
- std::string domain = node["emaildomain"].as_string();
+ std::string domain = root["emaildomain"].as_string();
// Make absolute link
if (domain.find("://") == std::string::npos)
@@ -230,70 +294,54 @@ void CSteamProto::OnAuthorizationError(const JSONNode &node)
return;
}
- if (node["captcha_needed"].as_bool())
+ if (root["captcha_needed"].as_bool())
{
- debugLogA("CSteamProto::OnAuthorizationError: captcha needed");
-
- std::string captchaId = node["captcha_gid"].as_string();
-
- GetCaptchaRequest *request = new GetCaptchaRequest(captchaId.c_str());
- HttpResponse *response = request->Send(m_hNetlibUser);
- delete request;
-
- CSteamCaptchaDialog captchaDialog(this, (BYTE*)response->pData, response->dataLength);
- delete response;
- if (captchaDialog.DoModal() != DIALOG_RESULT_OK)
- {
- DeleteAuthSettings();
- SetStatus(ID_STATUS_OFFLINE);
- return;
- }
-
- setString("CaptchaId", captchaId.c_str());
- setString("CaptchaText", captchaDialog.GetCaptchaText());
-
+ debugLogA(__FUNCTION__ ": captcha needed");
+ std::string captchaId = root["captcha_gid"].as_string();
PushRequest(
- new GetRsaKeyRequest(username),
- &CSteamProto::OnGotRsaKey);
+ new GetCaptchaRequest(captchaId.c_str()),
+ &CSteamProto::OnGotCaptcha,
+ mir_strdup(captchaId.c_str()));
return;
}
DeleteAuthSettings();
SetStatus(ID_STATUS_OFFLINE);
+ ShowNotification(L"Steam", message);
}
-void CSteamProto::OnAuthorizationSuccess(const JSONNode &node)
+void CSteamProto::OnAuthorizationSuccess(const JSONNode &root)
{
DeleteAuthSettings();
- if (!node["login_complete"].as_bool())
+ if (!root["login_complete"].as_bool())
{
SetStatus(ID_STATUS_OFFLINE);
return;
}
- std::string oauth = node["oauth"].as_string();
- JSONNode root = JSONNode::parse(oauth.c_str());
- if (!root)
+ std::string oauth = root["oauth"].as_string();
+ JSONNode node = JSONNode::parse(oauth.c_str());
+ if (node.isnull())
{
SetStatus(ID_STATUS_OFFLINE);
return;
}
- std::string steamId = root["steamid"].as_string();
+ std::string steamId = node["steamid"].as_string();
setString("SteamID", steamId.c_str());
- std::string token = root["oauth_token"].as_string();
+ std::string token = node["oauth_token"].as_string();
setString("TokenSecret", token.c_str());
- std::string cookie = root["webcookie"].as_string();
+ std::string cookie = node["webcookie"].as_string();
- PushRequest(
+ SendRequest(
new GetSessionRequest(token.c_str(), steamId.c_str(), cookie.c_str()),
&CSteamProto::OnGotSession);
// We need to load homepage to get sessionid cookie
- PushRequest(
+ SendRequest(
new GetSessionRequest2(),
&CSteamProto::OnGotSession);
@@ -302,17 +350,17 @@ void CSteamProto::OnAuthorizationSuccess(const JSONNode &node)
&CSteamProto::OnLoggedOn);
}
-void CSteamProto::OnGotSession(const HttpResponse *response)
+void CSteamProto::OnGotSession(const HttpResponse &response, void*)
{
if (!response)
return;
- for (int i = 0; i < response->headersCount; i++)
+ for (size_t i = 0; i < response.Headers.GetSize(); i++)
{
- if (lstrcmpiA(response->headers[i].szName, "Set-Cookie"))
+ if (lstrcmpiA(response.Headers[i]->szName, "Set-Cookie"))
continue;
- std::string cookies = response->headers[i].szValue;
+ std::string cookies = response.Headers[i]->szValue;
size_t start = cookies.find("sessionid=") + 10;
size_t end = cookies.substr(start).find(';');
std::string sessionId = cookies.substr(start, end - start + 10);
@@ -329,8 +377,8 @@ void CSteamProto::HandleTokenExpired()
// Try to relogin automatically (but only once)
if (isLoginAgain) {
// Notify error to user
+ debugLogA(__FUNCTION__ ": cannot obtain connection token");
ShowNotification(L"Steam", TranslateT("Cannot obtain connection token."));
-
// Just go offline; it also resets the isLoginAgain to false
SetStatus(ID_STATUS_OFFLINE);
}
@@ -350,28 +398,26 @@ void CSteamProto::HandleTokenExpired()
}
}
-void CSteamProto::OnLoggedOn(const HttpResponse *response)
+void CSteamProto::OnLoggedOn(const HttpResponse &response, void*)
{
- if (!CheckResponse(response))
+ if (!response.IsSuccess())
{
- if (response && response->resultCode == HTTP_CODE_UNAUTHORIZED)
- {
- // Probably expired TokenSecret
- HandleTokenExpired();
- return;
- }
-
// Probably timeout or no connection, we can do nothing here
+ debugLogA(__FUNCTION__ ": unknown login error");
ShowNotification(L"Steam", TranslateT("Unknown login error."));
-
SetStatus(ID_STATUS_OFFLINE);
return;
}
- JSONROOT root(response->pData);
+ if (response.GetStatusCode() == HTTP_CODE_UNAUTHORIZED)
+ {
+ // Probably expired TokenSecret
+ HandleTokenExpired();
+ return;
+ }
- JSONNode *node = json_get(root, "error");
- ptrW error(json_as_string(node));
+ JSONNode root = JSONNode::parse(response.Content);
+ CMStringW error = root["error"].as_mstring();
if (mir_wstrcmpi(error, L"OK"))
{
// Probably expired TokenSecret
@@ -379,15 +425,15 @@ void CSteamProto::OnLoggedOn(const HttpResponse *response)
return;
}
- node = json_get(root, "umqid");
- setString("UMQID", ptrA(mir_u2a(ptrW(json_as_string(node)))));
+ json_string umqId = root["umqid"].as_string();
+ setString("UMQID", umqId.c_str());
- node = json_get(root, "message");
- setDword("MessageID", json_as_int(node));
+ long messageId = root["umqid"].as_int();
+ setDword("MessageID", messageId);
- if (m_lastMessageTS <= 0) {
- node = json_get(root, "utc_timestamp");
- time_t timestamp = _wtoi64(ptrW(json_as_string(node)));
+ if (m_lastMessageTS <= 0)
+ {
+ time_t timestamp = _wtoi64(root["utc_timestamp"].as_mstring());
setDword("LastMessageTS", timestamp);
}
diff --git a/protocols/Steam/src/steam_menus.cpp b/protocols/Steam/src/steam_menus.cpp
index 78d675f088..98b86f333c 100644
--- a/protocols/Steam/src/steam_menus.cpp
+++ b/protocols/Steam/src/steam_menus.cpp
@@ -35,8 +35,7 @@ int CSteamProto::BlockCommand(WPARAM hContact, LPARAM)
PushRequest(
new BlockFriendRequest(token, sessionId, steamId, who),
&CSteamProto::OnFriendBlocked,
- who,
- MirFreeArg);
+ who);
return 0;
}
diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp
index e5f6665a6f..7374be5208 100644
--- a/protocols/Steam/src/steam_messages.cpp
+++ b/protocols/Steam/src/steam_messages.cpp
@@ -7,14 +7,7 @@ struct SendMessageParam
char *message;
};
-void MessageParamFree(void *arg)
-{
- SendMessageParam *param = (SendMessageParam*)arg;
- mir_free(param->message);
- mir_free(param);
-}
-
-int CSteamProto::OnSendMessage(MCONTACT hContact, const char* message)
+int CSteamProto::OnSendMessage(MCONTACT hContact, const char *message)
{
UINT hMessage = InterlockedIncrement(&hMessageProcess);
@@ -29,40 +22,39 @@ int CSteamProto::OnSendMessage(MCONTACT hContact, const char* message)
PushRequest(
new SendMessageRequest(token, umqid, steamId, message),
&CSteamProto::OnMessageSent,
- param, MessageParamFree);
+ param);
return hMessage;
}
-void CSteamProto::OnMessageSent(const HttpResponse *response, void *arg)
+void CSteamProto::OnMessageSent(const HttpResponse &response, void *arg)
{
SendMessageParam *param = (SendMessageParam*)arg;
- ptrW error(mir_wstrdup(TranslateT("Unknown error")));
+ const char *error = Translate("Unknown error");
ptrW steamId(getWStringA(param->hContact, "SteamID"));
time_t timestamp = NULL;
- if (ResponseHttpOk(response))
+ if (response)
{
- JSONROOT root(response->pData);
- JSONNode *node = json_get(root, "error");
- if (node)
- error = json_as_string(node);
+ JSONNode root = JSONNode::parse(response.Content);
+ JSONNode node = root["error"];
+ if (!node.isnull())
+ error = node.as_string().c_str();
- node = json_get(root, "utc_timestamp");
- if (node)
+ node = root["utc_timestamp"];
+ if (!node.isnull())
{
- timestamp = atol(ptrA(mir_u2a(ptrW(json_as_string(node)))));
+ timestamp = atol(node.as_string().c_str());
if (timestamp > getDword("LastMessageTS", 0))
setDword("LastMessageTS", timestamp);
}
}
- if (mir_wstrcmpi(error, L"OK") != 0)
+ if (mir_strcmpi(error, "OK") != 0)
{
- ptrA errorA(mir_u2a(error));
- debugLogA("CSteamProto::OnMessageSent: failed to send message for %s (%s)", steamId, errorA);
- ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hMessage, (LPARAM)errorA);
+ debugLogA(__FUNCTION__ ": failed to send message for %s (%s)", steamId, error);
+ ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hMessage, (LPARAM)error);
}
else
{
@@ -73,6 +65,9 @@ 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);
}
int CSteamProto::OnPreCreateMessage(WPARAM, LPARAM lParam)
diff --git a/protocols/Steam/src/steam_polling.cpp b/protocols/Steam/src/steam_polling.cpp
index aa5a5e2c98..78ffd06c8b 100644
--- a/protocols/Steam/src/steam_polling.cpp
+++ b/protocols/Steam/src/steam_polling.cpp
@@ -2,180 +2,141 @@
#define POLLING_ERRORS_LIMIT 5
-void CSteamProto::ParsePollData(JSONNode *data)
+void CSteamProto::ParsePollData(const JSONNode &data)
{
- JSONNode *node, *item = nullptr;
-
- // FIXME: Temporary solution for receivng too many duplicated typing events; should be reworked better
- std::string typingUser;
-
std::string steamIds;
- for (size_t i = 0; i < json_size(data); i++)
+ for (const JSONNode &item : data)
{
- item = json_at(data, i);
- if (item == nullptr)
- break;
-
- node = json_get(item, "steamid_from");
- ptrA steamId(mir_u2a(ptrW(json_as_string(node))));
+ json_string steamId = item["steamid_from"].as_string();
+ time_t timestamp = _wtol(item["utc_timestamp"].as_mstring());
- node = json_get(item, "utc_timestamp");
- time_t timestamp = atol(ptrA(mir_u2a(ptrW(json_as_string(node)))));
+ MCONTACT hContact = NULL;
+ if (!IsMe(steamId.c_str()) &&
+ !(hContact = FindContact(steamId.c_str())))
+ // probably this is info about random player playing on same server, so we ignore it
+ continue;
- node = json_get(item, "type");
- ptrW type(json_as_string(node));
- if (!lstrcmpi(type, L"saytext") || !lstrcmpi(type, L"emote") ||
- !lstrcmpi(type, L"my_saytext") || !lstrcmpi(type, L"my_emote"))
+ json_string type = item["type"].as_string();
+ if (!mir_strcmpi(type.c_str(), "my_saytext") ||
+ !mir_strcmpi(type.c_str(), "my_emote"))
{
- MCONTACT hContact = FindContact(steamId);
- if (!hContact)
- continue;
+ json_string text = item["text"].as_string();
- node = json_get(item, "text");
- ptrW text(json_as_string(node));
- T2Utf szMessage(text);
+ PROTORECVEVENT recv = { 0 };
+ recv.timestamp = timestamp;
+ recv.szMessage = (char*)text.c_str();
+ recv.flags = PREF_SENT;
+ Proto_RecvMessage(hContact, &recv);
+ }
+ else if (!mir_strcmpi(type.c_str(), "saytext") ||
+ !mir_strcmpi(type.c_str(), "emote"))
+ {
+ json_string text = item["text"].as_string();
PROTORECVEVENT recv = { 0 };
recv.timestamp = timestamp;
- recv.szMessage = szMessage;
- if (wcsstr(type, L"my_") == nullptr)
- {
- ProtoChainRecvMsg(hContact, &recv);
- }
- else
- {
- recv.flags = PREF_SENT;
- Proto_RecvMessage(hContact, &recv);
- }
+ recv.szMessage = (char*)text.c_str();
+ ProtoChainRecvMsg(hContact, &recv);
+
+ CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF);
+ m_typingTimestamps[steamId] = 0;
}
- else if (!lstrcmpi(type, L"typing"))
+ else if (!mir_strcmpi(type.c_str(), "typing") && hContact)
{
- // FIXME: Temporary solution for receivng too many duplicated typing events; should be reworked better
- if (typingUser == (char*)steamId)
- continue;
- typingUser = steamId;
-
- MCONTACT hContact = FindContact(steamId);
- if (hContact)
+ auto it = m_typingTimestamps.find(steamId);
+ if (it != m_typingTimestamps.end())
{
- CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)STEAM_TYPING_TIME);
+ if ((timestamp - it->second) < STEAM_TYPING_TIME)
+ continue;
}
+ CallService(MS_PROTO_CONTACTISTYPING, hContact, (LPARAM)STEAM_TYPING_TIME);
+ m_typingTimestamps[steamId] = timestamp;
}
- else if (!lstrcmpi(type, L"personastate"))
+ else if (!mir_strcmpi(type.c_str(), "personastate"))
{
- node = json_get(item, "persona_state");
- int status = node ? SteamToMirandaStatus(json_as_int(node)) : -1;
+ JSONNode node = item["persona_state"];
+ int status = !node.isnull()
+ ? SteamToMirandaStatus(node.as_int())
+ : -1;
- if (IsMe(steamId))
+ if (IsMe(steamId.c_str()))
{
- node = json_get(item, "persona_name");
- setWString("Nick", ptrW(json_as_string(node)));
-
if (status == -1 || status == ID_STATUS_OFFLINE)
continue;
-
- if (status != m_iStatus)
- {
- debugLogW(L"CSteamProto::ParsePollData: Change own status to %i", status);
- int oldStatus = m_iStatus;
- m_iStatus = m_iDesiredStatus = status;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
- }
-
+ SetStatus(status);
continue;
}
- MCONTACT hContact = FindContact(steamId);
- if (hContact == NULL)
- continue; // probably this is info about random player playing on same server, so we ignore it
-
if (status != -1)
SetContactStatus(hContact, status);
- node = json_get(item, "persona_name");
- setWString(hContact, "Nick", ptrW(json_as_string(node)));
-
// todo: find difference between state changing and info changing
steamIds.append(steamId).append(",");
}
- else if (!lstrcmpi(type, L"personarelationship"))
+ else if (!mir_strcmpi(type.c_str(), "personarelationship"))
{
- node = json_get(item, "persona_state");
- int state = json_as_int(node);
-
+ int state = item["persona_state"].as_int();
switch (state)
{
case 0:
{// removed
- MCONTACT hContact = FindContact(steamId);
+ MCONTACT hContact = FindContact(steamId.c_str());
if (hContact)
- {
ContactIsRemoved(hContact);
- }
}
break;
case 1:
{// ignored
- MCONTACT hContact = FindContact(steamId);
+ MCONTACT hContact = FindContact(steamId.c_str());
if (hContact)
- {
ContactIsIgnored(hContact);
- }
}
break;
case 2:
{// auth request
- MCONTACT hContact = FindContact(steamId);
+ MCONTACT hContact = FindContact(steamId.c_str());
if (hContact)
- {
ContactIsAskingAuth(hContact);
- }
else
{
// load info about this user from server
ptrA token(getStringA("TokenSecret"));
PushRequest(
- new GetUserSummariesRequest(token, steamId),
- &CSteamProto::OnAuthRequested,
- mir_strdup(steamId),
- MirFreeArg);
+ new GetUserSummariesRequest(token, steamId.c_str()),
+ &CSteamProto::OnAuthRequested);
}
}
break;
case 3:
- // add to list
- // todo
+ // todo: add to list
break;
- default: continue;
+ default:
+ continue;
}
}
- else if (!lstrcmpi(type, L"leftconversation"))
+ else if (!mir_strcmpi(type.c_str(), "leftconversation") && hContact)
{
if (!getBool("ShowChatEvents", true))
continue;
- // chatstates gone event
- MCONTACT hContact = FindContact(steamId);
- if (hContact)
- {
- BYTE bEventType = STEAM_DB_EVENT_CHATSTATES_GONE;
- DBEVENTINFO dbei = {};
- dbei.pBlob = &bEventType;
- dbei.cbBlob = 1;
- dbei.eventType = EVENTTYPE_STEAM_CHATSTATES;
- dbei.flags = DBEF_READ;
- dbei.timestamp = time(nullptr);
- dbei.szModule = m_szModuleName;
- db_event_add(hContact, &dbei);
- }
+ BYTE bEventType = STEAM_DB_EVENT_CHATSTATES_GONE;
+ DBEVENTINFO dbei = {};
+ dbei.pBlob = &bEventType;
+ dbei.cbBlob = 1;
+ dbei.eventType = EVENTTYPE_STEAM_CHATSTATES;
+ dbei.flags = DBEF_READ;
+ dbei.timestamp = time(nullptr);
+ dbei.szModule = m_szModuleName;
+ db_event_add(hContact, &dbei);
}
else
{
+ debugLogA(__FUNCTION__ ": Unknown event type \"%s\"", type.c_str());
continue;
}
}
@@ -191,122 +152,108 @@ void CSteamProto::ParsePollData(JSONNode *data)
}
}
-void CSteamProto::PollingThread(void*)
+struct PollParam
{
- debugLogW(L"CSteamProto::PollingThread: entering");
+ int errors;
+ int errorsLimit;
+};
- ptrA token(getStringA("TokenSecret"));
- ptrA umqId(getStringA("UMQID"));
- UINT32 messageId = getDword("MessageID", 0);
+void CSteamProto::OnGotPoll(const HttpResponse &response, void *arg)
+{
+ PollParam *param = (PollParam*)arg;
+ if (!response.IsSuccess())
+ {
+ param->errors++;
+ return;
+ }
- int errors = 0;
- int errorsLimit = getByte("PollingErrorsLimit", POLLING_ERRORS_LIMIT);
- while (IsOnline() && errors < errorsLimit)
+ JSONNode root = JSONNode::parse(response.Content);
+ if (root.isnull())
{
- PollRequest *request = new PollRequest(token, umqId, messageId, IdleSeconds());
- // request->nlc = m_pollingConnection;
- HttpResponse *response = request->Send(m_hNetlibUser);
- delete request;
+ param->errors++;
+ return;
+ }
- if (!ResponseHttpOk(response))
- {
- errors++;
- }
- else
- {
- ptrA body((char*)mir_calloc(response->dataLength + 2));
- mir_strncpy(body, response->pData, response->dataLength + 1);
- JSONROOT root(body);
- if (root == nullptr)
- {
- errors++;
- }
- else
- {
- JSONNode *node = json_get(root, "error");
- if (node) {
- ptrW error(json_as_string(node));
+ json_string error = root["error"].as_string();
+ if (!mir_strcmpi(error.c_str(), "Timeout"))
+ {
+ // Do nothing as this is not necessarily an error
+ }
+ else if (!mir_strcmpi(error.c_str(), "OK"))
+ {
+ // Remember last message timestamp
+ time_t timestamp = _wtoi64(root["utc_timestamp"].as_mstring());
+ if (timestamp > getDword("LastMessageTS", 0))
+ setDword("LastMessageTS", timestamp);
- if (!lstrcmpi(error, L"OK"))
- {
- // Remember last message timestamp
- node = json_get(root, "utc_timestamp");
- time_t timestamp = _wtoi64(ptrW(json_as_string(node)));
- if (timestamp > getDword("LastMessageTS", 0))
- setDword("LastMessageTS", timestamp);
+ long messageId = root["messagelast"].as_int();
+ setDword("MessageID", messageId);
- node = json_get(root, "messagelast");
- messageId = json_as_int(node);
+ JSONNode data = root["messages"].as_array();
+ ParsePollData(data);
- node = json_get(root, "messages");
- JSONNode *nroot = json_as_array(node);
+ // Reset error counter only when we've got OK
+ param->errors = 0;
- if (nroot != nullptr)
- {
- ParsePollData(nroot);
- json_delete(nroot);
- }
+ // m_pollingConnection = response->nlc;
+ }
+ else if (!mir_strcmpi(error.c_str(), "Not Logged On")) // 'else' below will handle this error, we don't need this particular check right now
+ {
+ // need to relogin
+ debugLogA(__FUNCTION__ ": Not Logged On");
- // Reset error counter only when we've got OK
- errors = 0;
+ // 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())
+ {
+ // let it jump out of further processing
+ param->errors = param->errorsLimit;
+ }
+ }
+ else
+ {
+ // something wrong
+ debugLogA(__FUNCTION__ ": %s (%d)", error.c_str(), response.GetStatusCode());
- // m_pollingConnection = response->nlc;
- }
- else if (!lstrcmpi(error, L"Timeout"))
- {
- // Do nothing as this is not necessarily an error
- }
- else if (!lstrcmpi(error, L"Not Logged On")) // 'else' below will handle this error, we don't need this particular check right now
- {
- // need to relogin
- debugLogW(L"CSteamProto::PollingThread: 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())
- {
- // load umqId and messageId again
- umqId = getStringA("UMQID"); // it's ptrA so we can assign it without fearing a memory leak
- messageId = getDword("MessageID", 0);
- }
- else
- {
- // let it jump out of further processing
- errors = errorsLimit;
- }
- }
- else
- {
- // something wrong
- debugLogW(L"CSteamProto::PollingThread: %s (%d)", error, response->resultCode);
+ // token has expired
+ if (response.GetStatusCode() == HTTP_CODE_UNAUTHORIZED)
+ delSetting("TokenSecret");
- // token has expired
- if (response->resultCode == HTTP_CODE_UNAUTHORIZED)
- delSetting("TokenSecret");
+ // too low timeout?
+ int timeout = root["sectimeout"].as_int();
+ if (timeout < STEAM_API_TIMEOUT)
+ debugLogA(__FUNCTION__ ": Timeout is too low (%d)", timeout);
- // too low timeout?
- node = json_get(root, "sectimeout");
- int timeout = json_as_int(node);
- if (timeout < STEAM_API_TIMEOUT)
- debugLogW(L"CSteamProto::PollingThread: Timeout is too low (%d)", timeout);
+ // let it jump out of further processing
+ param->errors = param->errorsLimit;
+ }
+}
- // let it jump out of further processing
- errors = errorsLimit;
- }
- }
- }
- }
+void CSteamProto::PollingThread(void*)
+{
+ debugLogA(__FUNCTION__ ": entering");
- delete response;
- }
+ ptrA token(getStringA("TokenSecret"));
- setDword("MessageID", messageId);
+ PollParam param;
+ param.errors = 0;
+ param.errorsLimit = getByte("PollingErrorsLimit", POLLING_ERRORS_LIMIT);
+ while (IsOnline() && param.errors < param.errorsLimit)
+ {
+ // request->nlc = m_pollingConnection;
+ ptrA umqId(getStringA("UMQID"));
+ UINT32 messageId = getDword("MessageID", 0);
+ SendRequest(
+ new PollRequest(token, umqId, messageId, IdleSeconds()),
+ &CSteamProto::OnGotPoll,
+ (void*)&param);
+ }
if (IsOnline())
{
- debugLogW(L"CSteamProto::PollingThread: unexpected termination; switching protocol to offline");
+ debugLogA(__FUNCTION__ ": unexpected termination; switching protocol to offline");
SetStatus(ID_STATUS_OFFLINE);
}
m_hPollingThread = nullptr;
- debugLogW(L"CSteamProto::PollingThread: leaving");
+ debugLogA(__FUNCTION__ ": leaving");
}
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index 89d997024e..68c6c28767 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -2,14 +2,13 @@
CSteamProto::CSteamProto(const char* protoName, const wchar_t* userName)
: PROTO<CSteamProto>(protoName, userName),
- hAuthProcess(1), hMessageProcess(1)
+ requestQueue(1), hAuthProcess(1), hMessageProcess(1)
{
CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
m_idleTS = 0;
m_lastMessageTS = 0;
isLoginAgain = false;
- m_hQueueThread = nullptr;
m_pollingConnection = nullptr;
m_hPollingThread = nullptr;
@@ -74,12 +73,13 @@ CSteamProto::CSteamProto(const char* protoName, const wchar_t* userName)
nlu.szSettingsModule = m_szModuleName;
m_hNetlibUser = Netlib_RegisterUser(&nlu);
- requestQueue = new RequestQueue(m_hNetlibUser);
+ debugLogA(__FUNCTION__":Setting protocol / module name to '%s'", m_szModuleName);
}
CSteamProto::~CSteamProto()
{
- delete requestQueue;
+ Netlib_CloseHandle(m_hNetlibUser);
+ m_hNetlibUser = NULL;
}
MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT* psr)
@@ -104,7 +104,7 @@ MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT* psr)
{
STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr;
hContact = AddContact(steamId, true);
- UpdateContactDetails(hContact, ssr->data);
+ UpdateContactDetails(hContact, *ssr->data);
}
return hContact;
@@ -128,7 +128,7 @@ int CSteamProto::Authorize(MEVENT hDbEvent)
PushRequest(
new ApprovePendingRequest(token, sessionId, steamId, who),
&CSteamProto::OnPendingApproved,
- who, MirFreeArg);
+ who);
return 0;
}
@@ -154,7 +154,7 @@ int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
PushRequest(
new IgnorePendingRequest(token, sessionId, steamId, who),
&CSteamProto::OnPendingIgnoreded,
- who, MirFreeArg);
+ who);
return 0;
}
@@ -296,7 +296,7 @@ int CSteamProto::SetStatus(int new_status)
if (new_status == m_iDesiredStatus)
return 0;
- debugLogW(L"CSteamProto::SetStatus: changing status from %i to %i", m_iStatus, new_status);
+ debugLogA(__FUNCTION__ ": changing status from %i to %i", m_iStatus, new_status);
int old_status = m_iStatus;
m_iDesiredStatus = new_status;
@@ -307,16 +307,11 @@ int CSteamProto::SetStatus(int new_status)
isLoginAgain = false;
m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
-
- ptrA token(getStringA("TokenSecret"));
- ptrA umqid(getStringA("UMQID"));
- SendRequest(new LogoffRequest(token, umqid));
-
- requestQueue->Stop();
if (!Miranda_IsTerminated())
SetAllContactsStatus(ID_STATUS_OFFLINE);
+
+ LogOut();
}
else if (old_status == ID_STATUS_OFFLINE)
{
@@ -324,38 +319,17 @@ int CSteamProto::SetStatus(int new_status)
m_lastMessageTS = getDword("LastMessageTS", 0);
m_iStatus = ID_STATUS_CONNECTING;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
- requestQueue->Start();
+ isTerminated = false;
- ptrA token(getStringA("TokenSecret"));
- ptrA sessionId(getStringA("SessionID"));
- if (mir_strlen(token) > 0 && mir_strlen(sessionId) > 0)
- {
- PushRequest(
- new LogonRequest(token),
- &CSteamProto::OnLoggedOn);
- }
- else
- {
- T2Utf username(getWStringA("Username"));
- if (username == NULL)
- {
- m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus);
- return 0;
- }
+ hRequestQueueThread = ForkThreadEx(&CSteamProto::RequestQueueThread, NULL, NULL);
- PushRequest(
- new GetRsaKeyRequest(username),
- &CSteamProto::OnGotRsaKey);
- }
+
}
else
- {
m_iStatus = new_status;
- ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
- }
+
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
return 0;
}
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index dab65cccce..b07f44649c 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -28,8 +28,16 @@ enum
CMI_MAX // this item shall be the last one
};
-typedef void(CSteamProto::*SteamResponseCallback)(const HttpResponse *response);
-typedef void(CSteamProto::*SteamResponseWithArgCallback)(const HttpResponse *response, void *arg);
+typedef void(CSteamProto::*HttpCallback)(const HttpResponse&, void*);
+typedef void(CSteamProto::*JsonCallback)(const JSONNode&, void*);
+
+struct RequestQueueItem
+{
+ HttpRequest *request;
+ HttpCallback httpCallback;
+ JsonCallback jsonCallback;
+ void *param;
+};
class CSteamProto : public PROTO<CSteamProto>
{
@@ -77,7 +85,11 @@ protected:
wchar_t *password;
bool isLoginAgain;
time_t m_idleTS;
- HANDLE m_evRequestsQueue, m_hQueueThread;
+ bool isTerminated, isConnected;
+ mir_cs requestQueueLock;
+ HANDLE hRequestsQueueEvent;
+ HANDLE hRequestQueueThread;
+ LIST<RequestQueueItem> requestQueue;
HANDLE m_pollingConnection, m_hPollingThread;
ULONG hAuthProcess;
ULONG hMessageProcess;
@@ -85,6 +97,7 @@ protected:
mir_cs requests_queue_lock;
mir_cs set_status_lock;
std::map<HANDLE, time_t> m_mpOutMessages;
+ std::map<std::string, time_t> m_typingTimestamps;
/**
* Used only to compare in steam_history.cpp, others should write such value directly to db profile, because PollingThread
@@ -97,36 +110,37 @@ protected:
static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2);
// requests
- RequestQueue *requestQueue;
-
+ HttpResponse* SendRequest(HttpRequest *request);
+ void SendRequest(HttpRequest *request, HttpCallback callback, void *param = NULL);
+ void SendRequest(HttpRequest *request, JsonCallback callback, void *param = NULL);
void PushRequest(HttpRequest *request);
- void PushRequest(HttpRequest *request, SteamResponseCallback response);
- void PushRequest(HttpRequest *request, SteamResponseWithArgCallback response, void *arg, HttpFinallyCallback last = NULL);
-
- void SendRequest(HttpRequest *request);
- void SendRequest(HttpRequest *request, SteamResponseCallback response);
- void SendRequest(HttpRequest *request, SteamResponseWithArgCallback response, void *arg, HttpFinallyCallback last = NULL);
-
- static void MirFreeArg(void *arg) { mir_free(arg); }
+ void PushRequest(HttpRequest *request, HttpCallback callback, void *param = NULL);
+ void PushRequest(HttpRequest *request, JsonCallback callback, void *param = NULL);
+ void __cdecl RequestQueueThread(void*);
// pooling thread
- void ParsePollData(JSONNode *data);
+ void ParsePollData(const JSONNode &data);
+ void OnGotPoll(const HttpResponse &response, void *arg);
void __cdecl PollingThread(void*);
- // account
+ // login
bool IsOnline();
bool IsMe(const char *steamId);
+ void Login();
bool Relogin();
+ void LogOut();
+
+ void OnGotRsaKey(const JSONNode &root, void*);
- void OnGotRsaKey(const HttpResponse *response);
+ void OnGotCaptcha(const HttpResponse &response, void *arg);
- void OnAuthorization(const HttpResponse *response);
- void OnAuthorizationError(const JSONNode &node);
- void OnAuthorizationSuccess(const JSONNode &node);
- void OnGotSession(const HttpResponse *response);
+ void OnAuthorization(const HttpResponse &response, void*);
+ void OnAuthorizationError(const JSONNode &root);
+ void OnAuthorizationSuccess(const JSONNode &root);
+ void OnGotSession(const HttpResponse &response, void*);
- void OnLoggedOn(const HttpResponse *response);
+ void OnLoggedOn(const HttpResponse &response, void*);
void HandleTokenExpired();
void DeleteAuthSettings();
@@ -137,8 +151,9 @@ protected:
MCONTACT GetContactFromAuthEvent(MEVENT hEvent);
- void UpdateContactDetails(MCONTACT hContact, JSONNode *data);
- void UpdateContactRelationship(MCONTACT hContact, JSONNode *data);
+ void UpdateContactDetails(MCONTACT hContact, const JSONNode &data);
+ void UpdateContactRelationship(MCONTACT hContact, const JSONNode &data);
+ void OnGotAppInfo(const JSONNode &root, void *arg);
void ContactIsRemoved(MCONTACT hContact);
void ContactIsFriend(MCONTACT hContact);
@@ -148,31 +163,31 @@ protected:
MCONTACT FindContact(const char *steamId);
MCONTACT AddContact(const char *steamId, bool isTemporary = false);
- void OnGotFriendList(const HttpResponse *response);
- void OnGotBlockList(const HttpResponse *response);
- void OnGotUserSummaries(const HttpResponse *response);
- void OnGotAvatar(const HttpResponse *response, void *arg);
+ void OnGotFriendList(const JSONNode &root, void*);
+ void OnGotBlockList(const JSONNode &root, void*);
+ void OnGotUserSummaries(const JSONNode &root, void*);
+ void OnGotAvatar(const HttpResponse &response, void *arg);
- void OnFriendAdded(const HttpResponse *response, void *arg);
- void OnFriendBlocked(const HttpResponse *response, void *arg);
- void OnFriendRemoved(const HttpResponse *response, void *arg);
+ void OnFriendAdded(const HttpResponse &response, void *arg);
+ void OnFriendBlocked(const HttpResponse &response, void *arg);
+ void OnFriendRemoved(const HttpResponse &response, void *arg);
- void OnAuthRequested(const HttpResponse *response, void *arg);
+ void OnAuthRequested(const JSONNode &root, void *arg);
- void OnPendingApproved(const HttpResponse *response, void *arg);
- void OnPendingIgnoreded(const HttpResponse *response, void *arg);
+ void OnPendingApproved(const JSONNode &root, void *arg);
+ void OnPendingIgnoreded(const JSONNode &root, void *arg);
- void OnSearchResults(const HttpResponse *response, void *arg);
- void OnSearchByNameStarted(const HttpResponse *response, void *arg);
+ void OnSearchResults(const HttpResponse &response, void *arg);
+ void OnSearchByNameStarted(const HttpResponse &response, void *arg);
// messages
int OnSendMessage(MCONTACT hContact, const char* message);
- void OnMessageSent(const HttpResponse *response, void *arg);
+ void OnMessageSent(const HttpResponse &response, void *arg);
int __cdecl OnPreCreateMessage(WPARAM, LPARAM lParam);
// history
- void OnGotConversations(const HttpResponse *response);
- void OnGotHistoryMessages(const HttpResponse *response, void *arg);
+ void OnGotConversations(const JSONNode &root, void *arg);
+ void OnGotHistoryMessages(const JSONNode &root, void*);
// menus
static int hChooserMenu;
diff --git a/protocols/Steam/src/steam_request.cpp b/protocols/Steam/src/steam_request.cpp
index 508552e232..ba2d931aa9 100644
--- a/protocols/Steam/src/steam_request.cpp
+++ b/protocols/Steam/src/steam_request.cpp
@@ -1,78 +1,98 @@
#include "stdafx.h"
-class SteamResponseDelegate
+HttpResponse* CSteamProto::SendRequest(HttpRequest *request)
{
-private:
- CSteamProto *proto;
- SteamResponseCallback responseCallback;
- SteamResponseWithArgCallback responseWithArgCallback;
- HttpFinallyCallback httpFinallyCallback;
-
- void *arg;
- bool hasArg;
-
-public:
- SteamResponseDelegate(CSteamProto *proto, SteamResponseCallback responseCallback)
- : proto(proto), responseCallback(responseCallback), responseWithArgCallback(nullptr), arg(nullptr), httpFinallyCallback(nullptr), hasArg(false) {}
-
- SteamResponseDelegate(CSteamProto *proto, SteamResponseWithArgCallback responseCallback, void *arg, HttpFinallyCallback httpFinallyCallback)
- : proto(proto), responseCallback(nullptr), responseWithArgCallback(responseCallback), arg(arg), httpFinallyCallback(httpFinallyCallback), hasArg(true) { }
-
- void Invoke(const HttpResponse *response)
- {
- if (hasArg)
- {
- (proto->*(responseWithArgCallback))(response, arg);
- if (httpFinallyCallback != nullptr)
- httpFinallyCallback(arg);
- }
- else
- (proto->*(responseCallback))(response);
- }
-};
+ NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
+ HttpResponse *response = new HttpResponse(request, pResp);
+ delete request;
+ return response;
+}
-static void SteamHttpResponse(const HttpResponse *response, void *arg)
+void CSteamProto::SendRequest(HttpRequest *request, HttpCallback callback, void *param)
{
- SteamResponseDelegate *delegate = (SteamResponseDelegate*)arg;
- delegate->Invoke(response);
+ NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
+ HttpResponse response(request, pResp);
+ if (callback)
+ (this->*callback)(response, param);
+ delete request;
}
-void SteamResponseDelegateFree(void *arg)
+void CSteamProto::SendRequest(HttpRequest *request, JsonCallback callback, void *param)
{
- SteamResponseDelegate *delegate = (SteamResponseDelegate*)arg;
- delete delegate;
+ NETLIBHTTPREQUEST *pResp = Netlib_HttpTransaction(m_hNetlibUser, (NETLIBHTTPREQUEST*)request);
+ HttpResponse response(request, pResp);
+ if (callback)
+ {
+ JSONNode root = JSONNode::parse(response.Content);
+ (this->*callback)(root, param);
+ }
+ delete request;
}
void CSteamProto::PushRequest(HttpRequest *request)
{
- requestQueue->Push(request);
+ RequestQueueItem *item = new RequestQueueItem();
+ item->request = request;
+ {
+ mir_cslock lock(requestQueueLock);
+ requestQueue.insert(item);
+ }
+ SetEvent(hRequestsQueueEvent);
}
-void CSteamProto::PushRequest(HttpRequest *request, SteamResponseCallback response)
+void CSteamProto::PushRequest(HttpRequest *request, HttpCallback callback, void *param)
{
- SteamResponseDelegate *delegate = new SteamResponseDelegate(this, response);
- requestQueue->Push(request, SteamHttpResponse, delegate, SteamResponseDelegateFree);
+ RequestQueueItem *item = new RequestQueueItem();
+ item->request = request;
+ item->httpCallback = callback;
+ item->param = param;
+ {
+ mir_cslock lock(requestQueueLock);
+ requestQueue.insert(item);
+ }
+ SetEvent(hRequestsQueueEvent);
}
-void CSteamProto::PushRequest(HttpRequest *request, SteamResponseWithArgCallback response, void *arg, HttpFinallyCallback last)
+void CSteamProto::PushRequest(HttpRequest *request, JsonCallback callback, void *param)
{
- SteamResponseDelegate *delegate = new SteamResponseDelegate(this, response, arg, last);
- requestQueue->Push(request, SteamHttpResponse, delegate, SteamResponseDelegateFree);
+ RequestQueueItem *item = new RequestQueueItem();
+ item->request = request;
+ item->jsonCallback = callback;
+ item->param = param;
+ {
+ mir_cslock lock(requestQueueLock);
+ requestQueue.insert(item);
+ }
+ SetEvent(hRequestsQueueEvent);
}
-void CSteamProto::SendRequest(HttpRequest *request)
+void CSteamProto::RequestQueueThread(void*)
{
- requestQueue->Send(request);
-}
+ Login();
-void CSteamProto::SendRequest(HttpRequest *request, SteamResponseCallback response)
-{
- SteamResponseDelegate *delegate = new SteamResponseDelegate(this, response);
- requestQueue->Send(request, SteamHttpResponse, delegate, SteamResponseDelegateFree);
-}
+ do
+ {
+ RequestQueueItem *item;
+ while (true)
+ {
+ {
+ mir_cslock lock(requestQueueLock);
+ if (!requestQueue.getCount())
+ break;
-void CSteamProto::SendRequest(HttpRequest *request, SteamResponseWithArgCallback response, void *arg, HttpFinallyCallback last)
-{
- SteamResponseDelegate *delegate = new SteamResponseDelegate(this, response, arg, last);
- requestQueue->Send(request, SteamHttpResponse, delegate, SteamResponseDelegateFree);
-}
+ 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;
+ }
+ WaitForSingleObject(hRequestsQueueEvent, 1000);
+ } while (!isTerminated);
+
+ hRequestQueueThread = NULL;
+} \ No newline at end of file