diff options
author | George Hazan <george.hazan@gmail.com> | 2025-04-24 17:43:33 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2025-04-24 17:43:33 +0300 |
commit | 53e0b5f3ff938adf11b2237727510e07e23ffdb6 (patch) | |
tree | f1b89510e1ce480200ca9c85df4914a3641795db | |
parent | cb1fe45eefc98557069ac57bee75762e25f91e1e (diff) |
Teams: fix for private messages sending
-rw-r--r-- | protocols/Teams/Teams.vcxproj | 1 | ||||
-rw-r--r-- | protocols/Teams/Teams.vcxproj.filters | 3 | ||||
-rw-r--r-- | protocols/Teams/src/requests/history.h | 56 | ||||
-rw-r--r-- | protocols/Teams/src/stdafx.h | 1 | ||||
-rw-r--r-- | protocols/Teams/src/teams_chatrooms.cpp | 2 | ||||
-rw-r--r-- | protocols/Teams/src/teams_history.cpp | 131 | ||||
-rw-r--r-- | protocols/Teams/src/teams_messages.cpp | 66 | ||||
-rw-r--r-- | protocols/Teams/src/teams_proto.cpp | 2 | ||||
-rw-r--r-- | protocols/Teams/src/teams_proto.h | 13 | ||||
-rw-r--r-- | protocols/Teams/src/teams_server.cpp | 2 | ||||
-rw-r--r-- | protocols/Teams/src/teams_utils.cpp | 3 | ||||
-rw-r--r-- | src/mir_app/src/MHttpResponse.cpp | 14 |
12 files changed, 132 insertions, 162 deletions
diff --git a/protocols/Teams/Teams.vcxproj b/protocols/Teams/Teams.vcxproj index 055768d98b..2c3d994fe9 100644 --- a/protocols/Teams/Teams.vcxproj +++ b/protocols/Teams/Teams.vcxproj @@ -49,7 +49,6 @@ <ClCompile Include="src\teams_trouter.cpp" /> <ClCompile Include="src\teams_utils.cpp" /> <ClInclude Include="src\requests\chatrooms.h" /> - <ClInclude Include="src\requests\history.h" /> <ClInclude Include="src\requests\search.h" /> <ClInclude Include="src\resource.h" /> <ClInclude Include="src\stdafx.h" /> diff --git a/protocols/Teams/Teams.vcxproj.filters b/protocols/Teams/Teams.vcxproj.filters index 3b9e085861..7f16e45a0d 100644 --- a/protocols/Teams/Teams.vcxproj.filters +++ b/protocols/Teams/Teams.vcxproj.filters @@ -84,9 +84,6 @@ <ClInclude Include="src\requests\chatrooms.h"> <Filter>Header Files\Requests</Filter> </ClInclude> - <ClInclude Include="src\requests\history.h"> - <Filter>Header Files\Requests</Filter> - </ClInclude> <ClInclude Include="src\requests\search.h"> <Filter>Header Files\Requests</Filter> </ClInclude> diff --git a/protocols/Teams/src/requests/history.h b/protocols/Teams/src/requests/history.h deleted file mode 100644 index 44276e78e0..0000000000 --- a/protocols/Teams/src/requests/history.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef _SKYPE_REQUEST_HISTORY_H_ -#define _SKYPE_REQUEST_HISTORY_H_ - -struct SyncConversations : public AsyncHttpRequest -{ - SyncConversations() : - AsyncHttpRequest(REQUEST_GET, HOST_DEFAULT, "/users/ME/conversations", &CTeamsProto::OnSyncConversations) - { - this << INT_PARAM("startTime", 0) << INT_PARAM("pageSize", 100) - << CHAR_PARAM("view", "msnp24Equivalent") << CHAR_PARAM("targetType", "Passport|Skype|Lync|Thread"); - } -}; - -struct GetHistoryRequest : public AsyncHttpRequest -{ - CMStringA m_who; - - GetHistoryRequest(MCONTACT _1, const char *who, int pageSize, int64_t timestamp, bool bOperative) : - AsyncHttpRequest(REQUEST_GET, HOST_DEFAULT, "/users/ME/conversations/" + mir_urlEncode(who) + "/messages", &CTeamsProto::OnGetServerHistory), - m_who(who) - { - hContact = _1; - if (bOperative) - pUserInfo = this; - - this << INT64_PARAM("startTime", timestamp) << INT_PARAM("pageSize", pageSize) - << CHAR_PARAM("view", "msnp24Equivalent") << CHAR_PARAM("targetType", "Passport|Skype|Lync|Thread"); - } -}; - -struct EmptyHistoryRequest : public AsyncHttpRequest -{ - EmptyHistoryRequest(const char *who) : - AsyncHttpRequest(REQUEST_DELETE, HOST_DEFAULT, "/users/ME/conversations/" + mir_urlEncode(who) + "/messages") - { - } -}; - -#endif //_SKYPE_REQUEST_HISTORY_H_ diff --git a/protocols/Teams/src/stdafx.h b/protocols/Teams/src/stdafx.h index 07aee25c19..25d04cc5e4 100644 --- a/protocols/Teams/src/stdafx.h +++ b/protocols/Teams/src/stdafx.h @@ -92,7 +92,6 @@ struct AsyncHttpRequest : public MTHttpRequest<CTeamsProto> #include "teams_proto.h" #include "requests/chatrooms.h" -#include "requests/history.h" #include "requests/search.h" #endif //_COMMON_H_ diff --git a/protocols/Teams/src/teams_chatrooms.cpp b/protocols/Teams/src/teams_chatrooms.cpp index 87a3314965..d2ee2fa99e 100644 --- a/protocols/Teams/src/teams_chatrooms.cpp +++ b/protocols/Teams/src/teams_chatrooms.cpp @@ -402,7 +402,7 @@ void CTeamsProto::OnGetChatInfo(MHttpResponse *response, AsyncHttpRequest*) if (arIds.getCount()) PushRequest(new GetChatMembersRequest(arIds, si)); - PushRequest(new GetHistoryRequest(si->hContact, T2Utf(si->ptszID), 100, 0, true)); + GetServerHistory(si->hContact, 100, 0, true); } wchar_t* CTeamsProto::GetChatContactNick(SESSION_INFO *si, const wchar_t *id, const wchar_t *name, bool *isQualified) diff --git a/protocols/Teams/src/teams_history.cpp b/protocols/Teams/src/teams_history.cpp index a2502a0eb3..aaf26da642 100644 --- a/protocols/Teams/src/teams_history.cpp +++ b/protocols/Teams/src/teams_history.cpp @@ -19,13 +19,82 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. /* HISTORY SYNC */ +void CTeamsProto::RefreshConversations() +{ + auto *pReq = new AsyncHttpRequest(REQUEST_GET, HOST_DEFAULT, "/users/ME/conversations", &CTeamsProto::OnSyncConversations); + pReq << INT_PARAM("startTime", getLastTime(0)) << INT_PARAM("pageSize", 100) + << CHAR_PARAM("view", "msnp24Equivalent") << CHAR_PARAM("targetType", "Passport|Skype|Lync|Thread"); + + PushRequest(pReq); +} + +void CTeamsProto::OnSyncConversations(MHttpResponse *response, AsyncHttpRequest *) +{ + TeamsReply reply(response); + if (reply.error()) + return; + + auto &root = reply.data(); + const JSONNode &metadata = root["_metadata"]; + const JSONNode &conversations = root["conversations"].as_array(); + + // int totalCount = metadata["totalCount"].as_int(); + std::string syncState = metadata["syncState"].as_string(); + + for (auto &it : conversations) { + const JSONNode &lastMessage = it["lastMessage"]; + if (!lastMessage) + continue; + + int iUserType; + std::string strConversationLink = lastMessage["conversationLink"].as_string(); + CMStringA szSkypename = UrlToSkypeId(strConversationLink.c_str(), &iUserType); + switch (iUserType) { + case 19: + { + auto &props = it["threadProperties"]; + if (!props["lastleaveat"]) + StartChatRoom(it["id"].as_mstring(), props["topic"].as_mstring(), props["version"].as_string().c_str()); + } + __fallthrough; + + case 8: + case 2: + int64_t id = _atoi64(lastMessage["id"].as_string().c_str()); + + MCONTACT hContact = FindContact(szSkypename); + if (hContact != NULL) { + auto lastMsgTime = getLastTime(hContact); + if (lastMsgTime && lastMsgTime < id && m_bAutoHistorySync) + GetServerHistory(hContact, 100, lastMsgTime, true); + } + } + } + + m_bHistorySynced = true; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::GetServerHistory(MCONTACT hContact, int pageSize, int64_t timestamp, bool bOperative) +{ + auto *pReq = new AsyncHttpRequest(REQUEST_GET, HOST_DEFAULT, "/users/ME/conversations/" + mir_urlEncode(getId(hContact)) + "/messages", &CTeamsProto::OnGetServerHistory); + pReq->hContact = hContact; + if (bOperative) + pReq->pUserInfo = this; + + pReq << INT64_PARAM("startTime", timestamp) << INT_PARAM("pageSize", pageSize) + << CHAR_PARAM("view", "msnp24Equivalent") << CHAR_PARAM("targetType", "Passport|Skype|Lync|Thread"); + + PushRequest(pReq); +} + void CTeamsProto::OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest *pRequest) { TeamsReply reply(response); if (reply.error()) return; - auto *pOrig = (GetHistoryRequest *)pRequest; auto &root = reply.data(); const JSONNode &metadata = root["_metadata"]; @@ -81,71 +150,25 @@ void CTeamsProto::OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest * } } - if (bSetLastTime && lastMsgTime > getLastTime(pOrig->hContact)) - setLastTime(pOrig->hContact, lastMsgTime); + if (bSetLastTime && lastMsgTime > getLastTime(pRequest->hContact)) + setLastTime(pRequest->hContact, lastMsgTime); if (totalCount >= 99 || conv.size() >= 99) - PushRequest(new GetHistoryRequest(pOrig->hContact, pOrig->m_who, 100, lastMsgTime, pRequest->pUserInfo != 0)); + GetServerHistory(pRequest->hContact, 100, lastMsgTime, pRequest->pUserInfo != 0); } INT_PTR CTeamsProto::SvcLoadHistory(WPARAM hContact, LPARAM) { - PushRequest(new GetHistoryRequest(hContact, getId(hContact), 100, 0, false)); + GetServerHistory(hContact, 100, 0, false); return 0; } -void CTeamsProto::OnSyncConversations(MHttpResponse *response, AsyncHttpRequest*) -{ - TeamsReply reply(response); - if (reply.error()) - return; - - auto &root = reply.data(); - const JSONNode &metadata = root["_metadata"]; - const JSONNode &conversations = root["conversations"].as_array(); - - // int totalCount = metadata["totalCount"].as_int(); - std::string syncState = metadata["syncState"].as_string(); - - for (auto &it: conversations) { - const JSONNode &lastMessage = it["lastMessage"]; - if (!lastMessage) - continue; - - int iUserType; - std::string strConversationLink = lastMessage["conversationLink"].as_string(); - CMStringA szSkypename = UrlToSkypeId(strConversationLink.c_str(), &iUserType); - switch (iUserType) { - case 19: - { - auto &props = it["threadProperties"]; - if (!props["lastleaveat"]) - StartChatRoom(it["id"].as_mstring(), props["topic"].as_mstring(), props["version"].as_string().c_str()); - } - __fallthrough; - - case 8: - case 2: - int64_t id = _atoi64(lastMessage["id"].as_string().c_str()); - - MCONTACT hContact = FindContact(szSkypename); - if (hContact != NULL) { - auto lastMsgTime = getLastTime(hContact); - if (lastMsgTime && lastMsgTime < id && m_bAutoHistorySync) - PushRequest(new GetHistoryRequest(hContact, szSkypename, 100, lastMsgTime, true)); - } - } - } - - m_bHistorySynced = true; -} - ////////////////////////////////////////////////////////////////////////////////////////// INT_PTR CTeamsProto::SvcEmptyHistory(WPARAM hContact, LPARAM flags) { - if (flags & CDF_DEL_HISTORY) { - PushRequest(new EmptyHistoryRequest(getId(hContact))); - } + if (flags & CDF_DEL_HISTORY) + PushRequest(new AsyncHttpRequest(REQUEST_DELETE, HOST_DEFAULT, "/users/ME/conversations/" + mir_urlEncode(getId(hContact)) + "/messages")); + return 0; } diff --git a/protocols/Teams/src/teams_messages.cpp b/protocols/Teams/src/teams_messages.cpp index e55b83816c..9c29ee3827 100644 --- a/protocols/Teams/src/teams_messages.cpp +++ b/protocols/Teams/src/teams_messages.cpp @@ -22,25 +22,43 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. void CTeamsProto::OnMessageSent(MHttpResponse *response, AsyncHttpRequest *pRequest) { + // to delete it in any case + std::unique_ptr<COwnMessage> pMessage((COwnMessage *)pRequest->pUserInfo); + MCONTACT hContact = pRequest->hContact; if (Contact::IsGroupChat(hContact)) return; - if (response != nullptr) { - if (response->resultCode != 201) { - std::string strError = Translate("Unknown error!"); + if (response == nullptr) { + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, pRequest->pUserInfo, (LPARAM)TranslateT("Network error!")); + return; + } + + if (response->resultCode == 201) { + JsonReply reply(response); + auto &pRoot = reply.data(); + CMStringA msgId(pRoot["OriginalArrivalTime"].as_mstring()); - if (!response->body.IsEmpty()) { - JSONNode jRoot = JSONNode::parse(response->body); - const JSONNode &jErr = jRoot["errorCode"]; - if (jErr) - strError = jErr.as_string(); - } + if (pMessage) { + pMessage->iTimestamp = _atoi64(msgId); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)pMessage->hMessage, (LPARAM)msgId.c_str()); - ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, pRequest->pUserInfo, _A2T(strError.c_str())); + mir_cslock lck(m_lckOutMessagesList); + m_OutMessages.remove(pMessage.get()); } } - else ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, pRequest->pUserInfo, (LPARAM)TranslateT("Network error!")); + else { + std::string strError = Translate("Unknown error!"); + + if (!response->body.IsEmpty()) { + JSONNode jRoot = JSONNode::parse(response->body); + const JSONNode &jErr = jRoot["errorCode"]; + if (jErr) + strError = jErr.as_string(); + } + + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, pRequest->pUserInfo, _A2T(strError.c_str())); + } } // outcoming message flow @@ -58,10 +76,6 @@ int CTeamsProto::SendServerMsg(MCONTACT hContact, const char *szMessage, int64_t if (existingMsgId) szUrl.AppendFormat("/%lld", existingMsgId); - AsyncHttpRequest *pReq = new AsyncHttpRequest(existingMsgId ? REQUEST_PUT : REQUEST_POST, HOST_DEFAULT, szUrl, &CTeamsProto::OnMessageSent); - pReq->hContact = hContact; - pReq->pUserInfo = (HANDLE)m_iMessageId; - JSONNode node; node << CHAR_PARAM("messagetype", bRich ? "RichText" : "Text") << CHAR_PARAM("contenttype", "text"); if (strncmp(str, "/me ", 4) == 0) @@ -69,15 +83,19 @@ int CTeamsProto::SendServerMsg(MCONTACT hContact, const char *szMessage, int64_t else node << CHAR_PARAM("content", str); + COwnMessage *pOwnMessage = nullptr; if (!existingMsgId) { int64_t iRandomId = getRandomId(); node << INT64_PARAM("clientmessageid", iRandomId); mir_cslock lck(m_lckOutMessagesList); - m_OutMessages.insert(new COwnMessage(m_iMessageId, iRandomId)); + m_OutMessages.insert(pOwnMessage = new COwnMessage(m_iMessageId, iRandomId)); } - pReq->m_szParam = node.write().c_str(); + AsyncHttpRequest *pReq = new AsyncHttpRequest(existingMsgId ? REQUEST_PUT : REQUEST_POST, HOST_DEFAULT, szUrl, &CTeamsProto::OnMessageSent); + pReq->hContact = hContact; + pReq->pUserInfo = pOwnMessage; + pReq->m_szParam = node.write().c_str(); PushRequest(pReq); return m_iMessageId; @@ -127,20 +145,6 @@ LBL_Deleted: } if (strMessageType == "Text" || strMessageType == "RichText") { - if (dbei.bSent && dbei.szId) { - for (auto &it: m_OutMessages) { - if (it->hClientMessageId == _atoi64(dbei.szId)) { - it->iTimestamp = dbei.iTimestamp; - - ProtoBroadcastAck(dbei.hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)it->hMessage, (LPARAM)dbei.szId); - - mir_cslock lck(m_lckOutMessagesList); - m_OutMessages.removeItem(&it); - return false; - } - } - } - if (strMessageType == "RichText") wszContent = RemoveHtml(wszContent); diff --git a/protocols/Teams/src/teams_proto.cpp b/protocols/Teams/src/teams_proto.cpp index 9c773120fe..2e4164748d 100644 --- a/protocols/Teams/src/teams_proto.cpp +++ b/protocols/Teams/src/teams_proto.cpp @@ -252,7 +252,7 @@ int CTeamsProto::UserIsTyping(MCONTACT hContact, int iState) node << INT64_PARAM("clientmessageid", getRandomId()) << CHAR_PARAM("contenttype", "Application/Message") << CHAR_PARAM("content", "") << CHAR_PARAM("messagetype", (iState == PROTOTYPE_SELFTYPING_ON) ? "Control/Typing" : "Control/ClearTyping"); - auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_CHATS, "/users/ME/conversations/" + mir_urlEncode(getId(hContact)) + "/messages"); + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/conversations/" + mir_urlEncode(getId(hContact)) + "/messages"); pReq->m_szParam = node.write().c_str(); PushRequest(pReq); return 0; diff --git a/protocols/Teams/src/teams_proto.h b/protocols/Teams/src/teams_proto.h index c5e072ad22..194072532d 100644 --- a/protocols/Teams/src/teams_proto.h +++ b/protocols/Teams/src/teams_proto.h @@ -197,9 +197,6 @@ public: void OnMessageSent(MHttpResponse *response, AsyncHttpRequest *pRequest); - void OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest *pRequest); - void OnSyncConversations(MHttpResponse *response, AsyncHttpRequest *pRequest); - void OnGetChatInfo(MHttpResponse *response, AsyncHttpRequest *pRequest); void OnGetChatMembers(MHttpResponse *response, AsyncHttpRequest *pRequest); @@ -213,7 +210,6 @@ private: static std::map<std::wstring, std::wstring> languages; LIST<void> m_PopupClasses; - OBJLIST<COwnMessage> m_OutMessages; // avatars void SetAvatarUrl(MCONTACT hContact, const CMStringW &tszUrl); @@ -267,14 +263,21 @@ private: INT_PTR __cdecl SvcOfflineFile(WPARAM, LPARAM); + // history + void GetServerHistory(MCONTACT hContact, int pageSize, int64_t timestamp, bool bOperative); + void RefreshConversations(); + + void OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest *pRequest); + void OnSyncConversations(MHttpResponse *response, AsyncHttpRequest *pRequest); + // menus static HGENMENU ContactMenuItems[CMI_MAX]; int OnPrebuildContactMenu(WPARAM hContact, LPARAM); static int PrebuildContactMenu(WPARAM hContact, LPARAM lParam); // messages - std::map<ULONGLONG, HANDLE> m_mpOutMessagesIds; mir_cs m_lckOutMessagesList; + LIST<COwnMessage> m_OutMessages; int SendServerMsg(MCONTACT hContact, const char *szMessage, int64_t iMessageId = 0); diff --git a/protocols/Teams/src/teams_server.cpp b/protocols/Teams/src/teams_server.cpp index b92f211000..ee55e90ce2 100644 --- a/protocols/Teams/src/teams_server.cpp +++ b/protocols/Teams/src/teams_server.cpp @@ -30,7 +30,7 @@ void CTeamsProto::OnCapabilitiesSended(MHttpResponse *response, AsyncHttpRequest CreateContactSubscription(); ReceiveAvatar(0); RefreshContactsInfo(); - PushRequest(new SyncConversations()); + RefreshConversations(); JSONNode root = JSONNode::parse(response->body); if (root) diff --git a/protocols/Teams/src/teams_utils.cpp b/protocols/Teams/src/teams_utils.cpp index a71e9f7e4e..615ba7a5de 100644 --- a/protocols/Teams/src/teams_utils.cpp +++ b/protocols/Teams/src/teams_utils.cpp @@ -556,6 +556,9 @@ void CTeamsProto::setLastTime(MCONTACT hContact, int64_t iValue) char buf[100]; _i64toa(iValue, buf, 10); setString(hContact, "LastMsgTime", buf); + + if (iValue > getLastTime(0)) + setString("LastMsgTime", buf); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/mir_app/src/MHttpResponse.cpp b/src/mir_app/src/MHttpResponse.cpp index 249c25173b..1b847ed6c6 100644 --- a/src/mir_app/src/MHttpResponse.cpp +++ b/src/mir_app/src/MHttpResponse.cpp @@ -42,14 +42,12 @@ JsonReply::JsonReply(MHttpResponse *pReply) return; } - m_errorCode = pReply->resultCode; - if (m_errorCode != 200) - return; - - m_root = json_parse(pReply->body); - if (m_root == nullptr) { - m_errorCode = 500; - return; + switch (m_errorCode = pReply->resultCode) { + case 200: case 201: case 204: + m_root = json_parse(pReply->body); + if (m_root == nullptr) + m_errorCode = 500; + break; } } |