From cbf3dd8f411c1336c7bde2b6bbd0eb74941ac60b Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Thu, 3 Apr 2014 12:29:38 +0000 Subject: Steam: authorization, login, contact list retrieving git-svn-id: http://svn.miranda-ng.org/main/trunk@8839 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Steam/Steam_10.vcxproj | 16 +- protocols/Steam/Steam_10.vcxproj.filters | 39 ++- protocols/Steam/src/Steam/authorization.h | 123 +++++++ protocols/Steam/src/Steam/crypto.h | 123 +++++++ protocols/Steam/src/Steam/friend.h | 85 +++++ protocols/Steam/src/Steam/friend_list.h | 57 ++++ protocols/Steam/src/Steam/login.h | 62 ++++ protocols/Steam/src/Steam/steam.h | 37 ++ protocols/Steam/src/common.h | 36 ++ protocols/Steam/src/http_request.h | 20 +- protocols/Steam/src/stdafx.cpp | 55 ++- protocols/Steam/src/steam_account.cpp | 90 +++++ protocols/Steam/src/steam_contacts.cpp | 550 ++++++++++++++++++++++++++++++ protocols/Steam/src/steam_dialogs.cpp | 16 +- protocols/Steam/src/steam_events.cpp | 2 +- protocols/Steam/src/steam_instances.cpp | 45 +++ protocols/Steam/src/steam_proto.cpp | 190 +---------- protocols/Steam/src/steam_proto.h | 45 ++- protocols/Steam/src/steam_thread.cpp | 20 ++ 19 files changed, 1402 insertions(+), 209 deletions(-) create mode 100644 protocols/Steam/src/Steam/authorization.h create mode 100644 protocols/Steam/src/Steam/crypto.h create mode 100644 protocols/Steam/src/Steam/friend.h create mode 100644 protocols/Steam/src/Steam/friend_list.h create mode 100644 protocols/Steam/src/Steam/login.h create mode 100644 protocols/Steam/src/Steam/steam.h create mode 100644 protocols/Steam/src/common.h create mode 100644 protocols/Steam/src/steam_account.cpp create mode 100644 protocols/Steam/src/steam_contacts.cpp create mode 100644 protocols/Steam/src/steam_instances.cpp create mode 100644 protocols/Steam/src/steam_thread.cpp (limited to 'protocols') diff --git a/protocols/Steam/Steam_10.vcxproj b/protocols/Steam/Steam_10.vcxproj index b83444ad7a..bfb6cb08df 100644 --- a/protocols/Steam/Steam_10.vcxproj +++ b/protocols/Steam/Steam_10.vcxproj @@ -84,7 +84,7 @@ 4996;%(DisableSpecificWarnings) MultiThreadedDebugDLL $(IntDir)\%(RelativeDir)\ - steam.h + common.h Use @@ -189,20 +189,28 @@ - + + + + + + + - - + + + Create + diff --git a/protocols/Steam/Steam_10.vcxproj.filters b/protocols/Steam/Steam_10.vcxproj.filters index 9dd3117f32..61152ad02f 100644 --- a/protocols/Steam/Steam_10.vcxproj.filters +++ b/protocols/Steam/Steam_10.vcxproj.filters @@ -13,6 +13,9 @@ {4df49e9a-8abc-4fcc-978b-8a6e6f86d70f} + + {f3fc3bb2-b1ba-4066-bd18-d2e458cd5724} + @@ -21,16 +24,22 @@ Source Files - + Source Files - + Source Files - + Source Files - + + Source Files + + + Source Files + + Source Files @@ -44,12 +53,30 @@ Header Files - + Header Files - + + Header Files\Steam + + Header Files + + Header Files\Steam + + + Header Files\Steam + + + Header Files\Steam + + + Header Files\Steam + + + Header Files\Steam + diff --git a/protocols/Steam/src/Steam/authorization.h b/protocols/Steam/src/Steam/authorization.h new file mode 100644 index 0000000000..376781ba94 --- /dev/null +++ b/protocols/Steam/src/Steam/authorization.h @@ -0,0 +1,123 @@ +#ifndef _STEAM_AUTHORIZATION_H_ +#define _STEAM_AUTHORIZATION_H_ + +namespace SteamWebApi +{ + class AuthorizationApi : public BaseApi + { + public: + + class Authorization : public Result + { + friend AuthorizationApi; + + private: + std::string steamid; + std::string token; + + std::string emailauth; + std::string emailsteamid; + + bool emailauth_needed; + + public: + bool IsEmailAuthNeeded() { return emailauth_needed; } + const char *GetSteamid() { return steamid.c_str(); } + const char *GetToken() { return token.c_str(); } + const char *GetAuthId() { return emailauth.c_str(); } + const char *GetAuthCode() { return emailsteamid.c_str(); } + + void SetAuthCode(char *code) + { + emailauth = code; + } + }; + + static void Authorize(HANDLE hConnection, const wchar_t *username, const char *password, Authorization *auth) + { + auth->success = false; + + ptrA base64Username(mir_urlEncode(ptrA(mir_utf8encodeW(username)))); + + CryptoApi::RsaKey rsaKey; + CryptoApi::GetRsaKey(hConnection, base64Username, &rsaKey); + if (!rsaKey.IsSuccess()) return; + + int size = rsaKey.GetEncryptedSize(); + BYTE *rsaEncryptedPassword = (BYTE*)mir_alloc(size); + rsaKey.Encrypt((unsigned char*)password, strlen(password), rsaEncryptedPassword); + ptrA base64RsaEncryptedPassword(mir_base64_encode(rsaEncryptedPassword, size)); + mir_free(rsaEncryptedPassword); + + CMStringA data; + data.AppendFormat("username=%s", base64Username); + data.AppendFormat("&password=%s", ptrA(mir_urlEncode(base64RsaEncryptedPassword))); + data.AppendFormat("&emailauth=%s", ptrA(mir_urlEncode(auth->emailauth.c_str()))); + data.AppendFormat("&emailsteamid=%s", auth->emailsteamid.c_str()); + //data.AppendFormat("&captchagid=%s", result->captchagid); + //data.AppendFormat("&captcha_text=%s", ptrA(mir_urlEncode(result->captcha_text))); + data.Append("&captchagid=-1"); + data.AppendFormat("&rsatimestamp=%llu", rsaKey.GetTimestamp()); + data.AppendFormat("&oauth_scope=%s", "read_profile%20write_profile%20read_client%20write_client"); + data.Append("&oauth_client_id=3638BFB1"); + + HttpRequest request(hConnection, REQUEST_POST, "https://steamcommunity.com/mobilelogin/dologin"); + request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); + request.SetData(data.GetBuffer(), data.GetLength()); + + mir_ptr response(request.Send()); + if (!response || response->resultCode != HTTP_STATUS_OK) + return; + + JSONNODE *root = json_parse(response->pData), *node; + + node = json_get(root, "success"); + auth->success = json_as_bool(node) > 0; + if (!auth->success) + { + node = json_get(root, "emailauth_needed"); + auth->emailauth_needed = json_as_bool(node) > 0; + if (auth->emailauth_needed) + { + node = json_get(root, "emailsteamid"); + auth->emailsteamid = ptrA(mir_u2a(json_as_string(node))); + auth->emailauth_needed = false; + + /*node = json_get(root, "emaildomain"); + result->emaildomain = json_as_string(node);*/ + } + + /*node = json_get(root, "captcha_needed"); + result->captcha_needed = json_as_bool(node) > 0; + if (result->captcha_needed) + { + node = json_get(root, "captcha_gid"); + result->captchagid = json_as_string(node); + }*/ + } + else + { + node = json_get(root, "login_complete"); + if (!json_as_bool(node)) + return; + + node = json_get(root, "oauth"); + CMStringA oauth = mir_u2a(json_as_string(node)); + oauth.Replace("\\\"", "\""); + root = json_parse(oauth.GetBuffer()); + //root = json_as_node(node); + + node = json_get(root, "steamid"); + auth->steamid = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(root, "oauth_token"); + auth->token = ptrA(mir_u2a(json_as_string(node))); + + auth->success = true; + } + } + }; +} + + +#endif //_STEAM_AUTHORIZATION_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/crypto.h b/protocols/Steam/src/Steam/crypto.h new file mode 100644 index 0000000000..91a8af7ba0 --- /dev/null +++ b/protocols/Steam/src/Steam/crypto.h @@ -0,0 +1,123 @@ +#ifndef _STEAM_CRYPTO_H_ +#define _STEAM_CRYPTO_H_ + + #include + #include + #include + #include + #include + #include + #include + +namespace SteamWebApi +{ + class CryptoApi : public BaseApi + { + public: + + class RsaKey : public Result + { + friend CryptoApi; + + private: + std::string modulus; + std::string exponent; + time_t timestamp; + + public: + RsaKey() : timestamp(0) { } + + const char * GetModulus() const + { + return modulus.c_str(); + } + + const char * GetExponent() const + { + return exponent.c_str(); + } + + time_t GetTimestamp() const + { + return timestamp; + } + + int GetEncryptedSize() const + { + BIGNUM *n = BN_new(); + if (!BN_hex2bn(&n, modulus.c_str())) + return NULL; + + BIGNUM *e = BN_new(); + if (!BN_hex2bn(&e, exponent.c_str())) + return NULL; + + RSA *rsa = RSA_new(); + rsa->n = n; + rsa->e = e; + + int size = RSA_size(rsa); + + RSA_free(rsa); + + return size; + } + + int Encrypt(BYTE *data, int dataSize, BYTE *encrypted) const + { + BIGNUM *n = BN_new(); + if (!BN_hex2bn(&n, modulus.c_str())) + return NULL; + + BIGNUM *e = BN_new(); + if (!BN_hex2bn(&e, exponent.c_str())) + return NULL; + + RSA *rsa = RSA_new(); + rsa->n = n; + rsa->e = e; + + if (RSA_public_encrypt(dataSize, data, encrypted, rsa, RSA_PKCS1_PADDING) < 0) + { + RSA_free(rsa); + return 1; + } + + RSA_free(rsa); + return 0; + } + }; + + static void GetRsaKey(HANDLE hConnection, const char *username, RsaKey *rsaKey) + { + rsaKey->success = false; + + HttpRequest request(hConnection, REQUEST_GET, "https://steamcommunity.com/mobilelogin/getrsakey"); + request.AddParameter("username", username); + + mir_ptr response(request.Send()); + if (!response || response->resultCode != HTTP_STATUS_OK) + return; + + JSONNODE *root = json_parse(response->pData), *node; + if (!root) return; + + node = json_get(root, "success"); + if (!json_as_bool(node)) return; + + node = json_get(root, "publickey_mod"); + rsaKey->modulus = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(root, "publickey_exp"); + rsaKey->exponent = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(root, "timestamp"); + rsaKey->timestamp = _atoi64(ptrA(mir_u2a(json_as_string(node)))); + + rsaKey->success = true; + } + }; +} + + +#endif //_STEAM_CRYPTO_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/friend.h b/protocols/Steam/src/Steam/friend.h new file mode 100644 index 0000000000..c6ec704b84 --- /dev/null +++ b/protocols/Steam/src/Steam/friend.h @@ -0,0 +1,85 @@ +#ifndef _STEAM_FRIEND_H_ +#define _STEAM_FRIEND_H_ + +namespace SteamWebApi +{ + class FriendApi : public BaseApi + { + public: + struct Friend : public Result + { + friend FriendApi; + //LIST friendIds; + + private: + std::string steamId; + + CMStringW nick; + std::string homepage; + std::string avatarUrl; + + DWORD lastEvent; + + public: + const char *GetSteamId() const { return steamId.c_str(); } + const wchar_t *GetNick() const { return nick.c_str(); } + const char *GetHomepage() const { return homepage.c_str(); } + const char *GetAvatarUrl() const { return avatarUrl.c_str(); } + const DWORD GetLastEvent() const { return lastEvent; } + }; + + static void LoadSummaries(HANDLE hConnection, const char *token, const char *steamId, Friend *result) + { + result->success = false; + + HttpRequest *request = new HttpRequest(hConnection, REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001"); + request->AddParameter("access_token", token); + request->AddParameter("steamids", steamId); + + mir_ptr response(request->Send()); + delete request; + + if (!response || response->resultCode != HTTP_STATUS_OK) + return; + + JSONNODE *root = json_parse(response->pData), *node, *child; + + /*node = json_get(root, "response"); + root = json_as_node(node);*/ + node = json_get(root, "players"); + root = json_as_array(node); + if (root != NULL) + { + for (int i = 0;; i++) + { + child = json_at(root, i); + if (child == NULL) + break; + + node = json_get(child, "steamid"); + ptrA cSteamId(ptrA(mir_u2a(json_as_string(node)))); + if (lstrcmpA(steamId, cSteamId)) + return; + result->steamId = steamId; + + node = json_get(child, "personaname"); + result->nick = json_as_string(node); + + node = json_get(child, "profileurl"); + result->homepage = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(child, "lastlogoff"); + //LastEventDateTS + result->lastEvent = json_as_int(node); + + node = json_get(child, "avatarfull"); + result->avatarUrl = ptrA(mir_u2a(json_as_string(node))); + } + } + + result->success = true; + } + }; +} + +#endif //_STEAM_FRIEND_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/friend_list.h b/protocols/Steam/src/Steam/friend_list.h new file mode 100644 index 0000000000..6b0a5adf50 --- /dev/null +++ b/protocols/Steam/src/Steam/friend_list.h @@ -0,0 +1,57 @@ +#ifndef _STEAM_FRIEND_LIST_H_ +#define _STEAM_FRIEND_LIST_H_ + +namespace SteamWebApi +{ + class FriendListApi : public BaseApi + { + public: + class FriendList : public Result + { + friend FriendListApi; + + private: + std::vector friendIds; + + public: + int GetCount() const { return friendIds.size(); } + + const char * operator[](int idx) const { return friendIds[idx].c_str(); } + }; + + static void Load(HANDLE hConnection, const char *token, const char *steamId, FriendList *friendList) + { + friendList->success = false; + + HttpRequest request(hConnection, REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001"); + request.AddParameter("access_token", token); + request.AddParameter("steamid", steamId); + + mir_ptr response(request.Send()); + if (!response || response->resultCode != HTTP_STATUS_OK) + return; + + JSONNODE *root = json_parse(response->pData), *node, *child; + + node = json_get(root, "friends"); + root = json_as_array(node); + if (root != NULL) + { + for (int i = 0;; i++) + { + child = json_at(root, i); + if (child == NULL) + break; + + node = json_get(child, "steamid"); + friendList->friendIds + .push_back((char*)ptrA(mir_u2a(json_as_string(node)))); + } + } + + friendList->success = true; + } + }; +} + +#endif //_STEAM_FRIEND_LIST_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/login.h b/protocols/Steam/src/Steam/login.h new file mode 100644 index 0000000000..e12d942f7b --- /dev/null +++ b/protocols/Steam/src/Steam/login.h @@ -0,0 +1,62 @@ +#ifndef _STEAM_LOGIN_H_ +#define _STEAM_LOGIN_H_ + +namespace SteamWebApi +{ + class LogInApi : public BaseApi + { + public: + class LogIn : public Result + { + friend LogInApi; + + private: + std::string steamid; + std::string umqid; + std::string message; + + public: + + const char *GetSteamId() { return steamid.c_str(); } + const char *GetSessionId() { return umqid.c_str(); } + const char *GetMessageId() { return message.c_str(); } + }; + + static void LogOn(HANDLE hConnection, const char *token, LogIn *login) + { + login->success = false; + + CMStringA data; + data.AppendFormat("access_token=%s", token); + + HttpRequest request(hConnection, REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001"); + request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); + request.SetData(data.GetBuffer(), data.GetLength()); + + mir_ptr response(request.Send()); + if (!response || response->resultCode != HTTP_STATUS_OK) + return; + + JSONNODE *root = json_parse(response->pData), *node; + + node = json_get(root, "error"); + ptrW error(json_as_string(node)); + if (lstrcmpi(error, L"OK")) + return; + + node = json_get(root, "steamid"); + login->steamid = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(root, "umqid"); + login->umqid = ptrA(mir_u2a(json_as_string(node))); + + node = json_get(root, "message"); + login->message = ptrA(mir_u2a(json_as_string(node))); + + login->success = true; + } + }; +} + + +#endif //_STEAM_LOGIN_H_ \ No newline at end of file diff --git a/protocols/Steam/src/Steam/steam.h b/protocols/Steam/src/Steam/steam.h new file mode 100644 index 0000000000..ac995f8314 --- /dev/null +++ b/protocols/Steam/src/Steam/steam.h @@ -0,0 +1,37 @@ +#ifndef _STEAM_H_ +#define _STEAM_H_ + +namespace SteamWebApi +{ + #define STEAM_API_URL "https://api.steampowered.com" + + struct Result + { + bool success; + }; + + class BaseApi + { + public: + class Result + { + protected: + bool success; + + public: + Result() : success(false) { } + bool IsSuccess() const { return success; } + }; + }; +} + +#include +#include + +#include "Steam\crypto.h" +#include "Steam\authorization.h" +#include "Steam\login.h" +#include "Steam\friend_list.h" +#include "Steam\friend.h" + +#endif //_STEAM_H_ \ No newline at end of file diff --git a/protocols/Steam/src/common.h b/protocols/Steam/src/common.h new file mode 100644 index 0000000000..9a106b3a47 --- /dev/null +++ b/protocols/Steam/src/common.h @@ -0,0 +1,36 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "resource.h" +#include "version.h" + +#define MODULE "Steam" + +class CSteamProto; +extern HINSTANCE g_hInstance; + +#include "http_request.h" + +#include "Steam\steam.h" + +#include "steam_proto.h" + +#endif //_COMMON_H_ \ No newline at end of file diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h index 6d142bdc73..3d433009e8 100644 --- a/protocols/Steam/src/http_request.h +++ b/protocols/Steam/src/http_request.h @@ -1,7 +1,7 @@ #ifndef _HTTP_REQUEST_H_ #define _HTTP_REQUEST_H_ -#include "steam.h" +#include "common.h" enum HTTP_STATUS { @@ -127,13 +127,21 @@ public: m_szUrl.AppendFormat("&%s=%s", szName, szValue); } - /*void AddParameter(LPCSTR szName, int value) + void AddParameter(LPCSTR szName, int value) { if (m_szUrl.Find('?') == -1) m_szUrl.AppendFormat("?%s=%i", szName, value); else m_szUrl.AppendFormat("&%s=%i", szName, value); - }*/ + } + + void AddParameter(LPCSTR szName, UINT64 value) + { + if (m_szUrl.Find('?') == -1) + m_szUrl.AppendFormat("?%s=%llu", szName, value); + else + m_szUrl.AppendFormat("&%s=%llu", szName, value); + } NETLIBHTTPREQUEST *Send() { @@ -148,4 +156,10 @@ private: HANDLE m_hNetlibUser; }; +/*class HttpPostRequest : public HttpRequest +{ +public: + HttpPostRequest(HANDLE hNetlibUser, LPCSTR url) : HttpRequest(hNetlibUser, REQUEST_POST, url) { } +};*/ + #endif //_HTTP_REQUEST_H_ \ No newline at end of file diff --git a/protocols/Steam/src/stdafx.cpp b/protocols/Steam/src/stdafx.cpp index 72b5c6b7b0..d3d389fe4d 100644 --- a/protocols/Steam/src/stdafx.cpp +++ b/protocols/Steam/src/stdafx.cpp @@ -1 +1,54 @@ -#include "steam.h" +#include "common.h" + +int hLangpack; +HINSTANCE g_hInstance; + +PLUGININFOEX pluginInfo = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {68F5A030-BA32-48EC-9507-5C2FBDEA5217} + { 0x68f5a030, 0xba32, 0x48ec, { 0x95, 0x7, 0x5c, 0x2f, 0xbd, 0xea, 0x52, 0x17 }} +}; + +DWORD WINAPI DllMain(HINSTANCE hInstance, DWORD, LPVOID) +{ + g_hInstance = hInstance; + + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP(&pluginInfo); + + PROTOCOLDESCRIPTOR pd = { sizeof(pd) }; + pd.szName = "STEAM"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = (pfnInitProto)CSteamProto::InitProtoInstance; + pd.fnUninit = (pfnUninitProto)CSteamProto::UninitProtoInstance; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + CSteamProto::UninitProtoInstances(); + + return 0; +} \ No newline at end of file diff --git a/protocols/Steam/src/steam_account.cpp b/protocols/Steam/src/steam_account.cpp new file mode 100644 index 0000000000..632969ad67 --- /dev/null +++ b/protocols/Steam/src/steam_account.cpp @@ -0,0 +1,90 @@ +#include "common.h" + +void CSteamProto::LogInThread(void* param) +{ + CMStringA token(getStringA("TokenSecret")); + if (token.IsEmpty()) + { + ptrW username(getWStringA("Username")); + ptrA password(getStringA("Password")); + + SteamWebApi::AuthorizationApi::Authorization authResult; + SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, &authResult); + + if (authResult.IsEmailAuthNeeded()/* || authResult.captcha_needed*/) + { + do + { + if (authResult.IsEmailAuthNeeded()) + { + GuardParam guard; + + //lstrcpy(guard.emailDomain, authResult.emaildomain); + + if (DialogBoxParam( + g_hInstance, + MAKEINTRESOURCE(IDD_GUARD), + NULL, + CSteamProto::GuardProc, + (LPARAM)&guard) != 1) + break; + + authResult.SetAuthCode(guard.code); + } + + //if (result->captcha_needed) + // ;// proto->fail + + SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, &authResult); + + } while (authResult.IsEmailAuthNeeded()/* || auth->captcha_needed*/); + } + + if (!authResult.IsSuccess()) + { + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, ID_STATUS_OFFLINE); + return; + } + + token = authResult.GetToken(); + setString("TokenSecret", token); + setString("SteamID", authResult.GetSteamid()); + } + + SteamWebApi::LogInApi::LogIn login; + SteamWebApi::LogInApi::LogOn(m_hNetlibUser, token, &login); + + if (!login.IsSuccess()) + { + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, ID_STATUS_OFFLINE); + return; + } + + setString("SessionID", login.GetSessionId()); + setString("MessageID", login.GetMessageId()); + + m_iStatus = m_iDesiredStatus; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iDesiredStatus); + + if (m_hPollingThread == NULL) + m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, NULL, NULL); + + SteamWebApi::FriendListApi::FriendList friendList; + SteamWebApi::FriendListApi::Load(m_hNetlibUser, token, login.GetSteamId(), &friendList); + + if (friendList.IsSuccess()) + { + for (int i = 0; i < friendList.GetCount(); i++) + { + if (!FindContact(friendList[i])) + { + SteamWebApi::FriendApi::Friend rFriend; + SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, friendList[i], &rFriend); + if (!rFriend.IsSuccess()) continue; + AddContact(rFriend); + } + } + } +} \ No newline at end of file diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp new file mode 100644 index 0000000000..83731165c9 --- /dev/null +++ b/protocols/Steam/src/steam_contacts.cpp @@ -0,0 +1,550 @@ +#include "common.h" + +MCONTACT CSteamProto::FindContact(const char *steamId) +{ + MCONTACT hContact = NULL; + + EnterCriticalSection(&this->contact_search_lock); + + for (hContact = db_find_first(this->m_szModuleName); hContact; hContact = db_find_next(hContact, this->m_szModuleName)) + { + ptrA cSteamId(db_get_sa(hContact, this->m_szModuleName, "SteamID")); + if (!lstrcmpA(cSteamId, steamId)) + break; + } + + LeaveCriticalSection(&this->contact_search_lock); + + return hContact; +} + +MCONTACT CSteamProto::AddContact(const SteamWebApi::FriendApi::Friend &contact) +{ + MCONTACT hContact = this->FindContact(contact.GetSteamId()); + if (!hContact) + { + hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0); + CallService(MS_PROTO_ADDTOCONTACT, hContact, (LPARAM)this->m_szModuleName); + + this->setString(hContact, "SteamID", contact.GetSteamId()); + this->setWString(hContact, "Nick", contact.GetNick()); + this->setString(hContact, "Homepage", contact.GetHomepage()); + this->setDword(hContact, "LastEventDateTS", contact.GetLastEvent()); + + /*DBVARIANT dbv; + if ( !this->getTString(SKYPE_SETTINGS_DEF_GROUP, &dbv)) + { + ::db_set_ts(hContact, "CList", "Group", dbv.ptszVal); + ::db_free(&dbv); + }*/ + } + + return hContact; +} + +//void CSteamProto::OnContactListLoadedAsync(Steam::FriendList::Result *friendList) +//{ +// if (friendList->success) +// { +// for (int i = 0; i < friendList->friendIds.getCount(); i++) +// { +// if (!FindContact(friendList->friendIds[i])) +// { +// Steam::Friend::Result rFriend; +// Steam::Friend(m_hNetlibUser) +// .LoadSummaries(friendList->friendIds[i], &rFriend); +// if (!rFriend.success) continue; +// AddContact(rFriend); +// } +// } +// } +//} + +//void CSkypeProto::UpdateContactAuthState(MCONTACT hContact, const ContactRef &contact) +//{ +// uint newTS = 0; +// contact->GetPropAuthreqTimestamp(newTS); +// DWORD oldTS = this->getDword("AuthTS", 0); +// if (newTS > oldTS) +// { +// bool result; +// if (contact->HasAuthorizedMe(result) && !result) +// this->setByte(hContact, "Auth", !result); +// else +// { +// this->delSetting(hContact, "Auth"); +// if (contact->IsMemberOfHardwiredGroup(CContactGroup::ALL_BUDDIES, result) && !result) +// this->setByte(hContact, "Grant", !result); +// else +// this->delSetting(hContact, "Grant"); +// } +// +// this->setDword(hContact, "AuthTS", newTS); +// } +//} +// +//void CSkypeProto::UpdateContactStatus(MCONTACT hContact, const ContactRef &contact) +//{ +// Contact::AVAILABILITY availability; +// contact->GetPropAvailability(availability); +// this->setWord(hContact, SKYPE_SETTINGS_STATUS, CSkypeProto::SkypeToMirandaStatus(availability)); +// +// if (availability == Contact::SKYPEOUT) +// this->setWord(hContact, SKYPE_SETTINGS_STATUS, ID_STATUS_ONTHEPHONE); +// else +// { +// if (availability == Contact::PENDINGAUTH) +// this->setByte(hContact, "Auth", 1); +// else +// this->delSetting(hContact, "Auth"); +// } +//} +// +//void CSkypeProto::UpdateContactClient(MCONTACT hContact, const ContactRef &contact) +//{ +// bool isMobile = false; +// contact->HasCapability(Contact::CAPABILITY_MOBILE_DEVICE, isMobile/*, true*/); +// +// this->setTString(hContact, "MirVer", isMobile ? L"SkypeMobile" : L"Skype"); +//} +// +//void CSkypeProto::UpdateContactOnlineSinceTime(MCONTACT hContact, const ContactRef &contact) +//{ +// uint newTS = 0; +// contact->GetPropLastonlineTimestamp(newTS); +// DWORD oldTS = ::db_get_dw(hContact, this->m_szModuleName, "OnlineSinceTS", 0); +// if (newTS > oldTS) +// this->setDword(hContact, "OnlineSinceTS", newTS); +//} +// +//void CSkypeProto::UpdateContactLastEventDate(MCONTACT hContact, const ContactRef &contact) +//{ +// uint newTS = 0; +// contact->GetPropLastusedTimestamp(newTS); +// DWORD oldTS = this->getDword(hContact, "LastEventDateTS", 0); +// if (newTS > oldTS) +// this->setDword(hContact, "LastEventDateTS", newTS); +//} +// +//void CSkypeProto::OnContactChanged(const ContactRef &contact, int prop) +//{ +// SEString data; +// contact->GetPropSkypename(data); +// wchar_t *sid = ::mir_utf8decodeW(data); +// MCONTACT hContact = this->GetContactBySid(sid); +// ::mir_free(sid); +// +// SEObject *contactObj = contact.fetch(); +// +// if (hContact) +// { +// switch(prop) +// { +// case Contact::P_AUTHREQ_TIMESTAMP: +// { +// uint newTS = 0; +// contact->GetPropAuthreqTimestamp(newTS); +// DWORD oldTS = this->getDword(hContact, "AuthTS", 0); +// if (newTS > oldTS) +// this->RaiseAuthRequestEvent(newTS, contact); +// } +// break; +// +// case Contact::P_AUTHREQUEST_COUNT: +// // todo: all authrequests after first should be catch here +// this->UpdateContactAuthState(hContact, contact); +// break; +// +// case Contact::P_AVAILABILITY: +// this->UpdateContactStatus(hContact, contact); +// this->UpdateChatUserStatus(contact); +// break; +// +// //case CContact::P_AVATAR_IMAGE: +// case Contact::P_AVATAR_TIMESTAMP: +// this->UpdateProfileAvatar(contactObj, hContact); +// break; +// +// //case CContact::P_MOOD_TEXT: +// case Contact::P_MOOD_TIMESTAMP: +// this->UpdateProfileStatusMessage(contactObj, hContact); +// break; +// +// case Contact::P_FULLNAME: +// this->UpdateChatUserNick(contact); +// break; +// +// case Contact::P_PROFILE_TIMESTAMP: +// this->UpdateProfile(contactObj, hContact); +// break; +// } +// } +//} +// +//void CSkypeProto::OnContactListChanged(const ContactRef &contact) +//{ +// bool result; +// +// contact->IsMemberOfHardwiredGroup(CContactGroup::ALL_BUDDIES, result); +// if (result) +// { +// if ( !this->contactList.contains(contact)) +// { +// CContact::Ref newContact(contact); +// this->contactList.append(newContact); +// newContact.fetch(); +// } +// } +// +// contact->IsMemberOfHardwiredGroup(CContactGroup::CONTACTS_WAITING_MY_AUTHORIZATION, result); +// if (result) +// { +// SEString data; +// +// uint newTS = 0; +// contact->GetPropAuthreqTimestamp(newTS); +// +// this->RaiseAuthRequestEvent(newTS, contact); +// } +//} +// +//bool CSkypeProto::IsProtoContact(MCONTACT hContact) +//{ +// return ::lstrcmpiA(::GetContactProto(hContact), this->m_szModuleName) == 0; +//} +// +//MCONTACT CSkypeProto::GetContactBySid(const wchar_t *sid) +//{ +// MCONTACT hContact = NULL; +// +// ::EnterCriticalSection(&this->contact_search_lock); +// +// for (hContact = ::db_find_first(this->m_szModuleName); hContact; hContact = ::db_find_next(hContact, this->m_szModuleName)) +// { +// ptrW contactSid(::db_get_wsa(hContact, this->m_szModuleName, SKYPE_SETTINGS_SID)); +// if (::lstrcmpi(contactSid, sid) == 0) +// break; +// } +// +// ::LeaveCriticalSection(&this->contact_search_lock); +// +// return hContact; +//} +// +//MCONTACT CSkypeProto::GetContactFromAuthEvent(HANDLE hEvent) +//{ +// // db_event_getContact +// DWORD body[3]; +// DBEVENTINFO dbei = { sizeof(DBEVENTINFO) }; +// dbei.cbBlob = sizeof(DWORD) * 2; +// dbei.pBlob = (PBYTE)&body; +// +// if (::db_event_get(hEvent, &dbei)) +// return INVALID_CONTACT_ID; +// +// if (dbei.eventType != EVENTTYPE_AUTHREQUEST) +// return INVALID_CONTACT_ID; +// +// if (strcmp(dbei.szModule, this->m_szModuleName) != 0) +// return INVALID_CONTACT_ID; +// +// return ::DbGetAuthEventContact(&dbei); +//} +// +// +//void __cdecl CSkypeProto::LoadContactList(void* data) +//{ +// this->debugLogW(L"Updating contacts list"); +// +// bool isFirstLoad = data != NULL; +// +// this->GetHardwiredContactGroup(CContactGroup::ALL_BUDDIES, this->commonList); +// this->commonList.fetch(); +// +// this->commonList->GetContacts(this->contactList); +// fetch(this->contactList); +// for (uint i = 0; i < this->contactList.size(); i++) +// { +// CContact::Ref contact = this->contactList[i]; +// +// MCONTACT hContact = this->AddContact(contact); +// +// if ( !isFirstLoad) +// { +// // todo: move to AddContact? +// this->UpdateContactAuthState(hContact, contact); +// this->UpdateContactStatus(hContact, contact); +// +// ptrW nick( ::db_get_wsa(hContact, "CList", "MyHandle")); +// if ( !nick || !::wcslen(nick)) +// { +// nick = ::mir_utf8decodeW(contact->GetNick()); +// ::db_set_ws(hContact, "CList", "MyHandle", nick); +// } +// +// this->UpdateProfile(contact.fetch(), hContact); +// } +// } +//} +// +//void __cdecl CSkypeProto::LoadAuthWaitList(void*) +//{ +// CContact::Refs authContacts; +// this->GetHardwiredContactGroup(CContactGroup::CONTACTS_WAITING_MY_AUTHORIZATION, this->authWaitList); +// this->authWaitList.fetch(); +// +// this->authWaitList->GetContacts(authContacts); +// for (uint i = 0; i < authContacts.size(); i++) +// { +// CContact::Ref contact = authContacts[i]; +// +// uint newTS = 0; +// contact->GetPropAuthreqTimestamp(newTS); +// +// this->RaiseAuthRequestEvent(newTS, contact); +// } +//} +// +//bool CSkypeProto::IsContactOnline(MCONTACT hContact) +//{ +// return this->getWord(hContact, SKYPE_SETTINGS_STATUS, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE; +//} +// +//void CSkypeProto::SetAllContactStatus(int status) +//{ +// ::EnterCriticalSection(&this->contact_search_lock); +// +// for (MCONTACT hContact = ::db_find_first(this->m_szModuleName); hContact; hContact = ::db_find_next(hContact, this->m_szModuleName)) +// { +// if (this->getByte(hContact, "IsSkypeOut", 0) != 0) +// continue; +// if (this->isChatRoom(hContact)) +// continue; +// if (this->IsContactOnline(hContact)) +// ::db_set_w(hContact, this->m_szModuleName, SKYPE_SETTINGS_STATUS, status); +// } +// +// ::LeaveCriticalSection(&this->contact_search_lock); +//} +// +//void CSkypeProto::OnSearchCompleted(HANDLE hSearch) +//{ +// this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_SUCCESS, hSearch, 0); +//} +// +//void CSkypeProto::OnContactFinded(CContact::Ref contact, HANDLE hSearch) +//{ +// PROTOSEARCHRESULT psr = {0}; +// psr.cbSize = sizeof(psr); +// psr.flags = PSR_TCHAR; +// +// SEString data; +// contact->GetPropSkypename(data); +// psr.id = ::mir_utf8decodeW(data); +// contact->GetPropDisplayname(data); +// psr.nick = ::mir_utf8decodeW(data); +// +// SEString firstName, lastName; +// contact->GetFullname(firstName, lastName); +// psr.firstName = ::mir_utf8decodeW(firstName); +// psr.lastName = ::mir_utf8decodeW(lastName); +// +// { +// contact->GetPropEmails(data); +// mir_ptr emails( ::mir_utf8decodeW(data)); +// +// wchar_t* main = ::wcstok(emails, L" "); +// if (main != NULL) +// { +// psr.email = main; +// } +// } +// +// this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_DATA, hSearch, (LPARAM)&psr); +//} +// +//void __cdecl CSkypeProto::SearchBySidAsync(void* arg) +//{ +// mir_ptr sid((wchar_t*)arg); +// +// MCONTACT hContact = this->GetContactBySid(sid); +// if (hContact) +// { +// this->ShowNotification(TranslateT("Contact already in your contact list"), 0, hContact); +// this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)SKYPE_SEARCH_BYSID, 0); +// return; +// } +// +// CContactSearch::Ref search; +// this->CreateIdentitySearch(::mir_u2a(sid), search); +// search.fetch(); +// search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYSID); +// +// bool valid; +// if (!search->IsValid(valid) || !valid || !search->Submit()) +// return; +// +// search->BlockWhileSearch(); +// search->Release(); +//} +// +//void __cdecl CSkypeProto::SearchByEmailAsync(void* arg) +//{ +// mir_ptr email((wchar_t *)arg); +// +// CContactSearch::Ref search; +// this->CreateContactSearch(search); +// search.fetch(); +// search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYEMAIL); +// +// bool valid; +// if (!search->AddEmailTerm(::mir_u2a(email), valid) || !valid || !search->Submit()) +// return; +// +// search->BlockWhileSearch(); +// search->Release(); +//} +// +//void __cdecl CSkypeProto::SearchByNamesAsync(void* arg) +//{ +// //todo: write me +// PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT *)arg; +// +// std::string nick = ::mir_utf8encodeW(psr->nick); +// std::string fName = ::mir_utf8encodeW(psr->firstName); +// std::string lName = " "; lName += ::mir_utf8encodeW(psr->lastName); +// +// CContactSearch::Ref search; +// this->CreateContactSearch(search); +// search.fetch(); +// search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYNAMES); +// +// bool valid; +// if (nick.length() != 0) +// { +// search->AddStrTerm( +// Contact::P_FULLNAME, +// CContactSearch::CONTAINS_WORD_PREFIXES, +// nick.c_str(), +// valid, +// true); +// } +// if (fName.length() != 0) +// { +// search->AddOr(); +// search->AddStrTerm( +// Contact::P_FULLNAME, +// CContactSearch::CONTAINS_WORD_PREFIXES, +// fName.c_str(), +// valid, +// true); +// } +// if (lName.length() != 0) +// { +// search->AddOr(); +// search->AddStrTerm( +// Contact::P_FULLNAME, +// CContactSearch::CONTAINS_WORD_PREFIXES, +// lName.c_str(), +// valid, +// true); +// } +// +// if (!search->Submit()) +// return; +// +// search->BlockWhileSearch(); +// search->Release(); +//} +// +//void CSkypeProto::OnContactsReceived(const ConversationRef &conversation, const MessageRef &message) +//{ +// CContact::Refs contacts; +// message->GetContacts(contacts); +// +// uint timestamp; +// message->GetPropTimestamp(timestamp); +// +// CMessage::TYPE messageType; +// message->GetPropType(messageType); +// +// SEString data; +// message->GetPropAuthor(data); +// +// CContact::Ref author; +// this->GetContact(data, author); +// +// MCONTACT hContact = this->AddContact(author); +// +// SEBinary guid; +// message->GetPropGuid(guid); +// ReadMessageParam param = { guid, messageType }; +// +// PROTORECVEVENT pre = { 0 }; +// pre.flags = PREF_UTF; +// pre.lParam = (LPARAM)¶m; +// pre.timestamp = timestamp; +// +// int msgSize = 1; +// pre.szMessage = (char *)::mir_alloc(msgSize); +// pre.szMessage[0] = 0; +// +// int len = 0; +// char* pCur = &pre.szMessage[0]; +// +// for (size_t i = 0; i < contacts.size(); i ++) +// { +// contacts[i]->GetIdentity(data); +// if ( ::lstrcmpi(mir_ptr(::mir_utf8decodeW(data)), this->login) != 0) +// this->AddContact(contacts[i]); +// } +// +// char *text = ::mir_utf8encode(::Translate("Contacts received")); +// +// this->AddDBEvent( +// hContact, +// SKYPE_DB_EVENT_TYPE_CONTACTS, +// timestamp, +// PREF_UTF, +// (DWORD)::strlen(text) + 1, +// (PBYTE)text); +//} +// +//void CSkypeProto::OnContactsSent(const ConversationRef &conversation, const MessageRef &message) +//{ +// SEString data; +// +// CMessage::TYPE messageType; +// message->GetPropType(messageType); +// +// uint timestamp; +// message->GetPropTimestamp(timestamp); +// +// CMessage::SENDING_STATUS status; +// message->GetPropSendingStatus(status); +// +// CParticipant::Refs participants; +// conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); +// participants[0]->GetPropIdentity(data); +// +// CContact::Ref receiver; +// this->GetContact(data, receiver); +// +// MCONTACT hContact = this->AddContact(receiver); +// this->SendBroadcast( +// hContact, +// ACKTYPE_CONTACTS, +// status == CMessage::FAILED_TO_SEND ? ACKRESULT_FAILED : ACKRESULT_SUCCESS, +// (HANDLE)message->getOID(), 0); +//} +// +//void CSkypeProto::OnContactsEvent(const ConversationRef &conversation, const MessageRef &message) +//{ +// SEString author; +// message->GetPropAuthor(author); +// +// if (::wcsicmp(mir_ptr(::mir_utf8decodeW(author)), this->login) == 0) +// this->OnContactsSent(conversation, message); +// else +// this->OnContactsReceived(conversation, message); +//} \ No newline at end of file diff --git a/protocols/Steam/src/steam_dialogs.cpp b/protocols/Steam/src/steam_dialogs.cpp index 5c2ad45743..a0f79d3744 100644 --- a/protocols/Steam/src/steam_dialogs.cpp +++ b/protocols/Steam/src/steam_dialogs.cpp @@ -1,4 +1,4 @@ -#include "steam.h" +#include "common.h" //#include //#pragma comment(lib, "GdiPlus.lib") @@ -192,8 +192,8 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP proto = (CSteamProto*)lParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); - ptrA username(proto->getStringA("Username")); - SetDlgItemTextA(hwnd, IDC_USERNAME, username); + ptrW username(proto->getWStringA("Username")); + SetDlgItemText(hwnd, IDC_USERNAME, username); ptrA password(proto->getStringA("Password")); SetDlgItemTextA(hwnd, IDC_PASSWORD, password); @@ -251,15 +251,15 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP case WM_NOTIFY: if (reinterpret_cast(lParam)->code == PSN_APPLY/* && !proto->IsOnline()*/) { - char username[128]; - GetDlgItemTextA(hwnd, IDC_SL, username, SIZEOF(username)); - proto->setString("Username", username); + wchar_t username[128]; + GetDlgItemText(hwnd, IDC_USERNAME, username, SIZEOF(username)); + proto->setWString("Username", username); /*mir_free(proto->login); proto->login = ::mir_wstrdup(sid);*/ char password[128]; - GetDlgItemTextA(hwnd, IDC_PW, password, SIZEOF(password)); - db_set_s(NULL, proto->m_szModuleName, "Password", password); + GetDlgItemTextA(hwnd, IDC_PASSWORD, password, SIZEOF(password)); + proto->setString("Password", password); /*wchar_t tstr[128]; GetDlgItemText(hwnd, IDC_GROUP, tstr, SIZEOF(tstr)); diff --git a/protocols/Steam/src/steam_events.cpp b/protocols/Steam/src/steam_events.cpp index dd78bd2acd..0099f43456 100644 --- a/protocols/Steam/src/steam_events.cpp +++ b/protocols/Steam/src/steam_events.cpp @@ -1,4 +1,4 @@ -#include "steam.h" +#include "common.h" int CSteamProto::OnModulesLoaded(WPARAM, LPARAM) { diff --git a/protocols/Steam/src/steam_instances.cpp b/protocols/Steam/src/steam_instances.cpp new file mode 100644 index 0000000000..82b62f9654 --- /dev/null +++ b/protocols/Steam/src/steam_instances.cpp @@ -0,0 +1,45 @@ +#include "common.h" + +int CSteamProto::CompareProtos(const CSteamProto *p1, const CSteamProto *p2) +{ + return lstrcmp(p1->m_tszUserName, p2->m_tszUserName); +} + +LIST CSteamProto::InstanceList(1, CSteamProto::CompareProtos); + +CSteamProto* CSteamProto::InitProtoInstance(const char* protoName, const wchar_t* userName) +{ + CSteamProto *ppro = new CSteamProto(protoName, userName); + InstanceList.insert(ppro); + + return ppro; +} + +int CSteamProto::UninitProtoInstance(CSteamProto* ppro) +{ + InstanceList.remove(ppro); + delete ppro; + + return 0; +} + +void CSteamProto::UninitProtoInstances() +{ + for (int i = InstanceList.getCount(); i > 0; i--) + UninitProtoInstance(InstanceList[i]); + InstanceList.destroy(); +} + +CSteamProto* CSteamProto::GetContactProtoInstance(MCONTACT hContact) +{ + char *proto = (char *)::CallService(MS_PROTO_GETCONTACTBASEPROTO, hContact, 0); + + if (proto == NULL) + return NULL; + + for (int i = 0; i < InstanceList.getCount(); i++) + if (!strcmp(proto, InstanceList[i]->m_szModuleName)) + return InstanceList[i]; + + return NULL; +} \ No newline at end of file diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp index acaacde37e..ad87d64f29 100644 --- a/protocols/Steam/src/steam_proto.cpp +++ b/protocols/Steam/src/steam_proto.cpp @@ -1,13 +1,16 @@ -#include "steam.h" +#include "common.h" CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) : PROTO(protoName, userName) { CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit); + + InitializeCriticalSection(&this->contact_search_lock); } CSteamProto::~CSteamProto() { + DeleteCriticalSection(&this->contact_search_lock); } MCONTACT __cdecl CSteamProto::AddToList(int flags, PROTOSEARCHRESULT* psr) @@ -69,9 +72,9 @@ DWORD_PTR __cdecl CSteamProto:: GetCaps(int type, MCONTACT hContact) case PFLAGNUM_2: return PF2_ONLINE; case PFLAG_UNIQUEIDTEXT: - return (DWORD_PTR)::Translate("Username"); + return (DWORD_PTR)Translate("SteamID"); case PFLAG_UNIQUEIDSETTING: - return (DWORD_PTR)"Username"; + return (DWORD_PTR)"SteamID"; default: return 0; } @@ -134,170 +137,6 @@ int __cdecl CSteamProto::SendUrl(MCONTACT hContact, int flags, const char *url) int __cdecl CSteamProto::SetApparentMode(MCONTACT hContact, int mode) { return 0; } -NETLIBHTTPREQUEST *CSteamProto::LoginRequest(const char *username, const char *password, const char *timestamp, const char *captchagid, const char *captcha_text, const char *emailauth, const char *emailsteamid) -{ - HttpRequest request = HttpRequest(m_hNetlibUser, REQUEST_POST, "https://steamcommunity.com/login/dologin/"); - request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); - request.AddHeader("Accept-Encoding", "deflate, gzip"); - - CMStringA param; - param.AppendFormat("username=%s", mir_urlEncode(username)); - param.AppendFormat("&password=%s", mir_urlEncode(password)); - param.AppendFormat("&captchagid=%s", captchagid); - param.AppendFormat("&captcha_text=%s", mir_urlEncode(captcha_text)); - param.AppendFormat("&emailauth=%s", mir_urlEncode(emailauth)); - param.AppendFormat("&emailsteamid=%s", emailsteamid); - param.AppendFormat("&rsatimestamp=%s", timestamp); - - request.SetData(param.GetBuffer(), param.GetLength()); - - return request.Send(); -} - -#include -#include -#include -#include -#include -#include - -bool CSteamProto::Login() -{ - ptrA username(getStringA("Username")); - - HttpRequest request(m_hNetlibUser, REQUEST_GET, "https://steamcommunity.com/login/getrsakey"); - request.AddParameter("username", username); - - mir_ptr response(request.Send()); - - if (!response || response->resultCode != HTTP_STATUS_OK) - return false; - - JSONNODE *root = json_parse(response->pData), *node; - if (!root) - return false; - - node = json_get(root, "success"); - if (!json_as_bool(node)) - return false; - - node = json_get(root, "timestamp"); - ptrA timestamp = ptrA(mir_t2a(json_as_string(node))); - - node = json_get(root, "publickey_mod"); - const char *mod = mir_t2a(json_as_string(node)); - - node = json_get(root, "publickey_exp"); - const char *exp = mir_t2a(json_as_string(node)); - - const char *password = getStringA("Password"); - - BIGNUM *modulus = BN_new(); - if (!BN_hex2bn(&modulus, mod)) - return false; - - BIGNUM *exponent = BN_new(); - if (!BN_hex2bn(&exponent, exp)) - return false; - - RSA *rsa = RSA_new(); - rsa->n = modulus; - rsa->e = exponent; - - int size = RSA_size(rsa); - BYTE *ePassword = (BYTE*)mir_calloc(size); - if (RSA_public_encrypt((int)strlen(password), (const unsigned char*)password, ePassword, rsa, RSA_PKCS1_PADDING) < 0) - return false; - - char *sPassword = mir_base64_encode(ePassword, size); - - bool captcha_needed, emailauth_needed; - CMStringA captchagid("-1"), captcha_text, emailauth, emailsteamid; - do - { - response = Authorize(username, sPassword, timestamp, captchagid.GetBuffer(), captcha_text.GetBuffer(), emailauth.GetBuffer(), emailsteamid.GetBuffer()); - if (!response || response->resultCode != HTTP_STATUS_OK) - return false; - - root = json_parse(response->pData); - - node = json_get(root, "emailauth_needed"); - emailauth_needed = json_as_bool(node); - if (emailauth_needed) - { - GuardParam guard; - - node = json_get(root, "emailsteamid"); - emailsteamid = ptrA(mir_t2a(json_as_string(node))); - - node = json_get(root, "emaildomain"); - strcpy(guard.domain, mir_u2a(json_as_string(node))); - - if (DialogBoxParam( - g_hInstance, - MAKEINTRESOURCE(IDD_GUARD), - NULL, - CSteamProto::GuardProc, - (LPARAM)&guard) != 1) - return false; - - emailauth = guard.code; - } - - node = json_get(root, "captcha_needed"); - captcha_needed = json_as_bool(node); - if (captcha_needed) - { - node = json_get(root, "captcha_gid"); - captchagid = ptrA(mir_t2a(json_as_string(node))); - - CMStringA url = CMStringA("https://steamcommunity.com/public/captcha.php?gid=") + captchagid; - CallService(MS_UTILS_OPENURL, 0, (LPARAM)url.GetBuffer()); - - //request = HttpRequest(m_hNetlibUser, REQUEST_GET, "https://steamcommunity.com/public/captcha.php?gid="); - //request.AddUrlPart(gid); - - //response = request.Send(); - - //if (!response || response->resultCode != HTTP_STATUS_OK) - // return false; - - CaptchaParam captcha; - captcha.size = response->dataLength; - captcha.data = (BYTE*)mir_alloc(response->dataLength); - memcpy(captcha.data, response->pData, captcha.size); - - if (DialogBoxParam( - g_hInstance, - MAKEINTRESOURCE(IDD_CAPTCHA), - NULL, - CSteamProto::CaptchaProc, - (LPARAM)&captcha) != 1) - return false; - - captcha_text = captcha.text; - } - - node = json_get(root, "success"); - if (!json_as_bool(node) && !emailauth_needed && !captcha_needed) - return false; - - } while (emailauth_needed || captcha_needed); - - node = json_get(root, "success"); - if (!json_as_bool(node)) - return false; - - // {"success":true, "login_complete" : true, "transfer_url" : "https:\/\/store.steampowered.com\/\/login\/transfer", "transfer_parameters" : {"steamid":"*", "token" : "*", "remember_login" : false, "webcookie" : "*"}} - - return true; -} - -bool CSteamProto::Logout() -{ - return true; -} - int CSteamProto::SetStatus(int new_status) { if (new_status == m_iDesiredStatus) @@ -308,9 +147,9 @@ int CSteamProto::SetStatus(int new_status) if (new_status == ID_STATUS_OFFLINE) { - Logout(); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + m_bTerminated = true; + m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); if (!Miranda_Terminated()) @@ -325,9 +164,16 @@ int CSteamProto::SetStatus(int new_status) { if (old_status == ID_STATUS_OFFLINE/* && !this->IsOnline()*/) { - this->m_iStatus = ID_STATUS_CONNECTING; - /*if (!Login()) - return 0;*/ + UINT64 id = 76561197960435530; + DWORD in_db = id; + id = in_db; + + m_iStatus = ID_STATUS_CONNECTING; + ForkThread(&CSteamProto::LogInThread, NULL); + + //ptrA steamId(getStringA("SteamID")); + //Steam::FriendList(m_hNetlibUser/*, token*/) + // .LoadAsync(steamId, CallbackConverter, this); } else { diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h index 623dc4296c..3a742a66b3 100644 --- a/protocols/Steam/src/steam_proto.h +++ b/protocols/Steam/src/steam_proto.h @@ -1,8 +1,6 @@ #ifndef _STEAM_PROTO_H_ #define _STEAM_PROTO_H_ -#include "http_request.h" - struct CaptchaParam { BYTE *data; @@ -12,10 +10,19 @@ struct CaptchaParam struct GuardParam { - char domain[32]; + wchar_t emailDomain[32]; char code[10]; }; +template +void CallbackConverter(void *owner, void *arg) +{ + T *typedArg = (T*)arg; + CSteamProto *proto = (CSteamProto*)owner; + if (owner != NULL) + (proto->*Callback)(typedArg); +} + class CSteamProto : public PROTO { public: @@ -67,24 +74,34 @@ public: virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam ); - // accounts - static CSteamProto* InitAccount(const char* protoName, const wchar_t* userName); - static int UninitAccount(CSteamProto* ppro); + // instances + static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName); + static int UninitProtoInstance(CSteamProto* ppro); - static CSteamProto* GetContactAccount(MCONTACT hContact); - static void UninitAccounts(); + static CSteamProto* GetContactProtoInstance(MCONTACT hContact); + static void UninitProtoInstances(); protected: + bool m_bTerminated; + HANDLE m_hPollingThread; + CRITICAL_SECTION contact_search_lock; - NETLIBHTTPREQUEST *LoginRequest(const char *username, const char *password, const char *timestamp, const char *captchagid, const char *captcha_text, const char *emailauth, const char *emailsteamid); - - bool Login(); - bool Logout(); - - // accounts + // instances static LIST InstanceList; static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2); + // pooling thread + int PollStatus(); + void __cdecl PollingThread(void*); + + // account + void __cdecl LogInThread(void*); + + // contacts + MCONTACT FindContact(const char *steamId); + MCONTACT AddContact(const SteamWebApi::FriendApi::Friend &contact); + //void OnContactListLoadedAsync(Steam::FriendList::Result *result); + //events int OnModulesLoaded(WPARAM, LPARAM); int OnPreShutdown(WPARAM, LPARAM); diff --git a/protocols/Steam/src/steam_thread.cpp b/protocols/Steam/src/steam_thread.cpp new file mode 100644 index 0000000000..04b631a41c --- /dev/null +++ b/protocols/Steam/src/steam_thread.cpp @@ -0,0 +1,20 @@ +#include "common.h" + +int CSteamProto::PollStatus() +{ + Sleep(2000); + + return 0; +} + +void CSteamProto::PollingThread(void*) +{ + debugLogA("CSteamProto::PollingThread: entering"); + + while (!m_bTerminated) + if (PollStatus() == -1) + break; + + m_hPollingThread = NULL; + debugLogA("CSteamProto::PollingThread: leaving"); +} \ No newline at end of file -- cgit v1.2.3