From e08dd78ccf05f9d5d768e5436fcfc5e8126356fe Mon Sep 17 00:00:00 2001
From: Alexander Lantsev <aunsane@gmail.com>
Date: Fri, 4 Apr 2014 14:13:16 +0000
Subject: Steam: some improvements

git-svn-id: http://svn.miranda-ng.org/main/trunk@8848 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
---
 protocols/Steam/src/Steam/authorization.h |  96 ++++--
 protocols/Steam/src/Steam/crypto.h        |   2 +-
 protocols/Steam/src/Steam/login.h         |  37 ++-
 protocols/Steam/src/Steam/poll.h          |  51 ++-
 protocols/Steam/src/Steam/steam.h         |   3 +-
 protocols/Steam/src/common.h              |   3 +
 protocols/Steam/src/http_request.h        |   6 +-
 protocols/Steam/src/resource.h            |   4 +-
 protocols/Steam/src/steam_account.cpp     | 114 ++++---
 protocols/Steam/src/steam_contacts.cpp    | 519 +-----------------------------
 protocols/Steam/src/steam_dialogs.cpp     |  87 ++---
 protocols/Steam/src/steam_proto.cpp       |  29 +-
 protocols/Steam/src/steam_proto.h         |  27 +-
 protocols/Steam/src/steam_thread.cpp      |  40 +--
 14 files changed, 319 insertions(+), 699 deletions(-)

(limited to 'protocols/Steam/src')

diff --git a/protocols/Steam/src/Steam/authorization.h b/protocols/Steam/src/Steam/authorization.h
index 049afbf55c..c0015cdebc 100644
--- a/protocols/Steam/src/Steam/authorization.h
+++ b/protocols/Steam/src/Steam/authorization.h
@@ -7,7 +7,7 @@ namespace SteamWebApi
 	{
 	public:
 
-		class Authorization : public Result
+		class AuthResult : public Result
 		{
 			friend AuthorizationApi;
 
@@ -16,27 +16,51 @@ namespace SteamWebApi
 			std::string token;
 
 			std::string emailauth;
+			std::string emaildomain;
 			std::string emailsteamid;
 
+			std::string captchagid;
+			std::string captcha_text;
+
+			std::wstring message;
+
+			bool captcha_needed;
 			bool emailauth_needed;
-//			bool emailauth_needed;
 
 		public:
-			bool IsEmailAuthNeeded() { return emailauth_needed; }
-			const char *GetSteamid() { return steamid.c_str(); }
-			const char *GetToken() { return token.c_str(); }
-			const char *GetAuthId() { return emailauth.c_str(); }
-			const char *GetAuthCode() { return emailsteamid.c_str(); }
+			AuthResult()
+			{
+				captcha_needed = false;
+				emailauth_needed = false;
+				captchagid = "-1";
+			}
+
+			bool IsCaptchaNeeded() const { return captcha_needed; }
+			bool IsEmailAuthNeeded() const { return emailauth_needed; }
+			const char *GetSteamid() const { return steamid.c_str(); }
+			const char *GetToken() const { return token.c_str(); }
+			const char *GetAuthId() const { return emailauth.c_str(); }
+			const char *GetAuthCode() const { return emailsteamid.c_str(); }
+			const char *GetEmailDomain() const { return emaildomain.c_str(); }
+			const char *GetCaptchaId() const { return captchagid.c_str(); }
+			const wchar_t *GetMessage() const { return message.c_str(); }
 
 			void SetAuthCode(char *code)
 			{
 				emailauth = code;
 			}
+
+			void SetCaptchaText(char *text)
+			{
+				captcha_text = text;
+			}
 		};
 
-		static void Authorize(HANDLE hConnection, const wchar_t *username, const char *password, Authorization *auth)
+		static void Authorize(HANDLE hConnection, const wchar_t *username, const char *password, AuthResult *authResult)
 		{
-			auth->success = false;
+			authResult->success = false;
+			authResult->captcha_needed = false;
+			authResult->emailauth_needed = false;
 
 			ptrA base64Username(mir_urlEncode(ptrA(mir_utf8encodeW(username))));
 
@@ -53,16 +77,15 @@ namespace SteamWebApi
 			CMStringA data;
 			data.AppendFormat("username=%s", base64Username);
 			data.AppendFormat("&password=%s", ptrA(mir_urlEncode(base64RsaEncryptedPassword)));
-			data.AppendFormat("&emailauth=%s", ptrA(mir_urlEncode(auth->emailauth.c_str())));
-			data.AppendFormat("&emailsteamid=%s", auth->emailsteamid.c_str());
-			//data.AppendFormat("&captchagid=%s", result->captchagid);
-			//data.AppendFormat("&captcha_text=%s", ptrA(mir_urlEncode(result->captcha_text)));
-			data.Append("&captchagid=-1");
+			data.AppendFormat("&emailauth=%s", ptrA(mir_urlEncode(authResult->emailauth.c_str())));
+			data.AppendFormat("&emailsteamid=%s", authResult->emailsteamid.c_str());
+			data.AppendFormat("&captchagid=%s", authResult->captchagid);
+			data.AppendFormat("&captcha_text=%s", ptrA(mir_urlEncode(authResult->captcha_text.c_str())));
 			data.AppendFormat("&rsatimestamp=%llu", rsaKey.GetTimestamp());
-			data.AppendFormat("&oauth_scope=%s", "read_profile%20write_profile%20read_client%20write_client");
-			data.Append("&oauth_client_id=3638BFB1");
+			data.AppendFormat("&oauth_scope=%s", "read_profile write_profile read_client write_client");
+			data.Append("&oauth_client_id=DE45CD61");
 
-			HttpRequest request(hConnection, REQUEST_POST, "https://steamcommunity.com/mobilelogin/dologin");
+			HttpRequest request(hConnection, REQUEST_POST, STEAM_COMMUNITY_URL "/mobilelogin/dologin");
 			request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
 			request.SetData(data.GetBuffer(), data.GetLength());
 			
@@ -73,27 +96,33 @@ namespace SteamWebApi
 			JSONNODE *root = json_parse(response->pData), *node;
 
 			node = json_get(root, "success");
-			auth->success = json_as_bool(node) > 0;
-			if (!auth->success)
+			authResult->success = json_as_bool(node) > 0;
+			if (!authResult->success)
 			{
 				node = json_get(root, "emailauth_needed");
-				auth->emailauth_needed = json_as_bool(node) > 0;
-				if (auth->emailauth_needed)
+				authResult->emailauth_needed = json_as_bool(node) > 0;
+				if (authResult->emailauth_needed)
 				{
 					node = json_get(root, "emailsteamid");
-					auth->emailsteamid = ptrA(mir_u2a(json_as_string(node)));
+					authResult->emailsteamid = ptrA(mir_u2a(json_as_string(node)));
 
-					/*node = json_get(root, "emaildomain");
-					result->emaildomain = json_as_string(node);*/
+					node = json_get(root, "emaildomain");
+					authResult->emaildomain = ptrA(mir_utf8encodeW(json_as_string(node)));
 				}
 
-				/*node = json_get(root, "captcha_needed");
-				result->captcha_needed = json_as_bool(node) > 0;
-				if (result->captcha_needed)
+				node = json_get(root, "captcha_needed");
+				authResult->captcha_needed = json_as_bool(node) > 0;
+				if (authResult->captcha_needed)
 				{
 					node = json_get(root, "captcha_gid");
-					result->captchagid = json_as_string(node);
-				}*/
+					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);
+				}
 			}
 			else
 			{
@@ -108,13 +137,14 @@ namespace SteamWebApi
 				//root = json_as_node(node);
 
 				node = json_get(root, "steamid");
-				auth->steamid = ptrA(mir_u2a(json_as_string(node)));
+				authResult->steamid = ptrA(mir_u2a(json_as_string(node)));
 
 				node = json_get(root, "oauth_token");
-				auth->token = ptrA(mir_u2a(json_as_string(node)));
+				authResult->token = ptrA(mir_u2a(json_as_string(node)));
 
-				auth->success = true;
-				auth->emailauth_needed = false;
+				authResult->success = true;
+				authResult->captcha_needed = false;
+				authResult->emailauth_needed = false;
 			}
 		}
 	};
diff --git a/protocols/Steam/src/Steam/crypto.h b/protocols/Steam/src/Steam/crypto.h
index 91a8af7ba0..6cd761ecde 100644
--- a/protocols/Steam/src/Steam/crypto.h
+++ b/protocols/Steam/src/Steam/crypto.h
@@ -92,7 +92,7 @@ namespace SteamWebApi
 		{
 			rsaKey->success = false;
 
-			HttpRequest request(hConnection, REQUEST_GET, "https://steamcommunity.com/mobilelogin/getrsakey");
+			HttpRequest request(hConnection, REQUEST_GET, STEAM_COMMUNITY_URL "/mobilelogin/getrsakey");
 			request.AddParameter("username", username);
 			
 			mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
diff --git a/protocols/Steam/src/Steam/login.h b/protocols/Steam/src/Steam/login.h
index 4d0c172681..aab7225a4d 100644
--- a/protocols/Steam/src/Steam/login.h
+++ b/protocols/Steam/src/Steam/login.h
@@ -3,12 +3,12 @@
 
 namespace SteamWebApi
 {
-	class LogInApi : public BaseApi
+	class LoginApi : public BaseApi
 	{
 	public:
-		class LogIn : public Result
+		class LoginResult : public Result
 		{
-			friend LogInApi;
+			friend LoginApi;
 
 		private:
 			std::string steamid;
@@ -22,12 +22,13 @@ namespace SteamWebApi
 			UINT32 GetMessageId() { return messageId; }
 		};
 		
-		static void LogOn(HANDLE hConnection, const char *token, LogIn *login)
+		static void Logon(HANDLE hConnection, const char *token, LoginResult *loginResult)
 		{
-			login->success = false;
+			loginResult->success = false;
 
 			CMStringA data;
 			data.AppendFormat("access_token=%s", token);
+			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");
@@ -45,18 +46,34 @@ namespace SteamWebApi
 				return;
 
 			node = json_get(root, "steamid");
-			login->steamid = ptrA(mir_u2a(json_as_string(node)));
+			loginResult->steamid = ptrA(mir_u2a(json_as_string(node)));
 
 			node = json_get(root, "umqid");
-			login->umqid = ptrA(mir_u2a(json_as_string(node)));
+			loginResult->umqid = ptrA(mir_u2a(json_as_string(node)));
 
 			node = json_get(root, "message");
-			login->messageId = json_as_int(node);
+			loginResult->messageId = json_as_int(node);
 
-			login->success = true;
+			loginResult->success = true;
+		}
+
+		static void Relogon(HANDLE hConnection, const char *token, LoginResult *loginResult)
+		{
+		}
+
+		static void Logoff(HANDLE hConnection, const char *token, const char *sessionId)
+		{
+			CMStringA data;
+			data.AppendFormat("access_token=%s", token);
+			data.AppendFormat("&umqid=%s", sessionId);
+
+			HttpRequest request(hConnection, REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/Logoff/v0001");
+			request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
+			request.SetData(data.GetBuffer(), data.GetLength());
+			
+			mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
 		}
 	};
 }
 
-
 #endif //_STEAM_LOGIN_H_
\ No newline at end of file
diff --git a/protocols/Steam/src/Steam/poll.h b/protocols/Steam/src/Steam/poll.h
index eec2e71453..c99bfecf0b 100644
--- a/protocols/Steam/src/Steam/poll.h
+++ b/protocols/Steam/src/Steam/poll.h
@@ -8,7 +8,8 @@ namespace SteamWebApi
 	public:
 		enum POOL_TYPE
 		{
-			MESSAGE = 0,
+			UNKNOWN = 0,
+			MESSAGE = 1,
 			TYPING = 2,
 			STATE = 3,
 			//POOL_TYPE_RELATIONSHIP = 4
@@ -25,6 +26,8 @@ namespace SteamWebApi
 			bool send;
 
 		public:
+			PoolItem() : timestamp(0), type(POOL_TYPE::UNKNOWN) { }
+
 			const char *GetSteamId() const { return steamId.c_str(); }
 			const DWORD GetTimestamp() const { return timestamp; }
 			POOL_TYPE GetType() const { return type; }
@@ -57,7 +60,7 @@ namespace SteamWebApi
 			const wchar_t *GetNickname() const { return nickname.c_str(); }
 		};
 
-		class Poll : public Result
+		class PollResult : public Result
 		{
 			friend PollApi;
 
@@ -66,23 +69,27 @@ namespace SteamWebApi
 			std::vector<PoolItem*> items;
 
 		public:
+			PollResult() : messageId(0) { }
+
 			UINT32 GetMessageId() const { return messageId; }
 			int GetItemCount() const { return items.size(); }
 			const PoolItem * operator[](int idx) const { return items.at(idx); }
 		};
 
-		static void PollStatus(HANDLE hConnection, const char *sessionId, const char *steamId, UINT32 messageId, Poll *poll)
+		static void PollStatus(HANDLE hConnection, const char *token, const char *sessionId, UINT32 messageId, PollResult *pollResult)
 		{
-			poll->success = false;
+			pollResult->success = false;
 
 			CMStringA data;
-			data.AppendFormat("steamid=%s", steamId);
+			data.AppendFormat("access_token=%s", token);
 			data.AppendFormat("&umqid=%s", sessionId);
-			data.AppendFormat("&message=%ui", messageId);
+			data.AppendFormat("&message=%i", messageId);
+			//data.Append("&sectimeout=30");
 
-			HttpRequest request(hConnection, REQUEST_POST, STEAM_API_URL "/ISteamWebUserPresenceOAuth/PollStatus/v0001");
+			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 = 35000;
 			
 			mir_ptr<NETLIBHTTPREQUEST> response(request.Send());
 			if (!response || response->resultCode != HTTP_STATUS_OK)
@@ -91,11 +98,21 @@ namespace SteamWebApi
 			JSONNODE *root = json_parse(response->pData), *node, *child;
 			node = json_get(root, "error");
 			ptrW error(json_as_string(node));
-			if (lstrcmpi(error, L"OK"))
+			/*if (!lstrcmpi(error, L"Not Logged On"))
+			{
+			}
+			else */
+			/*if (!lstrcmpi(error, L"Timeout"))
+			{
+				pollResult->messageId = messageId;
+				pollResult->success = true;
+				return;
+			}*/
+			else if (lstrcmpi(error, L"OK"))
 				return;
 
 			node = json_get(root, "messagelast");
-			poll->messageId = json_as_int(node);
+			pollResult->messageId = json_as_int(node);
 
 			node = json_get(root, "messages");
 			root = json_as_array(node);
@@ -107,12 +124,6 @@ namespace SteamWebApi
 					if (child == NULL)
 						break;
 
-					node = json_get(child, "steamid_from");
-					ptrA cSteamId(mir_u2a(json_as_string(node)));
-
-					node = json_get(child, "utc_timestamp");
-					DWORD timestamp = atol(ptrA(mir_u2a(json_as_string(node))));
-
 					PoolItem *item = NULL;
 
 					node = json_get(child, "type");
@@ -161,12 +172,18 @@ namespace SteamWebApi
 						int z = 0;
 					}
 
+					node = json_get(child, "steamid_from");
+					item->steamId = ptrA(mir_u2a(json_as_string(node)));
+
+					node = json_get(child, "utc_timestamp");
+					item->timestamp = atol(ptrA(mir_u2a(json_as_string(node))));
+
 					if (item != NULL)
-						poll->items.push_back(item);
+						pollResult->items.push_back(item);
 				}
 			}
 
-			poll->success = true;
+			pollResult->success = true;
 		}
 	};
 }
diff --git a/protocols/Steam/src/Steam/steam.h b/protocols/Steam/src/Steam/steam.h
index e035310755..fc23594dca 100644
--- a/protocols/Steam/src/Steam/steam.h
+++ b/protocols/Steam/src/Steam/steam.h
@@ -3,7 +3,8 @@
 
 namespace SteamWebApi
 {
-	#define STEAM_API_URL "https://api.steampowered.com"
+	#define STEAM_API_URL "https://api.steampowered.com:443"
+	#define STEAM_COMMUNITY_URL "https://steamcommunity.com"
 
 	struct Result
 	{
diff --git a/protocols/Steam/src/common.h b/protocols/Steam/src/common.h
index 9a106b3a47..34e155daa3 100644
--- a/protocols/Steam/src/common.h
+++ b/protocols/Steam/src/common.h
@@ -11,6 +11,9 @@
 #include <m_options.h>
 #include <m_popup.h>
 #include <m_json.h>
+//#include <m_skin.h>
+#include <m_icolib.h>
+#include <m_clist.h>
 #include <m_string.h>
 #include <m_freeimage.h>
 #include <m_protocols.h>
diff --git a/protocols/Steam/src/http_request.h b/protocols/Steam/src/http_request.h
index 3d433009e8..a065fec60e 100644
--- a/protocols/Steam/src/http_request.h
+++ b/protocols/Steam/src/http_request.h
@@ -16,7 +16,7 @@ enum HTTP_STATUS
 	HTTP_STATUS_INSUFICIENTE_STORAGE = 507*/
 };
 
-class HttpRequest : private NETLIBHTTPREQUEST//, public MZeroedObject
+class HttpRequest : public NETLIBHTTPREQUEST//, public MZeroedObject
 {
 public:
 	HttpRequest(HANDLE hNetlibUser, int request, LPCSTR url)
@@ -28,11 +28,13 @@ public:
 		dataLength = 0;
 		headersCount = 0;
 		szResultDescr = NULL;
-		flags = NLHRF_HTTP11;
+		flags = NLHRF_HTTP11 | NLHRF_SSL;
 		requestType = request;
 
 		m_hNetlibUser = hNetlibUser;
 		m_szUrl = mir_strdup(url);
+
+		AddHeader("User-Agent", "Steam App / Miranda / 0.0.1");
 	}
 
 	~HttpRequest()
diff --git a/protocols/Steam/src/resource.h b/protocols/Steam/src/resource.h
index 0d895c56fe..648047d1bc 100644
--- a/protocols/Steam/src/resource.h
+++ b/protocols/Steam/src/resource.h
@@ -1,6 +1,6 @@
 //{{NO_DEPENDENCIES}}
 // Microsoft Visual C++ generated include file.
-// Used by e:\Projects\C++\MirandaNG\protocols\Steam\res\Resource.rc
+// Used by d:\Projects\CPlusPlus\MirandaNG\protocols\Steam\res\Resource.rc
 //
 #define IDD_ACCMGR                      9
 #define IDD_OPT_MAIN                    10
@@ -23,6 +23,8 @@
 #define IDC_GROUP                       1021
 #define IDC_BM_LIST                     1064
 #define IDC_TEXT                        1082
+#define IDC_OPENDOMAIN                  1200
+#define IDC_GETDOMAIN                   1200
 
 // Next default values for new objects
 // 
diff --git a/protocols/Steam/src/steam_account.cpp b/protocols/Steam/src/steam_account.cpp
index 8f9b932347..a08926cff3 100644
--- a/protocols/Steam/src/steam_account.cpp
+++ b/protocols/Steam/src/steam_account.cpp
@@ -1,51 +1,64 @@
 #include "common.h"
 
-void CSteamProto::LogInThread(void* param)
+bool CSteamProto::IsOnline()
 {
-	CMStringA token(getStringA("TokenSecret"));
-	if (token.IsEmpty())
-	{
-		ptrW username(getWStringA("Username"));
-		ptrA password(getStringA("Password"));
+	return m_iStatus > ID_STATUS_OFFLINE;
+}
 
-		SteamWebApi::AuthorizationApi::Authorization authResult;
-		SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, &authResult);
-	
-		if (authResult.IsEmailAuthNeeded()/* || authResult.captcha_needed*/)
+void CSteamProto::Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResult)
+{
+	ptrW username(getWStringA("Username"));
+	ptrA password(getStringA("Password"));
+
+	// try to authorize
+	SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, authResult);
+	if (authResult->IsEmailAuthNeeded() || authResult->IsCaptchaNeeded())
+	{
+		do
 		{
-			do
+			if (authResult->IsEmailAuthNeeded())
 			{
-				if (authResult.IsEmailAuthNeeded())
-				{
-					GuardParam guard;
+				GuardParam guard;
 
-					//lstrcpy(guard.emailDomain, authResult.emaildomain);
+				lstrcpyA(guard.domain, authResult->GetEmailDomain());
 
-					if (DialogBoxParam(
-						g_hInstance,
-						MAKEINTRESOURCE(IDD_GUARD),
-						NULL,
-						CSteamProto::GuardProc,
-						(LPARAM)&guard) != 1)
-						break;
+				if (DialogBoxParam(
+					g_hInstance,
+					MAKEINTRESOURCE(IDD_GUARD),
+					NULL,
+					CSteamProto::GuardProc,
+					(LPARAM)&guard) != 1)
+					break;
 
-					authResult.SetAuthCode(guard.code);
-				}
-
-				//if (result->captcha_needed)
-				//	;// proto->fail
-
-				SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, &authResult);
+				authResult->SetAuthCode(guard.code);
+			}
+				
+			if (authResult->IsCaptchaNeeded())
+			{
+				// todo: show captcha dialog
+			}
 
-			} while (authResult.IsEmailAuthNeeded()/* || auth->captcha_needed*/);
-		}
+			// try to authorize with emailauthcode or captcha taxt
+			SteamWebApi::AuthorizationApi::Authorize(m_hNetlibUser, username, password, authResult);
+		} while (authResult->IsEmailAuthNeeded() || authResult->IsCaptchaNeeded());
+	}
+}
 
+void CSteamProto::LogInThread(void* param)
+{
+	CMStringA token(getStringA("TokenSecret"));
+	if (token.IsEmpty()/* && !this->IsOnline()*/)
+	{
+		SteamWebApi::AuthorizationApi::AuthResult authResult;
+		Authorize(&authResult);
+		// if some error
 		if (!authResult.IsSuccess())
 		{
+			// todo: dosplay error message from authResult.GetMessage()
+			//ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID);
 			m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
 			ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, ID_STATUS_OFFLINE);
 			return;
-			ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID);
 		}
 
 		token = authResult.GetToken();
@@ -53,30 +66,35 @@ void CSteamProto::LogInThread(void* param)
 		setString("SteamID", authResult.GetSteamid());
 	}
 
-	SteamWebApi::LogInApi::LogIn login;
-	SteamWebApi::LogInApi::LogOn(m_hNetlibUser, token, &login);
-
-	if (!login.IsSuccess())
+	SteamWebApi::LoginApi::LoginResult loginResult;
+	SteamWebApi::LoginApi::Logon(m_hNetlibUser, token, &loginResult);
+	// if some error
+	if (!loginResult.IsSuccess())
 	{
+		// 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", login.GetSessionId());
-	setDword("MessageID", login.GetMessageId());
-
-	m_iStatus = m_iDesiredStatus;
-	ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iDesiredStatus);
-
+	// start pooling thread
 	if (m_hPollingThread == NULL && !m_bTerminated)
 	{
 		m_bTerminated = false;
 		m_hPollingThread = ForkThreadEx(&CSteamProto::PollingThread, NULL, NULL);
 	}
 
+	// get contact list
 	SteamWebApi::FriendListApi::FriendList friendList;
-	SteamWebApi::FriendListApi::Load(m_hNetlibUser, token, login.GetSteamId(), &friendList);
+	SteamWebApi::FriendListApi::Load(m_hNetlibUser, token, loginResult.GetSteamId(), &friendList);
 	
 	if (friendList.IsSuccess())
 	{
@@ -91,4 +109,14 @@ void CSteamProto::LogInThread(void* param)
 			}
 		}
 	}
+}
+
+void CSteamProto::LogOutThread(void*)
+{
+	ptrA token(getStringA("TokenSecret"));
+	ptrA sessionId(getStringA("SessionID"));
+
+	SteamWebApi::LoginApi::Logoff(m_hNetlibUser, token, sessionId);
+
+	delSetting("SessionID");
 }
\ No newline at end of file
diff --git a/protocols/Steam/src/steam_contacts.cpp b/protocols/Steam/src/steam_contacts.cpp
index 8929d25bec..ab95bf4649 100644
--- a/protocols/Steam/src/steam_contacts.cpp
+++ b/protocols/Steam/src/steam_contacts.cpp
@@ -31,520 +31,13 @@ MCONTACT CSteamProto::AddContact(const SteamWebApi::FriendApi::Friend &contact)
 		this->setString(hContact, "Homepage", contact.GetHomepage());
 		this->setDword(hContact, "LastEventDateTS", contact.GetLastEvent());
 
-		/*DBVARIANT dbv;
-		if ( !this->getTString(SKYPE_SETTINGS_DEF_GROUP, &dbv))
+		DBVARIANT dbv;
+		if (!getWString("DefaultGroup", &dbv))
 		{
-			::db_set_ts(hContact, "CList", "Group", dbv.ptszVal);
-			::db_free(&dbv);
-		}*/
+			db_set_ts(hContact, "CList", "Group", dbv.ptszVal);
+			db_free(&dbv);
+		}
 	}
 
 	return hContact;
-}
-
-//void CSteamProto::OnContactListLoadedAsync(Steam::FriendList::Result *friendList)
-//{
-//	if (friendList->success)
-//	{
-//		for (int i = 0; i < friendList->friendIds.getCount(); i++)
-//		{
-//			if (!FindContact(friendList->friendIds[i]))
-//			{
-//				Steam::Friend::Result rFriend;
-//				Steam::Friend(m_hNetlibUser)
-//					.LoadSummaries(friendList->friendIds[i], &rFriend);
-//				if (!rFriend.success) continue;
-//				AddContact(rFriend);
-//			}
-//		}
-//	}
-//}
-
-//void CSkypeProto::UpdateContactAuthState(MCONTACT hContact, const ContactRef &contact)
-//{
-//	uint newTS = 0;
-//	contact->GetPropAuthreqTimestamp(newTS);
-//	DWORD oldTS = this->getDword("AuthTS", 0);
-//	if (newTS > oldTS)
-//	{
-//		bool result;
-//		if (contact->HasAuthorizedMe(result) && !result)
-//			this->setByte(hContact, "Auth", !result);
-//		else
-//		{
-//			this->delSetting(hContact, "Auth");
-//			if (contact->IsMemberOfHardwiredGroup(CContactGroup::ALL_BUDDIES, result) && !result)
-//				this->setByte(hContact, "Grant", !result);
-//			else
-//				this->delSetting(hContact, "Grant");
-//		}
-//
-//		this->setDword(hContact, "AuthTS", newTS);
-//	}
-//}
-//
-//void CSkypeProto::UpdateContactStatus(MCONTACT hContact, const ContactRef &contact)
-//{
-//	Contact::AVAILABILITY availability;
-//	contact->GetPropAvailability(availability);
-//	this->setWord(hContact, SKYPE_SETTINGS_STATUS, CSkypeProto::SkypeToMirandaStatus(availability));
-//
-//	if (availability == Contact::SKYPEOUT)
-//		this->setWord(hContact, SKYPE_SETTINGS_STATUS, ID_STATUS_ONTHEPHONE);
-//	else
-//	{
-//		if (availability == Contact::PENDINGAUTH)
-//			this->setByte(hContact, "Auth", 1);
-//		else
-//			this->delSetting(hContact, "Auth");
-//	}
-//}
-//
-//void CSkypeProto::UpdateContactClient(MCONTACT hContact, const ContactRef &contact)
-//{
-//	bool isMobile = false;
-//	contact->HasCapability(Contact::CAPABILITY_MOBILE_DEVICE, isMobile/*, true*/);
-//
-//	this->setTString(hContact, "MirVer", isMobile ? L"SkypeMobile" : L"Skype");
-//}
-//
-//void CSkypeProto::UpdateContactOnlineSinceTime(MCONTACT hContact, const ContactRef &contact)
-//{
-//	uint newTS = 0;
-//	contact->GetPropLastonlineTimestamp(newTS);
-//	DWORD oldTS = ::db_get_dw(hContact, this->m_szModuleName, "OnlineSinceTS", 0);
-//	if (newTS > oldTS)
-//		this->setDword(hContact, "OnlineSinceTS", newTS);
-//}
-//
-//void CSkypeProto::UpdateContactLastEventDate(MCONTACT hContact, const ContactRef &contact)
-//{
-//	uint newTS = 0;
-//	contact->GetPropLastusedTimestamp(newTS);
-//	DWORD oldTS = this->getDword(hContact, "LastEventDateTS", 0);
-//	if (newTS > oldTS)
-//		this->setDword(hContact, "LastEventDateTS", newTS);
-//}
-//
-//void CSkypeProto::OnContactChanged(const ContactRef &contact, int prop)
-//{
-//	SEString data;
-//	contact->GetPropSkypename(data);
-//	wchar_t *sid = ::mir_utf8decodeW(data);
-//	MCONTACT hContact = this->GetContactBySid(sid);
-//	::mir_free(sid);
-//
-//	SEObject *contactObj = contact.fetch();
-//
-//	if (hContact)
-//	{
-//		switch(prop)
-//		{
-//		case Contact::P_AUTHREQ_TIMESTAMP:
-//			{
-//				uint newTS = 0;
-//				contact->GetPropAuthreqTimestamp(newTS);
-//				DWORD oldTS = this->getDword(hContact, "AuthTS", 0);
-//				if (newTS > oldTS)
-//					this->RaiseAuthRequestEvent(newTS, contact);
-//			}
-//			break;
-//
-//		case Contact::P_AUTHREQUEST_COUNT:
-//			// todo: all authrequests after first should be catch here
-//			this->UpdateContactAuthState(hContact, contact);
-//			break;
-//
-//		case Contact::P_AVAILABILITY:
-//			this->UpdateContactStatus(hContact, contact);
-//			this->UpdateChatUserStatus(contact);
-//			break;
-//
-//		//case CContact::P_AVATAR_IMAGE:
-//		case Contact::P_AVATAR_TIMESTAMP:
-//			this->UpdateProfileAvatar(contactObj, hContact);
-//			break;
-//
-//		//case CContact::P_MOOD_TEXT:
-//		case Contact::P_MOOD_TIMESTAMP:
-//			this->UpdateProfileStatusMessage(contactObj, hContact);
-//			break;
-//
-//		case Contact::P_FULLNAME:
-//			this->UpdateChatUserNick(contact);
-//			break;
-//
-//		case Contact::P_PROFILE_TIMESTAMP:
-//			this->UpdateProfile(contactObj, hContact);
-//			break;
-//		}
-//	}
-//}
-//
-//void CSkypeProto::OnContactListChanged(const ContactRef &contact)
-//{
-//	bool result;
-//
-//	contact->IsMemberOfHardwiredGroup(CContactGroup::ALL_BUDDIES, result);
-//	if (result)
-//	{
-//		if ( !this->contactList.contains(contact))
-//		{
-//			CContact::Ref newContact(contact);
-//			this->contactList.append(newContact);
-//			newContact.fetch();
-//		}
-//	}
-//
-//	contact->IsMemberOfHardwiredGroup(CContactGroup::CONTACTS_WAITING_MY_AUTHORIZATION, result);
-//	if (result)
-//	{
-//		SEString data;
-//
-//		uint newTS = 0;
-//		contact->GetPropAuthreqTimestamp(newTS);
-//
-//		this->RaiseAuthRequestEvent(newTS, contact);
-//	}
-//}
-//
-//bool CSkypeProto::IsProtoContact(MCONTACT hContact)
-//{
-//	return ::lstrcmpiA(::GetContactProto(hContact), this->m_szModuleName) == 0;
-//}
-//
-//MCONTACT CSkypeProto::GetContactBySid(const wchar_t *sid)
-//{
-//	MCONTACT hContact = NULL;
-//
-//	::EnterCriticalSection(&this->contact_search_lock);
-//
-//	for (hContact = ::db_find_first(this->m_szModuleName); hContact; hContact = ::db_find_next(hContact, this->m_szModuleName))
-//	{
-//		ptrW contactSid(::db_get_wsa(hContact, this->m_szModuleName, SKYPE_SETTINGS_SID));
-//		if (::lstrcmpi(contactSid, sid) == 0)
-//			break;
-//	}
-//
-//	::LeaveCriticalSection(&this->contact_search_lock);
-//
-//	return hContact;
-//}
-//
-//MCONTACT CSkypeProto::GetContactFromAuthEvent(HANDLE hEvent)
-//{
-//	// db_event_getContact
-//	DWORD body[3];
-//	DBEVENTINFO dbei = { sizeof(DBEVENTINFO) };
-//	dbei.cbBlob = sizeof(DWORD) * 2;
-//	dbei.pBlob = (PBYTE)&body;
-//
-//	if (::db_event_get(hEvent, &dbei))
-//		return INVALID_CONTACT_ID;
-//
-//	if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
-//		return INVALID_CONTACT_ID;
-//
-//	if (strcmp(dbei.szModule, this->m_szModuleName) != 0)
-//		return INVALID_CONTACT_ID;
-//
-//	return ::DbGetAuthEventContact(&dbei);
-//}
-//
-//
-//void __cdecl CSkypeProto::LoadContactList(void* data)
-//{
-//	this->debugLogW(L"Updating contacts list");
-//
-//	bool isFirstLoad = data != NULL;
-//
-//	this->GetHardwiredContactGroup(CContactGroup::ALL_BUDDIES, this->commonList);
-//	this->commonList.fetch();
-//
-//	this->commonList->GetContacts(this->contactList);
-//	fetch(this->contactList);
-//	for (uint i = 0; i < this->contactList.size(); i++)
-//	{
-//		CContact::Ref contact = this->contactList[i];
-//
-//		MCONTACT hContact = this->AddContact(contact);
-//
-//		if ( !isFirstLoad)
-//		{
-//			// todo: move to AddContact?
-//			this->UpdateContactAuthState(hContact, contact);
-//			this->UpdateContactStatus(hContact, contact);
-//
-//			ptrW nick( ::db_get_wsa(hContact, "CList", "MyHandle"));
-//			if ( !nick || !::wcslen(nick))
-//			{
-//				nick = ::mir_utf8decodeW(contact->GetNick());
-//				::db_set_ws(hContact, "CList", "MyHandle", nick);
-//			}
-//
-//			this->UpdateProfile(contact.fetch(), hContact);
-//		}
-//	}
-//}
-//
-//void __cdecl CSkypeProto::LoadAuthWaitList(void*)
-//{
-//	CContact::Refs authContacts;
-//	this->GetHardwiredContactGroup(CContactGroup::CONTACTS_WAITING_MY_AUTHORIZATION, this->authWaitList);
-//	this->authWaitList.fetch();
-//
-//	this->authWaitList->GetContacts(authContacts);
-//	for (uint i = 0; i < authContacts.size(); i++)
-//	{
-//		CContact::Ref contact = authContacts[i];
-//
-//		uint newTS = 0;
-//		contact->GetPropAuthreqTimestamp(newTS);
-//
-//		this->RaiseAuthRequestEvent(newTS, contact);
-//	}
-//}
-//
-//bool CSkypeProto::IsContactOnline(MCONTACT hContact)
-//{
-//	return this->getWord(hContact, SKYPE_SETTINGS_STATUS, ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE;
-//}
-//
-//void CSkypeProto::SetAllContactStatus(int status)
-//{
-//	::EnterCriticalSection(&this->contact_search_lock);
-//
-//	for (MCONTACT hContact = ::db_find_first(this->m_szModuleName); hContact; hContact = ::db_find_next(hContact, this->m_szModuleName))
-//	{
-//		if (this->getByte(hContact, "IsSkypeOut", 0) != 0)
-//			continue;
-//		if (this->isChatRoom(hContact))
-//			continue;
-//		if (this->IsContactOnline(hContact))
-//			::db_set_w(hContact, this->m_szModuleName, SKYPE_SETTINGS_STATUS, status);
-//	}
-//
-//	::LeaveCriticalSection(&this->contact_search_lock);
-//}
-//
-//void CSkypeProto::OnSearchCompleted(HANDLE hSearch)
-//{
-//	this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_SUCCESS, hSearch, 0);
-//}
-//
-//void CSkypeProto::OnContactFinded(CContact::Ref contact, HANDLE hSearch)
-//{
-//	PROTOSEARCHRESULT psr = {0};
-//	psr.cbSize = sizeof(psr);
-//	psr.flags = PSR_TCHAR;
-//
-//	SEString data;
-//	contact->GetPropSkypename(data);
-//	psr.id = ::mir_utf8decodeW(data);
-//	contact->GetPropDisplayname(data);
-//	psr.nick  = ::mir_utf8decodeW(data);
-//
-//	SEString firstName, lastName;
-//	contact->GetFullname(firstName, lastName);
-//	psr.firstName = ::mir_utf8decodeW(firstName);
-//	psr.lastName = ::mir_utf8decodeW(lastName);
-//
-//	{
-//		contact->GetPropEmails(data);
-//		mir_ptr<wchar_t> emails( ::mir_utf8decodeW(data));
-//
-//		wchar_t* main = ::wcstok(emails, L" ");
-//		if (main != NULL)
-//		{
-//			psr.email = main;
-//		}
-//	}
-//
-//	this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_DATA, hSearch, (LPARAM)&psr);
-//}
-//
-//void __cdecl CSkypeProto::SearchBySidAsync(void* arg)
-//{
-//	mir_ptr<wchar_t> sid((wchar_t*)arg);
-//
-//	MCONTACT hContact = this->GetContactBySid(sid);
-//	if (hContact)
-//	{
-//		this->ShowNotification(TranslateT("Contact already in your contact list"), 0, hContact);
-//		this->SendBroadcast(ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)SKYPE_SEARCH_BYSID, 0);
-//		return;
-//	}
-//
-//	CContactSearch::Ref search;
-//	this->CreateIdentitySearch(::mir_u2a(sid), search);
-//	search.fetch();
-//	search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYSID);
-//
-//	bool valid;
-//	if (!search->IsValid(valid) || !valid || !search->Submit())
-//		return;
-//
-//	search->BlockWhileSearch();
-//	search->Release();
-//}
-//
-//void __cdecl CSkypeProto::SearchByEmailAsync(void* arg)
-//{
-//	mir_ptr<wchar_t> email((wchar_t *)arg);
-//
-//	CContactSearch::Ref search;
-//	this->CreateContactSearch(search);
-//	search.fetch();
-//	search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYEMAIL);
-//
-//	bool valid;
-//	if (!search->AddEmailTerm(::mir_u2a(email), valid) || !valid || !search->Submit())
-//		return; 
-//
-//	search->BlockWhileSearch();
-//	search->Release();
-//}
-//
-//void __cdecl CSkypeProto::SearchByNamesAsync(void* arg)
-//{
-//	//todo: write me
-//	PROTOSEARCHRESULT *psr = (PROTOSEARCHRESULT *)arg;
-//
-//	std::string nick = ::mir_utf8encodeW(psr->nick);
-//	std::string fName = ::mir_utf8encodeW(psr->firstName);
-//	std::string lName = " "; lName += ::mir_utf8encodeW(psr->lastName);
-//
-//	CContactSearch::Ref search;
-//	this->CreateContactSearch(search);
-//	search.fetch();
-//	search->SetProtoInfo((HANDLE)SKYPE_SEARCH_BYNAMES);
-//
-//	bool valid;
-//	if (nick.length() != 0)
-//	{
-//		search->AddStrTerm(
-//			Contact::P_FULLNAME,
-//			CContactSearch::CONTAINS_WORD_PREFIXES,
-//			nick.c_str(), 
-//			valid,
-//			true);
-//	}
-//	if (fName.length() != 0)
-//	{
-//		search->AddOr();
-//		search->AddStrTerm(
-//			Contact::P_FULLNAME,
-//			CContactSearch::CONTAINS_WORD_PREFIXES,
-//			fName.c_str(), 
-//			valid,
-//			true);
-//	}
-//	if (lName.length() != 0)
-//	{		
-//		search->AddOr();
-//		search->AddStrTerm(
-//			Contact::P_FULLNAME,
-//			CContactSearch::CONTAINS_WORD_PREFIXES,
-//			lName.c_str(), 
-//			valid,
-//			true);
-//	}
-//
-//	if (!search->Submit())
-//		return; 
-//
-//	search->BlockWhileSearch();
-//	search->Release();
-//}
-//
-//void CSkypeProto::OnContactsReceived(const ConversationRef &conversation, const MessageRef &message)
-//{
-//	CContact::Refs contacts;
-//	message->GetContacts(contacts);
-//
-//	uint timestamp;
-//	message->GetPropTimestamp(timestamp);
-//
-//	CMessage::TYPE messageType;
-//	message->GetPropType(messageType);
-//
-//	SEString data;
-//	message->GetPropAuthor(data);			
-//		
-//	CContact::Ref author;
-//	this->GetContact(data, author);
-//
-//	MCONTACT hContact = this->AddContact(author);
-//
-//	SEBinary guid;
-//	message->GetPropGuid(guid);
-//	ReadMessageParam param = { guid, messageType };
-//
-//	PROTORECVEVENT pre = { 0 };
-//	pre.flags = PREF_UTF;
-//	pre.lParam = (LPARAM)&param;
-//	pre.timestamp = timestamp;
-//
-//	int msgSize = 1;
-//	pre.szMessage = (char *)::mir_alloc(msgSize);
-//	pre.szMessage[0] = 0;
-//
-//	int len = 0;
-//	char* pCur = &pre.szMessage[0];
-//
-//	for (size_t i = 0; i < contacts.size(); i ++)
-//	{
-//		contacts[i]->GetIdentity(data);
-//		if ( ::lstrcmpi(mir_ptr<wchar_t>(::mir_utf8decodeW(data)), this->login) != 0)
-//			this->AddContact(contacts[i]);
-//	}
-//
-//	char *text = ::mir_utf8encode(::Translate("Contacts received"));
-//
-//	this->AddDBEvent(
-//		hContact,
-//		SKYPE_DB_EVENT_TYPE_CONTACTS,
-//		timestamp,
-//		PREF_UTF,
-//		(DWORD)::strlen(text) + 1,
-//		(PBYTE)text);
-//}
-//
-//void CSkypeProto::OnContactsSent(const ConversationRef &conversation, const MessageRef &message)
-//{
-//	SEString data;
-//
-//	CMessage::TYPE messageType;
-//	message->GetPropType(messageType);
-//
-//	uint timestamp;
-//	message->GetPropTimestamp(timestamp);
-//
-//	CMessage::SENDING_STATUS status;
-//	message->GetPropSendingStatus(status);
-//
-//	CParticipant::Refs participants;
-//	conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS);
-//	participants[0]->GetPropIdentity(data);
-//		
-//	CContact::Ref receiver;
-//	this->GetContact(data, receiver);
-//
-//	MCONTACT hContact = this->AddContact(receiver);
-//	this->SendBroadcast(
-//		hContact,
-//		ACKTYPE_CONTACTS,
-//		status == CMessage::FAILED_TO_SEND ? ACKRESULT_FAILED : ACKRESULT_SUCCESS,
-//		(HANDLE)message->getOID(), 0);
-//}
-//
-//void CSkypeProto::OnContactsEvent(const ConversationRef &conversation, const MessageRef &message)
-//{
-//	SEString author;
-//	message->GetPropAuthor(author);
-//			
-//	if (::wcsicmp(mir_ptr<wchar_t>(::mir_utf8decodeW(author)), this->login) == 0)
-//		this->OnContactsSent(conversation, message);
-//	else
-//		this->OnContactsReceived(conversation, message);
-//}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/protocols/Steam/src/steam_dialogs.cpp b/protocols/Steam/src/steam_dialogs.cpp
index a0f79d3744..c98f3c1eda 100644
--- a/protocols/Steam/src/steam_dialogs.cpp
+++ b/protocols/Steam/src/steam_dialogs.cpp
@@ -15,10 +15,19 @@ INT_PTR CALLBACK CSteamProto::GuardProc(HWND hwnd, UINT message, WPARAM wParam,
 		{
 			guard = (GuardParam*)lParam;
 			SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+			// load steam icon
+			char iconName[100];
+			mir_snprintf(iconName, SIZEOF(iconName), "%s_%s", MODULE, "main");
+			SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)Skin_GetIcon(iconName, 16));
+			SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)Skin_GetIcon(iconName, 32));
 		}
+		Utils_RestoreWindowPositionNoSize(hwnd, 0, "STEAM", "GuardWindow");
 		return TRUE;
 
 	case WM_CLOSE:
+		Skin_ReleaseIcon((HICON)SendMessage(hwnd, WM_SETICON, ICON_BIG, 0));
+		Skin_ReleaseIcon((HICON)SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0));
+		Utils_SaveWindowPosition(hwnd, NULL, "STEAM", "GuardWindow");
 		EndDialog(hwnd, 0);
 		break;
 
@@ -26,6 +35,11 @@ INT_PTR CALLBACK CSteamProto::GuardProc(HWND hwnd, UINT message, WPARAM wParam,
 	{
 		switch (LOWORD(wParam))
 		{
+		case IDC_GETDOMAIN:
+			CallService(MS_UTILS_OPENURL, 0, (LPARAM)guard->domain);
+			SetFocus(GetDlgItem(hwnd, IDC_TEXT));
+			break;
+
 		case IDOK:
 			GetDlgItemTextA(hwnd, IDC_TEXT, guard->code, sizeof(guard->code));
 			EndDialog(hwnd, IDOK);
@@ -198,13 +212,16 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP
 			ptrA password(proto->getStringA("Password"));
 			SetDlgItemTextA(hwnd, IDC_PASSWORD, password);
 
-			/*if (proto->IsOnline())
-				EnableWindow(GetDlgItem(hwnd, IDC_GROUP), FALSE);
-
-			SendDlgItemMessage(hwnd, IDC_GROUP, EM_LIMITTEXT, SKYPE_GROUP_NAME_LIMIT, 0);
+			ptrW groupName(proto->getWStringA(NULL, "DefaultGroup"));
+			SetDlgItemText(hwnd, IDC_GROUP, groupName);
+			SendDlgItemMessage(hwnd, IDC_GROUP, EM_LIMITTEXT, 64, 0);
 
-			ptrW defgroup( db_get_wsa(NULL, proto->m_szModuleName, SKYPE_SETTINGS_DEF_GROUP));
-			SetDlgItemText(hwnd, IDC_GROUP, defgroup);*/
+			if (proto->IsOnline())
+			{
+				EnableWindow(GetDlgItem(hwnd, IDC_USERNAME), FALSE);
+				EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD), FALSE);
+				EnableWindow(GetDlgItem(hwnd, IDC_GROUP), FALSE);
+			}
 		}
 		return TRUE;
 
@@ -215,12 +232,9 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP
 			case IDC_USERNAME:
 				{
 					if ((HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0;
-
-					//if (/*!proto->IsOnline() && */db_get_w(NULL, proto->m_szModuleName, "Status", ID_STATUS_OFFLINE) <= ID_STATUS_OFFLINE)
-					/*{
-						char username[128];
-						GetDlgItemTextA(hwnd, IDC_USERNAME, username, SIZEOF(username));
-					}*/
+					proto->delSetting("SteamID");
+					wchar_t username[128];
+					GetDlgItemText(hwnd, IDC_USERNAME, username, SIZEOF(username));
 					SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
 				}
 				break;
@@ -228,48 +242,47 @@ INT_PTR CALLBACK CSteamProto::MainOptionsProc(HWND hwnd, UINT message, WPARAM wP
 			case IDC_PASSWORD:
 				{
 					if ((HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0;
-					//if (proto->IsOnline())
-					/*{
-						char password[128];
-						GetDlgItemTextA(hwnd, IDC_PASSWORD, password, SIZEOF(password));
-					}*/
+					proto->delSetting("TokenSecret");
+					char password[128];
+					GetDlgItemTextA(hwnd, IDC_PASSWORD, password, SIZEOF(password));
 					SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
 				}
 				break;
 
-			/*case IDC_GROUP:
+			case IDC_GROUP:
 				{
 					if ((HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()))
 						return 0;
 					SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
 				}
-				break;*/
+				break;
 			}
 		}
 		break;
 
 	case WM_NOTIFY:
-		if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY/* && !proto->IsOnline()*/)
+		if (reinterpret_cast<NMHDR*>(lParam)->code == PSN_APPLY)
 		{
-			wchar_t username[128];
-			GetDlgItemText(hwnd, IDC_USERNAME, username, SIZEOF(username));
-			proto->setWString("Username", username);
-			/*mir_free(proto->login);
-			proto->login = ::mir_wstrdup(sid);*/
-
-			char password[128];
-			GetDlgItemTextA(hwnd, IDC_PASSWORD, password, SIZEOF(password));
-			proto->setString("Password", password);
-
-			/*wchar_t tstr[128];
-			GetDlgItemText(hwnd, IDC_GROUP, tstr, SIZEOF(tstr));
-			if (lstrlen(tstr) > 0)
+			if (!proto->IsOnline())
 			{
-				::db_set_ts(NULL, proto->m_szModuleName, SKYPE_SETTINGS_DEF_GROUP, tstr);
-				::Clist_CreateGroup(0, tstr);
+				wchar_t username[128];
+				GetDlgItemText(hwnd, IDC_USERNAME, username, SIZEOF(username));
+				proto->setWString("Username", username);
+
+				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");
 			}
-			else
-				::db_unset(NULL, proto->m_szModuleName, SKYPE_SETTINGS_DEF_GROUP);*/
 
 			return TRUE;
 		}
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp
index 187b9f577b..97a11c8d62 100644
--- a/protocols/Steam/src/steam_proto.cpp
+++ b/protocols/Steam/src/steam_proto.cpp
@@ -6,6 +6,26 @@ CSteamProto::CSteamProto(const char* protoName, const TCHAR* userName) :
 	CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
 
 	InitializeCriticalSection(&this->contact_search_lock);
+
+	// icons
+	wchar_t filePath[MAX_PATH];
+	GetModuleFileName(g_hInstance, filePath, MAX_PATH);
+
+	wchar_t sectionName[100];
+	mir_sntprintf(sectionName, SIZEOF(sectionName), _T("%s/%s"), LPGENT("Protocols"), LPGENT(MODULE));
+
+	char settingName[100];
+	mir_snprintf(settingName, SIZEOF(settingName), "%s_%s", MODULE, "main");
+
+	SKINICONDESC sid = {0};
+	sid.cbSize = sizeof(SKINICONDESC);
+	sid.flags = SIDF_ALL_TCHAR;
+	sid.ptszDefaultFile = filePath;
+	sid.pszName = settingName;
+	sid.ptszSection = sectionName;
+	sid.ptszDescription = LPGENT("Protocol icon");
+	sid.iDefaultIndex = -IDI_STEAM;
+	Skin_AddIcon(&sid);
 }
 
 CSteamProto::~CSteamProto()
@@ -149,6 +169,8 @@ int CSteamProto::SetStatus(int new_status)
 	{
 		m_bTerminated = true;
 
+		ForkThread(&CSteamProto::LogOutThread, NULL);
+
 		m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
 		ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
 
@@ -164,17 +186,12 @@ int CSteamProto::SetStatus(int new_status)
 	{
 		if (old_status == ID_STATUS_OFFLINE/* && !this->IsOnline()*/)
 		{
-
 			m_iStatus = ID_STATUS_CONNECTING;
 			ForkThread(&CSteamProto::LogInThread, NULL);
-
-				//ptrA steamId(getStringA("SteamID"));
-				//Steam::FriendList(m_hNetlibUser/*, token*/)
-				//	.LoadAsync(steamId, CallbackConverter<Steam::FriendList::Result, &CSteamProto::OnContactListLoadedAsync>, this);
 		}
 		else
 		{
-			/*if ( this->account->IsOnline())
+			/*if (IsOnline())
 			{
 				SetServerStatus(new_status);
 				return 0;
diff --git a/protocols/Steam/src/steam_proto.h b/protocols/Steam/src/steam_proto.h
index 3a742a66b3..853654fd37 100644
--- a/protocols/Steam/src/steam_proto.h
+++ b/protocols/Steam/src/steam_proto.h
@@ -1,27 +1,18 @@
 #ifndef _STEAM_PROTO_H_
 #define _STEAM_PROTO_H_
 
-struct CaptchaParam
-{
-	BYTE *data;
-	size_t size;
-	char text[10];
-};
-
 struct GuardParam
 {
-	wchar_t emailDomain[32];
 	char code[10];
+	char domain[32];
 };
 
-template<typename T, void (CSteamProto::*Callback)(T*)>
-void CallbackConverter(void *owner, void *arg)
+struct CaptchaParam
 {
-	T *typedArg = (T*)arg;
-	CSteamProto *proto = (CSteamProto*)owner;
-	if (owner != NULL)
-		(proto->*Callback)(typedArg);
-}
+	BYTE *data;
+	size_t size;
+	char text[10];
+};
 
 class CSteamProto : public PROTO<CSteamProto>
 {
@@ -91,16 +82,18 @@ protected:
 	static int CompareProtos(const CSteamProto *p1, const CSteamProto *p2);
 
 	// pooling thread
-	int PollStatus();
+	int PollStatus(const char *sessionId, const char *steamId, UINT32 messageId);
 	void __cdecl PollingThread(void*);
 
 	// account
+	bool IsOnline();
+	void Authorize(SteamWebApi::AuthorizationApi::AuthResult *authResult);
 	void __cdecl LogInThread(void*);
+	void __cdecl LogOutThread(void*);
 
 	// contacts
 	MCONTACT FindContact(const char *steamId);
 	MCONTACT AddContact(const SteamWebApi::FriendApi::Friend &contact);
-	//void OnContactListLoadedAsync(Steam::FriendList::Result *result);
 
 	//events
 	int OnModulesLoaded(WPARAM, LPARAM);
diff --git a/protocols/Steam/src/steam_thread.cpp b/protocols/Steam/src/steam_thread.cpp
index 42b2af3903..d1c6d8a3c0 100644
--- a/protocols/Steam/src/steam_thread.cpp
+++ b/protocols/Steam/src/steam_thread.cpp
@@ -24,52 +24,56 @@ int SteamToMirandaStatus(int state)
 }
 
 
-int CSteamProto::PollStatus()
+int CSteamProto::PollStatus(const char *sessionId, const char *steamId, UINT32 messageId)
 {
-	ptrA steamId(getStringA("SteamID"));
-	ptrA sessionId(getStringA("SessionID"));
-	ptrA messageId(getStringA("MessageID"));
-
-	SteamWebApi::PollApi::Poll poll;
-	SteamWebApi::PollApi::PollStatus(m_hNetlibUser, sessionId, steamId, messageId, &poll);
+	SteamWebApi::PollApi::PollResult pollResult;
+	SteamWebApi::PollApi::PollStatus(m_hNetlibUser, sessionId, steamId, messageId, &pollResult);
 
-	if (!poll.IsSuccess())
-		return -1;
+	if (!pollResult.IsSuccess())
+		return 0;
 
-	//setString
-
-	for (int i = 0; i < poll.GetItemCount(); i++)
+	for (int i = 0; i < pollResult.GetItemCount(); i++)
 	{
-		switch (poll[i]->GetType())
+		switch (pollResult[i]->GetType())
 		{
 		case SteamWebApi::PollApi::POOL_TYPE::TYPING:
 			break;
 
 		case SteamWebApi::PollApi::POOL_TYPE::MESSAGE:
 			{
-				const wchar_t *text = ((SteamWebApi::PollApi::Message*)poll[i])->GetText();
+				const wchar_t *text = ((SteamWebApi::PollApi::Message*)pollResult[i])->GetText();
 			}
 			break;
 
 		case SteamWebApi::PollApi::POOL_TYPE::STATE:
 			{
-				int status = ((SteamWebApi::PollApi::State*)poll[i])->GetStatus();
-				const wchar_t *nickname = ((SteamWebApi::PollApi::State*)poll[i])->GetNickname();
+				int status = ((SteamWebApi::PollApi::State*)pollResult[i])->GetStatus();
+				const wchar_t *nickname = ((SteamWebApi::PollApi::State*)pollResult[i])->GetNickname();
 			}
 			break;
 		}
 	}
 
-	return 0;
+	return pollResult.GetMessageId();
 }
 
 void CSteamProto::PollingThread(void*)
 {
 	debugLogA("CSteamProto::PollingThread: entering");
 
+	ptrA token(getStringA("TokenSecret"));
+	ptrA sessionId(getStringA("SessionID"));
+	UINT32 messageId = getDword("MessageID", 0);
+
 	while (!m_bTerminated)
-		if (PollStatus() == -1)
+	{
+		messageId = PollStatus(token, sessionId, messageId);
+		if (messageId == 0)
 			break;
+	}
+
+	if (messageId > 0)
+		setDword("MessageID", messageId);
 
 	m_hPollingThread = NULL;
 	debugLogA("CSteamProto::PollingThread: leaving");
-- 
cgit v1.2.3