From d2a83c7d22df33abd1678756fd4caba432700860 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Sun, 22 Mar 2015 21:07:19 +0000 Subject: SkypeWeb: - refactored HttpRequest 2 - status changing support (patch from MikalaiR) git-svn-id: http://svn.miranda-ng.org/main/trunk@12478 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/SkypeWeb/SkypeWeb_12.vcxproj | 3 + protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters | 9 +++ protocols/SkypeWeb/src/common.h | 3 + protocols/SkypeWeb/src/http_request.h | 81 ++++++++++++++++++++++++-- protocols/SkypeWeb/src/requests/contacts.h | 30 ++++------ protocols/SkypeWeb/src/requests/endpoint.h | 25 ++++++++ protocols/SkypeWeb/src/requests/login.h | 17 +++--- protocols/SkypeWeb/src/requests/logout.h | 7 +-- protocols/SkypeWeb/src/requests/profile.h | 6 +- protocols/SkypeWeb/src/requests/reg_info.h | 23 ++++++++ protocols/SkypeWeb/src/requests/status.h | 26 +++++++++ protocols/SkypeWeb/src/skype_events.cpp | 32 ++++++++++ protocols/SkypeWeb/src/skype_proto.cpp | 9 ++- protocols/SkypeWeb/src/skype_proto.h | 5 +- protocols/SkypeWeb/src/skype_utils.cpp | 20 +++++++ 15 files changed, 249 insertions(+), 47 deletions(-) create mode 100644 protocols/SkypeWeb/src/requests/endpoint.h create mode 100644 protocols/SkypeWeb/src/requests/reg_info.h create mode 100644 protocols/SkypeWeb/src/requests/status.h (limited to 'protocols') diff --git a/protocols/SkypeWeb/SkypeWeb_12.vcxproj b/protocols/SkypeWeb/SkypeWeb_12.vcxproj index d24592227f..4066989050 100644 --- a/protocols/SkypeWeb/SkypeWeb_12.vcxproj +++ b/protocols/SkypeWeb/SkypeWeb_12.vcxproj @@ -204,9 +204,12 @@ + + + diff --git a/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters b/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters index 8d6e04a255..37d2954121 100644 --- a/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters +++ b/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters @@ -54,6 +54,15 @@ Header Files\requests + + Header Files\requests + + + Header Files\requests + + + Header Files\requests + diff --git a/protocols/SkypeWeb/src/common.h b/protocols/SkypeWeb/src/common.h index afd15659c4..6a604be5b0 100644 --- a/protocols/SkypeWeb/src/common.h +++ b/protocols/SkypeWeb/src/common.h @@ -47,6 +47,9 @@ struct CSkypeProto; #include "requests\logout.h" #include "requests\profile.h" #include "requests\contacts.h" +#include "requests\status.h" +#include "requests\reg_info.h" +#include "requests\endpoint.h" #include "request_queue.h" #include "skype_proto.h" diff --git a/protocols/SkypeWeb/src/http_request.h b/protocols/SkypeWeb/src/http_request.h index 28b34c075d..5d34d04e3f 100644 --- a/protocols/SkypeWeb/src/http_request.h +++ b/protocols/SkypeWeb/src/http_request.h @@ -171,19 +171,14 @@ protected: HttpRequest() : Headers(*this) { cbSize = sizeof(NETLIBHTTPREQUEST); + flags = NLHRF_HTTP11 | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; } HttpRequest(int httpMethod, LPCSTR urlFormat, va_list args) : Headers(*this) { - this->HttpRequest::HttpRequest(); - requestType = httpMethod; - flags = NLHRF_HTTP11 | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; - Url.content.AppendFormatV(urlFormat, args); - if (Url.content.Find("://") == -1) - Url.content.Insert(0, flags & NLHRF_SSL ? "https://" : "http://"); } public: @@ -213,6 +208,8 @@ public: NETLIBHTTPREQUEST * Send(HANDLE hConnection) { + if (Url.content.Find("://") == -1) + Url.content.Insert(0, flags & NLHRF_SSL ? "https://" : "http://"); szUrl = Url.ToString(); pData = Body.ToString(); @@ -226,4 +223,76 @@ public: } }; +class HttpGetRequest : public HttpRequest +{ +public: + HttpGetRequest(LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_GET, urlFormat, args); + va_end(args); + } +}; + +class HttpPostRequest : public HttpRequest +{ +public: + HttpPostRequest(LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_POST, urlFormat, args); + va_end(args); + + Headers << CHAR_VALUE("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); + } +}; + +class HttpsRequest : public HttpRequest +{ +protected: + HttpsRequest() : HttpRequest() + { + flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; + } + +public: + HttpsRequest(int type, LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(type, urlFormat, args); + va_end(args); + + flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; + } +}; + +class HttpsGetRequest : public HttpsRequest +{ +public: + HttpsGetRequest(LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpRequest::HttpRequest(REQUEST_GET, urlFormat, args); + va_end(args); + } +}; + +class HttpsPostRequest : public HttpsRequest +{ +public: + HttpsPostRequest(LPCSTR urlFormat, ...) + { + va_list args; + va_start(args, urlFormat); + this->HttpsRequest::HttpsRequest(REQUEST_POST, urlFormat, args); + va_end(args); + + Headers << CHAR_VALUE("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); + } +}; + #endif //_HTTP_REQUEST_H_ \ No newline at end of file diff --git a/protocols/SkypeWeb/src/requests/contacts.h b/protocols/SkypeWeb/src/requests/contacts.h index aff095df65..96c0b1c203 100644 --- a/protocols/SkypeWeb/src/requests/contacts.h +++ b/protocols/SkypeWeb/src/requests/contacts.h @@ -1,14 +1,12 @@ #ifndef _SKYPE_REQUEST_CONTACTS_H_ #define _SKYPE_REQUEST_CONTACTS_H_ -class GetContactListRequest : public HttpRequest +class GetContactListRequest : public HttpsGetRequest { public: GetContactListRequest(const char *token, const char *skypename = "self") : - HttpRequest(REQUEST_GET, "api.skype.com/users/%s/contacts?hideDetails=true", skypename) + HttpsGetRequest("api.skype.com/users/%s/contacts", skypename) { - flags |= NLHRF_SSL; - Url << CHAR_VALUE("hideDetails", "true"); Headers @@ -18,14 +16,12 @@ public: } }; -class GetContactsInfoRequest : public HttpRequest +class GetContactsInfoRequest : public HttpsPostRequest { public: GetContactsInfoRequest(const char *token, const LIST &skypenames, const char *skypename = "self") : - HttpRequest(REQUEST_POST, "api.skype.com/users/%s/contacts/profiles", skypename) + HttpsPostRequest("api.skype.com/users/%s/contacts/profiles", skypename) { - flags |= NLHRF_SSL; - Headers << CHAR_VALUE("X-Skypetoken", "Accept") << CHAR_VALUE("X-Skypetoken", token) @@ -38,42 +34,36 @@ public: } }; -class GetContactsAuthRequest : public HttpRequest +class GetContactsAuthRequest : public HttpsGetRequest { public: GetContactsAuthRequest(const char *token, const char *skypename = "self") : - HttpRequest(REQUEST_GET, "api.skype.com/users/%s/contacts/auth-request", skypename) + HttpsGetRequest("api.skype.com/users/%s/contacts/auth-request", skypename) { - flags |= NLHRF_SSL; - Headers << CHAR_VALUE("X-Skypetoken", token) << CHAR_VALUE("Accept", "application/json"); } }; -class AuthAcceptRequest : public HttpRequest +class AuthAcceptRequest : public HttpsGetRequest { public: AuthAcceptRequest(const char *token, const char *who, const char *skypename = "self") : - HttpRequest(REQUEST_GET, "api.skype.com/users/%s/contacts/auth-request/%s/accept", skypename, who) + HttpsGetRequest("api.skype.com/users/%s/contacts/auth-request/%s/accept", skypename, who) { - flags |= NLHRF_SSL; - Headers << CHAR_VALUE("X-Skypetoken", token) << CHAR_VALUE("Accept", "application/json"); } }; -class AuthDeclineRequest : public HttpRequest +class AuthDeclineRequest : public HttpsGetRequest { public: AuthDeclineRequest(const char *token, const char *who, const char *skypename = "self") : - HttpRequest(REQUEST_GET, "api.skype.com/users/%s/contacts/auth-request/%s/decline", skypename) + HttpsGetRequest("api.skype.com/users/%s/contacts/auth-request/%s/decline", skypename) { - flags |= NLHRF_SSL; - Headers << CHAR_VALUE("X-Skypetoken", token) << CHAR_VALUE("Accept", "application/json"); diff --git a/protocols/SkypeWeb/src/requests/endpoint.h b/protocols/SkypeWeb/src/requests/endpoint.h new file mode 100644 index 0000000000..a6878f3f1f --- /dev/null +++ b/protocols/SkypeWeb/src/requests/endpoint.h @@ -0,0 +1,25 @@ +#ifndef _SKYPE_REQUEST_ENDPOINT_H_ +#define _SKYPE_REQUEST_ENDPOINT_H_ + +class GetEndpointRequest : public HttpsRequest +{ +public: + GetEndpointRequest(const char *regToken, const char *endpointURL) : + HttpsRequest(REQUEST_PUT, endpointURL) + { + flags |= NLHRF_SSL; + + Headers + << CHAR_VALUE("Accept", "application/json, text/javascript") + << CHAR_VALUE("Expires", "0") + << FORMAT_VALUE("RegistrationToken", "registrationToken=%s", regToken) + << CHAR_VALUE("Content-Type", "application/json; charset=UTF-8") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + + Body << + VALUE("{\"id\":\"messagingService\",\"type\":\"EndpointPresenceDoc\",\"selfLink\":\"uri\",\"privateInfo\":{\"epname\":\"skype\"},\"publicInfo\":{\"capabilities\":\"video | audio\",\"type\":1,\"skypeNameVersion\":\"908 / 1.0.30 / swx - skype.com\",\"nodeInfo\":\"xx\",\"version\":\"908 / 1.0.30\"}}"); + } +}; +#endif //_SKYPE_REQUEST_ENDPOINT_H_ \ No newline at end of file diff --git a/protocols/SkypeWeb/src/requests/login.h b/protocols/SkypeWeb/src/requests/login.h index 12f0e9e5cc..8c45c7237c 100644 --- a/protocols/SkypeWeb/src/requests/login.h +++ b/protocols/SkypeWeb/src/requests/login.h @@ -1,30 +1,29 @@ #ifndef _SKYPE_REQUEST_LOGIN_H_ #define _SKYPE_REQUEST_LOGIN_H_ -class LoginRequest : public HttpRequest +class LoginRequest : public HttpsPostRequest { public: LoginRequest() : - HttpRequest(REQUEST_POST, "login.skype.com/login") + HttpsPostRequest("login.skype.com/login") { - flags |= NLHRF_SSL; - Url << INT_VALUE("client_id", 578134) << CHAR_VALUE("redirect_uri", "https%3A%2F%2Fweb.skype.com"); Headers - << CHAR_VALUE("Host", "login.skype.com") - << CHAR_VALUE("Referer", "https://web.skype.com/"); + << CHAR_VALUE("Host", "login.skype.com"); } LoginRequest(const char *skypename, const char *password, const char *pie, const char *etm) : - HttpRequest(REQUEST_POST, "login.skype.com/login") + HttpsPostRequest("login.skype.com/login") { - this->LoginRequest::LoginRequest(); + Url + << INT_VALUE("client_id", 578134) + << CHAR_VALUE("redirect_uri", "https%3A%2F%2Fweb.skype.com"); Headers - << CHAR_VALUE("Content-Type", "application/x-www-form-urlencoded") + << CHAR_VALUE("Host", "login.skype.com") << CHAR_VALUE("Referer", "https://login.skype.com/login?method=skype&client_id=578134&redirect_uri=https%3A%2F%2Fweb.skype.com"); LPTIME_ZONE_INFORMATION tzi = tmi.getTziByContact(NULL); diff --git a/protocols/SkypeWeb/src/requests/logout.h b/protocols/SkypeWeb/src/requests/logout.h index 60f30e639c..b1585c9e91 100644 --- a/protocols/SkypeWeb/src/requests/logout.h +++ b/protocols/SkypeWeb/src/requests/logout.h @@ -1,13 +1,10 @@ #ifndef _SKYPE_REQUEST_LOGOUT_H_ #define _SKYPE_REQUEST_LOGOUT_H_ -class LogoutRequest : public HttpRequest +class LogoutRequest : public HttpsPostRequest { public: - LogoutRequest() : HttpRequest(REQUEST_POST, "login.skype.com/logout") - { - flags |= NLHRF_SSL; - } + LogoutRequest() : HttpsPostRequest("login.skype.com/logout") { } }; #endif //_SKYPE_REQUEST_LOGOUT_H_ diff --git a/protocols/SkypeWeb/src/requests/profile.h b/protocols/SkypeWeb/src/requests/profile.h index 2c0b4e8fb6..579ac446b4 100644 --- a/protocols/SkypeWeb/src/requests/profile.h +++ b/protocols/SkypeWeb/src/requests/profile.h @@ -1,14 +1,12 @@ #ifndef _SKYPE_REQUEST_PROFILE_H_ #define _SKYPE_REQUEST_PROFILE_H_ -class GetProfileRequest : public HttpRequest +class GetProfileRequest : public HttpsGetRequest { public: GetProfileRequest(const char *token, const char *skypename = "self") : - HttpRequest(REQUEST_GET, "api.skype.com/users/%s/profile", skypename) + HttpsGetRequest("api.skype.com/users/%s/profile", skypename) { - flags |= NLHRF_SSL; - Headers << CHAR_VALUE("X-Skypetoken", token) << CHAR_VALUE("Accept", "application/json"); diff --git a/protocols/SkypeWeb/src/requests/reg_info.h b/protocols/SkypeWeb/src/requests/reg_info.h new file mode 100644 index 0000000000..6ba0518524 --- /dev/null +++ b/protocols/SkypeWeb/src/requests/reg_info.h @@ -0,0 +1,23 @@ +#ifndef _SKYPE_REQUEST_REGINFO_H_ +#define _SKYPE_REQUEST_REGINFO_H_ + +class GetRegInfoRequest : public HttpsPostRequest +{ +public: + GetRegInfoRequest(const char *token) : + HttpsPostRequest("client-s.gateway.messenger.live.com/v1/users/ME/endpoints") + { + Headers + << CHAR_VALUE("Accept", "application/json, text/javascript") + << CHAR_VALUE("Expires", "0") + << FORMAT_VALUE("Authentication", "skypetoken=%s", token) + << CHAR_VALUE("Content-Type", "application/json; charset = UTF-8") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + + Body << VALUE("{}"); + } +}; + +#endif //_SKYPE_REQUEST_STATUS_H_ diff --git a/protocols/SkypeWeb/src/requests/status.h b/protocols/SkypeWeb/src/requests/status.h new file mode 100644 index 0000000000..07703e84ae --- /dev/null +++ b/protocols/SkypeWeb/src/requests/status.h @@ -0,0 +1,26 @@ +#ifndef _SKYPE_REQUEST_STATUS_H_ +#define _SKYPE_REQUEST_STATUS_H_ + +class SetStatusRequest : public HttpsRequest +{ +public: + SetStatusRequest(const char *regToken, bool status) : + HttpsRequest(REQUEST_PUT, "client-s.gateway.messenger.live.com/v1/users/ME/presenceDocs/messagingService") + { + Headers + << CHAR_VALUE("Accept", "application / json, text / javascript") + << CHAR_VALUE("Expires", "0") + << FORMAT_VALUE("RegistrationToken", "registrationToken=%s", regToken) + << CHAR_VALUE("Content-Type", "application/json; charset = UTF-8") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + + const char *data = status + ? "{\"status\":\"Online\"}" + : "{\"status\":\"Hidden\"}"; + Body << VALUE(data); + } +}; + +#endif //_SKYPE_REQUEST_STATUS_H_ diff --git a/protocols/SkypeWeb/src/skype_events.cpp b/protocols/SkypeWeb/src/skype_events.cpp index 5139642270..309110b285 100644 --- a/protocols/SkypeWeb/src/skype_events.cpp +++ b/protocols/SkypeWeb/src/skype_events.cpp @@ -89,8 +89,40 @@ void CSkypeProto::OnLoginSecond(const NETLIBHTTPREQUEST *response) cookies[match[1]] = match[2]; } + PushRequest(new GetRegInfoRequest(token.c_str()), &CSkypeProto::OnGetRegInfo); PushRequest(new GetProfileRequest(token.c_str()), &CSkypeProto::LoadProfile); PushRequest(new GetContactListRequest(token.c_str()), &CSkypeProto::LoadContactList); ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus = m_iDesiredStatus); +} + +void CSkypeProto::OnGetRegInfo(const NETLIBHTTPREQUEST *response) +{ + std::regex regex; + std::smatch match; + std::string content = response->pData; + for (int i = 0; i < response->headersCount; i++) + { + if (mir_strcmpi(response->headers[i].szName, "Set-RegistrationToken")) + continue; + + regex = "^(.+?)=(.+?);"; + content = response->headers[i].szValue; + + if (std::regex_search(content, match, regex)) + RegInfo[match[1]] = match[2]; + } + setString("RegistrationToken", RegInfo["registrationToken"].c_str()); + + for (int i = 0; i < response->headersCount; i++) + { + if (mir_strcmpi(response->headers[i].szName, "Location")) + continue; + content = response->headers[i].szValue; + } + setString("Endpoint", urlDecode(content.c_str()).c_str()); + debugLogA(getStringA("RegistrationToken")); + debugLogA(getStringA("Endpoint")); + PushRequest(new GetEndpointRequest(ptrA(getStringA("RegistrationToken")), ptrA(getStringA("Endpoint")))); + PushRequest(new SetStatusRequest(ptrA(getStringA("RegistrationToken")), true)); } \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_proto.cpp b/protocols/SkypeWeb/src/skype_proto.cpp index b566b1c245..82a3ec1b00 100644 --- a/protocols/SkypeWeb/src/skype_proto.cpp +++ b/protocols/SkypeWeb/src/skype_proto.cpp @@ -33,9 +33,9 @@ DWORD_PTR CSkypeProto::GetCaps(int type, MCONTACT) case PFLAGNUM_1: return PF1_AUTHREQ; case PFLAGNUM_2: - return PF2_ONLINE; + return PF2_ONLINE | PF2_INVISIBLE; case PFLAGNUM_3: - return PF2_ONLINE; + return PF2_ONLINE | PF2_INVISIBLE; case PFLAGNUM_4: return PF4_FORCEADDED | PF4_NOAUTHDENYREASON; case PFLAG_UNIQUEIDTEXT: @@ -147,6 +147,11 @@ int CSkypeProto::SetStatus(int iNewStatus) m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; } + else if (iNewStatus == ID_STATUS_INVISIBLE) + { + PushRequest(new GetEndpointRequest(ptrA(getStringA("RegistrationToken")), ptrA(getStringA("Endpoint")))); + PushRequest(new SetStatusRequest(ptrA(getStringA("RegistrationToken")), false)); + } else { if (old_status == ID_STATUS_CONNECTING) diff --git a/protocols/SkypeWeb/src/skype_proto.h b/protocols/SkypeWeb/src/skype_proto.h index dfe9aa87eb..4310050bad 100644 --- a/protocols/SkypeWeb/src/skype_proto.h +++ b/protocols/SkypeWeb/src/skype_proto.h @@ -83,6 +83,7 @@ private: char *password; RequestQueue *requestQueue; std::map cookies; + std::map RegInfo; static std::map languages; @@ -120,9 +121,10 @@ private: // events void OnLoginFirst(const NETLIBHTTPREQUEST *response); - void OnLoginSecond(const NETLIBHTTPREQUEST *response); + void OnGetRegInfo(const NETLIBHTTPREQUEST *response); + // profile void UpdateProfileFirstName(JSONNODE *root, MCONTACT hContact = NULL); void UpdateProfileLastName(JSONNODE *root, MCONTACT hContact = NULL); @@ -174,6 +176,7 @@ private: static void ShowNotification(const TCHAR *caption, const TCHAR *message, int flags = 0, MCONTACT hContact = NULL); static bool IsFileExists(std::tstring path); + std::string urlDecode(std::string SRC); template static INT_PTR __cdecl GlobalService(WPARAM wParam, LPARAM lParam) diff --git a/protocols/SkypeWeb/src/skype_utils.cpp b/protocols/SkypeWeb/src/skype_utils.cpp index 5ce367f768..a9a44e1c27 100644 --- a/protocols/SkypeWeb/src/skype_utils.cpp +++ b/protocols/SkypeWeb/src/skype_utils.cpp @@ -37,4 +37,24 @@ bool CSkypeProto::IsFileExists(std::tstring path) return true; } return false; +} + +std::string CSkypeProto::urlDecode(std::string SRC) +{ + std::string ret; + char ch; + int i, ii; + for (i = 0; i < SRC.length(); i++) + { + if (int(SRC[i]) == 37) + { + sscanf(SRC.substr(i + 1, 2).c_str(), "%x", &ii); + ch = static_cast(ii); + ret += ch; + i = i + 2; + } + else + ret += SRC[i]; + } + return (ret); } \ No newline at end of file -- cgit v1.2.3