From c89e8a054ac888b27065916ffde96af73404228c Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Sat, 4 Apr 2015 20:10:50 +0000 Subject: SkypeWeb: - history sync (patch from MikalaiR) - refactored message sending git-svn-id: http://svn.miranda-ng.org/main/trunk@12599 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/SkypeWeb/src/requests/contacts.h | 4 +- protocols/SkypeWeb/src/requests/messages.h | 22 ++++- protocols/SkypeWeb/src/skype_contacts.cpp | 2 +- protocols/SkypeWeb/src/skype_events.cpp | 6 +- protocols/SkypeWeb/src/skype_menus.cpp | 1 - protocols/SkypeWeb/src/skype_messages.cpp | 116 ++++++++++++++--------- protocols/SkypeWeb/src/skype_poll_processing.cpp | 5 +- protocols/SkypeWeb/src/skype_polling.cpp | 5 +- protocols/SkypeWeb/src/skype_profile.cpp | 2 +- protocols/SkypeWeb/src/skype_proto.cpp | 10 +- protocols/SkypeWeb/src/skype_proto.h | 22 ++--- protocols/SkypeWeb/src/skype_request.cpp | 40 ++++---- protocols/SkypeWeb/src/skype_utils.cpp | 1 - 13 files changed, 141 insertions(+), 95 deletions(-) (limited to 'protocols') diff --git a/protocols/SkypeWeb/src/requests/contacts.h b/protocols/SkypeWeb/src/requests/contacts.h index 786f59e10d..8a23526bf9 100644 --- a/protocols/SkypeWeb/src/requests/contacts.h +++ b/protocols/SkypeWeb/src/requests/contacts.h @@ -25,10 +25,8 @@ public: << CHAR_VALUE("X-Skypetoken", token) << CHAR_VALUE("Accept", "application/json"); - for (size_t i = 0; i < skypenames.getCount(); i++) - { + for (int i = 0; i < skypenames.getCount(); i++) Body << CHAR_VALUE("contacts[]", skypenames[i]); - } } }; diff --git a/protocols/SkypeWeb/src/requests/messages.h b/protocols/SkypeWeb/src/requests/messages.h index 389d9fa7bb..d2c000d8be 100644 --- a/protocols/SkypeWeb/src/requests/messages.h +++ b/protocols/SkypeWeb/src/requests/messages.h @@ -8,7 +8,7 @@ public: HttpRequest(REQUEST_POST, FORMAT, "%s/v1/users/ME/conversations/8:%s/messages", server, username) { Headers - << CHAR_VALUE("Accept", "application / json, text / javascript") + << 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") @@ -31,7 +31,7 @@ public: HttpRequest(REQUEST_POST, FORMAT, "%s/v1/users/ME/conversations/8:%s/messages", server, mir_urlEncode(username)) { Headers - << CHAR_VALUE("Accept", "application / json, text / javascript") + << 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") @@ -49,4 +49,22 @@ public: } }; +class GetHistoryRequest : public HttpRequest +{ +public: + GetHistoryRequest(const char *regToken, int time, const char *server = "client-s.gateway.messenger.live.com") : + HttpRequest(REQUEST_GET, FORMAT, "%s/v1/users/ME/conversations?startTime=%d&pageSize=100&view=msnp24Equivalent&targetType=Passport|Skype|Lync|Thread", server, time) + { + 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("BehaviorOverride", "redirectAs404") + << CHAR_VALUE("Referer", "https://web.skype.com/main") + << CHAR_VALUE("Origin", "https://web.skype.com") + << CHAR_VALUE("Connection", "keep-alive"); + } +}; + #endif //_SKYPE_REQUEST_MESSAGES_H_ diff --git a/protocols/SkypeWeb/src/skype_contacts.cpp b/protocols/SkypeWeb/src/skype_contacts.cpp index a9e7db7e97..5e779d545a 100644 --- a/protocols/SkypeWeb/src/skype_contacts.cpp +++ b/protocols/SkypeWeb/src/skype_contacts.cpp @@ -216,7 +216,7 @@ void CSkypeProto::LoadContactList(const NETLIBHTTPREQUEST *response) { PushRequest(new GetContactsInfoRequest(token, skypenames), &CSkypeProto::LoadContactsInfo); - for (size_t i = 0; i < skypenames.getCount(); i++) + for (int i = 0; i < skypenames.getCount(); i++) mir_free(skypenames[i]); skypenames.destroy(); } diff --git a/protocols/SkypeWeb/src/skype_events.cpp b/protocols/SkypeWeb/src/skype_events.cpp index 26c0c11ec2..db91d9f1b8 100644 --- a/protocols/SkypeWeb/src/skype_events.cpp +++ b/protocols/SkypeWeb/src/skype_events.cpp @@ -106,8 +106,8 @@ void CSkypeProto::OnGetRegInfo(const NETLIBHTTPREQUEST *response) { CMStringA szValue = response->headers[i].szValue, szCookieName, szCookieVal; int iStart = 0; - while (true) { - bool bFirstToken = (iStart == 0); + while (true) + { CMStringA szToken = szValue.Tokenize(";", iStart).Trim(); if (iStart == -1) break; @@ -137,6 +137,8 @@ void CSkypeProto::OnGetRegInfo(const NETLIBHTTPREQUEST *response) m_iStatus = m_iDesiredStatus; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_CONNECTING, m_iStatus); PushRequest(new SetStatusRequest(ptrA(getStringA("registrationToken")), MirandaToSkypeStatus(m_iStatus), getStringA("Server")), &CSkypeProto::OnSetStatus); + PushRequest(new GetHistoryRequest(ptrA(getStringA("registrationToken")), getDword("LastMsgTime", time(NULL)), ptrA(getStringA("Server"))), &CSkypeProto::OnGetServerHistory); + } void CSkypeProto::OnGetEndpoint(const NETLIBHTTPREQUEST *response) diff --git a/protocols/SkypeWeb/src/skype_menus.cpp b/protocols/SkypeWeb/src/skype_menus.cpp index de82902909..0bb9092828 100644 --- a/protocols/SkypeWeb/src/skype_menus.cpp +++ b/protocols/SkypeWeb/src/skype_menus.cpp @@ -66,7 +66,6 @@ int CSkypeProto::OnInitStatusMenu() { char text[MAX_PATH]; mir_strcpy(text, m_szModuleName); - char *tDest = text + strlen(text); CLISTMENUITEM mi = { sizeof(mi) }; mi.pszService = text; diff --git a/protocols/SkypeWeb/src/skype_messages.cpp b/protocols/SkypeWeb/src/skype_messages.cpp index 70436ce0e7..b863fa57fd 100644 --- a/protocols/SkypeWeb/src/skype_messages.cpp +++ b/protocols/SkypeWeb/src/skype_messages.cpp @@ -3,89 +3,113 @@ /* MESSAGE RECEIVING */ // writing message/even into db -int CSkypeProto::OnReceiveMessage(const char *from, const char *convLink, time_t timeStamp, char *content) +int CSkypeProto::OnReceiveMessage(const char *from, const char *convLink, time_t timestamp, char *content) { + setDword("LastMsgTime", timestamp); PROTORECVEVENT recv = { 0 }; recv.flags = PREF_UTF; - recv.timestamp = timeStamp; + recv.timestamp = timestamp; recv.szMessage = content; - debugLogA("Incoming message from %s", ContactUrlToName(from)); - if (IsMe(ContactUrlToName(from))) + + ptrA skypename(ContactUrlToName(from)); + debugLogA("Incoming message from %s", skypename); + if (IsMe(skypename)) { recv.flags |= PREF_SENT; MCONTACT hContact = GetContact(ContactUrlToName(convLink)); return ProtoChainRecvMsg(hContact, &recv); } - MCONTACT hContact = GetContact(ContactUrlToName(from)); + MCONTACT hContact = GetContact(skypename); return ProtoChainRecvMsg(hContact, &recv); } /* MESSAGE SENDING */ +struct SendMessageParam +{ + MCONTACT hContact; + HANDLE hMessage; +}; + // outcoming message flow int CSkypeProto::OnSendMessage(MCONTACT hContact, int flags, const char *szMessage) { - UINT hMessage = InterlockedIncrement(&hMessageProcess); + ULONG hMessage = InterlockedIncrement(&hMessageProcess); + + if (!IsOnline()) + { + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, NULL, (LPARAM)"You cannot send when you are offline."); + return 0; + } - SendMessageParam *param = (SendMessageParam*)mir_calloc(sizeof(SendMessageParam)); + SendMessageParam *param = new SendMessageParam(); param->hContact = hContact; param->hMessage = (HANDLE)hMessage; - param->msg = szMessage; - param->flags = flags; - ForkThread(&CSkypeProto::SendMsgThread, (void*)param); + ptrA message; + if (flags & PREF_UNICODE) + message = mir_utf8encodeW((wchar_t*)&szMessage[mir_strlen(szMessage) + 1]); + else if (flags & PREF_UTF) + message = mir_strdup(szMessage); + else + message = mir_utf8encode(szMessage); + + ptrA server(getStringA("Server")); + ptrA token(getStringA("registrationToken")); + ptrA username(getStringA(hContact, "Skypename")); + PushRequest(new SendMsgRequest(token, username, message, server), &CSkypeProto::OnMessageSent, param); return hMessage; } -void CSkypeProto::SendMsgThread(void *arg) +void CSkypeProto::OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg) { SendMessageParam *param = (SendMessageParam*)arg; + MCONTACT hContact = param->hContact; + HANDLE hMessage = param->hMessage; + delete param; - if (!IsOnline()) + if (response->resultCode != 200 || response->resultCode != 201) { - ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hMessage, (LPARAM)Translate("You cannot send messages when you are offline.")); - mir_free(param); + CMStringA error = "Unknown error"; + if (response) + { + JSONROOT root(response->pData); + JSONNODE *node = json_get(root, "errorCode"); + error = _T2A(json_as_string(node)); + } + ptrT username(getTStringA(hContact, "Skypename")); + debugLogA(__FUNCTION__": failed to send message for %s (%s)", username, error); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, hMessage, (LPARAM)error.GetBuffer()); return; } - CMStringA message = (param->flags & PREF_UNICODE) ? ptrA(mir_utf8encode(param->msg)) : param->msg; // TODO: mir_utf8encode check taken from FacebookRM, is it needed? Usually we get PREF_UTF8 flag instead. - - ptrA token(getStringA("registrationToken")); - ptrA username(getStringA(param->hContact, "Skypename")); - PushRequest( - new SendMsgRequest(token, username, message, getStringA("Server"))/*, - &CSkypeProto::OnMessageSent*/); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, hMessage, 0); } -void CSkypeProto::OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg) +void CSkypeProto::OnGetServerHistory(const NETLIBHTTPREQUEST *response) { - SendMessageParam *param = (SendMessageParam*)arg; - - ptrT error(mir_tstrdup(TranslateT("Unknown error"))); - ptrT username(getTStringA(param->hContact, "Skypename")); - - if (response != NULL && (response->resultCode == 201 || response->resultCode == 200)) - { - JSONROOT root(response->pData); - JSONNODE *node = json_get(root, "errorCode"); - if (node) - error = json_as_string(node); - } + if (response == NULL) + return; - int status = ACKRESULT_FAILED; + JSONROOT root(response->pData); + if (root == NULL) + return; - if (error == NULL) + JSONNODE *conversations = json_as_array(json_get(root, "conversations")); + for (size_t i = 0; i < json_size(conversations); i++) { - status = ACKRESULT_SUCCESS; + JSONNODE *message = json_get(json_at(conversations, i), "lastMessage"); + + ptrA clientMsgId(mir_t2a(ptrT(json_as_string(json_get(message, "clientmessageid"))))); + ptrA skypeEditedId(mir_t2a(ptrT(json_as_string(json_get(message, "skypeeditedid"))))); + ptrA messageType(mir_t2a(ptrT(json_as_string(json_get(message, "messagetype"))))); + ptrA from(mir_t2a(ptrT(json_as_string(json_get(message, "from"))))); + ptrA content(mir_t2a(ptrT(json_as_string(json_get(message, "content"))))); + ptrT composeTime(json_as_string(json_get(message, "composetime"))); + ptrA conversationLink(mir_t2a(ptrT(json_as_string(json_get(message, "conversationLink"))))); + time_t timestamp = IsoToUnixTime(composeTime); + if (conversationLink != NULL && strstr(conversationLink, "/8:")) + OnReceiveMessage(from, conversationLink, timestamp, content); } - else - debugLog(_T("CSkypeProto::OnMessageSent: failed to send message for %s (%s)"), username, error); - - ProtoBroadcastAck( - param->hContact, - ACKTYPE_MESSAGE, - status, - param->hMessage, - error); } \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_poll_processing.cpp b/protocols/SkypeWeb/src/skype_poll_processing.cpp index 24baf6f8e1..e2f0f6c0de 100644 --- a/protocols/SkypeWeb/src/skype_poll_processing.cpp +++ b/protocols/SkypeWeb/src/skype_poll_processing.cpp @@ -86,7 +86,7 @@ void CSkypeProto::ProcessNewMessageRes(JSONNODE *node) char *convname; if (strstr(conversationLink, "/19:")) { - const char *chatname, *topic; + const char *chatname; chatname = ContactUrlToName(conversationLink); convname = mir_strdup(chatname); return; //chats not supported @@ -100,7 +100,8 @@ void CSkypeProto::ProcessNewMessageRes(JSONNODE *node) } else if (!mir_strcmpi(messagetype, "Control/ClearTyping")) { - return; + MCONTACT hContact = GetContact(ContactUrlToName(from)); + CallService(MS_PROTO_CONTACTISTYPING, hContact, 0); } else if (!mir_strcmpi(messagetype, "Text") || !mir_strcmpi(messagetype, "RichText")) { diff --git a/protocols/SkypeWeb/src/skype_polling.cpp b/protocols/SkypeWeb/src/skype_polling.cpp index 668359667f..528f9e7d53 100644 --- a/protocols/SkypeWeb/src/skype_polling.cpp +++ b/protocols/SkypeWeb/src/skype_polling.cpp @@ -5,13 +5,12 @@ void CSkypeProto::ParsePollData(JSONNODE *data) { debugLogA("CSkypeProto::ParsePollData"); - JSONNODE *node, *item = NULL; + JSONNODE *node; 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++) + for (size_t i = 0; i < json_size(messages); i++) { JSONNODE *message = json_at(messages, i); JSONNODE *resType = json_get(message, "resourceType"); diff --git a/protocols/SkypeWeb/src/skype_profile.cpp b/protocols/SkypeWeb/src/skype_profile.cpp index 2b5ec95218..c260380fc2 100644 --- a/protocols/SkypeWeb/src/skype_profile.cpp +++ b/protocols/SkypeWeb/src/skype_profile.cpp @@ -427,7 +427,7 @@ void CSkypeProto::UpdateProfileXStatusMessage(JSONNODE *root, MCONTACT hContact) void CSkypeProto::UpdateProfileAvatar(JSONNODE *root, MCONTACT hContact) { - JSONNODE *node = json_get(root, "avatarUrl"); + //JSONNODE *node = json_get(root, "avatarUrl"); // add avatar support } diff --git a/protocols/SkypeWeb/src/skype_proto.cpp b/protocols/SkypeWeb/src/skype_proto.cpp index 3937a4e6c7..eb420ad998 100644 --- a/protocols/SkypeWeb/src/skype_proto.cpp +++ b/protocols/SkypeWeb/src/skype_proto.cpp @@ -141,7 +141,15 @@ int CSkypeProto::SetStatus(int iNewStatus) isTerminated = true; //if (m_pollingConnection) // CallService(MS_NETLIB_SHUTDOWN, (WPARAM)m_pollingConnection, 0); - PushRequest(new LogoutRequest()); + LogoutRequest *logoutRequest = new LogoutRequest(); + if (!cookies.empty()) + { + CMStringA allCookies; + for (std::map::iterator cookie = cookies.begin(); cookie != cookies.end(); ++cookie) + allCookies.AppendFormat("%s=%s; ", cookie->first.c_str(), cookie->second.c_str()); + logoutRequest->Headers << CHAR_VALUE("Set-Cookie", allCookies); + } + PushRequest(logoutRequest); requestQueue->Stop(); if (!Miranda_Terminated()) diff --git a/protocols/SkypeWeb/src/skype_proto.h b/protocols/SkypeWeb/src/skype_proto.h index 5e598a8e99..1be152508d 100644 --- a/protocols/SkypeWeb/src/skype_proto.h +++ b/protocols/SkypeWeb/src/skype_proto.h @@ -1,21 +1,8 @@ #ifndef _SKYPE_PROTO_H_ #define _SKYPE_PROTO_H_ -struct SendMessageParam -{ - MCONTACT hContact; - HANDLE hMessage; - const char *msg; - int flags; -}; - -enum ARG_FREE_TYPE -{ - ARG_NO_FREE, - ARG_MIR_FREE -}; - typedef void(CSkypeProto::*SkypeResponseCallback)(const NETLIBHTTPREQUEST *response); +typedef void(CSkypeProto::*SkypeResponseWithArgCallback)(const NETLIBHTTPREQUEST *response, void *arg); struct CSkypeProto : public PROTO < CSkypeProto > { @@ -116,7 +103,9 @@ private: INT_PTR __cdecl OnAccountManagerInit(WPARAM, LPARAM); // requests - void PushRequest(HttpRequest *request, SkypeResponseCallback response = NULL); + void PushRequest(HttpRequest *request); + void PushRequest(HttpRequest *request, SkypeResponseCallback response); + void PushRequest(HttpRequest *request, SkypeResponseWithArgCallback response, void *arg); // icons static IconInfo Icons[]; @@ -184,10 +173,11 @@ private: int __cdecl OnContactDeleted(MCONTACT, LPARAM); // messages - int OnReceiveMessage(const char *from, const char *convLink, time_t timeStamp, char *content); + int OnReceiveMessage(const char *from, const char *convLink, time_t timestamp, char *content); int OnSendMessage(MCONTACT hContact, int flags, const char *message); void __cdecl CSkypeProto::SendMsgThread(void *arg); void OnMessageSent(const NETLIBHTTPREQUEST *response, void *arg); + void OnGetServerHistory(const NETLIBHTTPREQUEST *response); //polling void __cdecl ParsePollData(JSONNODE *data); void __cdecl PollingThread(void*); diff --git a/protocols/SkypeWeb/src/skype_request.cpp b/protocols/SkypeWeb/src/skype_request.cpp index 61d9754ec0..b0026de980 100644 --- a/protocols/SkypeWeb/src/skype_request.cpp +++ b/protocols/SkypeWeb/src/skype_request.cpp @@ -5,14 +5,24 @@ class SkypeResponseDelegate private: CSkypeProto *proto; SkypeResponseCallback responseCallback; + SkypeResponseWithArgCallback responseWithArgCallback; + + void *arg; + bool hasArg; public: SkypeResponseDelegate(CSkypeProto *proto, SkypeResponseCallback responseCallback) - : proto(proto), responseCallback(responseCallback) { } + : proto(proto), responseCallback(responseCallback), arg(NULL), hasArg(false) {} + + SkypeResponseDelegate(CSkypeProto *proto, SkypeResponseWithArgCallback responseCallback, void *arg) + : proto(proto), responseWithArgCallback(responseCallback), arg(arg), hasArg(true) { } void Invoke(const NETLIBHTTPREQUEST *response) { - (proto->*(responseCallback))(response); + if (hasArg) + (proto->*(responseWithArgCallback))(response, arg); + else + (proto->*(responseCallback))(response); } }; @@ -21,22 +31,20 @@ static void SkypeHttpResponse(const NETLIBHTTPREQUEST *response, void *arg) ((SkypeResponseDelegate*)arg)->Invoke(response); } -void CSkypeProto::PushRequest(HttpRequest *request, SkypeResponseCallback response) +void CSkypeProto::PushRequest(HttpRequest *request) { - if (!cookies.empty()) - { - CMStringA allCookies; - for (std::map::iterator cookie = cookies.begin(); cookie != cookies.end(); ++cookie) - allCookies.AppendFormat("%s=%s; ", cookie->first.c_str(), cookie->second.c_str()); - request->Headers << CHAR_VALUE("Set-Cookie", allCookies); - } - - if (response == NULL) - { - requestQueue->Push(request); - return; - } + requestQueue->Push(request); + return; +} +void CSkypeProto::PushRequest(HttpRequest *request, SkypeResponseCallback response) +{ SkypeResponseDelegate *delegate = new SkypeResponseDelegate(this, response); requestQueue->Push(request, SkypeHttpResponse, delegate); +} + +void CSkypeProto::PushRequest(HttpRequest *request, SkypeResponseWithArgCallback response, void *arg) +{ + SkypeResponseDelegate *delegate = new SkypeResponseDelegate(this, response, arg); + requestQueue->Push(request, SkypeHttpResponse, delegate); } \ No newline at end of file diff --git a/protocols/SkypeWeb/src/skype_utils.cpp b/protocols/SkypeWeb/src/skype_utils.cpp index df66f1ee97..4b3723dfe3 100644 --- a/protocols/SkypeWeb/src/skype_utils.cpp +++ b/protocols/SkypeWeb/src/skype_utils.cpp @@ -78,7 +78,6 @@ bool CSkypeProto::IsMe(const char *skypeName) char *CSkypeProto::MirandaToSkypeStatus(int status) { - char *result = "Online"; switch (status) { case ID_STATUS_AWAY: -- cgit v1.2.3