From 641c67a9d552b07664308c2ae3384cc95a75a2d0 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Sun, 15 Mar 2015 11:20:05 +0000 Subject: Steam: - added support for templated url - fixed broken login - version bump git-svn-id: http://svn.miranda-ng.org/main/trunk@12408 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Steam/src/Steam/authorization.h | 54 +-- protocols/Steam/src/Steam/captcha.h | 4 +- protocols/Steam/src/Steam/friend_list.h | 6 +- protocols/Steam/src/Steam/pending.h | 18 +- protocols/Steam/src/Steam/rsa_key.h | 2 +- protocols/Steam/src/Steam/session.h | 50 +-- protocols/Steam/src/Steam/steam.h | 130 ++++-- protocols/Steam/src/steam_account.cpp | 527 +++++++++++------------ protocols/Steam/src/steam_pooling.cpp | 6 +- protocols/Steam/src/steam_proto.h | 681 +++++++++++++++--------------- protocols/Steam/src/steam_queue.cpp | 11 +- protocols/Steam/src/version.h | 2 +- 12 files changed, 750 insertions(+), 741 deletions(-) (limited to 'protocols/Steam/src') diff --git a/protocols/Steam/src/Steam/authorization.h b/protocols/Steam/src/Steam/authorization.h index 194a5dee36..e72eef1a11 100644 --- a/protocols/Steam/src/Steam/authorization.h +++ b/protocols/Steam/src/Steam/authorization.h @@ -5,49 +5,55 @@ namespace SteamWebApi { class AuthorizationRequest : public HttpsPostRequest { - void InitData(const char *username, const char *password, const char *timestamp, const char *guardId = "-1", const char *guardCode = "", const char *captchaId = "-1", const char *captchaText = "") + public: + AuthorizationRequest(const char *username, const char *password, const char *timestamp) : + HttpsPostRequest(STEAM_WEB_URL "/mobilelogin/dologin") { + flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; + char data[1024]; mir_snprintf(data, SIZEOF(data), - "username=%s&password=%s&emailsteamid=%s&emailauth=%s&captchagid=%s&captcha_text=%s&rsatimestamp=%s&donotcache=%ld&remember_login=true&oauth_client_id=DE45CD61&oauth_scope=read_profile write_profile read_client write_client", - username, + "username=%s&password=%s&oauth_client_id=3638BFB1&oauth_scope=read_profile write_profile read_client write_client&captchagid=-1&rsatimestamp=%s", + ptrA(mir_urlEncode(username)), ptrA(mir_urlEncode(password)), - guardId, - guardCode, - captchaId, - ptrA(mir_urlEncode(captchaText)), - timestamp, - time(NULL)); + timestamp); SetData(data, strlen(data)); } - public: - AuthorizationRequest(const char *username, const char *password, const char *timestamp) : - HttpsPostRequest(STEAM_COM_URL "/mobilelogin/dologin") + AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *guardCode) : + HttpsPostRequest(STEAM_WEB_URL "/mobilelogin/dologin") { flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; - InitData(username, password, timestamp); - } - - AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *guardId, const char *guardCode) : - HttpsPostRequest(STEAM_COM_URL "/mobilelogin/dologin") - { - flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; + char data[1024]; + mir_snprintf(data, SIZEOF(data), + "username=%s&password=%s&emailauth=%s&loginfriendlyname=MirandaNG&oauth_client_id=3638BFB1&oauth_scope=read_profile write_profile read_client write_client&captchagid=-1&rsatimestamp=%s", + ptrA(mir_urlEncode(username)), + ptrA(mir_urlEncode(password)), + guardCode, + timestamp); - InitData(username, password, timestamp, guardId, guardCode); + SetData(data, strlen(data)); } - AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *guardId, const char *guardCode, const char *captchaId, const char *captchaText) : - HttpsPostRequest(STEAM_COM_URL "/mobilelogin/dologin") + AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *captchaId, const char *captchaText) : + HttpsPostRequest(STEAM_WEB_URL "/mobilelogin/dologin") { flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; - InitData(username, password, timestamp, guardId, guardCode, captchaId, captchaText); + char data[1024]; + mir_snprintf(data, SIZEOF(data), + "username=%s&password=%s&captchagid=%s&captcha_text=%s&oauth_client_id=3638BFB1&oauth_scope=read_profile write_profile read_client write_client&rsatimestamp=%s", + ptrA(mir_urlEncode(username)), + ptrA(mir_urlEncode(password)), + captchaId, + ptrA(mir_urlEncode(captchaText)), + timestamp); + + SetData(data, strlen(data)); } }; } - #endif //_STEAM_AUTHORIZATION_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/captcha.h b/protocols/Steam/src/Steam/captcha.h index cb02fdda49..6ad01048ca 100644 --- a/protocols/Steam/src/Steam/captcha.h +++ b/protocols/Steam/src/Steam/captcha.h @@ -6,8 +6,8 @@ namespace SteamWebApi class GetCaptchaRequest : public HttpGetRequest { public: - GetCaptchaRequest(const char *url) : - HttpGetRequest(url) + GetCaptchaRequest(const char *captchaId) : + HttpGetRequest(STEAM_WEB_URL "/public/captcha.php?gid=%s", captchaId) { flags = NLHRF_HTTP11 | NLHRF_NODUMP; } diff --git a/protocols/Steam/src/Steam/friend_list.h b/protocols/Steam/src/Steam/friend_list.h index feed63f706..eccc3d1224 100644 --- a/protocols/Steam/src/Steam/friend_list.h +++ b/protocols/Steam/src/Steam/friend_list.h @@ -19,7 +19,7 @@ namespace SteamWebApi { public: AddFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/actions/AddFriendAjax") + HttpsPostRequest(STEAM_WEB_URL "/actions/AddFriendAjax") { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); @@ -42,7 +42,7 @@ namespace SteamWebApi { public: BlockFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/actions/BlockUserAjax") + HttpsPostRequest(STEAM_WEB_URL "/actions/BlockUserAjax") { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); @@ -65,7 +65,7 @@ namespace SteamWebApi { public: RemoveFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/actions/RemoveFriendAjax") + HttpsPostRequest(STEAM_WEB_URL "/actions/RemoveFriendAjax") { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); diff --git a/protocols/Steam/src/Steam/pending.h b/protocols/Steam/src/Steam/pending.h index 5cdd85b885..68b86ad689 100644 --- a/protocols/Steam/src/Steam/pending.h +++ b/protocols/Steam/src/Steam/pending.h @@ -7,7 +7,7 @@ namespace SteamWebApi { public: ApprovePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/profiles/%s/home_process") + HttpsPostRequest(STEAM_WEB_URL "/profiles/%s/home_process", steamId) { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); @@ -15,10 +15,6 @@ namespace SteamWebApi char cookie[MAX_PATH]; mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId); - char url[MAX_PATH]; - mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/profiles/%s/home_process", steamId); - this->url = url; - char data[MAX_PATH]; mir_snprintf(data, SIZEOF(data), "sessionID=%s&id=%s&perform=accept&action=approvePending&itype=friend&json=1&xml=0", sessionId, who); @@ -31,7 +27,7 @@ namespace SteamWebApi { public: IgnorePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/profiles/%s/home_process") + HttpsPostRequest(STEAM_WEB_URL "/profiles/%s/home_process", steamId) { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); @@ -39,10 +35,6 @@ namespace SteamWebApi char cookie[MAX_PATH]; mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId); - char url[MAX_PATH]; - mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/profiles/%s/home_process", steamId); - this->url = url; - char data[MAX_PATH]; mir_snprintf(data, SIZEOF(data), "sessionID=%s&id=%s&perform=ignore&action=approvePending&itype=friend&json=1&xml=0", sessionId, who); @@ -55,7 +47,7 @@ namespace SteamWebApi { public: BlockPendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) : - HttpsPostRequest(STEAM_COM_URL "/profiles/%s/home_process") + HttpsPostRequest(STEAM_WEB_URL "/profiles/%s/home_process", steamId) { char login[MAX_PATH]; mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); @@ -63,10 +55,6 @@ namespace SteamWebApi char cookie[MAX_PATH]; mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId); - char url[MAX_PATH]; - mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/profiles/%s/home_process", steamId); - this->url = url; - char data[MAX_PATH]; mir_snprintf(data, SIZEOF(data), "sessionID=%s&id=%s&perform=block&action=approvePending&itype=friend&json=1&xml=0", sessionId, who); diff --git a/protocols/Steam/src/Steam/rsa_key.h b/protocols/Steam/src/Steam/rsa_key.h index c4f9efc72d..be7d7ac79c 100644 --- a/protocols/Steam/src/Steam/rsa_key.h +++ b/protocols/Steam/src/Steam/rsa_key.h @@ -7,7 +7,7 @@ namespace SteamWebApi { public: RsaKeyRequest(const char *username) : - HttpsGetRequest(STEAM_COM_URL "/mobilelogin/getrsakey") + HttpsGetRequest(STEAM_WEB_URL "/mobilelogin/getrsakey") { flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; diff --git a/protocols/Steam/src/Steam/session.h b/protocols/Steam/src/Steam/session.h index a5fd950e1d..ea42cc77c4 100644 --- a/protocols/Steam/src/Steam/session.h +++ b/protocols/Steam/src/Steam/session.h @@ -3,59 +3,11 @@ namespace SteamWebApi { - //class SessionApi : public BaseApi - //{ - //public: - // class SessionId : public Result - // { - // friend SessionApi; - - // private: - // std::string sessionid; - - // public: - - // const char *GetSessionId() { return sessionid.c_str(); } - // }; - - // static void GetSessionId(HANDLE hConnection, const char *token, const char *steamId, SessionId *sessionId) - // { - // sessionId->success = false; - - // char login[MAX_PATH]; - // mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token); - - // char cookie[MAX_PATH]; - // mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s", ptrA(mir_urlEncode(login))); - - // SecureHttpGetRequest request(hConnection, STEAM_COM_URL "/mobilesettings/GetManifest/v0001"); - // request.AddHeader("Cookie", cookie); - - // mir_ptr response(request.Send()); - // if (!response) - // return; - - // for (int i = 0; i < response->headersCount; i++) - // { - // if (lstrcmpiA(response->headers[i].szName, "Set-Cookie")) - // continue; - - // std::string cookies = response->headers[i].szValue; - // size_t start = cookies.find("sessionid=") + 10; - // size_t end = cookies.substr(start).find(';'); - // sessionId->sessionid = cookies.substr(start, end - start + 10); - // break; - // } - - // sessionId->success = true; - // } - //}; - class GetSessionRequest : public HttpsPostRequest { public: GetSessionRequest(const char *token, const char *steamId, const char *cookie) : - HttpsPostRequest(STEAM_COM_URL "/mobileloginsucceeded") + HttpsPostRequest(STEAM_WEB_URL "/mobileloginsucceeded") { flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP; diff --git a/protocols/Steam/src/Steam/steam.h b/protocols/Steam/src/Steam/steam.h index c32da7e92a..a2a373a3d3 100644 --- a/protocols/Steam/src/Steam/steam.h +++ b/protocols/Steam/src/Steam/steam.h @@ -4,33 +4,31 @@ namespace SteamWebApi { #define STEAM_API_URL "https://api.steampowered.com" - #define STEAM_COM_URL "https://steamcommunity.com" + #define STEAM_WEB_URL "https://steamcommunity.com" class HttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject { - public: - std::string url; - - HttpRequest(int type, LPCSTR url) + private: + CMStringA url; + + protected: + HttpRequest() { cbSize = sizeof(NETLIBHTTPREQUEST); - requestType = type; - this->url = url; - szUrl = (char*)this->url.c_str(); - timeout = 0; - flags = NLHRF_HTTP11 | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; + AddHeader("user-agent", "Steam 1.2.0 / iPhone"); } - ~HttpRequest() + HttpRequest(int type, LPCSTR urlFormat, va_list args) { - for (int i = 0; i < headersCount; i++) - { - mir_free(headers[i].szName); - mir_free(headers[i].szValue); - } - mir_free(headers); - mir_free(pData); + this->HttpRequest::HttpRequest(); + + requestType = type; + //timeout = 0; + flags = NLHRF_HTTP11 | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; + + url.AppendFormatV(urlFormat, args); + szUrl = url.GetBuffer(); } void AddHeader(LPCSTR szName, LPCSTR szValue) @@ -41,20 +39,23 @@ namespace SteamWebApi headersCount++; } - void AddParameter(LPCSTR szName, LPCSTR szValue) + void AddParameter(const char *fmt, ...) { - if (url.find('?') == -1) - url.append("?").append(szName).append("=").append(szValue); + va_list args; + va_start(args, fmt); + if (url.Find('?') == -1) + url += '?'; else - url.append("&").append(szName).append("=").append(szValue); + url += '&'; + url.AppendFormatV(fmt, args); + va_end(args); + + szUrl = url.GetBuffer(); } - void AddParameter(LPCSTR szValue) + void AddParameter(LPCSTR name, LPCSTR value) { - if (url.find('?') == -1) - url.append("?").append(szValue); - else - url.append("&").append(szValue); + AddParameter("%s=%s", name, value); } void SetData(const char *data, size_t size) @@ -67,28 +68,76 @@ namespace SteamWebApi memcpy(pData, data, size); pData[size] = 0; } + + public: + HttpRequest(int type, LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(type, urlFormat, args); + va_end(args); + } + + ~HttpRequest() + { + for (int i = 0; i < headersCount; i++) + { + mir_free(headers[i].szName); + mir_free(headers[i].szValue); + } + mir_free(headers); + mir_free(pData); + } + + NETLIBHTTPREQUEST * Send(HANDLE hConnection) + { + char message[1024]; + mir_snprintf(message, SIZEOF(message), "Send request to %s", szUrl); + CallService(MS_NETLIB_LOG, (WPARAM)hConnection, (LPARAM)&message); + + return (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hConnection, (LPARAM)this); + } }; class HttpGetRequest : public HttpRequest { public: - HttpGetRequest(LPCSTR url) : HttpRequest(REQUEST_GET, url) { } + HttpGetRequest(LPCSTR urlFormat, ...) : HttpRequest() + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_GET, urlFormat, args); + va_end(args); + } }; - /*class HttpPostRequest : public HttpRequest + class HttpPostRequest : public HttpRequest { public: - HttpPostRequest(LPCSTR url) : HttpRequest(REQUEST_POST, url) + HttpPostRequest(LPCSTR urlFormat, ...) : HttpRequest() { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_POST, urlFormat, args); + va_end(args); + AddHeader("Content-Type", "application/x-www-form-urlencoded"); } - };*/ + }; class HttpsRequest : public HttpRequest { + protected: + HttpsRequest() : HttpRequest() { } + public: - HttpsRequest(int type, LPCSTR url) : HttpRequest(type, url) + HttpsRequest(int type, LPCSTR urlFormat, ...) : HttpRequest() { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(type, urlFormat, args); + va_end(args); + flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; } }; @@ -96,15 +145,26 @@ namespace SteamWebApi class HttpsGetRequest : public HttpsRequest { public: - HttpsGetRequest(LPCSTR url) : HttpsRequest(REQUEST_GET, url) { } + HttpsGetRequest(LPCSTR urlFormat, ...) : HttpsRequest() + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_GET, urlFormat, args); + va_end(args); + } }; class HttpsPostRequest : public HttpsRequest { public: - HttpsPostRequest(LPCSTR url) : HttpsRequest(REQUEST_POST, url) + HttpsPostRequest(LPCSTR urlFormat, ...) : HttpsRequest() { - AddHeader("Content-Type", "application/x-www-form-urlencoded"); + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_POST, urlFormat, args); + va_end(args); + + AddHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); } }; } diff --git a/protocols/Steam/src/steam_account.cpp b/protocols/Steam/src/steam_account.cpp index 7e16e5b850..94b26e384d 100644 --- a/protocols/Steam/src/steam_account.cpp +++ b/protocols/Steam/src/steam_account.cpp @@ -1,263 +1,266 @@ -#include "common.h" - -bool CSteamProto::IsOnline() -{ - return m_iStatus > ID_STATUS_OFFLINE && m_hPollingThread; -} - -bool CSteamProto::IsMe(const char *steamId) -{ - ptrA mySteamId(getStringA("SteamID")); - if (!lstrcmpA(steamId, mySteamId)) - return true; - - return false; -} - -void CSteamProto::OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg) -{ - if (response == NULL) - return; - - // load rsa key parts - JSONROOT root(response->pData); - if (!root) - return; - - JSONNODE *node = json_get(root, "success"); - if (!json_as_bool(node)) { - return; - } - - node = json_get(root, "publickey_mod"); - ptrA modulus(mir_u2a(ptrT(json_as_string(node)))); - - // exponent "010001" is used as constant in CSteamProto::RsaEncrypt - /*node = json_get(root, "publickey_exp"); - ptrA exponent(mir_u2a(ptrT(json_as_string(node))));*/ - - node = json_get(root, "timestamp"); - ptrA timestamp(mir_u2a(ptrT(json_as_string(node)))); - setString("Timestamp", timestamp); - - // encrcrypt password - ptrA base64RsaEncryptedPassword; - ptrA password(getStringA("Password")); - - DWORD error = 0; - DWORD encryptedSize = 0; - DWORD passwordSize = (DWORD)strlen(password); - if ((error = RsaEncrypt(modulus, password, NULL, encryptedSize)) != 0) - { - debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); - return; - } - - BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize); - if ((error = RsaEncrypt(modulus, password, encryptedPassword, encryptedSize)) != 0) - { - debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); - return; - } - - base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize); - mir_free(encryptedPassword); - - setString("EncryptedPassword", base64RsaEncryptedPassword); - - // run authorization request - ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username"))))); - - PushRequest( - new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp), - &CSteamProto::OnAuthorization); -} - -void CSteamProto::OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg) -{ - if (response == NULL) { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - JSONROOT root(response->pData); - - JSONNODE *node = json_get(root, "success"); - if (json_as_bool(node) == 0) - { - node = json_get(root, "message"); - ptrT message(json_as_string(node)); - if (!lstrcmpi(message, L"Incorrect login")) - { - ShowNotification(TranslateTS(message)); - SetStatus(ID_STATUS_OFFLINE); - return; - } - - node = json_get(root, "emailauth_needed"); - if (json_as_bool(node) > 0) - { - node = json_get(root, "emailsteamid"); - ptrA guardId(mir_u2a(ptrT(json_as_string(node)))); - - node = json_get(root, "emaildomain"); - ptrA emailDomain(mir_utf8encodeW(ptrT(json_as_string(node)))); - - GuardParam guard; - mir_strncpy(guard.domain, emailDomain, SIZEOF(guard.domain)); - - if (DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_GUARD), NULL, CSteamProto::GuardProc, (LPARAM)&guard) != 1) { - return; - } - - ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username"))))); - ptrA base64RsaEncryptedPassword(getStringA("EncryptedPassword")); - ptrA timestamp(getStringA("Timestamp")); - - PushRequest( - new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp, guardId, guard.code), - &CSteamProto::OnAuthorization); - } - - node = json_get(root, "captcha_needed"); - if (json_as_bool(node) > 0) - { - node = json_get(root, "captcha_gid"); - ptrA captchaId(mir_u2a(ptrT(json_as_string(node)))); - - char url[MAX_PATH]; - mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/public/captcha.php?gid=%s", captchaId); - - SteamWebApi::GetCaptchaRequest *request = new SteamWebApi::GetCaptchaRequest(url); - request->szUrl = (char*)request->url.c_str(); - NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)request); - delete request; - - CaptchaParam captcha = { 0 }; - captcha.size = response->dataLength; - captcha.data = (BYTE*)mir_alloc(captcha.size); - memcpy(captcha.data, response->pData, captcha.size); - - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response); - - int res = DialogBoxParam( - g_hInstance, - MAKEINTRESOURCE(IDD_CAPTCHA), - NULL, - CSteamProto::CaptchaProc, - (LPARAM)&captcha); - - mir_free(captcha.data); - - if (res != 1) - { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username"))))); - ptrA base64RsaEncryptedPassword(getStringA("EncryptedPassword")); - ptrA timestamp(getStringA("Timestamp")); - - PushRequest( - new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp, "-1", "", captchaId, captcha.text), - &CSteamProto::OnAuthorization); - } - - return; - } - - node = json_get(root, "login_complete"); - if (!json_as_bool(node)) - { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - node = json_get(root, "oauth"); - JSONROOT nroot(_T2A(ptrT(json_as_string(node)))); - - node = json_get(nroot, "steamid"); - ptrA steamId(mir_u2a(ptrT(json_as_string(node)))); - setString("SteamID", steamId); - - node = json_get(nroot, "oauth_token"); - ptrA token(mir_u2a(ptrT(json_as_string(node)))); - setString("TokenSecret", token); - - node = json_get(nroot, "webcookie"); - ptrA cookie(mir_u2a(ptrT(json_as_string(node)))); - - delSetting("Timestamp"); - delSetting("EncryptedPassword"); - - PushRequest( - new SteamWebApi::GetSessionRequest(token, steamId, cookie), - &CSteamProto::OnGotSession); - - PushRequest( - new SteamWebApi::LogonRequest(token), - &CSteamProto::OnLoggedOn); -} - -void CSteamProto::OnGotSession(const NETLIBHTTPREQUEST *response, void *arg) -{ - if (response == NULL) - return; - - for (int i = 0; i < response->headersCount; i++) - { - if (lstrcmpiA(response->headers[i].szName, "Set-Cookie")) - continue; - - 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); - setString("SessionID", sessionId.c_str()); - break; - } -} - -void CSteamProto::OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg) -{ - if (response == NULL) - { - SetStatus(ID_STATUS_OFFLINE); - return; - } - - JSONROOT root(response->pData); - - JSONNODE *node = json_get(root, "error"); - ptrW error(json_as_string(node)); - if (lstrcmpi(error, L"OK")/* || response->resultCode == HTTP_STATUS_UNAUTHORIZED*/) - { - //delSetting("TokenSecret"); - //delSetting("Cookie"); - - // set status to offline - SetStatus(ID_STATUS_OFFLINE); - return; - } - - node = json_get(root, "umqid"); - setString("UMQID", ptrA(mir_u2a(ptrT(json_as_string(node))))); - - node = json_get(root, "message"); - setDword("MessageID", json_as_int(node)); - - // load contact list - ptrA token(getStringA("TokenSecret")); - ptrA steamId(getStringA("SteamID")); - - PushRequest( - new SteamWebApi::GetFriendListRequest(token, steamId), - &CSteamProto::OnGotFriendList); - - // start polling thread - m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, 0, NULL); - - // go to online now - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); +#include "common.h" + +bool CSteamProto::IsOnline() +{ + return m_iStatus > ID_STATUS_OFFLINE && m_hPollingThread; +} + +bool CSteamProto::IsMe(const char *steamId) +{ + ptrA mySteamId(getStringA("SteamID")); + if (!lstrcmpA(steamId, mySteamId)) + return true; + + return false; +} + +void CSteamProto::OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg) +{ + if (response == NULL) + return; + + // load rsa key parts + JSONROOT root(response->pData); + if (!root) + return; + + JSONNODE *node = json_get(root, "success"); + if (!json_as_bool(node)) { + return; + } + + node = json_get(root, "publickey_mod"); + ptrA modulus(mir_u2a(ptrT(json_as_string(node)))); + + // exponent "010001" is used as constant in CSteamProto::RsaEncrypt + /*node = json_get(root, "publickey_exp"); + ptrA exponent(mir_u2a(ptrT(json_as_string(node))));*/ + + node = json_get(root, "timestamp"); + ptrA timestamp(mir_u2a(ptrT(json_as_string(node)))); + setString("Timestamp", timestamp); + + // encrcrypt password + ptrA base64RsaEncryptedPassword; + ptrA password(getStringA("Password")); + + DWORD error = 0; + DWORD encryptedSize = 0; + DWORD passwordSize = (DWORD)strlen(password); + if ((error = RsaEncrypt(modulus, password, NULL, encryptedSize)) != 0) + { + debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); + return; + } + + BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize); + if ((error = RsaEncrypt(modulus, password, encryptedPassword, encryptedSize)) != 0) + { + debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error); + return; + } + + base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize); + mir_free(encryptedPassword); + + //setString("EncryptedPassword", base64RsaEncryptedPassword); + PasswordParam *param = (PasswordParam*)mir_alloc(sizeof(PasswordParam)); + strcpy(param->password, base64RsaEncryptedPassword); + strcpy(param->timestamp, timestamp); + + // run authorization request + ptrA username(mir_utf8encodeW(getWStringA("Username"))); + + PushRequest( + new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp), + &CSteamProto::OnAuthorization, param, ARG_NO_FREE); +} + +void CSteamProto::OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg) +{ + if (response == NULL) { + SetStatus(ID_STATUS_OFFLINE); + return; + } + + JSONROOT root(response->pData); + + JSONNODE *node = json_get(root, "success"); + if (json_as_bool(node) == 0) + { + node = json_get(root, "message"); + ptrT message(json_as_string(node)); + if (!lstrcmpi(message, L"Incorrect login")) + { + ShowNotification(TranslateTS(message)); + SetStatus(ID_STATUS_OFFLINE); + mir_free(arg); + return; + } + + node = json_get(root, "emailauth_needed"); + if (json_as_bool(node) > 0) + { + node = json_get(root, "emailsteamid"); + ptrA guardId(mir_u2a(ptrT(json_as_string(node)))); + + node = json_get(root, "emaildomain"); + ptrA emailDomain(mir_utf8encodeW(ptrT(json_as_string(node)))); + + GuardParam guard; + mir_strncpy(guard.domain, emailDomain, SIZEOF(guard.domain)); + + if (DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_GUARD), NULL, CSteamProto::GuardProc, (LPARAM)&guard) != IDOK) + return; + + ptrA username(mir_utf8encodeW(getWStringA("Username"))); + PasswordParam *param = (PasswordParam*)arg; + + PushRequest( + new SteamWebApi::AuthorizationRequest(username, param->password, param->timestamp, guard.code), + &CSteamProto::OnAuthorization); + return; + } + + node = json_get(root, "captcha_needed"); + if (json_as_bool(node) > 0) + { + node = json_get(root, "captcha_gid"); + ptrA captchaId(mir_u2a(ptrT(json_as_string(node)))); + + SteamWebApi::GetCaptchaRequest *request = new SteamWebApi::GetCaptchaRequest(captchaId); + NETLIBHTTPREQUEST *response = request->Send(m_hNetlibUser); + delete request; + + CaptchaParam captcha = { 0 }; + captcha.size = response->dataLength; + captcha.data = (BYTE*)mir_alloc(captcha.size); + memcpy(captcha.data, response->pData, captcha.size); + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response); + + int res = DialogBoxParam( + g_hInstance, + MAKEINTRESOURCE(IDD_CAPTCHA), + NULL, + CSteamProto::CaptchaProc, + (LPARAM)&captcha); + + mir_free(captcha.data); + + if (res != 1) + { + SetStatus(ID_STATUS_OFFLINE); + return; + } + + ptrA username(mir_utf8encodeW(getWStringA("Username"))); + PasswordParam *param = (PasswordParam*)arg; + + PushRequest( + new SteamWebApi::AuthorizationRequest(username, param->password, param->timestamp, captchaId, captcha.text), + &CSteamProto::OnAuthorization); + return; + } + + SetStatus(ID_STATUS_OFFLINE); + mir_free(arg); + return; + } + + mir_free(arg); + + node = json_get(root, "login_complete"); + if (!json_as_bool(node)) + { + SetStatus(ID_STATUS_OFFLINE); + return; + } + + node = json_get(root, "oauth"); + JSONROOT nroot(_T2A(ptrT(json_as_string(node)))); + + node = json_get(nroot, "steamid"); + ptrA steamId(mir_u2a(ptrT(json_as_string(node)))); + setString("SteamID", steamId); + + node = json_get(nroot, "oauth_token"); + ptrA token(mir_u2a(ptrT(json_as_string(node)))); + setString("TokenSecret", token); + + node = json_get(nroot, "webcookie"); + ptrA cookie(mir_u2a(ptrT(json_as_string(node)))); + + delSetting("Timestamp"); + delSetting("EncryptedPassword"); + + PushRequest( + new SteamWebApi::GetSessionRequest(token, steamId, cookie), + &CSteamProto::OnGotSession); + + PushRequest( + new SteamWebApi::LogonRequest(token), + &CSteamProto::OnLoggedOn); +} + +void CSteamProto::OnGotSession(const NETLIBHTTPREQUEST *response, void *arg) +{ + if(response == NULL) + return; + + for (int i = 0; i < response->headersCount; i++) + { + if (lstrcmpiA(response->headers[i].szName, "Set-Cookie")) + continue; + + 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); + setString("SessionID", sessionId.c_str()); + break; + } +} + +void CSteamProto::OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg) +{ + if (response == NULL) + { + SetStatus(ID_STATUS_OFFLINE); + return; + } + + JSONROOT root(response->pData); + + JSONNODE *node = json_get(root, "error"); + ptrW error(json_as_string(node)); + if (lstrcmpi(error, L"OK")/* || response->resultCode == HTTP_STATUS_UNAUTHORIZED*/) + { + //delSetting("TokenSecret"); + //delSetting("Cookie"); + + // set status to offline + SetStatus(ID_STATUS_OFFLINE); + return; + } + + node = json_get(root, "umqid"); + setString("UMQID", ptrA(mir_u2a(ptrT(json_as_string(node))))); + + node = json_get(root, "message"); + setDword("MessageID", json_as_int(node)); + + // load contact list + ptrA token(getStringA("TokenSecret")); + ptrA steamId(getStringA("SteamID")); + + PushRequest( + new SteamWebApi::GetFriendListRequest(token, steamId), + &CSteamProto::OnGotFriendList); + + // start polling thread + m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, 0, NULL); + + // go to online now + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); } \ No newline at end of file diff --git a/protocols/Steam/src/steam_pooling.cpp b/protocols/Steam/src/steam_pooling.cpp index 7097cc0dff..1bf9f8314e 100644 --- a/protocols/Steam/src/steam_pooling.cpp +++ b/protocols/Steam/src/steam_pooling.cpp @@ -178,10 +178,8 @@ void CSteamProto::PollingThread(void*) while (!isTerminated && !breaked && errors < POLLING_ERRORS_LIMIT) { SteamWebApi::PollRequest *request = new SteamWebApi::PollRequest(token, umqId, messageId, IdleSeconds()); - debugLogA("CSteamProto::PollingThread: %s", request->szUrl); - request->szUrl = (char*)request->url.c_str(); - request->nlc = m_pollingConnection; - NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)request); + //request->nlc = m_pollingConnection; + NETLIBHTTPREQUEST *response = request->Send(m_hNetlibUser); delete request; if (response == NULL || response->resultCode != HTTP_STATUS_OK) diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h index 6ee5b79a8a..514410caea 100644 --- a/protocols/Steam/src/steam_proto.h +++ b/protocols/Steam/src/steam_proto.h @@ -1,338 +1,345 @@ -#ifndef _STEAM_PROTO_H_ -#define _STEAM_PROTO_H_ - -#define STEAM_SEARCH_BYID 1001 -#define STEAM_SEARCH_BYNAME 1002 -#define STEAM_TYPING_TIME 10 - -struct GuardParam -{ - char code[10]; - char domain[32]; -}; - -struct CaptchaParam -{ - BYTE *data; - size_t size; - char text[10]; -}; - -struct SendAuthParam -{ - MCONTACT hContact; - HANDLE hAuth; -}; - -struct SendMessageParam -{ - MCONTACT hContact; - HANDLE hMessage; - const char *msg; - int flags; -}; - -struct STEAM_SEARCH_RESULT -{ - PROTOSEARCHRESULT hdr; - JSONNODE *data; -}; - -enum -{ - CMI_AUTH_REQUEST, - //CMI_AUTH_GRANT, - //CMI_AUTH_REVOKE, - CMI_BLOCK, - CMI_JOIN_GAME, - SMI_BLOCKED_LIST, - CMI_MAX // this item shall be the last one -}; - -enum HTTP_STATUS -{ - HTTP_STATUS_NONE = 0, - HTTP_STATUS_OK = 200, - HTTP_STATUS_FOUND = 302, - HTTP_STATUS_BAD_REQUEST = 400, - HTTP_STATUS_UNAUTHORIZED = 401, - HTTP_STATUS_FORBIDDEN = 403, - HTTP_STATUS_NOT_FOUND = 404, - HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - HTTP_STATUS_TOO_MANY_REQUESTS = 429, - HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - HTTP_STATUS_INSUFICIENTE_STORAGE = 507 -}; - -enum ARG_FREE_TYPE -{ - ARG_NO_FREE, - ARG_MIR_FREE -}; - -typedef void (CSteamProto::*RESPONSE)(const NETLIBHTTPREQUEST *response, void *arg); - -struct QueueItem -{ - SteamWebApi::HttpRequest *request; - void *arg; - ARG_FREE_TYPE arg_free_type; - RESPONSE responseCallback; - //RESPONSE responseFailedCallback; - - QueueItem(SteamWebApi::HttpRequest *request) : - request(request), arg(NULL), responseCallback(NULL)/*, responseFailedCallback(NULL)*/ { } - - QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response) : - request(request), arg(NULL), responseCallback(response)/*, responseFailedCallback(NULL)*/ { } - - //QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response, RESPONSE responseFailedCallback) : - // request(request), arg(NULL), responseCallback(response), responseFailedCallback(responseFailedCallback) { } - - ~QueueItem() { - // Free request - delete request; - - // Free argument - switch (arg_free_type) - { - case ARG_NO_FREE: - break; - case ARG_MIR_FREE: - mir_free(arg); - default: - break; - } - - responseCallback = NULL; - //responseFailedCallback = NULL; - } -}; - -class CSteamProto : public PROTO -{ -public: - // PROTO_INTERFACE - CSteamProto(const char *protoName, const wchar_t *userName); - ~CSteamProto(); - - // PROTO_INTERFACE - virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr); - virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, MEVENT hDbEvent); - - virtual int __cdecl Authorize(MEVENT hDbEvent); - virtual int __cdecl AuthDeny(MEVENT hDbEvent, const TCHAR *szReason); - virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT *); - virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR * szMessage); - - virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath); - virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer); - virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason); - virtual int __cdecl FileResume(HANDLE hTransfer, int *action, const TCHAR** szFilename); - - virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); - virtual int __cdecl GetInfo(MCONTACT hContact, int infoType); - - virtual HANDLE __cdecl SearchBasic(const TCHAR *id); - virtual HANDLE __cdecl SearchByEmail(const TCHAR *email); - virtual HANDLE __cdecl SearchByName(const TCHAR *nick, const TCHAR *firstName, const TCHAR *lastName); - virtual HWND __cdecl SearchAdvanced(HWND owner); - virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); - - virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*); - virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET*); - virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*); - virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*); - - virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); - virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles); - virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg); - virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url); - - virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode); - virtual int __cdecl SetStatus(int iNewStatus); - - virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact); - virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt); - virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg); - - virtual int __cdecl UserIsTyping(MCONTACT hContact, int type); - - virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam); - - // instances - static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName); - static int UninitProtoInstance(CSteamProto* ppro); - - static CSteamProto* GetContactProtoInstance(MCONTACT hContact); - static void UninitProtoInstances(); - - // menus - static void InitMenus(); - static void UninitMenus(); - -protected: - bool isTerminated; - time_t m_idleTS; - HANDLE m_evRequestsQueue, m_hQueueThread; - HANDLE m_pollingConnection, m_hPollingThread; - ULONG hAuthProcess; - ULONG hMessageProcess; - CRITICAL_SECTION contact_search_lock; - CRITICAL_SECTION requests_queue_lock; - CRITICAL_SECTION set_status_lock; - LIST requestsQueue; - - // instances - static LIST InstanceList; - static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2); - - // queue - void InitQueue(); - void UninitQueue(); - - void StartQueue(); - void StopQueue(); - - void PushRequest(SteamWebApi::HttpRequest *request); - void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response); - void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg, ARG_FREE_TYPE arg_free_type); - - void ExecuteRequest(QueueItem *requestItem); - - void __cdecl SendMsgThread(void*); - void __cdecl QueueThread(void*); - - // pooling thread - void ParsePollData(JSONNODE *data); - void __cdecl PollingThread(void*); - - // account - bool IsOnline(); - bool IsMe(const char *steamId); - - void OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg); - - void OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotSession(const NETLIBHTTPREQUEST *response, void *arg); - - void OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg); - - // contacts - void SetContactStatus(MCONTACT hContact, WORD status); - void SetAllContactsStatus(WORD status); - - MCONTACT GetContactFromAuthEvent(MEVENT hEvent); - - void UpdateContact(MCONTACT hContact, JSONNODE *data); - void ProcessContact(std::map::iterator *it, MCONTACT hContact); - - void ContactIsRemoved(MCONTACT hContact); - void ContactIsFriend(MCONTACT hContact); - void ContactIsIgnored(MCONTACT hContact); - - MCONTACT FindContact(const char *steamId); - MCONTACT AddContact(const char *steamId, bool isTemporary = false); - - void OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotBlockList(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg); - void OnGotAvatar(const NETLIBHTTPREQUEST *response, void *arg); - - void OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg); - void OnFriendBlocked(const NETLIBHTTPREQUEST *response, void *arg); - void OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg); - - void OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg); - - void OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg); - void OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg); - - void OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg); - - void OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg); - void OnSearchByNameFinished(const NETLIBHTTPREQUEST *response, void *arg); - - // messages - void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg); - - // menus - HGENMENU m_hMenuRoot; - static HANDLE hChooserMenu; - static HGENMENU contactMenuItems[CMI_MAX]; - - int __cdecl AuthRequestCommand(WPARAM, LPARAM); - int __cdecl BlockCommand(WPARAM, LPARAM); - int __cdecl JoinToGameCommand(WPARAM, LPARAM); - - INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM); - - static INT_PTR MenuChooseService(WPARAM wParam, LPARAM lParam); - - static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam); - int OnPrebuildContactMenu(WPARAM wParam, LPARAM); - - void OnInitStatusMenu(); - - // avatars - TCHAR* GetAvatarFilePath(MCONTACT hContact); - bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATIONT &pai); - void CheckAvatarChange(MCONTACT hContact, std::string avatarUrl); - - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); - - // xstatuses - INT_PTR __cdecl OnGetXStatusEx(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl OnGetXStatusIcon(WPARAM wParam, LPARAM lParam); - INT_PTR __cdecl OnRequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam); - HICON GetXStatusIcon(int status, UINT flags); - int GetContactXStatus(MCONTACT hContact); - - // events - int OnModulesLoaded(WPARAM, LPARAM); - int OnPreShutdown(WPARAM, LPARAM); - int __cdecl OnIdleChanged(WPARAM, LPARAM); - INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam); - static int __cdecl OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam); - - // utils - static WORD SteamToMirandaStatus(int state); - static int MirandaToSteamState(int status); - - static int RsaEncrypt(const char *pszModulus, const char *data, BYTE *encrypted, DWORD &encryptedSize); - - MEVENT AddDBEvent(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, DWORD cbBlob, PBYTE pBlob); - - static void CSteamProto::ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); - static void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); - - // dialog procs - static INT_PTR CALLBACK GuardProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK CaptchaProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK MainOptionsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); - static LRESULT CALLBACK BlockListOptionsSubProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static INT_PTR CALLBACK BlockListOptionsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); - - // helpers - inline int IdleSeconds() { - // Based on idle time we report Steam server will mark us as online/away/snooze - switch (this->m_iStatus) { - case ID_STATUS_AWAY: - return STEAM_API_IDLEOUT_AWAY; - case ID_STATUS_NA: - return STEAM_API_IDLEOUT_SNOOZE; - default: - return 0; - } - - // ... or we can report real idle info - // return m_idleTS ? time(0) - m_idleTS : 0; - } -}; - -int OnReloadIcons(WPARAM wParam, LPARAM lParam); -void SetContactExtraIcon(MCONTACT hContact, int status); - +#ifndef _STEAM_PROTO_H_ +#define _STEAM_PROTO_H_ + +#define STEAM_SEARCH_BYID 1001 +#define STEAM_SEARCH_BYNAME 1002 +#define STEAM_TYPING_TIME 10 + +struct PasswordParam +{ + char password[513]; + char timestamp[16]; +}; + + +struct GuardParam +{ + char code[10]; + char domain[32]; +}; + +struct CaptchaParam +{ + BYTE *data; + size_t size; + char text[10]; +}; + +struct SendAuthParam +{ + MCONTACT hContact; + HANDLE hAuth; +}; + +struct SendMessageParam +{ + MCONTACT hContact; + HANDLE hMessage; + const char *msg; + int flags; +}; + +struct STEAM_SEARCH_RESULT +{ + PROTOSEARCHRESULT hdr; + JSONNODE *data; +}; + +enum +{ + CMI_AUTH_REQUEST, + //CMI_AUTH_GRANT, + //CMI_AUTH_REVOKE, + CMI_BLOCK, + CMI_JOIN_GAME, + SMI_BLOCKED_LIST, + CMI_MAX // this item shall be the last one +}; + +enum HTTP_STATUS +{ + HTTP_STATUS_NONE = 0, + HTTP_STATUS_OK = 200, + HTTP_STATUS_FOUND = 302, + HTTP_STATUS_BAD_REQUEST = 400, + HTTP_STATUS_UNAUTHORIZED = 401, + HTTP_STATUS_FORBIDDEN = 403, + HTTP_STATUS_NOT_FOUND = 404, + HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + HTTP_STATUS_TOO_MANY_REQUESTS = 429, + HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + HTTP_STATUS_INSUFICIENTE_STORAGE = 507 +}; + +enum ARG_FREE_TYPE +{ + ARG_NO_FREE, + ARG_MIR_FREE +}; + +typedef void (CSteamProto::*RESPONSE)(const NETLIBHTTPREQUEST *response, void *arg); + +struct QueueItem +{ + SteamWebApi::HttpRequest *request; + void *arg; + ARG_FREE_TYPE arg_free_type; + RESPONSE responseCallback; + //RESPONSE responseFailedCallback; + + QueueItem(SteamWebApi::HttpRequest *request) : + request(request), arg(NULL), responseCallback(NULL)/*, responseFailedCallback(NULL)*/ { } + + QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response) : + request(request), arg(NULL), responseCallback(response)/*, responseFailedCallback(NULL)*/ { } + + //QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response, RESPONSE responseFailedCallback) : + // request(request), arg(NULL), responseCallback(response), responseFailedCallback(responseFailedCallback) { } + + ~QueueItem() { + // Free request + delete request; + + // Free argument + switch (arg_free_type) + { + case ARG_NO_FREE: + break; + case ARG_MIR_FREE: + mir_free(arg); + default: + break; + } + + responseCallback = NULL; + //responseFailedCallback = NULL; + } +}; + +class CSteamProto : public PROTO +{ +public: + // PROTO_INTERFACE + CSteamProto(const char *protoName, const wchar_t *userName); + ~CSteamProto(); + + // PROTO_INTERFACE + virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr); + virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, MEVENT hDbEvent); + + virtual int __cdecl Authorize(MEVENT hDbEvent); + virtual int __cdecl AuthDeny(MEVENT hDbEvent, const TCHAR *szReason); + virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT *); + virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR * szMessage); + + virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath); + virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer); + virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason); + virtual int __cdecl FileResume(HANDLE hTransfer, int *action, const TCHAR** szFilename); + + virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); + virtual int __cdecl GetInfo(MCONTACT hContact, int infoType); + + virtual HANDLE __cdecl SearchBasic(const TCHAR *id); + virtual HANDLE __cdecl SearchByEmail(const TCHAR *email); + virtual HANDLE __cdecl SearchByName(const TCHAR *nick, const TCHAR *firstName, const TCHAR *lastName); + virtual HWND __cdecl SearchAdvanced(HWND owner); + virtual HWND __cdecl CreateExtendedSearchUI(HWND owner); + + virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*); + virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET*); + virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*); + virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*); + + virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); + virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles); + virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg); + virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url); + + virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode); + virtual int __cdecl SetStatus(int iNewStatus); + + virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact); + virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt); + virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg); + + virtual int __cdecl UserIsTyping(MCONTACT hContact, int type); + + virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam); + + // instances + static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName); + static int UninitProtoInstance(CSteamProto* ppro); + + static CSteamProto* GetContactProtoInstance(MCONTACT hContact); + static void UninitProtoInstances(); + + // menus + static void InitMenus(); + static void UninitMenus(); + +protected: + bool isTerminated; + time_t m_idleTS; + HANDLE m_evRequestsQueue, m_hQueueThread; + HANDLE m_pollingConnection, m_hPollingThread; + ULONG hAuthProcess; + ULONG hMessageProcess; + CRITICAL_SECTION contact_search_lock; + CRITICAL_SECTION requests_queue_lock; + CRITICAL_SECTION set_status_lock; + LIST requestsQueue; + + // instances + static LIST InstanceList; + static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2); + + // queue + void InitQueue(); + void UninitQueue(); + + void StartQueue(); + void StopQueue(); + + void PushRequest(SteamWebApi::HttpRequest *request); + void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response); + void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg, ARG_FREE_TYPE arg_free_type); + + void ExecuteRequest(QueueItem *requestItem); + + void __cdecl SendMsgThread(void*); + void __cdecl QueueThread(void*); + + // pooling thread + void ParsePollData(JSONNODE *data); + void __cdecl PollingThread(void*); + + // account + bool IsOnline(); + bool IsMe(const char *steamId); + + void OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg); + + void OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotSession(const NETLIBHTTPREQUEST *response, void *arg); + + void OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg); + + // contacts + void SetContactStatus(MCONTACT hContact, WORD status); + void SetAllContactsStatus(WORD status); + + MCONTACT GetContactFromAuthEvent(MEVENT hEvent); + + void UpdateContact(MCONTACT hContact, JSONNODE *data); + void ProcessContact(std::map::iterator *it, MCONTACT hContact); + + void ContactIsRemoved(MCONTACT hContact); + void ContactIsFriend(MCONTACT hContact); + void ContactIsIgnored(MCONTACT hContact); + + MCONTACT FindContact(const char *steamId); + MCONTACT AddContact(const char *steamId, bool isTemporary = false); + + void OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotBlockList(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg); + void OnGotAvatar(const NETLIBHTTPREQUEST *response, void *arg); + + void OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg); + void OnFriendBlocked(const NETLIBHTTPREQUEST *response, void *arg); + void OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg); + + void OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg); + + void OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg); + void OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg); + + void OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg); + + void OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg); + void OnSearchByNameFinished(const NETLIBHTTPREQUEST *response, void *arg); + + // messages + void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg); + + // menus + HGENMENU m_hMenuRoot; + static HANDLE hChooserMenu; + static HGENMENU contactMenuItems[CMI_MAX]; + + int __cdecl AuthRequestCommand(WPARAM, LPARAM); + int __cdecl BlockCommand(WPARAM, LPARAM); + int __cdecl JoinToGameCommand(WPARAM, LPARAM); + + INT_PTR __cdecl OpenBlockListCommand(WPARAM, LPARAM); + + static INT_PTR MenuChooseService(WPARAM wParam, LPARAM lParam); + + static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam); + int OnPrebuildContactMenu(WPARAM wParam, LPARAM); + + void OnInitStatusMenu(); + + // avatars + TCHAR* GetAvatarFilePath(MCONTACT hContact); + bool GetDbAvatarInfo(PROTO_AVATAR_INFORMATIONT &pai); + void CheckAvatarChange(MCONTACT hContact, std::string avatarUrl); + + INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); + INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); + + // xstatuses + INT_PTR __cdecl OnGetXStatusEx(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl OnGetXStatusIcon(WPARAM wParam, LPARAM lParam); + INT_PTR __cdecl OnRequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam); + HICON GetXStatusIcon(int status, UINT flags); + int GetContactXStatus(MCONTACT hContact); + + // events + int OnModulesLoaded(WPARAM, LPARAM); + int OnPreShutdown(WPARAM, LPARAM); + int __cdecl OnIdleChanged(WPARAM, LPARAM); + INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam); + static int __cdecl OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam); + + // utils + static WORD SteamToMirandaStatus(int state); + static int MirandaToSteamState(int status); + + static int RsaEncrypt(const char *pszModulus, const char *data, BYTE *encrypted, DWORD &encryptedSize); + + MEVENT AddDBEvent(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, DWORD cbBlob, PBYTE pBlob); + + static void CSteamProto::ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); + static void CSteamProto::ShowNotification(const wchar_t *caption, const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); + + // dialog procs + static INT_PTR CALLBACK GuardProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK CaptchaProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK MainOptionsProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK BlockListOptionsSubProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK BlockListOptionsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + + // helpers + inline int IdleSeconds() { + // Based on idle time we report Steam server will mark us as online/away/snooze + switch (this->m_iStatus) { + case ID_STATUS_AWAY: + return STEAM_API_IDLEOUT_AWAY; + case ID_STATUS_NA: + return STEAM_API_IDLEOUT_SNOOZE; + default: + return 0; + } + + // ... or we can report real idle info + // return m_idleTS ? time(0) - m_idleTS : 0; + } +}; + +int OnReloadIcons(WPARAM wParam, LPARAM lParam); +void SetContactExtraIcon(MCONTACT hContact, int status); + #endif //_STEAM_PROTO_H_ \ No newline at end of file diff --git a/protocols/Steam/src/steam_queue.cpp b/protocols/Steam/src/steam_queue.cpp index ff61da24a7..6ef1aee6f7 100644 --- a/protocols/Steam/src/steam_queue.cpp +++ b/protocols/Steam/src/steam_queue.cpp @@ -63,9 +63,7 @@ void CSteamProto::StopQueue() ptrA umqid(getStringA("UMQID")); SteamWebApi::HttpRequest *request = new SteamWebApi::LogoffRequest(token, umqid); - debugLogA("CSteamProto::StopQueue: %s", request->szUrl); - request->szUrl = (char*)request->url.c_str(); - NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)request); + NETLIBHTTPREQUEST *response = request->Send(m_hNetlibUser); CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response); delete request; @@ -113,10 +111,7 @@ void CSteamProto::ExecuteRequest(QueueItem *item) return; } - debugLogA("CSteamProto::ExecuteRequest: %s", item->request->szUrl); - - item->request->szUrl = (char*)item->request->url.c_str(); - NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)item->request); + NETLIBHTTPREQUEST *response = item->request->Send(m_hNetlibUser); if (item->responseCallback != NULL) (this->*(item->responseCallback))(response, item->arg); @@ -128,7 +123,7 @@ void CSteamProto::ExecuteRequest(QueueItem *item) } /*else if (requestItem->responseFailedCallback != NULL) { - (this->*(requestItem->responseFailedCallback))(response); + (this->*(requestItem->responseFailedCallback))(response); }*/ delete item; diff --git a/protocols/Steam/src/version.h b/protocols/Steam/src/version.h index e33f795d5b..007f994986 100644 --- a/protocols/Steam/src/version.h +++ b/protocols/Steam/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 11 #define __RELEASE_NUM 3 -#define __BUILD_NUM 0 +#define __BUILD_NUM 1 #include -- cgit v1.2.3