From f9e66715bee0af7f9b1f2698da1fe11c35479210 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Tue, 31 Mar 2015 18:37:50 +0000 Subject: SteamWeb: contact's status support (patch from MikalaiR) git-svn-id: http://svn.miranda-ng.org/main/trunk@12576 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/SkypeWeb/SkypeWeb_10.vcxproj | 5 ++ protocols/SkypeWeb/SkypeWeb_10.vcxproj.filters | 15 +++++ protocols/SkypeWeb/SkypeWeb_12.vcxproj | 5 ++ protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters | 15 +++++ protocols/SkypeWeb/src/common.h | 3 + protocols/SkypeWeb/src/requests/endpoint.h | 2 +- protocols/SkypeWeb/src/requests/logout.h | 4 +- protocols/SkypeWeb/src/requests/messages.h | 26 ++++++++ protocols/SkypeWeb/src/requests/poll.h | 27 ++++++++ protocols/SkypeWeb/src/requests/subscriptions.h | 27 ++++++++ protocols/SkypeWeb/src/skype_events.cpp | 6 ++ protocols/SkypeWeb/src/skype_poll_processing.cpp | 12 ++++ protocols/SkypeWeb/src/skype_polling.cpp | 82 ++++++++++++++++++++++++ protocols/SkypeWeb/src/skype_proto.h | 18 ++++-- protocols/SkypeWeb/src/skype_status.cpp | 13 +++- protocols/SkypeWeb/src/skype_utils.cpp | 33 +++++----- 16 files changed, 265 insertions(+), 28 deletions(-) create mode 100644 protocols/SkypeWeb/src/requests/messages.h create mode 100644 protocols/SkypeWeb/src/requests/poll.h create mode 100644 protocols/SkypeWeb/src/requests/subscriptions.h create mode 100644 protocols/SkypeWeb/src/skype_poll_processing.cpp create mode 100644 protocols/SkypeWeb/src/skype_polling.cpp (limited to 'protocols') diff --git a/protocols/SkypeWeb/SkypeWeb_10.vcxproj b/protocols/SkypeWeb/SkypeWeb_10.vcxproj index 9892d88e2f..4e27946177 100644 --- a/protocols/SkypeWeb/SkypeWeb_10.vcxproj +++ b/protocols/SkypeWeb/SkypeWeb_10.vcxproj @@ -204,9 +204,12 @@ + + + @@ -217,6 +220,7 @@ + @@ -232,6 +236,7 @@ + diff --git a/protocols/SkypeWeb/SkypeWeb_10.vcxproj.filters b/protocols/SkypeWeb/SkypeWeb_10.vcxproj.filters index 4b9c206ad3..ecb2632146 100644 --- a/protocols/SkypeWeb/SkypeWeb_10.vcxproj.filters +++ b/protocols/SkypeWeb/SkypeWeb_10.vcxproj.filters @@ -63,6 +63,15 @@ Header Files\requests + + Header Files\requests + + + Header Files\requests + + + Header Files\requests + @@ -110,6 +119,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/protocols/SkypeWeb/SkypeWeb_12.vcxproj b/protocols/SkypeWeb/SkypeWeb_12.vcxproj index 833ce5cb0a..7f776adc57 100644 --- a/protocols/SkypeWeb/SkypeWeb_12.vcxproj +++ b/protocols/SkypeWeb/SkypeWeb_12.vcxproj @@ -207,9 +207,12 @@ + + + @@ -235,6 +238,8 @@ + + diff --git a/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters b/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters index 4b9c206ad3..e7e11629e4 100644 --- a/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters +++ b/protocols/SkypeWeb/SkypeWeb_12.vcxproj.filters @@ -63,6 +63,15 @@ Header Files\requests + + Header Files\requests + + + Header Files\requests + + + Header Files\requests + @@ -109,6 +118,12 @@ Source Files + + + Source Files + + + Source Files diff --git a/protocols/SkypeWeb/src/common.h b/protocols/SkypeWeb/src/common.h index 6a604be5b0..97e8356f09 100644 --- a/protocols/SkypeWeb/src/common.h +++ b/protocols/SkypeWeb/src/common.h @@ -50,6 +50,9 @@ struct CSkypeProto; #include "requests\status.h" #include "requests\reg_info.h" #include "requests\endpoint.h" +#include "requests\subscriptions.h" +#include "requests\messages.h" +#include "requests\poll.h" #include "request_queue.h" #include "skype_proto.h" diff --git a/protocols/SkypeWeb/src/requests/endpoint.h b/protocols/SkypeWeb/src/requests/endpoint.h index d6e0fdda7c..bc3bdaff32 100644 --- a/protocols/SkypeWeb/src/requests/endpoint.h +++ b/protocols/SkypeWeb/src/requests/endpoint.h @@ -21,7 +21,7 @@ public: << 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\"}}"); + VALUE("{\"id\":\"messagingService\",\"type\":\"EndpointPresenceDoc\",\"selfLink\":\"uri\",\"privateInfo\":{\"epname\":\"Miranda\"},\"publicInfo\":{\"capabilities\":\"\",\"type\":1,\"skypeNameVersion\":\"0/0.95.4//\",\"nodeInfo\":\"xx\",\"version\":\"0/0.95.4\"}}"); } }; #endif //_SKYPE_REQUEST_ENDPOINT_H_ \ No newline at end of file diff --git a/protocols/SkypeWeb/src/requests/logout.h b/protocols/SkypeWeb/src/requests/logout.h index 2083973e7c..57caff2239 100644 --- a/protocols/SkypeWeb/src/requests/logout.h +++ b/protocols/SkypeWeb/src/requests/logout.h @@ -1,10 +1,10 @@ #ifndef _SKYPE_REQUEST_LOGOUT_H_ #define _SKYPE_REQUEST_LOGOUT_H_ -class LogoutRequest : public HttpsPostRequest +class LogoutRequest : public HttpsGetRequest { public: - LogoutRequest() : HttpsPostRequest("login.skype.com/logout") + LogoutRequest() : HttpsGetRequest("login.skype.com/logout") { //flags = NLHRF_SSL | NLHRF_NODUMPSEND | NLHRF_DUMPASTEXT; Url diff --git a/protocols/SkypeWeb/src/requests/messages.h b/protocols/SkypeWeb/src/requests/messages.h new file mode 100644 index 0000000000..a61441e10a --- /dev/null +++ b/protocols/SkypeWeb/src/requests/messages.h @@ -0,0 +1,26 @@ +#ifndef _SKYPE_REQUEST_MESSAGES_H_ +#define _SKYPE_REQUEST_MESSAGES_H_ + +class SendMsgRequest : public HttpsPostRequest +{ +public: + SendMsgRequest(const char *regToken, const char *username, const char *message) : + HttpsPostRequest("client-s.gateway.messenger.live.com/v1/users/ME/conversations/8:%s/messages", username) + { + CMStringA auth = "registrationToken="; + auth += regToken; + Headers + << CHAR_VALUE("Accept", "application / json, text / javascript") + << CHAR_VALUE("Expires", "0") + << CHAR_VALUE("RegistrationToken", auth) + << CHAR_VALUE("Content-Type", "application/json; charset = UTF-8") + << CHAR_VALUE("BehaviorOverride", "redirectAs404") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + + Body << FORMAT_VALUE("{\"clientmessageid\":\"\",\"content\":\"%s\",\"messagetype\":\"RichText\",\"contenttype\":\"text\"}", message); + } +}; + +#endif //_SKYPE_REQUEST_MESSAGES_H_ diff --git a/protocols/SkypeWeb/src/requests/poll.h b/protocols/SkypeWeb/src/requests/poll.h new file mode 100644 index 0000000000..edec20dec7 --- /dev/null +++ b/protocols/SkypeWeb/src/requests/poll.h @@ -0,0 +1,27 @@ +#ifndef _SKYPE_POLL_H_ +#define _SKYPE_POLL_H_ + +class PollRequest : public HttpsPostRequest +{ +public: + PollRequest(const char *regToken) : + HttpsPostRequest("client-s.gateway.messenger.live.com/v1/users/ME/endpoints/SELF/subscriptions/0/poll") + { + timeout = 30 * 1000; + flags |= NLHRF_PERSISTENT; + CMStringA data; + CMStringA auth = "registrationToken="; + auth += regToken; + Headers + << CHAR_VALUE("Connection", "keep-alive") + << CHAR_VALUE("Accept", "application/json, text/javascript") + << CHAR_VALUE("Expires", "0") + << CHAR_VALUE("RegistrationToken", auth) + << CHAR_VALUE("Content-Type", "application/json; charset=UTF-8") + << CHAR_VALUE("BehaviorOverride", "redirectAs404") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + } +}; +#endif //_SKYPE_POLL_H_ \ No newline at end of file diff --git a/protocols/SkypeWeb/src/requests/subscriptions.h b/protocols/SkypeWeb/src/requests/subscriptions.h new file mode 100644 index 0000000000..609d5cfec3 --- /dev/null +++ b/protocols/SkypeWeb/src/requests/subscriptions.h @@ -0,0 +1,27 @@ +#ifndef _SKYPE_REQUEST_SUBSCIPTIONS_H_ +#define _SKYPE_REQUEST_SUBSCIPTIONS_H_ + +class SubscriptionsRequest : public HttpsPostRequest +{ +public: + SubscriptionsRequest(const char *regToken) : + HttpsPostRequest("client-s.gateway.messenger.live.com/v1/users/ME/endpoints/SELF/subscriptions") + { + CMStringA auth = "registrationToken="; + auth += regToken; + Headers + << CHAR_VALUE("Accept", "application/json, text/javascript") + << CHAR_VALUE("Expires", "0") + << CHAR_VALUE("RegistrationToken", auth) + << CHAR_VALUE("Content-Type", "application/json; charset = UTF-8") + << CHAR_VALUE("BehaviorOverride", "redirectAs404") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + + const char *data = "{\"channelType\":\"httpLongPoll\",\"template\":\"raw\",\"interestedResources\":[\"/v1/users/ME/conversations/ALL/properties\",\"/v1/users/ME/conversations/ALL/messages\",\"/v1/users/ME/contacts/ALL\",\"/v1/threads/ALL\"]}"; + Body << VALUE(data); + } +}; + +#endif //_SKYPE_REQUEST_SUBSCIPTIONS_H_ diff --git a/protocols/SkypeWeb/src/skype_events.cpp b/protocols/SkypeWeb/src/skype_events.cpp index 2414a799ed..fdc0dd246c 100644 --- a/protocols/SkypeWeb/src/skype_events.cpp +++ b/protocols/SkypeWeb/src/skype_events.cpp @@ -122,6 +122,12 @@ void CSkypeProto::OnGetRegInfo(const NETLIBHTTPREQUEST *response) } } PushRequest(new GetEndpointRequest(getStringA("registrationToken"), getStringA("endpointId"))); + + SubscriptionsRequest *request = new SubscriptionsRequest(getStringA("registrationToken")); + request->Send(m_hNetlibUser); + delete request; + + m_hPollingThread = ForkThreadEx(&CSkypeProto::PollingThread, 0, NULL); PushRequest(new SetStatusRequest(getStringA("registrationToken"), ID_STATUS_ONLINE), &CSkypeProto::OnSetStatus); } diff --git a/protocols/SkypeWeb/src/skype_poll_processing.cpp b/protocols/SkypeWeb/src/skype_poll_processing.cpp new file mode 100644 index 0000000000..4bf8b3e689 --- /dev/null +++ b/protocols/SkypeWeb/src/skype_poll_processing.cpp @@ -0,0 +1,12 @@ +#include "common.h" + +void CSkypeProto::ProcessUserPresenceRes(JSONNODE *node) +{ + debugLogA("CSkypeProto::ProcessUserPresenceRes"); + ptrA selfLink(mir_t2a(ptrT(json_as_string(json_get(node, "selfLink"))))); + ptrA status(mir_t2a(ptrT(json_as_string(json_get(node, "status"))))); + + char *skypename = ContactUrlToName(selfLink); + MCONTACT hContact = GetContact(skypename); + SetContactStatus(hContact, ID_STATUS_ONLINE); +} \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_polling.cpp b/protocols/SkypeWeb/src/skype_polling.cpp new file mode 100644 index 0000000000..8dc73280a7 --- /dev/null +++ b/protocols/SkypeWeb/src/skype_polling.cpp @@ -0,0 +1,82 @@ +#include "common.h" + +#define POLLING_ERRORS_LIMIT 3 + +void CSkypeProto::ParsePollData(JSONNODE *data) +{ + debugLogA("CSkypeProto::ParsePollData"); + JSONNODE *node, *item = NULL; + node = json_get(data, "eventMessages"); + if (node != NULL) + { + int index, length; + JSONNODE *messages = json_as_array(node); + for (int i = 0; i < json_size(messages); i++) + { + JSONNODE *message = json_at(messages, i); + JSONNODE *resType = json_get(message, "resourceType"); + TCHAR *resourceType = json_as_string(resType); + JSONNODE *resource = json_get(message, "resource"); + + if (!mir_tstrcmpi(resourceType, L"NewMessage")) + { + continue; + } + else if (!mir_tstrcmpi(resourceType, L"UserPresence")) + { + ProcessUserPresenceRes(resource); + } + else if (!mir_tstrcmpi(resourceType, L"EndpointPresence")) + { + continue; + } + else if (!mir_tstrcmpi(resourceType, L"ConversationUpdate")) + { + continue; + } + else if (!mir_tstrcmpi(resourceType, L"ThreadUpdate")) + { + continue; + } + + } + } + +} + +void CSkypeProto::PollingThread(void*) +{ + debugLog(_T("CSkypeProto::PollingThread: entering")); + + ptrA regToken(getStringA("registrationToken")); + + int errors = 0; + bool breaked = false; + while (!isTerminated && !breaked && errors < POLLING_ERRORS_LIMIT) + { + PollRequest *request = new PollRequest(regToken); + NETLIBHTTPREQUEST *response = request->Send(m_hNetlibUser); + delete request; + + if (response != NULL) + { + JSONROOT root(response->pData); + ParsePollData (root); + } + /*if (response->resultCode != 200) + { + errors++; + continue; + } + else + errors = 0;*/ + } + m_hPollingThread = NULL; + debugLog(_T("CSkypeProto::PollingThread: leaving")); + + if (!isTerminated) + { + debugLog(_T("CSkypeProto::PollingThread: unexpected termination; switching protocol to offline")); + SetStatus(ID_STATUS_OFFLINE); + } +} \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_proto.h b/protocols/SkypeWeb/src/skype_proto.h index bab1b29248..1f35f810ff 100644 --- a/protocols/SkypeWeb/src/skype_proto.h +++ b/protocols/SkypeWeb/src/skype_proto.h @@ -1,5 +1,5 @@ -#ifndef _TOX_PROTO_H_ -#define _TOX_PROTO_H_ +#ifndef _SKYPE_PROTO_H_ +#define _SKYPE_PROTO_H_ typedef void(CSkypeProto::*SkypeResponseCallback)(const NETLIBHTTPREQUEST *response); @@ -82,9 +82,10 @@ public: private: char *password; RequestQueue *requestQueue; + bool isTerminated; std::map cookies; std::map RegInfo; - + HANDLE m_pollingConnection, m_hPollingThread; static std::map languages; static INT_PTR CALLBACK PasswordEditorProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); @@ -170,13 +171,16 @@ private: // messages int OnReceiveMessage(MCONTACT hContact, PROTORECVEVENT *pre); int OnSendMessage(MCONTACT hContact, int flags, const char *message); - + //polling + void __cdecl CSkypeProto::ParsePollData(JSONNODE *data); + void __cdecl CSkypeProto::PollingThread(void*); + void CSkypeProto::ProcessUserPresenceRes(JSONNODE *node); // utils static void ShowNotification(const TCHAR *message, int flags = 0, MCONTACT hContact = NULL); static void ShowNotification(const TCHAR *caption, const TCHAR *message, int flags = 0, MCONTACT hContact = NULL); - void CSkypeProto::SetServerStatus(int iNewStatus); + void SetServerStatus(int iNewStatus); static bool IsFileExists(std::tstring path); - std::string urlDecode(std::string SRC); + char *ContactUrlToName(const char *url); template static INT_PTR __cdecl GlobalService(WPARAM wParam, LPARAM lParam) @@ -186,4 +190,4 @@ private: } }; -#endif //_TOX_PROTO_H_ \ No newline at end of file +#endif //_SKYPE_PROTO_H_ \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_status.cpp b/protocols/SkypeWeb/src/skype_status.cpp index b40aa44198..5de3e6f683 100644 --- a/protocols/SkypeWeb/src/skype_status.cpp +++ b/protocols/SkypeWeb/src/skype_status.cpp @@ -1,4 +1,5 @@ #include "common.h" + int CSkypeProto::SetStatus(int iNewStatus) { if (iNewStatus == m_iDesiredStatus) @@ -13,6 +14,7 @@ int CSkypeProto::SetStatus(int iNewStatus) switch (iNewStatus) { case ID_STATUS_OFFLINE: + isTerminated = true; PushRequest(new LogoutRequest()); requestQueue->Stop(); if (!Miranda_Terminated()) @@ -27,21 +29,28 @@ int CSkypeProto::SetStatus(int iNewStatus) case ID_STATUS_AWAY: case ID_STATUS_DND: case ID_STATUS_IDLE: - PushRequest(new GetEndpointRequest(ptrA(getStringA("registrationToken")), getStringA("endpointId"))); + { + GetEndpointRequest *request = new GetEndpointRequest(getStringA("registrationToken"), getStringA("endpointId")); + request->Send(m_hNetlibUser); + delete request; PushRequest(new SetStatusRequest(ptrA(getStringA("registrationToken")), iNewStatus), &CSkypeProto::OnSetStatus); break; + } default: if (old_status == ID_STATUS_CONNECTING) return 0; if (m_iStatus == ID_STATUS_INVISIBLE || m_iStatus == ID_STATUS_AWAY || m_iStatus == ID_STATUS_DND || m_iStatus == ID_STATUS_IDLE) { - PushRequest(new GetEndpointRequest(ptrA(getStringA("registrationToken")), getStringA("endpointId"))); + GetEndpointRequest *request = new GetEndpointRequest(getStringA("registrationToken"), getStringA("endpointId")); + request->Send(m_hNetlibUser); + delete request; PushRequest(new SetStatusRequest(ptrA(getStringA("registrationToken")), ID_STATUS_ONLINE), &CSkypeProto::OnSetStatus); } else if (old_status == ID_STATUS_OFFLINE && m_iStatus == ID_STATUS_OFFLINE) { // login + isTerminated = false; m_iStatus = ID_STATUS_CONNECTING; requestQueue->Start(); diff --git a/protocols/SkypeWeb/src/skype_utils.cpp b/protocols/SkypeWeb/src/skype_utils.cpp index a9a44e1c27..92a7ba792d 100644 --- a/protocols/SkypeWeb/src/skype_utils.cpp +++ b/protocols/SkypeWeb/src/skype_utils.cpp @@ -39,22 +39,23 @@ bool CSkypeProto::IsFileExists(std::tstring path) return false; } -std::string CSkypeProto::urlDecode(std::string SRC) +char *CSkypeProto::ContactUrlToName(const char *url) { - std::string ret; - char ch; - int i, ii; - for (i = 0; i < SRC.length(); i++) + char *tempname = NULL; + const char *start, *end; + start = strstr(url, "/8:"); + + if (!start) + return NULL; + start = start + 3; + if ((end = strchr(start, '/'))) { - 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]; + mir_free(tempname); + tempname = mir_strndup(start, end - start); + return tempname; } - return (ret); -} \ No newline at end of file + mir_free(tempname); + tempname = mir_strdup(start); + + return tempname; +} -- cgit v1.2.3