summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2025-04-24 17:43:33 +0300
committerGeorge Hazan <george.hazan@gmail.com>2025-04-24 17:43:33 +0300
commit53e0b5f3ff938adf11b2237727510e07e23ffdb6 (patch)
treef1b89510e1ce480200ca9c85df4914a3641795db
parentcb1fe45eefc98557069ac57bee75762e25f91e1e (diff)
Teams: fix for private messages sending
-rw-r--r--protocols/Teams/Teams.vcxproj1
-rw-r--r--protocols/Teams/Teams.vcxproj.filters3
-rw-r--r--protocols/Teams/src/requests/history.h56
-rw-r--r--protocols/Teams/src/stdafx.h1
-rw-r--r--protocols/Teams/src/teams_chatrooms.cpp2
-rw-r--r--protocols/Teams/src/teams_history.cpp131
-rw-r--r--protocols/Teams/src/teams_messages.cpp66
-rw-r--r--protocols/Teams/src/teams_proto.cpp2
-rw-r--r--protocols/Teams/src/teams_proto.h13
-rw-r--r--protocols/Teams/src/teams_server.cpp2
-rw-r--r--protocols/Teams/src/teams_utils.cpp3
-rw-r--r--src/mir_app/src/MHttpResponse.cpp14
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;
}
}