summaryrefslogtreecommitdiff
path: root/protocols/Steam/src
diff options
context:
space:
mode:
authorAlexander Lantsev <aunsane@gmail.com>2014-06-03 12:39:16 +0000
committerAlexander Lantsev <aunsane@gmail.com>2014-06-03 12:39:16 +0000
commit6c0bc679241489afbe3a9ae55bd41da5ed6056b6 (patch)
tree44886b327d83b68eb03a02cf05a8cb82afeafc02 /protocols/Steam/src
parent6cca309d4028ad6d19307036444f8f6d14762c20 (diff)
Steam: work commit
- added requests queue - code refactoring Note: this commit may contain regress of functionality and bugs git-svn-id: http://svn.miranda-ng.org/main/trunk@9401 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/Steam/src')
-rw-r--r--protocols/Steam/src/Steam/authorization.h41
-rw-r--r--protocols/Steam/src/Steam/avatar.h4
-rw-r--r--protocols/Steam/src/Steam/crypto.h14
-rw-r--r--protocols/Steam/src/Steam/friend.h11
-rw-r--r--protocols/Steam/src/Steam/friend_list.h58
-rw-r--r--protocols/Steam/src/Steam/login.h26
-rw-r--r--protocols/Steam/src/Steam/message.h18
-rw-r--r--protocols/Steam/src/Steam/pending.h48
-rw-r--r--protocols/Steam/src/Steam/poll.h19
-rw-r--r--protocols/Steam/src/Steam/rsa_key.h13
-rw-r--r--protocols/Steam/src/Steam/search.h13
-rw-r--r--protocols/Steam/src/Steam/session.h19
-rw-r--r--protocols/Steam/src/Steam/steam.h102
-rw-r--r--protocols/Steam/src/steam_account.cpp202
-rw-r--r--protocols/Steam/src/steam_contacts.cpp356
-rw-r--r--protocols/Steam/src/steam_messages.cpp15
-rw-r--r--protocols/Steam/src/steam_pooling.cpp338
-rw-r--r--protocols/Steam/src/steam_proto.cpp115
-rw-r--r--protocols/Steam/src/steam_proto.h135
-rw-r--r--protocols/Steam/src/steam_queue.cpp146
-rw-r--r--protocols/Steam/src/steam_utils.cpp5
21 files changed, 1627 insertions, 71 deletions
diff --git a/protocols/Steam/src/Steam/authorization.h b/protocols/Steam/src/Steam/authorization.h
index a8911034a0..0fcc5c9923 100644
--- a/protocols/Steam/src/Steam/authorization.h
+++ b/protocols/Steam/src/Steam/authorization.h
@@ -173,6 +173,47 @@ namespace SteamWebApi
}
}
};
+
+ class AuthorizationRequest : public HttpsPostRequest
+ {
+ void InitData(const char *username, const char *password, const char *timestamp, const char *guardId = "-1", const char *guardCode = "")
+ {
+ char data[1024];
+ mir_snprintf(data, SIZEOF(data),
+ "username=%s&password=%s&emailsteamid=%s&emailauth=%s&captchagid=%s&captcha_text=%s&rsatimestamp=%s&donotcache=%ld&remember_login=true&oauth_client_id=DE45CD61&oauth_scope=read_profile write_profile read_client write_client",
+ username,
+ ptrA(mir_urlEncode(password)),
+ guardId,
+ guardCode,
+ "-1",
+ "",
+ timestamp,
+ time(NULL));
+
+ SetData(data, strlen(data));
+ }
+
+ public:
+ AuthorizationRequest(const char *username, const char *password, const char *timestamp) :
+ HttpsPostRequest(STEAM_COM_URL "/mobilelogin/dologin")
+ {
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+
+ InitData(username, password, timestamp);
+ }
+
+ AuthorizationRequest(const char *username, const char *password, const char *timestamp, const char *guardId, const char *guardCode) :
+ HttpsPostRequest(STEAM_COM_URL "/mobilelogin/dologin")
+ {
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+
+ InitData(username, password, timestamp, guardId, guardCode);
+ }
+
+ /*const wchar_t *GetUsername() { return username; }
+ const char *GetPassword() { return password; }
+ const char *GetTimestamp() { return timestamp; }*/
+ };
}
diff --git a/protocols/Steam/src/Steam/avatar.h b/protocols/Steam/src/Steam/avatar.h
index 253e4a3299..1ad2637def 100644
--- a/protocols/Steam/src/Steam/avatar.h
+++ b/protocols/Steam/src/Steam/avatar.h
@@ -31,7 +31,7 @@ namespace SteamWebApi
{
avatar->success = false;
- HttpGetRequest request(hConnection, avatarUrl);
+ /*HttpGetRequest request(hConnection, avatarUrl);
request.ResetFlags(NLHRF_HTTP11 | NLHRF_NODUMP);
mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
@@ -43,7 +43,7 @@ namespace SteamWebApi
avatar->size = response->dataLength;
avatar->data = (BYTE*)mir_alloc(avatar->size);
- memcpy(avatar->data, response->pData, avatar->size);
+ memcpy(avatar->data, response->pData, avatar->size);*/
avatar->success = true;
}
diff --git a/protocols/Steam/src/Steam/crypto.h b/protocols/Steam/src/Steam/crypto.h
index 6cd761ecde..553e311cf7 100644
--- a/protocols/Steam/src/Steam/crypto.h
+++ b/protocols/Steam/src/Steam/crypto.h
@@ -1,13 +1,13 @@
#ifndef _STEAM_CRYPTO_H_
#define _STEAM_CRYPTO_H_
- #include <openssl/rsa.h>
- #include <openssl/bio.h>
- #include <openssl/bn.h>
- #include <openssl/err.h>
- #include <openssl/evp.h>
- #include <openssl/rand.h>
- #include <openssl/engine.h>
+#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
namespace SteamWebApi
{
diff --git a/protocols/Steam/src/Steam/friend.h b/protocols/Steam/src/Steam/friend.h
index 3fa559b2ec..d3ed0cc8ee 100644
--- a/protocols/Steam/src/Steam/friend.h
+++ b/protocols/Steam/src/Steam/friend.h
@@ -149,6 +149,17 @@ namespace SteamWebApi
summaries->success = true;
}
};
+
+ class GetUserSummariesRequest : public HttpsGetRequest
+ {
+ public:
+ GetUserSummariesRequest(const char *token, const char *steamIds) :
+ HttpsGetRequest(STEAM_API_URL "/ISteamUserOAuth/GetUserSummaries/v0001")
+ {
+ AddParameter("access_token", token);
+ AddParameter("steamids", steamIds);
+ }
+ };
}
#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
index d5c1c5dc34..94f25d4427 100644
--- a/protocols/Steam/src/Steam/friend_list.h
+++ b/protocols/Steam/src/Steam/friend_list.h
@@ -165,6 +165,64 @@ namespace SteamWebApi
result->success = true;
}
};
+
+ class GetFriendListRequest : public HttpsGetRequest
+ {
+ public:
+ GetFriendListRequest(const char *token, const char *steamId) :
+ HttpsGetRequest(STEAM_API_URL "/ISteamUserOAuth/GetFriendList/v0001")
+ {
+ AddParameter("access_token", token);
+ AddParameter("steamid", steamId);
+ AddParameter("relationship=friend,ignoredfriend,requestrecipient");
+ }
+ };
+
+ class AddFriendRequest : public HttpsPostRequest
+ {
+ public:
+ AddFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
+ HttpsPostRequest(STEAM_COM_URL "/actions/AddFriendAjax")
+ {
+ char login[MAX_PATH];
+ mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token);
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId);
+
+ char data[128];
+ mir_snprintf(data, SIZEOF(data),
+ "sessionID=%s&steamid=%s",
+ sessionId,
+ who);
+
+ SetData(data, strlen(data));
+ AddHeader("Cookie", cookie);
+ }
+ };
+
+ class RemoveFriendRequest : public HttpsPostRequest
+ {
+ public:
+ RemoveFriendRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
+ HttpsPostRequest(STEAM_COM_URL "/actions/RemoveFriendAjax")
+ {
+ char login[MAX_PATH];
+ mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token);
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId);
+
+ char data[128];
+ mir_snprintf(data, SIZEOF(data),
+ "sessionID=%s&steamid=%s",
+ sessionId,
+ who);
+
+ SetData(data, strlen(data));
+ AddHeader("Cookie", cookie);
+ }
+ };
}
#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
index 84d29ef2f2..c3ee1c5b17 100644
--- a/protocols/Steam/src/Steam/login.h
+++ b/protocols/Steam/src/Steam/login.h
@@ -71,6 +71,32 @@ namespace SteamWebApi
mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
}
};
+
+ class LogonRequest : public HttpsPostRequest
+ {
+ public:
+ LogonRequest(const char *token) :
+ HttpsPostRequest(STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logon/v0001")
+ {
+ char data[256];
+ mir_snprintf(data, SIZEOF(data), "access_token=%s", token);
+
+ SetData(data, strlen(data));
+ }
+ };
+
+ class LogoffRequest : public HttpsPostRequest
+ {
+ public:
+ LogoffRequest(const char *token, const char *umqId) :
+ HttpsPostRequest(STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001")
+ {
+ char data[256];
+ mir_snprintf(data, SIZEOF(data), "access_token=%s&umqid=%s", token, umqId);
+
+ SetData(data, strlen(data));
+ }
+ };
}
#endif //_STEAM_LOGIN_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/Steam/message.h b/protocols/Steam/src/Steam/message.h
index bb9fec3bc1..12284315bc 100644
--- a/protocols/Steam/src/Steam/message.h
+++ b/protocols/Steam/src/Steam/message.h
@@ -103,6 +103,24 @@ namespace SteamWebApi
sendResult->success = true;
}
};
+
+ class SendMessageRequest : public HttpsPostRequest
+ {
+ public:
+ SendMessageRequest(const char *token, const char *umqId, const char *steamId, const char *text) :
+ HttpsPostRequest(STEAM_API_URL "/ISteamWebUserPresenceOAuth/Message/v0001")
+ {
+ char data[1024];
+ mir_snprintf(data, SIZEOF(data),
+ "access_token=%s&umqid=%s&steamid_dst=%s&type=saytext&text=%s",
+ token,
+ umqId,
+ steamId,
+ ptrA(mir_urlEncode(text)));
+
+ SetData(data, strlen(data));
+ }
+ };
}
diff --git a/protocols/Steam/src/Steam/pending.h b/protocols/Steam/src/Steam/pending.h
index ea65627b32..639804fb44 100644
--- a/protocols/Steam/src/Steam/pending.h
+++ b/protocols/Steam/src/Steam/pending.h
@@ -96,6 +96,54 @@ namespace SteamWebApi
result->success = true;
}
};
+
+ class ApprovePendingRequest : public HttpsPostRequest
+ {
+ public:
+ ApprovePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
+ HttpsPostRequest(STEAM_COM_URL "/profiles/%s/home_process")
+ {
+ char login[MAX_PATH];
+ mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token);
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId);
+
+ char url[MAX_PATH];
+ mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/profiles/%s/home_process", steamId);
+ this->url = url;
+
+ char data[MAX_PATH];
+ mir_snprintf(data, SIZEOF(data), "sessionID=%s&id=%s&perform=accept&action=approvePending&itype=friend&json=1&xml=0", sessionId, who);
+
+ SetData(data, strlen(data));
+ AddHeader("Cookie", cookie);
+ }
+ };
+
+ class IgnorePendingRequest : public HttpsPostRequest
+ {
+ public:
+ IgnorePendingRequest(const char *token, const char *sessionId, const char *steamId, const char *who) :
+ HttpsPostRequest(STEAM_COM_URL "/profiles/%s/home_process")
+ {
+ char login[MAX_PATH];
+ mir_snprintf(login, SIZEOF(login), "%s||oauth:%s", steamId, token);
+
+ char cookie[MAX_PATH];
+ mir_snprintf(cookie, SIZEOF(cookie), "steamLogin=%s;sessionid=%s;forceMobile=1", login, sessionId);
+
+ char url[MAX_PATH];
+ mir_snprintf(url, SIZEOF(url), STEAM_COM_URL "/profiles/%s/home_process", steamId);
+ this->url = url;
+
+ char data[MAX_PATH];
+ mir_snprintf(data, SIZEOF(data), "sessionID=%s&id=%s&perform=ignore&action=approvePending&itype=friend&json=1&xml=0", sessionId, who);
+
+ SetData(data, strlen(data));
+ AddHeader("Cookie", cookie);
+ }
+ };
}
#endif //_STEAM_PENDING_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/Steam/poll.h b/protocols/Steam/src/Steam/poll.h
index 218787e9ac..73597e81c4 100644
--- a/protocols/Steam/src/Steam/poll.h
+++ b/protocols/Steam/src/Steam/poll.h
@@ -94,7 +94,7 @@ namespace SteamWebApi
SecureHttpPostRequest request(hConnection, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001");
request.SetData(data, strlen(data));
- request.SetTimeout(90000); // may need to encrease timeout
+ request.SetTimeout(30000); // may need to encrease timeout
mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
if (!response)
@@ -226,6 +226,23 @@ namespace SteamWebApi
pollResult->success = true;
}
};
+
+ class PollRequest : public HttpsPostRequest
+ {
+ public:
+ PollRequest(const char *token, const char *umqId, UINT32 messageId) :
+ HttpsPostRequest(STEAM_API_URL "/ISteamWebUserPresenceOAuth/Poll/v0001")
+ {
+ timeout = 30000;
+ flags |= NLHRF_PERSISTENT;
+
+ char data[256];
+ mir_snprintf(data, SIZEOF(data), "access_token=%s&umqid=%s&message=%u", token, umqId, messageId);
+
+ SetData(data, strlen(data));
+ AddHeader("Connection", "keep-alive");
+ }
+ };
}
diff --git a/protocols/Steam/src/Steam/rsa_key.h b/protocols/Steam/src/Steam/rsa_key.h
index 35b2eb6f28..2ea9a20558 100644
--- a/protocols/Steam/src/Steam/rsa_key.h
+++ b/protocols/Steam/src/Steam/rsa_key.h
@@ -56,7 +56,18 @@ namespace SteamWebApi
rsaKey->success = true;
}
};
-}
+ class RsaKeyRequest : public HttpsGetRequest
+ {
+ public:
+ RsaKeyRequest(const char *username) :
+ HttpsGetRequest(STEAM_COM_URL "/mobilelogin/getrsakey")
+ {
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+
+ AddParameter("username", (char*)username);
+ }
+ };
+}
#endif //_STEAM_RSA_KEY_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/Steam/search.h b/protocols/Steam/src/Steam/search.h
index 1efe0e807b..ff85f5960f 100644
--- a/protocols/Steam/src/Steam/search.h
+++ b/protocols/Steam/src/Steam/search.h
@@ -91,6 +91,19 @@ namespace SteamWebApi
searchResult->success = true;
}
};
+
+ class SearchRequest : public HttpsGetRequest
+ {
+ public:
+ SearchRequest(const char *token, const char *text) :
+ HttpsGetRequest(STEAM_API_URL "/ISteamUserOAuth/Search/v0001")
+ {
+ AddParameter("access_token", token);
+ AddParameter("keywords", ptrA(mir_urlEncode(text)));
+ // todo: may need to load all results (15 first at now)
+ AddParameter("offset=0&count=15&targets=users&fields=all");
+ }
+ };
}
#endif //_STEAM_SEARCH_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/Steam/session.h b/protocols/Steam/src/Steam/session.h
index cad2f96dbf..3ddcc219cd 100644
--- a/protocols/Steam/src/Steam/session.h
+++ b/protocols/Steam/src/Steam/session.h
@@ -50,6 +50,25 @@ namespace SteamWebApi
sessionId->success = true;
}
};
+
+ class GetSessionRequest : public HttpsPostRequest
+ {
+ public:
+ GetSessionRequest(const char *token, const char *steamId, const char *cookie) :
+ HttpsPostRequest(STEAM_COM_URL "/mobileloginsucceeded")
+ {
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMP;
+
+ char data[512];
+ mir_snprintf(data, SIZEOF(data),
+ "oauth_token=%s&steamid=%s&webcookie=%s",
+ token,
+ steamId,
+ cookie);
+
+ SetData(data, strlen(data));
+ }
+ };
}
#endif //_STEAM_SESSION_H_ \ No newline at end of file
diff --git a/protocols/Steam/src/Steam/steam.h b/protocols/Steam/src/Steam/steam.h
index 66d9068100..df039288a5 100644
--- a/protocols/Steam/src/Steam/steam.h
+++ b/protocols/Steam/src/Steam/steam.h
@@ -28,6 +28,108 @@ namespace SteamWebApi
HTTP_STATUS GetStatus() const { return status; }
};
};
+
+ class HttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject
+ {
+ public:
+ std::string url;
+
+ HttpRequest(int type, LPCSTR url)
+ {
+ cbSize = sizeof(NETLIBHTTPREQUEST);
+
+ requestType = type;
+ this->url = url;
+ szUrl = (char*)this->url.c_str();
+ timeout = 0;
+ flags = NLHRF_HTTP11 | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT;
+ }
+
+ ~HttpRequest()
+ {
+ for (int i = 0; i < headersCount; i++)
+ {
+ mir_free(headers[i].szName);
+ mir_free(headers[i].szValue);
+ }
+ mir_free(headers);
+ mir_free(pData);
+ }
+
+ void AddHeader(LPCSTR szName, LPCSTR szValue)
+ {
+ headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1));
+ headers[headersCount].szName = mir_strdup(szName);
+ headers[headersCount].szValue = mir_strdup(szValue);
+ headersCount++;
+ }
+
+ void AddParameter(LPCSTR szName, LPCSTR szValue)
+ {
+ if (url.find('?') == -1)
+ url.append("?").append(szName).append("=").append(szValue);
+ else
+ url.append("&").append(szName).append("=").append(szValue);
+ }
+
+ void AddParameter(LPCSTR szValue)
+ {
+ if (url.find('?') == -1)
+ url.append("?").append(szValue);
+ else
+ url.append("&").append(szValue);
+ }
+
+ void SetData(const char *data, size_t size)
+ {
+ if (pData != NULL)
+ mir_free(pData);
+
+ dataLength = (int)size;
+ pData = (char*)mir_alloc(size + 1);
+ memcpy(pData, data, size);
+ pData[size] = 0;
+ }
+ };
+
+ class HttpGetRequest : public HttpRequest
+ {
+ public:
+ HttpGetRequest(LPCSTR url) : HttpRequest(REQUEST_GET, url) { }
+ };
+
+ /*class HttpPostRequest : public HttpRequest
+ {
+ public:
+ HttpPostRequest(LPCSTR url) : HttpRequest(REQUEST_POST, url)
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+ }
+ };*/
+
+ class HttpsRequest : public HttpRequest
+ {
+ public:
+ HttpsRequest(int type, LPCSTR url) : HttpRequest(type, url)
+ {
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT;
+ }
+ };
+
+ class HttpsGetRequest : public HttpsRequest
+ {
+ public:
+ HttpsGetRequest(LPCSTR url) : HttpsRequest(REQUEST_GET, url) { }
+ };
+
+ class HttpsPostRequest : public HttpsRequest
+ {
+ public:
+ HttpsPostRequest(LPCSTR url) : HttpsRequest(REQUEST_POST, url)
+ {
+ AddHeader("Content-Type", "application/x-www-form-urlencoded");
+ }
+ };
}
#include "Steam\rsa_key.h"
diff --git a/protocols/Steam/src/steam_account.cpp b/protocols/Steam/src/steam_account.cpp
index 812962db81..59915ddeac 100644
--- a/protocols/Steam/src/steam_account.cpp
+++ b/protocols/Steam/src/steam_account.cpp
@@ -14,6 +14,196 @@ bool CSteamProto::IsMe(const char *steamId)
return false;
}
+void CSteamProto::OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ // load rsa key parts
+ 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");
+ ptrA modulus(mir_u2a(json_as_string(node)));
+
+ // exponent "010001" is used as constant in CSteamProto::RsaEncrypt
+ /*node = json_get(root, "publickey_exp");
+ ptrA exponent(mir_u2a(json_as_string(node)));*/
+
+ node = json_get(root, "timestamp");
+ ptrA timestamp(mir_u2a(json_as_string(node)));
+ setString("Timestamp", timestamp);
+
+ // encrcrypt password
+ ptrA base64RsaEncryptedPassword;
+ ptrA password(getStringA("Password"));
+
+ DWORD error = 0;
+ DWORD encryptedSize = 0;
+ DWORD passwordSize = (DWORD)strlen(password);
+ if ((error = RsaEncrypt(modulus, password, NULL, encryptedSize)) != 0)
+ {
+ debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error);
+ return;
+ }
+
+ BYTE *encryptedPassword = (BYTE*)mir_calloc(encryptedSize);
+ if ((error = RsaEncrypt(modulus, password, encryptedPassword, encryptedSize)) != 0)
+ {
+ debugLogA("CSteamProto::OnGotRsaKey: encryption error (%lu)", error);
+ return;
+ }
+
+ base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize);
+ mir_free(encryptedPassword);
+
+ setString("EncryptedPassword", base64RsaEncryptedPassword);
+
+ // run authorization request
+ ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username")))));
+
+ PushRequest(
+ new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp),
+ &CSteamProto::OnAuthorization);
+}
+
+void CSteamProto::OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ JSONNODE *root = json_parse(response->pData), *node;
+
+ node = json_get(root, "success");
+ if (json_as_bool(node) == 0)
+ {
+ node = json_get(root, "emailauth_needed");
+ if (json_as_bool(node) > 0)
+ {
+ node = json_get(root, "emailsteamid");
+ ptrA guardId(mir_u2a(json_as_string(node)));
+
+ node = json_get(root, "emaildomain");
+ ptrA emailDomain(mir_utf8encodeW(json_as_string(node)));
+
+ GuardParam guard;
+ lstrcpyA(guard.domain, emailDomain);
+
+ if (DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_GUARD),
+ NULL,
+ CSteamProto::GuardProc,
+ (LPARAM)&guard) != 1)
+ return;
+
+ ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username")))));
+ ptrA base64RsaEncryptedPassword(getStringA("EncryptedPassword"));
+ ptrA timestamp(getStringA("Timestamp"));
+
+ PushRequest(
+ new SteamWebApi::AuthorizationRequest(username, base64RsaEncryptedPassword, timestamp, guardId, guard.code),
+ &CSteamProto::OnAuthorization);
+ }
+
+ // todo: show captcha dialog
+ /*node = json_get(root, "captcha_needed");
+ if (json_as_bool(node) > 0)
+ {
+ node = json_get(root, "captcha_gid");
+ authResult->captchagid = ptrA(mir_u2a(json_as_string(node)));
+ }
+
+ if (!authResult->emailauth_needed && !authResult->captcha_needed)
+ {
+ node = json_get(root, "message");
+ authResult->message = json_as_string(node);
+ }*/
+
+ return;
+ }
+
+ node = json_get(root, "login_complete");
+ if (!json_as_bool(node))
+ return;
+
+ node = json_get(root, "oauth");
+ root = json_parse(ptrA(mir_u2a(json_as_string(node))));
+
+ node = json_get(root, "steamid");
+ ptrA steamId(mir_u2a(json_as_string(node)));
+ setString("SteamID", steamId);
+
+ node = json_get(root, "oauth_token");
+ ptrA token(mir_u2a(json_as_string(node)));
+ setString("TokenSecret", token);
+
+ node = json_get(root, "webcookie");
+ ptrA cookie(mir_u2a(json_as_string(node)));
+
+ delSetting("Timestamp");
+ delSetting("EncryptedPassword");
+
+ PushRequest(
+ new SteamWebApi::GetSessionRequest(token, steamId, cookie),
+ &CSteamProto::OnGotSession);
+
+ PushRequest(
+ new SteamWebApi::LogonRequest(token),
+ &CSteamProto::OnLoggedOn);
+}
+
+void CSteamProto::OnGotSession(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ for (int i = 0; i < response->headersCount; i++)
+ {
+ if (lstrcmpiA(response->headers[i].szName, "Set-Cookie"))
+ continue;
+
+ std::string cookies = response->headers[i].szValue;
+ size_t start = cookies.find("sessionid=") + 10;
+ size_t end = cookies.substr(start).find(';');
+ std::string sessionId = cookies.substr(start, end - start + 10);
+ setString("SessionID", sessionId.c_str());
+ break;
+ }
+}
+
+void CSteamProto::OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ JSONNODE *root = json_parse(response->pData), *node;
+
+ node = json_get(root, "error");
+ ptrW error(json_as_string(node));
+ if (lstrcmpi(error, L"OK")/* || response->resultCode == HTTP_STATUS_UNAUTHORIZED*/)
+ {
+ //delSetting("TokenSecret");
+ //delSetting("Cookie");
+
+ // set status to offline
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, ID_STATUS_OFFLINE);
+ return;
+ }
+
+ node = json_get(root, "umqid");
+ setString("UMQID", ptrA(mir_u2a(json_as_string(node))));
+
+ node = json_get(root, "message");
+ setDword("MessageID", json_as_int(node));
+
+ // load contact list
+ ptrA token(getStringA("TokenSecret"));
+ ptrA steamId(getStringA("SteamID"));
+
+ PushRequest(
+ new SteamWebApi::GetFriendListRequest(token, steamId),
+ &CSteamProto::OnGotFriendList);
+
+ // start polling thread
+ m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, 0, NULL);
+
+ // go to online now
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus);
+}
+
void CSteamProto::SetServerStatusThread(void *arg)
{
WORD status = *((WORD*)&arg);
@@ -66,7 +256,7 @@ void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResul
ptrA password(getStringA("Password"));
- DWORD error = 0;
+ /*DWORD error = 0;
DWORD encryptedSize = 0;
DWORD passwordSize = (DWORD)strlen(password);
if ((error = RsaEncrypt(rsaKey, password, passwordSize, NULL, encryptedSize)) != 0)
@@ -83,7 +273,7 @@ void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResul
}
base64RsaEncryptedPassword = mir_base64_encode(encryptedPassword, encryptedSize);
- mir_free(encryptedPassword);
+ mir_free(encryptedPassword);*/
// try to authorize
debugLogA("CSteamProto::Authorize: call SteamWebApi::AuthorizationApi::Authorize");
@@ -123,7 +313,7 @@ void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResul
void CSteamProto::LogInThread(void* param)
{
- while (m_bTerminated || m_hPollingThread != NULL)
+ while (isTerminated || m_hPollingThread != NULL)
Sleep(500);
ptrA token(getStringA("TokenSecret"));
@@ -195,7 +385,7 @@ void CSteamProto::LogInThread(void* param)
// start pooling thread
if (m_hPollingThread == NULL)
{
- m_bTerminated = false;
+ isTerminated = false;
m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, NULL, NULL);
}
}
@@ -205,12 +395,12 @@ void CSteamProto::LogOutThread(void*)
ptrA token(getStringA("TokenSecret"));
ptrA umqId(getStringA("UMQID"));
- while (!Miranda_Terminated() && m_bTerminated && m_hPollingThread != NULL)
+ while (!Miranda_Terminated() && isTerminated && m_hPollingThread != NULL)
Sleep(200);
debugLogA("CSteamProto::LogOutThread: call SteamWebApi::LoginApi::Logoff");
SteamWebApi::LoginApi::Logoff(m_hNetlibUser, token, umqId);
delSetting("UMQID");
- m_bTerminated = false;
+ isTerminated = false;
} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index 75c85812ce..f0bf2454ac 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -181,6 +181,126 @@ void CSteamProto::UpdateContactsThread(void *arg)
}
}
+void CSteamProto::UpdateContact(MCONTACT hContact, JSONNODE *data)
+{
+ JSONNODE *node = NULL;
+
+ // set common data
+ node = json_get(data, "personaname");
+ setWString(hContact, "Nick", json_as_string(node));
+
+ node = json_get(data, "profileurl");
+ setString(hContact, "Homepage", ptrA(mir_u2a(json_as_string(node))));
+
+ // set name
+ node = json_get(data, "realname");
+ if (node != NULL)
+ {
+ std::wstring realname = json_as_string(node);
+ if (!realname.empty())
+ {
+ size_t pos = realname.find(' ', 1);
+ if (pos != std::string::npos)
+ {
+ const wchar_t *firstName = realname.substr(0, pos).c_str();
+ const wchar_t *lastName = realname.substr(pos + 1).c_str();
+
+ setWString(hContact, "FirstName", firstName);
+ setWString(hContact, "LastName", lastName);
+ }
+ else
+ {
+ setWString(hContact, "FirstName", realname.c_str());
+ delSetting(hContact, "LastName");
+ }
+ }
+ }
+ else
+ {
+ delSetting(hContact, "FirstName");
+ delSetting(hContact, "LastName");
+ }
+
+ //// avatar
+
+ //node = json_get(data, "avatarfull");
+ //item->avatarUrl = ptrA(mir_u2a(json_as_string(node)));
+
+ //ptrA oldAvatar(getStringA("AvatarUrl"));
+ //if (lstrcmpiA(oldAvatar, summary->GetAvatarUrl()))
+ //{
+ // // todo: need to place in thread
+ // SteamWebApi::AvatarApi::Avatar avatar;
+ // debugLogA("CSteamProto::UpdateContact: SteamWebApi::AvatarApi::GetAvatar");
+ // SteamWebApi::AvatarApi::GetAvatar(m_hNetlibUser, summary->GetAvatarUrl(), &avatar);
+
+ // if (avatar.IsSuccess() && avatar.GetDataSize() > 0)
+ // {
+ // ptrW avatarPath(GetAvatarFilePath(hContact));
+ // FILE *fp = _wfopen(avatarPath, L"wb");
+ // if (fp)
+ // {
+ // fwrite(avatar.GetData(), sizeof(char), avatar.GetDataSize(), fp);
+ // fclose(fp);
+
+ // PROTO_AVATAR_INFORMATIONW pai = { sizeof(pai) };
+ // pai.format = PA_FORMAT_JPEG;
+ // pai.hContact = hContact;
+ // wcscpy(pai.filename, avatarPath);
+
+ // ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&pai, 0);
+
+ // setString("AvatarUrl", summary->GetAvatarUrl());
+ // }
+ // }
+ //}
+
+ // set country
+ node = json_get(data, "loccountrycode");
+ if (node != NULL)
+ {
+ const char *iso = ptrA(mir_u2a(json_as_string(node)));
+ char *country = (char *)CallService(MS_UTILS_GETCOUNTRYBYISOCODE, (WPARAM)iso, 0);
+ setString(hContact, "Country", country);
+ }
+ else
+ this->delSetting(hContact, "Country");
+
+ // only for contacts
+ if (hContact)
+ {
+ node = json_get(data, "lastlogoff");
+ setDword(hContact, "LastEventDateTS", json_as_int(node));
+
+ node = json_get(data, "gameid");
+ DWORD gameId = atol(ptrA(mir_u2a(json_as_string(node))));
+ if (gameId > 0)
+ {
+ node = json_get(data, "gameextrainfo");
+ const wchar_t *gameInfo = json_as_string(node);
+
+ db_set_ws(hContact, "CList", "StatusMsg", gameInfo);
+ setWord(hContact, "Status", ID_STATUS_OUTTOLUNCH);
+
+ setWString(hContact, "GameInfo", gameInfo);
+ setDword(hContact, "GameID", gameId);
+ }
+ else
+ {
+ node = json_get(data, "personastate");
+ WORD status = SteamToMirandaStatus(json_as_int(node));
+ setWord(hContact, "Status", status);
+
+ db_unset(hContact, "CList", "StatusMsg");
+ delSetting(hContact, "GameID");
+ }
+ }
+
+
+ /*node = json_get(data, "timecreated");
+ time_t created = json_as_int(node);*/
+}
+
MCONTACT CSteamProto::AddContact(const char *steamId, bool isTemporary)
{
MCONTACT hContact = this->FindContact(steamId);
@@ -214,6 +334,242 @@ MCONTACT CSteamProto::AddContact(const char *steamId, bool isTemporary)
return hContact;
}
+void CSteamProto::OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ JSONNODE *root = json_parse(response->pData), *node, *child;
+
+ if (root == NULL)
+ return;
+
+ std::string steamIds;
+
+ node = json_get(root, "friends");
+ root = json_as_array(node);
+ if (root != NULL)
+ {
+ for (size_t i = 0; i < json_size(root); i++)
+ {
+ child = json_at(root, i);
+ if (child == NULL)
+ break;
+
+ node = json_get(child, "steamid");
+ ptrA steamId(mir_u2a(json_as_string(node)));
+
+ node = json_get(child, "relationship");
+ ptrA relationship(mir_u2a(json_as_string(node)));
+ if (!lstrcmpiA(relationship, "friend"))
+ {
+ if (!FindContact(steamId))
+ {
+ AddContact(steamId);
+ steamIds.append(steamId).append(",");
+ }
+ }
+ else if (!lstrcmpiA(relationship, "ignoredfriend"))
+ {
+ // todo
+ }
+ else if (!lstrcmpiA(relationship, "requestrecipient"))
+ {
+ MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ hContact = AddContact(steamId, true);
+
+ RaiseAuthRequestThread((void*)hContact);
+ }
+ else continue;
+ }
+ }
+
+ if (!steamIds.empty())
+ {
+ steamIds.pop_back();
+ ptrA token(getStringA("TokenSecret"));
+
+ PushRequest(
+ new SteamWebApi::GetUserSummariesRequest(token, steamIds.c_str()),
+ &CSteamProto::OnGotUserSummaries);
+ }
+}
+
+void CSteamProto::OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ JSONNODE *root = json_parse(response->pData), *node, *item;
+
+ node = json_get(root, "players");
+ root = json_as_array(node);
+ if (root != NULL)
+ {
+ for (size_t i = 0; i < json_size(root); i++)
+ {
+ item = json_at(root, i);
+ if (item == NULL)
+ break;
+
+ node = json_get(item, "steamid");
+ ptrA steamId(mir_u2a(json_as_string(node)));
+
+ MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ hContact = AddContact(steamId);
+
+ UpdateContact(hContact, item);
+ }
+ }
+}
+
+void CSteamProto::OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ SendAuthParam *param = (SendAuthParam*)arg;
+
+ if (response->resultCode != HTTP_STATUS_OK || lstrcmpiA(response->pData, "true"))
+ {
+ ptrA steamId(getStringA(param->hContact, "SteamID"));
+ debugLogA("CSteamProto::OnFriendAdded: failed to add friend %s", steamId);
+
+ ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_FAILED, param->hAuth, 0);
+
+ return;
+ }
+
+ delSetting(param->hContact, "Auth");
+ delSetting(param->hContact, "Grant");
+ db_unset(param->hContact, "CList", "NotOnList");
+
+ ProtoBroadcastAck(param->hContact, ACKTYPE_AUTHREQ, ACKRESULT_SUCCESS, param->hAuth, 0);
+}
+
+void CSteamProto::OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ if (response->resultCode != HTTP_STATUS_OK || lstrcmpiA(response->pData, "true"))
+ {
+ debugLogA("CSteamProto::OnFriendRemoved: failed to remove friend %s", ptrA((char*)arg));
+ }
+}
+
+void CSteamProto::OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ if (response == NULL || response->resultCode != HTTP_STATUS_OK)
+ {
+ debugLogA("CSteamProto::OnAuthRequested: failed to request info for %s", ptrA((char*)arg));
+ return;
+ }
+
+ JSONNODE *root = json_parse(response->pData), *node;
+
+ node = json_get(root, "players");
+ root = json_at(json_as_array(node), 0);
+ if (root != NULL)
+ {
+ node = json_get(root, "steamid");
+ ptrA steamId(mir_u2a(json_as_string(node)));
+
+ MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ hContact = AddContact(steamId);
+
+ UpdateContact(hContact, root);
+
+ char *nickName = getStringA(hContact, "Nick");
+ char *firstName = getStringA(hContact, "FirstName");
+ char *lastName = getStringA(hContact, "LastName");
+
+ char reason[MAX_PATH];
+ mir_snprintf(reason, SIZEOF(reason), Translate("%s has added you to his or her Friend List"), nickName);
+
+ // blob is: 0(DWORD), hContact(DWORD), nick(ASCIIZ), firstName(ASCIIZ), lastName(ASCIIZ), sid(ASCIIZ), reason(ASCIIZ)
+ DWORD cbBlob = (DWORD)(sizeof(DWORD)* 2 + strlen(nickName) + strlen(firstName) + strlen(lastName) + strlen(steamId) + strlen(reason) + 5);
+
+ PBYTE pBlob, pCurBlob;
+ pCurBlob = pBlob = (PBYTE)mir_alloc(cbBlob);
+
+ *((PDWORD)pCurBlob) = 0;
+ pCurBlob += sizeof(DWORD);
+ *((PDWORD)pCurBlob) = (DWORD)hContact;
+ pCurBlob += sizeof(DWORD);
+ strcpy((char*)pCurBlob, nickName);
+ pCurBlob += strlen(nickName) + 1;
+ strcpy((char*)pCurBlob, firstName);
+ pCurBlob += strlen(firstName) + 1;
+ strcpy((char*)pCurBlob, lastName);
+ pCurBlob += strlen(lastName) + 1;
+ strcpy((char*)pCurBlob, steamId);
+ pCurBlob += strlen(steamId) + 1;
+ strcpy((char*)pCurBlob, mir_strdup(reason));
+
+ AddDBEvent(hContact, EVENTTYPE_AUTHREQUEST, time(NULL), DBEF_UTF, cbBlob, pBlob);
+ }
+}
+
+void CSteamProto::OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ if (response->resultCode != HTTP_STATUS_OK || lstrcmpiA(response->pData, "true"))
+ {
+ debugLogA("CSteamProto::OnPendingApproved: failed to approve pending from %s", ptrA((char*)arg));
+ }
+}
+
+void CSteamProto::OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ if (response->resultCode != HTTP_STATUS_OK || lstrcmpiA(response->pData, "true"))
+ {
+ debugLogA("CSteamProto::OnPendingIgnoreded: failed to ignore pending from %s", ptrA((char*)arg));
+ }
+}
+
+void CSteamProto::OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ if (response == NULL || response->resultCode != HTTP_STATUS_OK)
+ {
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)STEAM_SEARCH_BYID, 0);
+ return;
+ }
+
+ JSONNODE *root = json_parse(response->pData), *node;
+
+ node = json_get(root, "players");
+ root = json_at(json_as_array(node), 0);
+ if (root != NULL)
+ {
+ STEAM_SEARCH_RESULT ssr = { 0 };
+ ssr.hdr.cbSize = sizeof(STEAM_SEARCH_RESULT);
+ ssr.hdr.flags = PSR_TCHAR;
+
+ ssr.hdr.id = (wchar_t*)arg;
+
+ node = json_get(root, "personaname");
+ ssr.hdr.nick = mir_wstrdup(json_as_string(node));
+
+ node = json_get(root, "realname");
+ if (node != NULL)
+ {
+ std::wstring realname = json_as_string(node);
+ if (!realname.empty())
+ {
+ size_t pos = realname.find(' ', 1);
+ if (pos != std::string::npos)
+ {
+ ssr.hdr.firstName = mir_wstrdup(realname.substr(0, pos).c_str());
+ ssr.hdr.lastName = mir_wstrdup(realname.substr(pos + 1).c_str());
+ }
+ else
+ ssr.hdr.firstName = mir_wstrdup(realname.c_str());
+ }
+ }
+
+ //ssr.contact = contact;
+ ssr.data = json_copy(root);
+
+ 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::OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg)
+{
+}
+
void CSteamProto::RaiseAuthRequestThread(void *arg)
{
MCONTACT hContact = (MCONTACT)arg;
diff --git a/protocols/Steam/src/steam_messages.cpp b/protocols/Steam/src/steam_messages.cpp
index ec94d20907..80e68ecdc0 100644
--- a/protocols/Steam/src/steam_messages.cpp
+++ b/protocols/Steam/src/steam_messages.cpp
@@ -33,4 +33,19 @@ void CSteamProto::SendTypingThread(void *arg)
SteamWebApi::MessageApi::SendResult sendResult;
debugLogA("CSteamProto::SendTypingThread: call SteamWebApi::PollApi::SteamWebApi::MessageApi::SendMessage");
SteamWebApi::MessageApi::SendTyping(m_hNetlibUser, token, umqId, steamId, &sendResult);
+}
+
+void CSteamProto::OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg)
+{
+ SendMessageParam *param = (SendMessageParam*)arg;
+
+ int status = response->resultCode == HTTP_STATUS_OK ? ACKRESULT_SUCCESS : ACKRESULT_FAILED;
+
+ ProtoBroadcastAck(
+ param->hContact,
+ ACKTYPE_MESSAGE,
+ status,
+ param->hMessage, 0);
+
+ mir_free(param);
} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_pooling.cpp b/protocols/Steam/src/steam_pooling.cpp
new file mode 100644
index 0000000000..826187c9a4
--- /dev/null
+++ b/protocols/Steam/src/steam_pooling.cpp
@@ -0,0 +1,338 @@
+#include "common.h"
+
+void CSteamProto::PollServer(const char *token, const char *umqId, UINT32 messageId, SteamWebApi::PollApi::PollResult *pollResult)
+{
+ debugLogA("CSteamProto::PollServer: call SteamWebApi::PollApi::Poll");
+ SteamWebApi::PollApi::Poll(m_hNetlibUser, token, umqId, messageId, pollResult);
+
+ if (!pollResult->IsSuccess())
+ return;
+
+ CMStringA updatedIds;
+ for (size_t i = 0; i < pollResult->GetItemCount(); i++)
+ {
+ const SteamWebApi::PollApi::PoolItem *item = pollResult->GetAt(i);
+ switch (item->GetType())
+ {
+ case SteamWebApi::PollApi::POOL_TYPE_TYPING:
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_MESSAGE:
+ {
+ SteamWebApi::PollApi::Message *message = (SteamWebApi::PollApi::Message*)item;
+
+ MCONTACT hContact = FindContact(message->GetSteamId());
+ if (hContact)
+ {
+ const wchar_t *text = message->GetText();
+
+ PROTORECVEVENT recv = { 0 };
+ recv.flags = PREF_UTF;
+ recv.timestamp = message->GetTimestamp();
+ recv.szMessage = mir_utf8encodeW(text);
+
+ ProtoChainRecvMsg(hContact, &recv);
+ }
+ }
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_MYMESSAGE:
+ {
+ SteamWebApi::PollApi::Message *message = (SteamWebApi::PollApi::Message*)item;
+
+ MCONTACT hContact = FindContact(message->GetSteamId());
+ if (hContact)
+ {
+ const wchar_t *text = message->GetText();
+
+ AddDBEvent(hContact, EVENTTYPE_MESSAGE, time(NULL), DBEF_UTF | DBEF_SENT, lstrlen(text), (BYTE*)mir_utf8encodeW(text));
+ }
+ }
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_STATE:
+ {
+ SteamWebApi::PollApi::State *state = (SteamWebApi::PollApi::State*)item;
+
+ WORD status = CSteamProto::SteamToMirandaStatus(state->GetStatus());
+ const char *steamId = state->GetSteamId();
+ const wchar_t *nickname = state->GetNickname();
+
+ if (IsMe(steamId))
+ {
+ if (status == ID_STATUS_OFFLINE)
+ continue;
+
+ if (status != m_iStatus)
+ {
+ debugLogA("Change own status to %i", status);
+ WORD oldStatus = m_iStatus;
+ m_iStatus = m_iDesiredStatus = status;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ }
+ /*else
+ {
+ MCONTACT hContact = FindContact(steamId);
+ if (hContact)
+ SetContactStatus(hContact, status);
+ }*/
+
+ if (updatedIds.IsEmpty())
+ updatedIds.Append(steamId);
+ else
+ updatedIds.AppendFormat(",%s", steamId);
+ }
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_CONTACT_ADD:
+ {
+ SteamWebApi::PollApi::Relationship *crs = (SteamWebApi::PollApi::Relationship*)item;
+
+ const char *steamId = crs->GetSteamId();
+ if (updatedIds.IsEmpty())
+ updatedIds.Append(steamId);
+ else
+ updatedIds.AppendFormat(",%s", steamId);
+ }
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_CONTACT_REMOVE:
+ {
+ SteamWebApi::PollApi::Relationship *crs = (SteamWebApi::PollApi::Relationship*)item;
+
+ const char *steamId = crs->GetSteamId();
+ MCONTACT hContact = FindContact(steamId);
+ if (hContact)
+ CallService(MS_DB_CONTACT_DELETE, hContact, 0);
+ }
+ break;
+
+ case SteamWebApi::PollApi::POOL_TYPE_CONTACT_REQUEST:
+ {
+ SteamWebApi::PollApi::Relationship *crs = (SteamWebApi::PollApi::Relationship*)item;
+
+ const char *steamId = crs->GetSteamId();
+
+ MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ hContact = AddContact(steamId, true);
+
+ RaiseAuthRequestThread((void*)hContact);
+ }
+ break;
+ }
+ }
+
+ if (!updatedIds.IsEmpty())
+ UpdateContactsThread(mir_strdup(updatedIds));
+}
+
+void CSteamProto::ParsePollData(JSONNODE *data)
+{
+ JSONNODE *node, *item = NULL;
+
+ for (size_t i = 0; i < json_size(data); i++)
+ {
+ item = json_at(data, i);
+ if (item == NULL)
+ break;
+
+ node = json_get(item, "steamid_from");
+ ptrA steamId(mir_u2a(json_as_string(node)));
+
+ node = json_get(item, "utc_timestamp");
+ time_t timestamp = atol(ptrA(mir_u2a(json_as_string(node))));
+
+ node = json_get(item, "type");
+ ptrW type(json_as_string(node));
+ if (!lstrcmpi(type, L"saytext") || !lstrcmpi(type, L"emote") ||
+ !lstrcmpi(type, L"my_saytext") || !lstrcmpi(type, L"my_emote"))
+ {
+ node = json_get(item, "text");
+ const wchar_t *text = json_as_string(node);
+
+ if (_tcsstr(type, L"my_") == NULL)
+ {
+ MCONTACT hContact = FindContact(steamId);
+ if (hContact)
+ {
+ PROTORECVEVENT recv = { 0 };
+ recv.flags = PREF_UTF;
+ recv.timestamp = timestamp;
+ recv.szMessage = mir_utf8encodeW(text);
+
+ ProtoChainRecvMsg(hContact, &recv);
+ }
+ }
+ else
+ {
+ MCONTACT hContact = FindContact(steamId);
+ if (hContact)
+ AddDBEvent(hContact, EVENTTYPE_MESSAGE, timestamp, DBEF_UTF | DBEF_SENT, lstrlen(text), (BYTE*)mir_utf8encodeW(text));
+ }
+
+ /*node = json_get(item, "text");
+ if (node != NULL) message->text = json_as_string(node);
+
+ node = json_get(item, "utc_timestamp");
+ message->timestamp = atol(ptrA(mir_u2a(json_as_string(node))));*/
+ }
+ /*else if (!lstrcmpi(type, L"typing"))
+ {
+ }*/
+ else if (!lstrcmpi(type, L"personastate"))
+ {
+ node = json_get(item, "persona_state");
+ int status = SteamToMirandaStatus(json_as_int(node));
+
+ if (IsMe(steamId))
+ {
+ if (status == ID_STATUS_OFFLINE)
+ continue;
+
+ if (status != m_iStatus)
+ {
+ debugLogA("CSteamProto::ParsePollData: Change own status to %i", status);
+ WORD oldStatus = m_iStatus;
+ m_iStatus = m_iDesiredStatus = status;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ }
+ else if(!FindContact(steamId))
+ {
+ MCONTACT hContact = AddContact(steamId);
+
+ setWord(hContact, "Status", status);
+
+ node = json_get(item, "persona_name");
+ setWString(hContact, "Nick", json_as_string(node));
+ }
+
+ // todo: find difference between state changing and info changing
+ }
+ else if (!lstrcmpi(type, L"personarelationship"))
+ {
+ node = json_get(item, "persona_state");
+ int state = json_as_int(node);
+
+ switch (state)
+ {
+ case 0:
+ // removed
+ break;
+
+ case 1:
+ // ignored
+ break;
+
+ case 2:
+ { // auth request
+ /*MCONTACT hContact = FindContact(steamId);
+ if (!hContact)
+ hContact = AddContact(steamId, true);*/
+
+ //RaiseAuthRequestThread((void*)hContact);
+
+ ptrA token(getStringA("TokenSecret"));
+
+ PushRequest(
+ new SteamWebApi::GetUserSummariesRequest(token, steamId),
+ &CSteamProto::OnAuthRequested,
+ mir_strdup(steamId));
+ }
+ break;
+
+ case 3:
+ // add to list
+ break;
+
+ default: continue;
+ }
+ }
+ /*else if (!lstrcmpi(type, L"leftconversation"))
+ {
+ }*/
+ else
+ {
+ continue;
+ }
+ }
+}
+
+void CSteamProto::PollingThread(void*)
+{
+ debugLogA("CSteamProto::PollingThread: entering");
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA umqId(getStringA("UMQID"));
+ UINT32 messageId = getDword("MessageID", 0);
+
+ //SteamWebApi::PollApi::PollResult pollResult;
+ bool breaked = false;
+ while (!isTerminated && !breaked)
+ {
+ SteamWebApi::PollRequest *request = new SteamWebApi::PollRequest(token, umqId, messageId);
+ debugLogA("CSteamProto::PollingThread: %s", request->szUrl);
+ request->szUrl = (char*)request->url.c_str();
+ request->nlc = m_pollingConnection;
+ NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)request);
+ delete request;
+
+ if (response == NULL || 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"))
+ {
+
+ node = json_get(root, "messagelast");
+ messageId = json_as_int(node);
+
+ node = json_get(root, "messages");
+ root = json_as_array(node);
+
+ if (root != NULL)
+ ParsePollData(root);
+
+ m_pollingConnection = response->nlc;
+ }
+ else if (!lstrcmpi(error, L"Timeout"))
+ {
+ continue;
+ }
+ else if (!lstrcmpi(error, L"Not Logged On"))
+ {
+ if (!IsOnline())
+ {
+ // need to relogin
+ debugLogA("CSteamProto::PollingThread: not logged on");
+
+ SetStatus(ID_STATUS_OFFLINE);
+ }
+
+ breaked = true;
+ }
+ else if (lstrcmpi(error, L"Timeout"))
+ {
+ // something wrong
+ debugLogA("CSteamProto::PollingThread: error (%d)", response->resultCode);
+
+ // token has expired
+ if (response->resultCode == HTTP_STATUS_UNAUTHORIZED)
+ delSetting("TokenSecret");
+
+ breaked = true;
+ }
+
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response);
+ }
+
+ setDword("MessageID", messageId);
+
+ m_hPollingThread = NULL;
+ debugLogA("CSteamProto::PollingThread: leaving");
+} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index cc589ec3bc..3705916e46 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -3,12 +3,15 @@
CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) :
PROTO<CSteamProto>(protoName, userName),
hAuthProcess(1),
- hMessageProcess(1)
+ hMessageProcess(1),
+ requestsQueue(1)
{
CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
InitializeCriticalSection(&this->contact_search_lock);
+ InitQueue();
+
// icons
wchar_t filePath[MAX_PATH];
GetModuleFileName(g_hInstance, filePath, MAX_PATH);
@@ -41,6 +44,8 @@ CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) :
CSteamProto::~CSteamProto()
{
+ UninitQueue();
+
DeleteCriticalSection(&this->contact_search_lock);
}
@@ -53,15 +58,21 @@ MCONTACT __cdecl CSteamProto::AddToList(int flags, PROTOSEARCHRESULT* psr)
ptrA steamId(mir_u2a(psr->id));
if (!FindContact(steamId))
{
- hContact = AddContact(steamId, true);
- ForkThread(&CSteamProto::UpdateContactsThread, (void*)mir_strdup(steamId));
+ //hContact = AddContact(steamId, true);
+ //ForkThread(&CSteamProto::UpdateContactsThread, (void*)mir_strdup(steamId));
+
+ ptrA token(getStringA("TokenSecret"));
+
+ PushRequest(
+ new SteamWebApi::GetUserSummariesRequest(token, steamId),
+ &CSteamProto::OnGotUserSummaries);
}
}
else if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT))
{
STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT*)psr;
hContact = AddContact(ssr->contact->GetSteamId(), true);
- UpdateContact(hContact, ssr->contact);
+ UpdateContact(hContact, ssr->data);
}
return hContact;
@@ -80,7 +91,17 @@ int __cdecl CSteamProto::Authorize(HANDLE hDbEvent)
if (hContact == INVALID_CONTACT_ID)
return 1;
- ForkThread(&CSteamProto::AuthAllowThread, (void*)hContact);
+ //ForkThread(&CSteamProto::AuthAllowThread, (void*)hContact);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new SteamWebApi::ApprovePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingApproved,
+ who);
return 0;
}
@@ -96,7 +117,17 @@ int __cdecl CSteamProto::AuthDeny(HANDLE hDbEvent, const TCHAR* szReason)
if (hContact == INVALID_CONTACT_ID)
return 1;
- ForkThread(&CSteamProto::AuthDenyThread, (void*)hContact);
+ //ForkThread(&CSteamProto::AuthDenyThread, (void*)hContact);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new SteamWebApi::IgnorePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingIgnoreded,
+ who);
return 0;
}
@@ -119,7 +150,17 @@ int __cdecl CSteamProto::AuthRequest(MCONTACT hContact, const TCHAR* szMessage)
param->hContact = hContact;
param->hAuth = (HANDLE)hAuth;
- ForkThread(&CSteamProto::AddContactThread, param);
+ //ForkThread(&CSteamProto::AddContactThread, param);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ ptrA who(getStringA(hContact, "SteamID"));
+
+ PushRequest(
+ new SteamWebApi::AddFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendAdded,
+ param);
return hAuth;
}
@@ -175,7 +216,15 @@ HANDLE __cdecl CSteamProto::SearchBasic(const TCHAR* id)
if (!this->IsOnline())
return 0;
- ForkThread(&CSteamProto::SearchByIdThread, mir_wstrdup(id));
+ //ForkThread(&CSteamProto::SearchByIdThread, mir_wstrdup(id));
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA steamId(mir_u2a(id));
+
+ PushRequest(
+ new SteamWebApi::GetUserSummariesRequest(token, steamId),
+ &CSteamProto::OnSearchByIdEnded,
+ mir_wstrdup(id));
return (HANDLE)STEAM_SEARCH_BYID;
}
@@ -187,16 +236,21 @@ HANDLE __cdecl CSteamProto::SearchByEmail(const TCHAR* email)
HANDLE __cdecl CSteamProto::SearchByName(const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName)
{
- if (!this->IsOnline())
+ //if (!this->IsOnline())
return 0;
+ ptrA token(getStringA("TokenSecret"));
+
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));
+ //ForkThread(&CSteamProto::SearchByNameThread, mir_wstrdup(keywords));
+ PushRequest(
+ new SteamWebApi::SearchRequest(token, mir_utf8encodeW(keywords)),
+ &CSteamProto::OnSearchByNameStarted);
return (HANDLE)STEAM_SEARCH_BYNAME;
}
@@ -238,10 +292,19 @@ int __cdecl CSteamProto::SendMsg(MCONTACT hContact, int flags, const char *msg)
SendMessageParam *param = (SendMessageParam*)mir_calloc(sizeof(SendMessageParam));
param->hContact = hContact;
- param->text = mir_utf8encode(msg);
+ //param->text = mir_utf8encode(msg);
param->hMessage = (HANDLE)hMessage;
- ForkThread(&CSteamProto::SendMessageThread, param);
+ //ForkThread(&CSteamProto::SendMessageThread, param);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA umqid(getStringA("UMQID"));
+ ptrA steamId(getStringA(hContact, "SteamId"));
+
+ PushRequest(
+ new SteamWebApi::SendMessageRequest(token, umqid, steamId, ptrA(mir_utf8encode(msg))),
+ &CSteamProto::OnMessageSent,
+ param);
return hMessage;
}
@@ -252,22 +315,24 @@ int __cdecl CSteamProto::SetApparentMode(MCONTACT hContact, int mode) { return 0
int CSteamProto::SetStatus(int new_status)
{
- debugLogA("CSteamProto::SetStatus: from %i to %i", m_iStatus, new_status);
-
if (new_status == m_iDesiredStatus)
return 0;
+ debugLogA("CSteamProto::SetStatus: changing status from %i to %i", m_iStatus, new_status);
+
int old_status = m_iStatus;
m_iDesiredStatus = new_status;
if (new_status == ID_STATUS_OFFLINE)
{
- m_bTerminated = true;
- ForkThread(&CSteamProto::LogOutThread, NULL);
+ //isTerminated = true;
+ //ForkThread(&CSteamProto::LogOutThread, NULL);
m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ StopQueue();
+
if (!Miranda_Terminated())
SetAllContactsStatus(ID_STATUS_OFFLINE);
}
@@ -276,7 +341,8 @@ int CSteamProto::SetStatus(int new_status)
m_iStatus = ID_STATUS_CONNECTING;
ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
- ForkThread(&CSteamProto::LogInThread, NULL);
+ //ForkThread(&CSteamProto::LogInThread, NULL);
+ StartQueue();
}
return 0;
@@ -305,7 +371,20 @@ int __cdecl CSteamProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM
return this->OnOptionsInit(wParam, lParam);*/
case EV_PROTO_ONCONTACTDELETED:
- ForkThread(&CSteamProto::RemoveContactThread, (void*)getStringA(wParam, "SteamID"));
+ if (IsOnline())
+ {
+ //ForkThread(&CSteamProto::RemoveContactThread, (void*)getStringA(wParam, "SteamID"));
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(wParam, "SteamID");
+
+ PushRequest(
+ new SteamWebApi::RemoveFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendRemoved,
+ who);
+ }
return 0;
/*case EV_PROTO_ONMENU:
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index 88a18a74f1..8e930d287a 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -34,6 +34,7 @@ struct STEAM_SEARCH_RESULT
{
PROTOSEARCHRESULT hdr;
const SteamWebApi::FriendApi::Summary *contact;
+ JSONNODE *data;
};
enum
@@ -46,6 +47,26 @@ enum
CMI_MAX // this item shall be the last one
};
+typedef void (CSteamProto::*RESPONSE)(const NETLIBHTTPREQUEST *response, void *arg);
+
+struct QueueItem
+{
+ SteamWebApi::HttpRequest *request;
+ void *arg;
+ RESPONSE responseCallback;
+ RESPONSE responseFailedCallback;
+
+ QueueItem(SteamWebApi::HttpRequest *request) :
+ request(request), arg(NULL), responseCallback(NULL), responseFailedCallback(NULL) { }
+
+ QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response) :
+ request(request), arg(NULL), responseCallback(response), responseFailedCallback(NULL) { }
+
+ QueueItem(SteamWebApi::HttpRequest *request, RESPONSE response, RESPONSE responseFailedCallback) :
+ request(request), arg(NULL), responseCallback(response), responseFailedCallback(responseFailedCallback) { }
+
+ ~QueueItem() { delete request; responseCallback = NULL; }
+};
class CSteamProto : public PROTO<CSteamProto>
{
@@ -55,48 +76,48 @@ public:
~CSteamProto();
// PROTO_INTERFACE
- virtual MCONTACT __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr );
- virtual MCONTACT __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent );
+ virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT *psr);
+ virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, HANDLE hDbEvent);
- virtual int __cdecl Authorize( HANDLE hDbEvent );
- virtual int __cdecl AuthDeny( HANDLE hDbEvent, const TCHAR* szReason );
- virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT* );
- virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR* szMessage );
+ virtual int __cdecl Authorize(HANDLE hDbEvent);
+ virtual int __cdecl AuthDeny(HANDLE hDbEvent, const TCHAR *szReason);
+ virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT *);
+ virtual int __cdecl AuthRequest(MCONTACT hContact, const TCHAR * szMessage);
- virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath );
- virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer );
- virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason );
- virtual int __cdecl FileResume( HANDLE hTransfer, int* action, const TCHAR** szFilename );
+ virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szPath);
+ virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer);
+ virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const TCHAR* szReason);
+ virtual int __cdecl FileResume(HANDLE hTransfer, int *action, const TCHAR** szFilename);
- virtual DWORD_PTR __cdecl GetCaps( int type, MCONTACT hContact = NULL );
- virtual int __cdecl GetInfo(MCONTACT hContact, int infoType );
+ virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL);
+ virtual int __cdecl GetInfo(MCONTACT hContact, int infoType);
- virtual HANDLE __cdecl SearchBasic( const TCHAR* id );
- virtual HANDLE __cdecl SearchByEmail( const TCHAR* email );
- virtual HANDLE __cdecl SearchByName( const TCHAR* nick, const TCHAR* firstName, const TCHAR* lastName );
- virtual HWND __cdecl SearchAdvanced( HWND owner );
- virtual HWND __cdecl CreateExtendedSearchUI( HWND owner );
+ virtual HANDLE __cdecl SearchBasic(const TCHAR *id);
+ virtual HANDLE __cdecl SearchByEmail(const TCHAR *email);
+ virtual HANDLE __cdecl SearchByName(const TCHAR *nick, const TCHAR *firstName, const TCHAR *lastName);
+ virtual HWND __cdecl SearchAdvanced(HWND owner);
+ virtual HWND __cdecl CreateExtendedSearchUI(HWND owner);
- virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT* );
- virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET* );
- virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT* );
- virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT* );
+ virtual int __cdecl RecvContacts(MCONTACT hContact, PROTORECVEVENT*);
+ virtual int __cdecl RecvFile(MCONTACT hContact, PROTORECVFILET*);
+ virtual int __cdecl RecvMsg(MCONTACT hContact, PROTORECVEVENT*);
+ virtual int __cdecl RecvUrl(MCONTACT hContact, PROTORECVEVENT*);
virtual int __cdecl SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList);
- virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles );
- virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg );
- virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url );
+ virtual HANDLE __cdecl SendFile(MCONTACT hContact, const TCHAR* szDescription, TCHAR** ppszFiles);
+ virtual int __cdecl SendMsg(MCONTACT hContact, int flags, const char* msg);
+ virtual int __cdecl SendUrl(MCONTACT hContact, int flags, const char* url);
- virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode );
- virtual int __cdecl SetStatus( int iNewStatus );
+ virtual int __cdecl SetApparentMode(MCONTACT hContact, int mode);
+ virtual int __cdecl SetStatus(int iNewStatus);
- virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact );
- virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt );
- virtual int __cdecl SetAwayMsg( int m_iStatus, const TCHAR* msg );
+ virtual HANDLE __cdecl GetAwayMsg(MCONTACT hContact);
+ virtual int __cdecl RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT* evt);
+ virtual int __cdecl SetAwayMsg(int m_iStatus, const TCHAR* msg);
- virtual int __cdecl UserIsTyping(MCONTACT hContact, int type );
+ virtual int __cdecl UserIsTyping(MCONTACT hContact, int type);
- virtual int __cdecl OnEvent( PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam );
+ virtual int __cdecl OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPARAM lParam);
// instances
static CSteamProto* InitProtoInstance(const char* protoName, const wchar_t* userName);
@@ -110,18 +131,37 @@ public:
static void UninitMenus();
protected:
- bool m_bTerminated;
- HANDLE m_hPollingThread;
+ bool isTerminated;
+ HANDLE m_evRequestsQueue, m_hQueueThread;
+ HANDLE m_pollingConnection, m_hPollingThread;
ULONG hAuthProcess;
ULONG hMessageProcess;
CRITICAL_SECTION contact_search_lock;
+ CRITICAL_SECTION requests_queue_lock;
+ LIST<QueueItem> requestsQueue;
// instances
static LIST<CSteamProto> InstanceList;
static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2);
+ // queue
+ void InitQueue();
+ void UninitQueue();
+
+ void StartQueue();
+ void StopQueue();
+
+ void PushRequest(SteamWebApi::HttpRequest *request);
+ void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response);
+ void PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg);
+
+ void ExecuteRequest(QueueItem *requestItem);
+
+ void __cdecl QueueThread(void*);
+
// pooling thread
void PollServer(const char *sessionId, const char *steamId, UINT32 messageId, SteamWebApi::PollApi::PollResult *pollResult);
+ void ParsePollData(JSONNODE *data);
void __cdecl PollingThread(void*);
// account
@@ -133,6 +173,13 @@ protected:
void __cdecl LogOutThread(void*);
void __cdecl SetServerStatusThread(void*);
+ void OnGotRsaKey(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnAuthorization(const NETLIBHTTPREQUEST *response, void *arg);
+ void OnGotSession(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnLoggedOn(const NETLIBHTTPREQUEST *response, void *arg);
+
// contacts
void SetContactStatus(MCONTACT hContact, WORD status);
void SetAllContactsStatus(WORD status);
@@ -142,9 +189,27 @@ protected:
void UpdateContact(MCONTACT hContact, const SteamWebApi::FriendApi::Summary *summary);
void __cdecl UpdateContactsThread(void*);
+ void UpdateContact(MCONTACT hContact, JSONNODE *data);
+
MCONTACT FindContact(const char *steamId);
MCONTACT AddContact(const char *steamId, bool isTemporary = false);
+ void OnGotFriendList(const NETLIBHTTPREQUEST *response, void *arg);
+ void OnGotUserSummaries(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnFriendAdded(const NETLIBHTTPREQUEST *response, void *arg);
+ void OnFriendRemoved(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnAuthRequested(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnPendingApproved(const NETLIBHTTPREQUEST *response, void *arg);
+ void OnPendingIgnoreded(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnSearchByIdEnded(const NETLIBHTTPREQUEST *response, void *arg);
+
+ void OnSearchByNameStarted(const NETLIBHTTPREQUEST *response, void *arg);
+ void OnSearchByNameFinished(const NETLIBHTTPREQUEST *response, void *arg);
+
void __cdecl RaiseAuthRequestThread(void*);
void __cdecl AuthAllowThread(void*);
void __cdecl AuthDenyThread(void*);
@@ -161,6 +226,8 @@ protected:
void __cdecl SendMessageThread(void*);
void __cdecl SendTypingThread(void*);
+ void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg);
+
// menus
HGENMENU m_hMenuRoot;
static HANDLE hChooserMenu;
@@ -191,7 +258,7 @@ protected:
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);
+ static int RsaEncrypt(const char *pszModulus, const char *data, BYTE *encrypted, DWORD &encryptedSize);
HANDLE AddDBEvent(MCONTACT hContact, WORD type, DWORD timestamp, DWORD flags, DWORD cbBlob, PBYTE pBlob);
diff --git a/protocols/Steam/src/steam_queue.cpp b/protocols/Steam/src/steam_queue.cpp
new file mode 100644
index 0000000000..22096f70be
--- /dev/null
+++ b/protocols/Steam/src/steam_queue.cpp
@@ -0,0 +1,146 @@
+#include "common.h"
+
+void CSteamProto::InitQueue()
+{
+ InitializeCriticalSection(&requests_queue_lock);
+ m_evRequestsQueue = CreateEvent(NULL, FALSE, FALSE, NULL);
+}
+
+void CSteamProto::UninitQueue()
+{
+ requestsQueue.destroy();
+ CloseHandle(m_evRequestsQueue);
+ DeleteCriticalSection(&requests_queue_lock);
+}
+
+void CSteamProto::StartQueue()
+{
+ isTerminated = false;
+
+ if (m_hQueueThread == NULL)
+ {
+ ptrA token(getStringA("TokenSecret"));
+ if (token && lstrlenA(token) > 0)
+ {
+ PushRequest(
+ new SteamWebApi::LogonRequest(token),
+ &CSteamProto::OnLoggedOn);
+ }
+ else
+ {
+ ptrA username(mir_urlEncode(ptrA(mir_utf8encodeW(getWStringA("Username")))));
+ if (username == NULL || strlen(username) == 0)
+ return;
+ PushRequest(new SteamWebApi::RsaKeyRequest(username), (RESPONSE)&CSteamProto::OnGotRsaKey);
+ }
+
+ m_hQueueThread = ForkThreadEx(&CSteamProto::QueueThread, 0, NULL);
+ }
+}
+
+void CSteamProto::StopQueue()
+{
+ isTerminated = true;
+
+ {
+ mir_cslock lock(requests_queue_lock);
+
+ int count = requestsQueue.getCount();
+ while (count > 0)
+ requestsQueue.remove(count - 1);
+ }
+
+ // logoff
+ ptrA token(getStringA("TokenSecret"));
+ ptrA umqid(getStringA("UMQID"));
+
+ SteamWebApi::HttpRequest *request = new SteamWebApi::LogoffRequest(token, umqid);
+ debugLogA("CSteamProto::StopQueue: %s", request->szUrl);
+ request->szUrl = (char*)request->url.c_str();
+ NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)request);
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response);
+ delete request;
+
+ m_hQueueThread = NULL;
+}
+
+void CSteamProto::PushRequest(SteamWebApi::HttpRequest *request)
+{
+ PushRequest(request, NULL, NULL);
+}
+
+void CSteamProto::PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response)
+{
+ PushRequest(request, response, NULL);
+}
+
+void CSteamProto::PushRequest(SteamWebApi::HttpRequest *request, RESPONSE response, void *arg)
+{
+ if (isTerminated)
+ return;
+
+ {
+ mir_cslock lock(requests_queue_lock);
+ QueueItem *item = new QueueItem(request, response);
+ item->arg = arg;
+ requestsQueue.insert(item);
+ }
+
+ SetEvent(m_evRequestsQueue);
+}
+
+void CSteamProto::ExecuteRequest(QueueItem *item)
+{
+ if (isTerminated)
+ return;
+
+ debugLogA("CSteamProto::ExecuteRequest: %s", item->request->szUrl);
+
+ item->request->szUrl = (char*)item->request->url.c_str();
+ NETLIBHTTPREQUEST *response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)item->request);
+
+ if (item->responseCallback != NULL)
+ (this->*(item->responseCallback))(response, item->arg);
+
+ // todo: add succeed and failed handlers if need
+ if (response != NULL/* && response->resultCode != 200*/)
+ {
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)response);
+ }
+ /*else if (requestItem->responseFailedCallback != NULL)
+ {
+ (this->*(requestItem->responseFailedCallback))(response);
+ }*/
+
+ delete item;
+}
+
+void CSteamProto::QueueThread(void*)
+{
+ debugLogA("CSteamProto::QueueThread: entering");
+
+ while (!isTerminated)
+ {
+ WaitForSingleObject(m_evRequestsQueue, 1000);
+
+ while (true)
+ {
+ QueueItem *item = NULL;
+
+ {
+ mir_cslock lock(requests_queue_lock);
+
+ if (requestsQueue.getCount() == 0)
+ break;
+
+ item = requestsQueue[0];
+ requestsQueue.remove(0);
+ }
+
+ if (item != NULL)
+ ExecuteRequest(item);
+ }
+ }
+
+ debugLogA("CSteamProto::QueueThread: leaving");
+} \ No newline at end of file
diff --git a/protocols/Steam/src/steam_utils.cpp b/protocols/Steam/src/steam_utils.cpp
index bc5d624a75..1ac29f593c 100644
--- a/protocols/Steam/src/steam_utils.cpp
+++ b/protocols/Steam/src/steam_utils.cpp
@@ -44,9 +44,8 @@ int CSteamProto::MirandaToSteamState(int status)
}
}
-int CSteamProto::RsaEncrypt(const SteamWebApi::RsaKeyApi::RsaKey &rsaKey, const char *data, DWORD dataSize, BYTE *encryptedData, DWORD &encryptedSize)
+int CSteamProto::RsaEncrypt(const char *pszModulus, const char *data, BYTE *encryptedData, DWORD &encryptedSize)
{
- const char *pszModulus = rsaKey.GetModulus();
DWORD cchModulus = (DWORD)strlen(pszModulus);
// convert hex string to byte array
@@ -100,6 +99,8 @@ int CSteamProto::RsaEncrypt(const SteamWebApi::RsaKeyApi::RsaKey &rsaKey, const
if (!CryptImportKey(hCSP, pKeyBlob, cbKeyBlob, 0, 0, &phKey))
return GetLastError();
+ DWORD dataSize = strlen(data);
+
// if data is not allocated just renurn size
if (encryptedData == NULL)
{