From 5d2487dc97a63b0545b2d7d56405e7417fa2dd75 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Wed, 9 Apr 2014 12:06:39 +0000 Subject: Steam: - add searching by name - added contact info updating - small improvements git-svn-id: http://svn.miranda-ng.org/main/trunk@8901 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Steam/Steam_10.vcxproj | 1 + protocols/Steam/Steam_10.vcxproj.filters | 3 + protocols/Steam/Steam_12.vcxproj | 1 + protocols/Steam/Steam_12.vcxproj.filters | 3 + protocols/Steam/src/Steam/authorization.h | 20 ++-- protocols/Steam/src/Steam/friend.h | 58 ++++++---- protocols/Steam/src/Steam/friend_list.h | 5 +- protocols/Steam/src/Steam/login.h | 11 +- protocols/Steam/src/Steam/message.h | 15 ++- protocols/Steam/src/Steam/poll.h | 11 +- protocols/Steam/src/Steam/rsa_key.h | 23 +--- protocols/Steam/src/Steam/search.h | 36 ++++-- protocols/Steam/src/Steam/steam.h | 7 +- protocols/Steam/src/http_request.h | 54 ++------- protocols/Steam/src/steam_account.cpp | 182 +++++------------------------- protocols/Steam/src/steam_contacts.cpp | 179 +++++++++++++++++++++++++---- protocols/Steam/src/steam_dialogs.cpp | 26 +++-- protocols/Steam/src/steam_proto.cpp | 25 +++- protocols/Steam/src/steam_proto.h | 26 ++++- protocols/Steam/src/steam_thread.cpp | 28 ++++- protocols/Steam/src/steam_utils.cpp | 134 ++++++++++++++++++++++ 21 files changed, 526 insertions(+), 322 deletions(-) create mode 100644 protocols/Steam/src/steam_utils.cpp diff --git a/protocols/Steam/Steam_10.vcxproj b/protocols/Steam/Steam_10.vcxproj index 3660f2db5c..62342a80da 100644 --- a/protocols/Steam/Steam_10.vcxproj +++ b/protocols/Steam/Steam_10.vcxproj @@ -215,6 +215,7 @@ Create + diff --git a/protocols/Steam/Steam_10.vcxproj.filters b/protocols/Steam/Steam_10.vcxproj.filters index 4513b5e30e..4303fa4594 100644 --- a/protocols/Steam/Steam_10.vcxproj.filters +++ b/protocols/Steam/Steam_10.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + diff --git a/protocols/Steam/Steam_12.vcxproj b/protocols/Steam/Steam_12.vcxproj index c4cbfb26de..4e9d7a373b 100644 --- a/protocols/Steam/Steam_12.vcxproj +++ b/protocols/Steam/Steam_12.vcxproj @@ -218,6 +218,7 @@ Create + diff --git a/protocols/Steam/Steam_12.vcxproj.filters b/protocols/Steam/Steam_12.vcxproj.filters index 5c30306822..04374351bd 100644 --- a/protocols/Steam/Steam_12.vcxproj.filters +++ b/protocols/Steam/Steam_12.vcxproj.filters @@ -45,6 +45,9 @@ Source Files + + Source Files + diff --git a/protocols/Steam/src/Steam/authorization.h b/protocols/Steam/src/Steam/authorization.h index f7fa0444ee..e9b1733107 100644 --- a/protocols/Steam/src/Steam/authorization.h +++ b/protocols/Steam/src/Steam/authorization.h @@ -77,14 +77,17 @@ namespace SteamWebApi data.AppendFormat("&oauth_scope=%s", "read_profile write_profile read_client write_client"); data.Append("&oauth_client_id=DE45CD61"); - HttpRequest request(hConnection, REQUEST_POST, STEAM_COMMUNITY_URL "/mobilelogin/dologin"); + HttpRequest request(hConnection, REQUEST_POST, STEAM_COM_URL "/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) + if (!response) + return; + + if ((authResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; - + JSONNODE *root = json_parse(response->pData), *node; node = json_get(root, "success"); @@ -123,10 +126,7 @@ namespace SteamWebApi 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); + root = json_parse(ptrA(mir_u2a(json_as_string(node)))); node = json_get(root, "steamid"); authResult->steamid = ptrA(mir_u2a(json_as_string(node))); @@ -134,8 +134,8 @@ namespace SteamWebApi node = json_get(root, "oauth_token"); authResult->token = ptrA(mir_u2a(json_as_string(node))); - node = json_get(root, "webcookie"); - authResult->cookie = ptrA(mir_u2a(json_as_string(node))); + /*node = json_get(root, "webcookie"); + authResult->cookie = ptrA(mir_u2a(json_as_string(node)));*/ authResult->success = true; authResult->captcha_needed = false; diff --git a/protocols/Steam/src/Steam/friend.h b/protocols/Steam/src/Steam/friend.h index 2c89dd718a..c01226e823 100644 --- a/protocols/Steam/src/Steam/friend.h +++ b/protocols/Steam/src/Steam/friend.h @@ -6,7 +6,7 @@ namespace SteamWebApi class FriendApi : public BaseApi { public: - struct Friend : public Result + struct Summary : public Result { friend FriendApi; @@ -36,18 +36,31 @@ namespace SteamWebApi const DWORD GetLastEvent() const { return lastEvent; } }; - static void LoadSummaries(HANDLE hConnection, const char *token, const char *steamId, Friend *result) + struct Summaries : public Result { - result->success = false; + friend FriendApi; + + private: + std::vector items; - HttpRequest *request = new HttpRequest(hConnection, REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001"); - request->AddParameter("access_token", token); - request->AddParameter("steamids", steamId); + public: + int GetItemCount() const { return items.size(); } + const Summary *GetAt(int idx) const { return items.at(idx); } + }; - mir_ptr response(request->Send()); - delete request; + static void LoadSummaries(HANDLE hConnection, const char *token, const char *steamIds, Summaries *summaries) + { + summaries->success = false; - if (!response || response->resultCode != HTTP_STATUS_OK) + HttpRequest request(hConnection, REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001"); + request.AddParameter("access_token", token); + request.AddParameter("steamids", steamIds); + + mir_ptr response(request.Send()); + if (!response) + return; + + if ((summaries->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; JSONNODE *root = json_parse(response->pData), *node, *child; @@ -62,43 +75,44 @@ namespace SteamWebApi if (child == NULL) break; + Summary *item = new Summary(); + node = json_get(child, "steamid"); - ptrA cSteamId(ptrA(mir_u2a(json_as_string(node)))); - if (lstrcmpA(steamId, cSteamId)) - return; - result->steamId = steamId; + item->steamId = ptrA(mir_u2a(json_as_string(node))); node = json_get(child, "personaname"); - result->nickname = json_as_string(node); + item->nickname = json_as_string(node); node = json_get(child, "realname"); if (node != NULL) - result->realname = json_as_string(node); + item->realname = json_as_string(node); node = json_get(child, "loccountrycode"); if (node != NULL) - result->countryCode = ptrA(mir_u2a(json_as_string(node))); + item->countryCode = ptrA(mir_u2a(json_as_string(node))); node = json_get(child, "personastate"); - result->state = json_as_int(node); + item->state = json_as_int(node); node = json_get(child, "profileurl"); - result->homepage = ptrA(mir_u2a(json_as_string(node))); + item->homepage = ptrA(mir_u2a(json_as_string(node))); node = json_get(child, "timecreated"); - result->created = json_as_int(node); + item->created = json_as_int(node); node = json_get(child, "lastlogoff"); - result->lastEvent = json_as_int(node); + item->lastEvent = json_as_int(node); node = json_get(child, "avatarfull"); - result->avatarUrl = ptrA(mir_u2a(json_as_string(node))); + item->avatarUrl = ptrA(mir_u2a(json_as_string(node))); + + summaries->items.push_back(item); } } else return; - result->success = true; + summaries->success = true; } }; } diff --git a/protocols/Steam/src/Steam/friend_list.h b/protocols/Steam/src/Steam/friend_list.h index 5cd683fa9b..59df8918b0 100644 --- a/protocols/Steam/src/Steam/friend_list.h +++ b/protocols/Steam/src/Steam/friend_list.h @@ -28,7 +28,10 @@ namespace SteamWebApi request.AddParameter("steamid", steamId); mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((friendList->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; JSONNODE *root = json_parse(response->pData), *node, *child; diff --git a/protocols/Steam/src/Steam/login.h b/protocols/Steam/src/Steam/login.h index a6f743c45c..d46e0a8e52 100644 --- a/protocols/Steam/src/Steam/login.h +++ b/protocols/Steam/src/Steam/login.h @@ -28,16 +28,19 @@ namespace SteamWebApi CMStringA data; data.AppendFormat("access_token=%s", token); - data.Append("&ui_mode=web"); + //data.Append("&ui_mode=web"); 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) + if (!response) return; - + + if ((loginResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) + return; + JSONNODE *root = json_parse(response->pData), *node; node = json_get(root, "error"); diff --git a/protocols/Steam/src/Steam/message.h b/protocols/Steam/src/Steam/message.h index d5059c4833..d390049e4c 100644 --- a/protocols/Steam/src/Steam/message.h +++ b/protocols/Steam/src/Steam/message.h @@ -34,7 +34,10 @@ namespace SteamWebApi request.SetData(data.GetBuffer(), data.GetLength()); mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((sendResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; sendResult->success = true; @@ -56,7 +59,10 @@ namespace SteamWebApi request.SetData(data.GetBuffer(), data.GetLength()); mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((sendResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; JSONNODE *root = json_parse(response->pData), *node; @@ -88,7 +94,10 @@ namespace SteamWebApi request.SetData(data.GetBuffer(), data.GetLength()); mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((sendResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; sendResult->success = true; diff --git a/protocols/Steam/src/Steam/poll.h b/protocols/Steam/src/Steam/poll.h index f5b0c602ea..78d337d388 100644 --- a/protocols/Steam/src/Steam/poll.h +++ b/protocols/Steam/src/Steam/poll.h @@ -16,7 +16,7 @@ namespace SteamWebApi //POOL_TYPE_RELATIONSHIP }; - class PoolItem : public Result + class PoolItem// : public Result { friend PollApi; @@ -74,7 +74,7 @@ namespace SteamWebApi UINT32 GetMessageId() const { return messageId; } int IsNeedRelogin() const { return need_relogin; } int GetItemCount() const { return items.size(); } - const PoolItem * operator[](int idx) const { return items.at(idx); } + const PoolItem *GetAt(int idx) const { return items.at(idx); } }; static void PollStatus(HANDLE hConnection, const char *token, const char *sessionId, UINT32 messageId, PollResult *pollResult) @@ -91,10 +91,13 @@ namespace SteamWebApi HttpRequest request(hConnection, REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001"); request.AddHeader("Content-Type", "application/x-www-form-urlencoded"); request.SetData(data.GetBuffer(), data.GetLength()); - request.timeout = 90000; // may need to encrease timeout + request.SetTimeout(90000); // may need to encrease timeout mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((pollResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; JSONNODE *root = json_parse(response->pData), *node, *child; diff --git a/protocols/Steam/src/Steam/rsa_key.h b/protocols/Steam/src/Steam/rsa_key.h index a5322d3523..60efe6ee47 100644 --- a/protocols/Steam/src/Steam/rsa_key.h +++ b/protocols/Steam/src/Steam/rsa_key.h @@ -1,20 +1,6 @@ #ifndef _STEAM_CRYPTO_H_ #define _STEAM_CRYPTO_H_ - //#include - //#include - //#include - //#include - //#include - //#include - //#include - -//#include "../RSA/RSA.h"; -//#include "../RSA/Key.h"; -//#include "../RSA/BigInt.h"; -// -//#include ; - namespace SteamWebApi { class RsaKeyApi : public BaseApi @@ -42,11 +28,14 @@ namespace SteamWebApi ptrA base64Username(mir_urlEncode(ptrA(mir_utf8encodeW(username)))); - HttpRequest request(hConnection, REQUEST_GET, STEAM_COMMUNITY_URL "/mobilelogin/getrsakey"); + HttpRequest request(hConnection, REQUEST_GET, STEAM_COM_URL "/mobilelogin/getrsakey"); request.AddParameter("username", (char*)base64Username); - + mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) + return; + + if ((rsaKey->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) return; JSONNODE *root = json_parse(response->pData), *node; diff --git a/protocols/Steam/src/Steam/search.h b/protocols/Steam/src/Steam/search.h index ad4bd9c5d9..dc6f6c0487 100644 --- a/protocols/Steam/src/Steam/search.h +++ b/protocols/Steam/src/Steam/search.h @@ -7,8 +7,15 @@ namespace SteamWebApi { public: - class SearchItem : public Result + class SearchItem// : public Result { + friend SearchApi; + + private: + std::string steamId; + + public: + const char *GetSteamId() const { return steamId.c_str(); } }; class SearchResult : public Result @@ -22,7 +29,8 @@ namespace SteamWebApi public: SearchResult() : count(0) { } - int GetCount() { return count; } + int GetItemCount() { return count; } + const SearchItem *GetAt(int idx) const { return items.at(idx); } }; static void Search(HANDLE hConnection, const char *token, const char *text, SearchResult *searchResult) @@ -31,15 +39,20 @@ namespace SteamWebApi searchResult->count = 0; searchResult->items.clear(); + // todo: may need to load all results + // 15 first at now HttpRequest request(hConnection, REQUEST_GET, STEAM_API_URL "/ISteamUserOAuth/Search/v0001"); - request.AddParameter("access_token=%s", token); - request.AddParameter("&keywords=%s", text); - request.AddParameter("&offset=0&count=50&targets=users&fields=all"); - + request.AddParameter("access_token", token); + request.AddParameter("keywords", ptrA(mir_urlEncode(text))); + request.AddParameter("offset=0&count=15&targets=users&fields=all"); + mir_ptr response(request.Send()); - if (!response || response->resultCode != HTTP_STATUS_OK) + if (!response) return; - + + if ((searchResult->status = (HTTP_STATUS)response->resultCode) != HTTP_STATUS_OK) + return; + JSONNODE *root = json_parse(response->pData), *node, *child;; node = json_get(root, "success"); @@ -66,7 +79,12 @@ namespace SteamWebApi if (child == NULL) break; - SearchItem *item = NULL; + SearchItem *item = new SearchItem(); + + node = json_get(child, "steamid"); + item->steamId = ptrA(mir_u2a(json_as_string(node))); + + searchResult->items.push_back(item); } } diff --git a/protocols/Steam/src/Steam/steam.h b/protocols/Steam/src/Steam/steam.h index acdb86393d..8ff9a645d2 100644 --- a/protocols/Steam/src/Steam/steam.h +++ b/protocols/Steam/src/Steam/steam.h @@ -4,7 +4,7 @@ namespace SteamWebApi { #define STEAM_API_URL "https://api.steampowered.com" - #define STEAM_COMMUNITY_URL "https://steamcommunity.com" + #define STEAM_COM_URL "https://steamcommunity.com" struct Result { @@ -18,10 +18,13 @@ namespace SteamWebApi { protected: bool success; + HTTP_STATUS status; public: - Result() : success(false) { } + Result() : success(false), status(HTTP_STATUS_NONE) { } + bool IsSuccess() const { return success; } + HTTP_STATUS GetStatus() const { return status; } }; }; } diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h index f69b524c8a..2e3f9e17a2 100644 --- a/protocols/Steam/src/http_request.h +++ b/protocols/Steam/src/http_request.h @@ -5,7 +5,8 @@ enum HTTP_STATUS { - HTTP_STATUS_OK = 200/*, + HTTP_STATUS_NONE = 0, + HTTP_STATUS_OK = 200, HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED = 401, HTTP_STATUS_FORBIDDEN = 403, @@ -13,10 +14,10 @@ enum HTTP_STATUS HTTP_STATUS_METHOD_NOT_ALLOWED = 405, HTTP_STATUS_TOO_MANY_REQUESTS = 429, HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - HTTP_STATUS_INSUFICIENTE_STORAGE = 507*/ + HTTP_STATUS_INSUFICIENTE_STORAGE = 507 }; -class HttpRequest : public NETLIBHTTPREQUEST//, public MZeroedObject +class HttpRequest : protected NETLIBHTTPREQUEST//, public MZeroedObject { public: HttpRequest(HANDLE hNetlibUser, int request, LPCSTR url) @@ -74,48 +75,6 @@ public: memcpy(pData, data, size); } - /*void AddBasicAuthHeader(LPCSTR szLogin, LPCSTR szPassword) - { - char cPair[128]; - mir_snprintf( - cPair, - SIZEOF(cPair), - "%s:%s", - szLogin, - szPassword); - - char *ePair = (char *)mir_base64_encode((BYTE*)cPair, (UINT)strlen(cPair)); - - char value[128]; - mir_snprintf( - value, - SIZEOF(value), - "Basic %s", - ePair); - - mir_free(ePair); - - headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount+1)); - headers[headersCount].szName = mir_strdup("Authorization"); - headers[headersCount].szValue = mir_strdup(value); - headersCount++; - } - - void AddBearerAuthHeader(LPCSTR szValue) - { - char value[128]; - mir_snprintf( - value, - SIZEOF(value), - "Bearer %s", - szValue); - - headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount+1)); - headers[headersCount].szName = mir_strdup("Authorization"); - headers[headersCount].szValue = mir_strdup(value); - headersCount++; - }*/ - void AddUrlPart(LPCSTR szPart) { m_szUrl += szPart; @@ -153,6 +112,11 @@ public: m_szUrl.AppendFormat("&%s", szValue); } + void SetTimeout(int timeout) + { + timeout = timeout; + } + NETLIBHTTPREQUEST *Send() { szUrl = m_szUrl.GetBuffer(); diff --git a/protocols/Steam/src/steam_account.cpp b/protocols/Steam/src/steam_account.cpp index c0686cf7bd..812b9a75b5 100644 --- a/protocols/Steam/src/steam_account.cpp +++ b/protocols/Steam/src/steam_account.cpp @@ -1,51 +1,5 @@ #include "common.h" -WORD CSteamProto::SteamToMirandaStatus(int state) -{ - switch (state) - { - case 0: //Offline - return ID_STATUS_OFFLINE; - case 2: //Busy - return ID_STATUS_DND; - case 3: //Away - return ID_STATUS_AWAY; - /*case 4: //Snoozing - prim = PURPLE_STATUS_EXTENDED_AWAY; - break; - case 5: //Looking to trade - return "trade"; - case 6: //Looking to play - return "play";*/ - //case 1: //Online - default: - return ID_STATUS_ONLINE; - } -} - -int CSteamProto::MirandaToSteamState(int status) -{ - switch (status) - { - case ID_STATUS_OFFLINE: - return 0; //Offline - case ID_STATUS_DND: - return 2; //Busy - case ID_STATUS_AWAY: - return 3; //Away - /*case 4: //Snoozing - prim = PURPLE_STATUS_EXTENDED_AWAY; - break; - case 5: //Looking to trade - return "trade"; - case 6: //Looking to play - return "play";*/ - //case 1: //Online - default: - return ID_STATUS_ONLINE; - } -} - bool CSteamProto::IsOnline() { return m_iStatus > ID_STATUS_OFFLINE && m_hPollingThread; @@ -94,8 +48,6 @@ void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResul if (lstrlen(nickname) == 0 && username) setWString("Nick", username); - return; - // get rsa public key SteamWebApi::RsaKeyApi::RsaKey rsaKey; SteamWebApi::RsaKeyApi::GetRsaKey(m_hNetlibUser, username, &rsaKey); @@ -104,105 +56,21 @@ void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResul ptrA password(getStringA("Password")); - const char *pszModulus = rsaKey.GetModulus(); - DWORD cchModulus = strlen(pszModulus); - - // convert hex string to byte array - DWORD cbLen = 0, dwSkip = 0, dwFlags = 0; - if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, NULL, &cbLen, &dwSkip, &dwFlags)) - { - debugLogA("CSteamProto::Authorize: Cannot get size of rsa modulus in binary (%lu)", GetLastError()); - return; - } - - // Allocate a new buffer. - BYTE *pbBuffer = (BYTE*)malloc(cbLen); - if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, pbBuffer, &cbLen, &dwSkip, &dwFlags)) - { - debugLogA("CSteamProto::Authorize: Cannot convert rsa modulus to binary (%lu)", GetLastError()); - return; - } - - // reverse byte array, because of microsoft - for (int i = 0; i < cbLen / 2; ++i) - { - BYTE temp = pbBuffer[cbLen - i - 1]; - pbBuffer[cbLen - i - 1] = pbBuffer[i]; - pbBuffer[i] = temp; - } - - HCRYPTPROV hCSP = 0; - if (!CryptAcquireContext(&hCSP, NULL, NULL, PROV_RSA_AES, CRYPT_SILENT) && - !CryptAcquireContext(&hCSP, NULL, NULL, PROV_RSA_AES, CRYPT_SILENT | CRYPT_NEWKEYSET)) - { - debugLogA("CSteamProto::Authorize: Cannot create rsa context (%lu)", GetLastError()); - return; - } - - // Move the key into the key container. - DWORD cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbLen; - BYTE *pKeyBlob = (BYTE*)malloc(cbKeyBlob); - - // Fill in the data. - PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pKeyBlob; - pPublicKey->bType = PUBLICKEYBLOB; - pPublicKey->bVersion = CUR_BLOB_VERSION; // Always use this value. - pPublicKey->reserved = 0; // Must be zero. - pPublicKey->aiKeyAlg = CALG_RSA_KEYX; // RSA public-key key exchange. - - // The next block of data is the RSAPUBKEY structure. - RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pKeyBlob + sizeof(PUBLICKEYSTRUC)); - pRsaPubKey->magic = 0x31415352; // RSA1 // Use public key - pRsaPubKey->bitlen = cbLen * 8; // Number of bits in the modulus. - pRsaPubKey->pubexp = 0x10001; // "010001" // Exponent. - - // Copy the modulus into the blob. Put the modulus directly after the - // RSAPUBKEY structure in the blob. - BYTE *pKey = (BYTE*)(((BYTE *)pRsaPubKey) + sizeof(RSAPUBKEY)); - //pKeyBlob + sizeof(BLOBHEADER)+ sizeof(RSAPUBKEY); - memcpy(pKey, pbBuffer, cbLen); - - // Now import public key - HCRYPTKEY phKey = 0; - if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey)) - { - debugLogA("CSteamProto::Authorize: Cannot import rsa key to context (%lu)", GetLastError()); - return; - } - - // encrypt password + DWORD error = 0; DWORD encryptedSize = 0; - DWORD pwdLength = strlen(password); - if (!CryptEncrypt(phKey, 0, TRUE, 0, NULL, &encryptedSize, pwdLength)) + if ((error = RsaEncrypt(rsaKey, password, strlen(password), NULL, encryptedSize)) != 0) { - debugLogA("CSteamProto::Authorize: Cannot get rsa encrypt length (%lu)", GetLastError()); + debugLogA("CSteamProto::Rsa: encryption error (%lu)", error); return; } BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize); - memcpy(encryptedPassword, password, pwdLength); - if (!CryptEncrypt(phKey, 0, TRUE, 0, encryptedPassword, &pwdLength, encryptedSize)) + if ((error = RsaEncrypt(rsaKey, password, strlen(password), encryptedPassword, encryptedSize)) != 0) { - debugLogA("CSteamProto::Authorize: Cannot rsa encrypt password (%lu)", GetLastError()); + debugLogA("CSteamProto::Rsa: encryption error (%lu)", error); return; } - // reverse byte array again - for (int i = 0; i < encryptedSize / 2; ++i) - { - BYTE temp = encryptedPassword[encryptedSize - i - 1]; - encryptedPassword[encryptedSize - i - 1] = encryptedPassword[i]; - encryptedPassword[i] = temp; - } - - // save rsa encrypted password to db - db_set_blob(NULL, this->m_szModuleName, "EncryptedPassword", encryptedPassword, encryptedSize); - - CryptDestroyKey(phKey); - free(pKeyBlob); - CryptReleaseContext(hCSP, 0); - free(pbBuffer); - base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize); mir_free(encryptedPassword); @@ -245,8 +113,8 @@ void CSteamProto::LogInThread(void* param) if (this->IsOnline()) return; - CMStringA token(getStringA("TokenSecret")); - if (token.IsEmpty()) + ptrA token(getStringA("TokenSecret")); + if (!token || lstrlenA(token) == 0) { SteamWebApi::AuthorizationApi::AuthResult authResult; Authorize(&authResult); @@ -262,31 +130,40 @@ void CSteamProto::LogInThread(void* param) return; } - token = authResult.GetToken(); + token = mir_strdup(authResult.GetToken()); + setString("TokenSecret", token); - setString("Cookie", authResult.GetCookie()); + //setString("Cookie", authResult.GetCookie()); setString("SteamID", authResult.GetSteamid()); } SteamWebApi::LoginApi::LoginResult loginResult; SteamWebApi::LoginApi::Logon(m_hNetlibUser, token, &loginResult); + // if some error if (!loginResult.IsSuccess()) { - debugLogA("CSteamProto::login: Error"); + debugLogA("CSteamProto::Login: Error (%d)", loginResult.GetStatus()); + + // token has expired + if (loginResult.GetStatus() == HTTP_STATUS_UNAUTHORIZED) + { + delSetting("TokenSecret"); + delSetting("Cookie"); + } + // set status to offline m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, ID_STATUS_OFFLINE); return; } - else - { - setString("SessionID", loginResult.GetSessionId()); - setDword("MessageID", loginResult.GetMessageId()); - // set selected status - m_iStatus = m_iDesiredStatus; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iDesiredStatus); - } + + setString("SessionID", loginResult.GetSessionId()); + setDword("MessageID", loginResult.GetMessageId()); + + // set selected status + m_iStatus = m_iDesiredStatus; + ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iDesiredStatus); // get contact list SteamWebApi::FriendListApi::FriendList friendList; @@ -298,10 +175,11 @@ void CSteamProto::LogInThread(void* param) { if (!FindContact(friendList[i])) { - SteamWebApi::FriendApi::Friend rFriend; + // todo + /*SteamWebApi::FriendApi::Friend rFriend; SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, friendList[i], &rFriend); if (!rFriend.IsSuccess()) continue; - AddContact(rFriend); + AddContact(rFriend);*/ } } } diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp index 8e9aa87f9f..6038ca029c 100644 --- a/protocols/Steam/src/steam_contacts.cpp +++ b/protocols/Steam/src/steam_contacts.cpp @@ -18,6 +18,66 @@ void CSteamProto::SetAllContactsStatus(WORD status) } } +void CSteamProto::UpdateContact(MCONTACT hContact, const SteamWebApi::FriendApi::Summary *contact) +{ + if (hContact && !FindContact(contact->GetSteamId())) + return; + + // set common data + setWString(hContact, "Nick", contact->GetNickname()); + setWord(hContact, "Status", SteamToMirandaStatus(contact->GetState())); + setString(hContact, "Homepage", contact->GetHomepage()); + setDword(hContact, "LastEventDateTS", contact->GetLastEvent()); + + // set name + ptrW realname(mir_wstrdup(contact->GetRealname())); + const wchar_t *p = wcschr(realname, ' '); + if (p == NULL) + setWString(hContact, "FirstName", realname); + else + { + int length = p - (wchar_t*)realname; + realname[length] = '\0'; + setWString(hContact, "LastName", realname); + setWString(hContact, "LastName", p + 1); + } + + // set country + const char *isoCode = contact->GetCountryCode(); + if (!lstrlenA(isoCode)) + this->delSetting(hContact, "Country"); + else + { + // todo: is should be free()? + char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)isoCode, 0); + setString(hContact, "Country", country); + } +} + +void CSteamProto::UpdateContactsThread(void *arg) +{ + ptrA steamIds((char*)arg); + + ptrA token(getStringA("TokenSecret")); + + SteamWebApi::FriendApi::Summaries summarues; + SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, steamIds, &summarues); + + if (!summarues.IsSuccess()) + return; + + for (int i = 0; i < summarues.GetItemCount(); i++) + { + const SteamWebApi::FriendApi::Summary *contact = summarues.GetAt(i); + + MCONTACT hContact = this->FindContact(contact->GetSteamId()); + if (!hContact) + { + UpdateContact(hContact, contact); + } + } +} + MCONTACT CSteamProto::FindContact(const char *steamId) { MCONTACT hContact = NULL; @@ -36,20 +96,19 @@ MCONTACT CSteamProto::FindContact(const char *steamId) return hContact; } -MCONTACT CSteamProto::AddContact(const SteamWebApi::FriendApi::Friend &contact) +MCONTACT CSteamProto::AddContact(const SteamWebApi::FriendApi::Summary *contact) { - MCONTACT hContact = this->FindContact(contact.GetSteamId()); + MCONTACT hContact = this->FindContact(contact->GetSteamId()); if (!hContact) { + // create contact hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0); CallService(MS_PROTO_ADDTOCONTACT, hContact, (LPARAM)this->m_szModuleName); - setString(hContact, "SteamID", contact.GetSteamId()); - setWString(hContact, "Nick", contact.GetNickname()); - setString(hContact, "Homepage", contact.GetHomepage()); - setDword(hContact, "LastEventDateTS", contact.GetLastEvent()); - db_set_ws(hContact, "CList", "MyHandle", contact.GetNickname()); + // update info + UpdateContact(hContact, contact); + // move to default group DBVARIANT dbv; if (!getWString("DefaultGroup", &dbv)) { @@ -68,37 +127,109 @@ void CSteamProto::SearchByIdThread(void* arg) ptrA token(getStringA("TokenSecret")); - SteamWebApi::FriendApi::Friend rFriend; - SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, steamId, &rFriend); + SteamWebApi::FriendApi::Summaries summarues; + SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, steamId, &summarues); - if (!rFriend.IsSuccess()) + if (!summarues.IsSuccess()) { ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)STEAM_SEARCH_BYID, 0); return; } - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_TCHAR; + if (summarues.GetItemCount() == 0) + return; + + const SteamWebApi::FriendApi::Summary *contact = summarues.GetAt(0); - psr.id = mir_wstrdup(steamIdW); - psr.nick = mir_wstrdup(rFriend.GetNickname()); + STEAM_SEARCH_RESULT ssr = { 0 }; + ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT); + ssr.hdr.flags = PSR_TCHAR; + + ssr.hdr.id = mir_wstrdup(steamIdW); + ssr.hdr.nick = mir_wstrdup(contact->GetNickname()); - const wchar_t *realname = rFriend.GetRealname(); + const wchar_t *realname = contact->GetRealname(); const wchar_t *p = wcschr(realname, ' '); if (p == NULL) - psr.firstName = mir_wstrdup(realname); + ssr.hdr.firstName = mir_wstrdup(realname); else { int length = p - realname; - psr.firstName = (wchar_t*)mir_alloc(sizeof(wchar_t) * (length + 1)); - wmemcpy(psr.firstName, realname, length); - psr.firstName[length] = '\0'; - psr.lastName = mir_wstrdup(p + 1); + ssr.hdr.firstName = (wchar_t*)mir_alloc(sizeof(wchar_t) * (length + 1)); + wmemcpy(ssr.hdr.firstName, realname, length); + ssr.hdr.firstName[length] = '\0'; + ssr.hdr.lastName = mir_wstrdup(p + 1); } + + ssr.contact = contact; - //psr.reserved[0] = &psr; - - ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)STEAM_SEARCH_BYID, (LPARAM)&psr); + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)STEAM_SEARCH_BYID, (LPARAM)&ssr); ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)STEAM_SEARCH_BYID, 0); +} + +void CSteamProto::SearchByNameThread(void* arg) +{ + ptrW keywordsW((wchar_t*)arg); + ptrA keywords(mir_utf8encodeW(keywordsW)); + + ptrA token(getStringA("TokenSecret")); + + SteamWebApi::SearchApi::SearchResult searchResult; + SteamWebApi::SearchApi::Search(m_hNetlibUser, token, keywords, &searchResult); + + if (!searchResult.IsSuccess()) + { + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)STEAM_SEARCH_BYNAME, 0); + return; + } + + CMStringA steamIds; + for (int i = 0; i < searchResult.GetItemCount(); i++) + { + const SteamWebApi::SearchApi::SearchItem *item = searchResult.GetAt(i); + if (steamIds.IsEmpty()) + steamIds.Append(item->GetSteamId()); + else + steamIds.AppendFormat(",%s", item->GetSteamId()); + } + + SteamWebApi::FriendApi::Summaries summarues; + SteamWebApi::FriendApi::LoadSummaries(m_hNetlibUser, token, steamIds, &summarues); + + if (!summarues.IsSuccess()) + { + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)STEAM_SEARCH_BYNAME, 0); + return; + } + + for (int i = 0; i < summarues.GetItemCount(); i++) + { + const SteamWebApi::FriendApi::Summary *contact = summarues.GetAt(i); + + STEAM_SEARCH_RESULT ssr = { 0 }; + ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT); + ssr.hdr.flags = PSR_TCHAR; + + ssr.hdr.id = mir_a2u(contact->GetSteamId()); + ssr.hdr.nick = mir_wstrdup(contact->GetNickname()); + + const wchar_t *realname = contact->GetRealname(); + const wchar_t *p = wcschr(realname, ' '); + if (p == NULL) + ssr.hdr.firstName = mir_wstrdup(realname); + else + { + int length = p - realname; + ssr.hdr.firstName = (wchar_t*)mir_alloc(sizeof(wchar_t) * (length + 1)); + wmemcpy(ssr.hdr.firstName, realname, length); + ssr.hdr.firstName[length] = '\0'; + ssr.hdr.lastName = mir_wstrdup(p + 1); + } + + ssr.contact = contact; + + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)STEAM_SEARCH_BYNAME, (LPARAM)&ssr); + } + + ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)STEAM_SEARCH_BYNAME, 0); } \ No newline at end of file diff --git a/protocols/Steam/src/steam_dialogs.cpp b/protocols/Steam/src/steam_dialogs.cpp index a03114f6c8..ad836d841a 100644 --- a/protocols/Steam/src/steam_dialogs.cpp +++ b/protocols/Steam/src/steam_dialogs.cpp @@ -167,8 +167,10 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP switch(LOWORD(wParam)) { case IDC_USERNAME: + if ((HWND)lParam == GetFocus()) { - if ((HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + EnableWindow(GetDlgItem(hwnd, IDC_USERNAME), !proto->IsOnline()); + if (HIWORD(wParam) != EN_CHANGE) return 0; proto->delSetting("SteamID"); proto->delSetting("Cookies"); proto->delSetting("TokenSecret"); @@ -179,8 +181,10 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP break; case IDC_PASSWORD: + if ((HWND)lParam == GetFocus()) { - if ((HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD), !proto->IsOnline()); + if (HIWORD(wParam) != EN_CHANGE) return 0; proto->delSetting("Cookie"); proto->delSetting("TokenSecret"); char password[128]; @@ -212,17 +216,17 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP char password[128]; GetDlgItemTextA(hwnd, IDC_PASSWORD, password, SIZEOF(password)); proto->setString("Password", password); + } - wchar_t groupName[128]; - GetDlgItemText(hwnd, IDC_GROUP, groupName, SIZEOF(groupName)); - if (lstrlen(groupName) > 0) - { - proto->setWString(NULL, "DefaultGroup", groupName); - Clist_CreateGroup(0, groupName); - } - else - proto->delSetting(NULL, "DefaultGroup"); + wchar_t groupName[128]; + GetDlgItemText(hwnd, IDC_GROUP, groupName, SIZEOF(groupName)); + if (lstrlen(groupName) > 0) + { + proto->setWString(NULL, "DefaultGroup", groupName); + Clist_CreateGroup(0, groupName); } + else + proto->delSetting(NULL, "DefaultGroup"); return TRUE; } diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp index 2684818880..1a7f7f2b7b 100644 --- a/protocols/Steam/src/steam_proto.cpp +++ b/protocols/Steam/src/steam_proto.cpp @@ -27,6 +27,8 @@ CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) : sid.ptszDescription = LPGENT("Protocol icon"); sid.iDefaultIndex = -IDI_STEAM; Skin_AddIcon(&sid); + + SetAllContactsStatus(ID_STATUS_OFFLINE); } CSteamProto::~CSteamProto() @@ -36,11 +38,11 @@ CSteamProto::~CSteamProto() MCONTACT __cdecl CSteamProto::AddToList(int flags, PROTOSEARCHRESULT* psr) { - /*CContact::Ref contact; - this->GetContact((char *)mir_ptr(::mir_utf8encodeW(psr->id)), contact); - return this->AddContact(contact);*/ + if (psr->cbSize != sizeof(STEAM_SEARCH_RESULT)) + return 0; - return 0; + STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr; + return AddContact(ssr->contact); } MCONTACT __cdecl CSteamProto::AddToListByEvent(int flags, int iContact, HANDLE hDbEvent) @@ -93,7 +95,7 @@ DWORD_PTR __cdecl CSteamProto:: GetCaps(int type, MCONTACT hContact) switch(type) { case PFLAGNUM_1: - return PF1_IM | PF1_BASICSEARCH; + return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME; case PFLAGNUM_2: return PF2_ONLINE; case PFLAG_UNIQUEIDTEXT: @@ -124,7 +126,18 @@ HANDLE __cdecl CSteamProto::SearchByEmail(const TCHAR* email) HANDLE __cdecl CSteamProto::SearchByName(const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName) { - return 0; + if (!this->IsOnline()) + return 0; + + CMString keywords; + keywords.AppendFormat(L" %s", nick); + keywords.AppendFormat(L" %s", firstName); + keywords.AppendFormat(L" %s", lastName); + keywords.Trim(); + + ForkThread(&CSteamProto::SearchByNameThread, mir_wstrdup(keywords)); + + return (HANDLE)STEAM_SEARCH_BYNAME; } HWND __cdecl CSteamProto::SearchAdvanced( HWND owner ) { return 0; } diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h index 28ef2f853a..1e2bcdd6a6 100644 --- a/protocols/Steam/src/steam_proto.h +++ b/protocols/Steam/src/steam_proto.h @@ -24,6 +24,13 @@ struct SendMessageParam const char *text; }; +struct STEAM_SEARCH_RESULT +{ + PROTOSEARCHRESULT hdr; + const SteamWebApi::FriendApi::Summary *contact; +}; + + class CSteamProto : public PROTO { public: @@ -97,9 +104,6 @@ protected: void __cdecl PollingThread(void*); // account - static WORD SteamToMirandaStatus(int state); - static int MirandaToSteamState(int status); - bool IsOnline(); bool IsMe(const char *steamId); void Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResult); @@ -111,10 +115,14 @@ protected: void SetContactStatus(MCONTACT hContact, WORD status); void SetAllContactsStatus(WORD status); - MCONTACT FindContact(const char *steamId); - MCONTACT AddContact(const SteamWebApi::FriendApi::Friend &contact); + void UpdateContact(MCONTACT hContact, const SteamWebApi::FriendApi::Summary *contact); + void __cdecl UpdateContactsThread(void*); + MCONTACT FindContact(const char *steamId); + MCONTACT AddContact(const SteamWebApi::FriendApi::Summary *contact); + void __cdecl SearchByIdThread(void*); + void __cdecl SearchByNameThread(void*); // messages void __cdecl SendMessageThread(void*); @@ -126,7 +134,13 @@ protected: INT_PTR __cdecl OnAccountManagerInit(WPARAM wParam, LPARAM lParam); static int __cdecl OnOptionsInit(void *obj, WPARAM wParam, LPARAM lParam); - //options + // utils + static WORD SteamToMirandaStatus(int state); + static int MirandaToSteamState(int status); + + static int RsaEncrypt(const SteamWebApi::RsaKeyApi::RsaKey &rsaKey, const char *data, DWORD dataSize, BYTE *encrypted, DWORD &encryptedSize); + + // options 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); diff --git a/protocols/Steam/src/steam_thread.cpp b/protocols/Steam/src/steam_thread.cpp index ef6cb813b0..a4adad5ba8 100644 --- a/protocols/Steam/src/steam_thread.cpp +++ b/protocols/Steam/src/steam_thread.cpp @@ -7,9 +7,10 @@ void CSteamProto::PollStatus(const char *token, const char *sessionId, UINT32 me if (!pollResult->IsSuccess()) return; + CMStringA updatedIds; for (int i = 0; i < pollResult->GetItemCount(); i++) { - const SteamWebApi::PollApi::PoolItem *item = pollResult->operator[](i); + const SteamWebApi::PollApi::PoolItem *item = pollResult->GetAt(i); switch (item->GetType()) { case SteamWebApi::PollApi::POOL_TYPE_TYPING: @@ -83,11 +84,19 @@ void CSteamProto::PollStatus(const char *token, const char *sessionId, UINT32 me SetContactStatus(hContact, status); } + + if (updatedIds.IsEmpty()) + updatedIds.Append(steamId); + else + updatedIds.AppendFormat(",%s", steamId); } } break; } } + + if (!updatedIds.IsEmpty()) + ForkThread(&CSteamProto::UpdateContactsThread, mir_strdup(updatedIds)); } void CSteamProto::PollingThread(void*) @@ -117,15 +126,22 @@ void CSteamProto::PollingThread(void*) }*/ if (!pollResult.IsSuccess()) + { + SetStatus(ID_STATUS_OFFLINE); + + // token has expired + if (pollResult.GetStatus() == HTTP_STATUS_UNAUTHORIZED) + { + delSetting("TokenSecret"); + delSetting("Cookie"); + } + break; + } messageId = pollResult.GetMessageId(); - } - - if (pollResult.IsSuccess()) setDword("MessageID", messageId); - else - SetStatus(ID_STATUS_OFFLINE); + } m_hPollingThread = NULL; debugLogA("CSteamProto::PollingThread: leaving"); diff --git a/protocols/Steam/src/steam_utils.cpp b/protocols/Steam/src/steam_utils.cpp new file mode 100644 index 0000000000..2f2caca443 --- /dev/null +++ b/protocols/Steam/src/steam_utils.cpp @@ -0,0 +1,134 @@ +#include "common.h" + +WORD CSteamProto::SteamToMirandaStatus(int state) +{ + switch (state) + { + case 0: //Offline + return ID_STATUS_OFFLINE; + case 2: //Busy + return ID_STATUS_DND; + case 3: //Away + return ID_STATUS_AWAY; + /*case 4: //Snoozing + prim = PURPLE_STATUS_EXTENDED_AWAY; + break; + case 5: //Looking to trade + return "trade"; + case 6: //Looking to play + return "play";*/ + //case 1: //Online + default: + return ID_STATUS_ONLINE; + } +} + +int CSteamProto::MirandaToSteamState(int status) +{ + switch (status) + { + case ID_STATUS_OFFLINE: + return 0; //Offline + case ID_STATUS_DND: + return 2; //Busy + case ID_STATUS_AWAY: + return 3; //Away + /*case 4: //Snoozing + prim = PURPLE_STATUS_EXTENDED_AWAY; + break; + case 5: //Looking to trade + return "trade"; + case 6: //Looking to play + return "play";*/ + //case 1: //Online + default: + return ID_STATUS_ONLINE; + } +} + +int CSteamProto::RsaEncrypt(const SteamWebApi::RsaKeyApi::RsaKey &rsaKey, const char *data, DWORD dataSize, BYTE *encryptedData, DWORD &encryptedSize) +{ + const char *pszModulus = rsaKey.GetModulus(); + DWORD cchModulus = strlen(pszModulus); + + // convert hex string to byte array + DWORD cbLen = 0, dwSkip = 0, dwFlags = 0; + if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, NULL, &cbLen, &dwSkip, &dwFlags)) + return GetLastError(); + + // allocate a new buffer. + BYTE *pbBuffer = (BYTE*)malloc(cbLen); + if (!CryptStringToBinaryA(pszModulus, cchModulus, CRYPT_STRING_HEX, pbBuffer, &cbLen, &dwSkip, &dwFlags)) + return GetLastError(); + + // reverse byte array, because of microsoft + for (int i = 0; i < cbLen / 2; ++i) + { + BYTE temp = pbBuffer[cbLen - i - 1]; + pbBuffer[cbLen - i - 1] = pbBuffer[i]; + pbBuffer[i] = temp; + } + + HCRYPTPROV hCSP = 0; + if (!CryptAcquireContext(&hCSP, NULL, NULL, PROV_RSA_AES, CRYPT_SILENT) && + !CryptAcquireContext(&hCSP, NULL, NULL, PROV_RSA_AES, CRYPT_SILENT | CRYPT_NEWKEYSET)) + return GetLastError(); + + // Move the key into the key container. + DWORD cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + cbLen; + BYTE *pKeyBlob = (BYTE*)malloc(cbKeyBlob); + + // Fill in the data. + PUBLICKEYSTRUC *pPublicKey = (PUBLICKEYSTRUC*)pKeyBlob; + pPublicKey->bType = PUBLICKEYBLOB; + pPublicKey->bVersion = CUR_BLOB_VERSION; // Always use this value. + pPublicKey->reserved = 0; // Must be zero. + pPublicKey->aiKeyAlg = CALG_RSA_KEYX; // RSA public-key key exchange. + + // The next block of data is the RSAPUBKEY structure. + RSAPUBKEY *pRsaPubKey = (RSAPUBKEY*)(pKeyBlob + sizeof(PUBLICKEYSTRUC)); + pRsaPubKey->magic = 0x31415352; // RSA1 // Use public key + pRsaPubKey->bitlen = cbLen * 8; // Number of bits in the modulus. + pRsaPubKey->pubexp = 0x10001; // "010001" // Exponent. + + // Copy the modulus into the blob. Put the modulus directly after the + // RSAPUBKEY structure in the blob. + BYTE *pKey = (BYTE*)(((BYTE *)pRsaPubKey) + sizeof(RSAPUBKEY)); + //pKeyBlob + sizeof(BLOBHEADER)+ sizeof(RSAPUBKEY); + memcpy(pKey, pbBuffer, cbLen); + + // Now import public key + HCRYPTKEY phKey = 0; + if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey)) + return GetLastError(); + + // if data is not allocated just renurn size + if (encryptedData == NULL) + { + // get length of encrypted data + if (!CryptEncrypt(phKey, 0, TRUE, 0, NULL, &encryptedSize, dataSize)) + return GetLastError(); + return 0; + } + + // encrypt password + memcpy(encryptedData, data, dataSize); + if (!CryptEncrypt(phKey, 0, TRUE, 0, encryptedData, &dataSize, encryptedSize)) + return GetLastError(); + + // reverse byte array again + for (int i = 0; i < encryptedSize / 2; ++i) + { + BYTE temp = encryptedData[encryptedSize - i - 1]; + encryptedData[encryptedSize - i - 1] = encryptedData[i]; + encryptedData[i] = temp; + } + + free(pKeyBlob); + CryptDestroyKey(phKey); + + free(pbBuffer); + CryptReleaseContext(hCSP, 0); + + return 0; +} \ No newline at end of file -- cgit v1.2.3