diff options
author | George Hazan <george.hazan@gmail.com> | 2025-04-03 22:13:22 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2025-04-03 22:13:27 +0300 |
commit | fc73bfb84eeaf09ef147774c92ea2b8592032122 (patch) | |
tree | 67737f47161e96c59488a7fc3eca82960a8b276c /protocols/Teams/src | |
parent | 0f361039b66b42b704b6b3601a1c3a88e317cc7d (diff) |
Teams: minus polling
Diffstat (limited to 'protocols/Teams/src')
25 files changed, 360 insertions, 106 deletions
diff --git a/protocols/Teams/src/main.cpp b/protocols/Teams/src/main.cpp index d2ac241040..07778b2405 100644 --- a/protocols/Teams/src/main.cpp +++ b/protocols/Teams/src/main.cpp @@ -1,3 +1,20 @@ +/* +Copyright (C) 2025 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/>. +*/ + #include "stdafx.h" CMPlugin g_plugin; diff --git a/protocols/Teams/src/requests/capabilities.h b/protocols/Teams/src/requests/capabilities.h index 566d946e3e..b9785a2a92 100644 --- a/protocols/Teams/src/requests/capabilities.h +++ b/protocols/Teams/src/requests/capabilities.h @@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. struct SendCapabilitiesRequest : public AsyncHttpRequest { SendCapabilitiesRequest(const char *hostname, CTeamsProto *ppro) : - AsyncHttpRequest(REQUEST_PUT, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szId) + "/presenceDocs/messagingService", &CTeamsProto::OnCapabilitiesSended) + AsyncHttpRequest(REQUEST_PUT, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szEndpoint) + "/presenceDocs/messagingService", &CTeamsProto::OnCapabilitiesSended) { JSONNode privateInfo; privateInfo.set_name("privateInfo"); privateInfo << CHAR_PARAM("epname", hostname); diff --git a/protocols/Teams/src/requests/poll.h b/protocols/Teams/src/requests/poll.h index b2573a43e2..008873cd14 100644 --- a/protocols/Teams/src/requests/poll.h +++ b/protocols/Teams/src/requests/poll.h @@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. struct PollRequest : public AsyncHttpRequest { PollRequest(CTeamsProto *ppro) : - AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szId) + "/subscriptions/0/poll") + AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szEndpoint) + "/subscriptions/0/poll") { flags |= NLHRF_PERSISTENT; timeout = 120000; diff --git a/protocols/Teams/src/stdafx.cxx b/protocols/Teams/src/stdafx.cxx index 4a1e1f0e70..b64bcca703 100644 --- a/protocols/Teams/src/stdafx.cxx +++ b/protocols/Teams/src/stdafx.cxx @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2025 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 diff --git a/protocols/Teams/src/teams_avatars.cpp b/protocols/Teams/src/teams_avatars.cpp index 6bbac21d04..533aa62d08 100644 --- a/protocols/Teams/src/teams_avatars.cpp +++ b/protocols/Teams/src/teams_avatars.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -191,7 +191,7 @@ struct SetAvatarRequest : public AsyncHttpRequest void CTeamsProto::OnSentAvatar(MHttpResponse *response, AsyncHttpRequest*) { - SkypeReply root(response); + TeamsReply root(response); if (root.error()) return; } diff --git a/protocols/Teams/src/teams_chatrooms.cpp b/protocols/Teams/src/teams_chatrooms.cpp index 42c5f269ce..e4012e376f 100644 --- a/protocols/Teams/src/teams_chatrooms.cpp +++ b/protocols/Teams/src/teams_chatrooms.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -353,7 +353,7 @@ void CTeamsProto::SendChatMessage(SESSION_INFO *si, const wchar_t *tszMessage) void CTeamsProto::OnGetChatMembers(MHttpResponse *response, AsyncHttpRequest *pRequest) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; @@ -375,7 +375,7 @@ void CTeamsProto::OnGetChatMembers(MHttpResponse *response, AsyncHttpRequest *pR void CTeamsProto::OnGetChatInfo(MHttpResponse *response, AsyncHttpRequest*) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; diff --git a/protocols/Teams/src/teams_contacts.cpp b/protocols/Teams/src/teams_contacts.cpp index b8f94be72d..90fde17b50 100644 --- a/protocols/Teams/src/teams_contacts.cpp +++ b/protocols/Teams/src/teams_contacts.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -102,7 +102,7 @@ MCONTACT CTeamsProto::AddContact(const char *skypeId, const char *nick, bool isT void CTeamsProto::LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest*) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; @@ -140,7 +140,7 @@ void CTeamsProto::LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest*) void CTeamsProto::LoadContactList(MHttpResponse *response, AsyncHttpRequest*) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; diff --git a/protocols/Teams/src/teams_endpoint.cpp b/protocols/Teams/src/teams_endpoint.cpp index 39b6958abb..ead0857bf0 100644 --- a/protocols/Teams/src/teams_endpoint.cpp +++ b/protocols/Teams/src/teams_endpoint.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -17,15 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" -void CTeamsProto::ProcessTimer() -{ - if (!IsOnline()) - return; - - PushRequest(new GetContactListRequest()); - SendPresence(); -} - void CTeamsProto::SendCreateEndpoint() { auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints", &CTeamsProto::OnEndpointCreated); @@ -83,19 +74,17 @@ void CTeamsProto::OnEndpointCreated(MHttpResponse *response, AsyncHttpRequest*) if (name == "registrationToken") m_szToken = val.Detach(); else if (name == "endpointId") - m_szId = val.Detach(); + m_szEndpoint = val.Detach(); } } - if (m_szId && m_hPollingThread == nullptr) - ForkThread(&CTeamsProto::PollingThread); - + StartTrouter(); PushRequest(new CreateSubscriptionsRequest()); } void CTeamsProto::OnEndpointDeleted(MHttpResponse *, AsyncHttpRequest *) { - m_szId = nullptr; + m_szEndpoint = nullptr; m_szToken = nullptr; } diff --git a/protocols/Teams/src/teams_files.cpp b/protocols/Teams/src/teams_files.cpp index a6e7d07087..4efb89a662 100644 --- a/protocols/Teams/src/teams_files.cpp +++ b/protocols/Teams/src/teams_files.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) 2025 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/>. +*/ + #include "stdafx.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -48,7 +65,7 @@ void CTeamsProto::ReceiveFileThread(void *param) nlhr.AddHeader("Cookie", szCookie); NLHR_PTR response(Netlib_HttpTransaction(m_hNetlibUser, &nlhr)); if (response) { - SkypeReply reply(response); + TeamsReply reply(response); if (!reply.error()) { auto &root = reply.data(); if (root["content_state"].as_string() == "ready") diff --git a/protocols/Teams/src/teams_history.cpp b/protocols/Teams/src/teams_history.cpp index eb6a9ca39f..a2502a0eb3 100644 --- a/protocols/Teams/src/teams_history.cpp +++ b/protocols/Teams/src/teams_history.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -21,7 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. void CTeamsProto::OnGetServerHistory(MHttpResponse *response, AsyncHttpRequest *pRequest) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; @@ -96,7 +96,7 @@ INT_PTR CTeamsProto::SvcLoadHistory(WPARAM hContact, LPARAM) void CTeamsProto::OnSyncConversations(MHttpResponse *response, AsyncHttpRequest*) { - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) return; diff --git a/protocols/Teams/src/teams_http.cpp b/protocols/Teams/src/teams_http.cpp index 18e3067119..cc448b3a1d 100644 --- a/protocols/Teams/src/teams_http.cpp +++ b/protocols/Teams/src/teams_http.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 diff --git a/protocols/Teams/src/teams_login.cpp b/protocols/Teams/src/teams_login.cpp index 9e4f2a966a..b3c800d13a 100644 --- a/protocols/Teams/src/teams_login.cpp +++ b/protocols/Teams/src/teams_login.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -40,8 +40,6 @@ void CTeamsProto::LoggedIn() m_iStatus = m_iDesiredStatus; ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - m_impl.m_heartBeat.StartSafe(600 * 1000); - SendCreateEndpoint(); } diff --git a/protocols/Teams/src/teams_menus.cpp b/protocols/Teams/src/teams_menus.cpp index 9238c33946..8605e30a52 100644 --- a/protocols/Teams/src/teams_menus.cpp +++ b/protocols/Teams/src/teams_menus.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 diff --git a/protocols/Teams/src/teams_messages.cpp b/protocols/Teams/src/teams_messages.cpp index e55b83816c..c660ee0c60 100644 --- a/protocols/Teams/src/teams_messages.cpp +++ b/protocols/Teams/src/teams_messages.cpp @@ -154,6 +154,7 @@ LBL_Deleted: return true; } +/* void CTeamsProto::ProcessNewMessage(const JSONNode &node) { int iUserType; @@ -199,6 +200,7 @@ void CTeamsProto::ProcessNewMessage(const JSONNode &node) ProtoChainRecvMsg(hContact, dbei); } } +*/ void CTeamsProto::OnMarkRead(MCONTACT hContact, MEVENT hDbEvent) { diff --git a/protocols/Teams/src/teams_mood.cpp b/protocols/Teams/src/teams_mood.cpp index 66a2b15444..fb366ac97a 100644 --- a/protocols/Teams/src/teams_mood.cpp +++ b/protocols/Teams/src/teams_mood.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 diff --git a/protocols/Teams/src/teams_options.cpp b/protocols/Teams/src/teams_options.cpp index 040583ad85..693af22fb1 100644 --- a/protocols/Teams/src/teams_options.cpp +++ b/protocols/Teams/src/teams_options.cpp @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 diff --git a/protocols/Teams/src/teams_polling.cpp b/protocols/Teams/src/teams_polling.cpp index ca59ac8f6a..11a918034e 100644 --- a/protocols/Teams/src/teams_polling.cpp +++ b/protocols/Teams/src/teams_polling.cpp @@ -17,42 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdafx.h" -void CTeamsProto::PollingThread(void *) -{ - debugLogA(__FUNCTION__ ": entering"); - - m_iPollingId = -1; - - while (true) { - if (m_isTerminated || m_szId == nullptr) - break; - - std::unique_ptr<PollRequest> request(new PollRequest(this)); - request->nlc = m_hPollingConn; - NLHR_PTR response(DoSend(request.get())); - if (m_isTerminated || m_szId == nullptr) - break; - - if (response == nullptr || response->resultCode != 200) { - m_hPollingConn = nullptr; - continue; - } - - m_hPollingConn = response->nlc; - if (!response->body.IsEmpty()) - ParsePollData(response->body); - } - - if (!m_isTerminated) { - debugLogA(__FUNCTION__ ": unexpected termination; switching protocol to offline"); - SetStatus(ID_STATUS_OFFLINE); - } - - m_hPollingConn = nullptr; - m_hPollingThread = nullptr; - debugLogA(__FUNCTION__ ": leaving"); -} - void CTeamsProto::ParsePollData(const char *szData) { debugLogA(__FUNCTION__); @@ -171,6 +135,3 @@ void CTeamsProto::ProcessUserPresence(const JSONNode &node) } } } - -void CTeamsProto::ProcessConversationUpdate(const JSONNode &) {} -void CTeamsProto::ProcessThreadUpdate(const JSONNode &) {} diff --git a/protocols/Teams/src/teams_popups.cpp b/protocols/Teams/src/teams_popups.cpp index efac8c26f9..59cca9e937 100644 --- a/protocols/Teams/src/teams_popups.cpp +++ b/protocols/Teams/src/teams_popups.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) 2025 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/>. +*/ + #include "stdafx.h" void CTeamsProto::InitPopups() diff --git a/protocols/Teams/src/teams_profile.cpp b/protocols/Teams/src/teams_profile.cpp index a26d88b1fe..29a04937c6 100644 --- a/protocols/Teams/src/teams_profile.cpp +++ b/protocols/Teams/src/teams_profile.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -105,7 +105,7 @@ void CTeamsProto::LoadProfile(MHttpResponse *response, AsyncHttpRequest *pReques { MCONTACT hContact = (DWORD_PTR)pRequest->pUserInfo; - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) { ProtoBroadcastAck(hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, 0); return; diff --git a/protocols/Teams/src/teams_proto.cpp b/protocols/Teams/src/teams_proto.cpp index 28dcf637ad..d452c09781 100644 --- a/protocols/Teams/src/teams_proto.cpp +++ b/protocols/Teams/src/teams_proto.cpp @@ -1,3 +1,20 @@ +/* +Copyright (c) 2025 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/>. +*/ + #include "stdafx.h" CTeamsProto::CTeamsProto(const char *protoName, const wchar_t *userName) : @@ -83,6 +100,7 @@ void CTeamsProto::OnModulesLoaded() void CTeamsProto::OnShutdown() { StopQueue(); + StopTrouter(); } INT_PTR CTeamsProto::GetCaps(int type, MCONTACT) @@ -203,6 +221,7 @@ int CTeamsProto::SetStatus(int iNewStatus) if (iNewStatus == ID_STATUS_OFFLINE) { m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; StopQueue(); + StopTrouter(); ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, ID_STATUS_OFFLINE); diff --git a/protocols/Teams/src/teams_proto.h b/protocols/Teams/src/teams_proto.h index 850aae8808..c836053a21 100644 --- a/protocols/Teams/src/teams_proto.h +++ b/protocols/Teams/src/teams_proto.h @@ -1,4 +1,8 @@ #define TEAMS_CLIENT_ID "8ec6bc83-69c8-4392-8f08-b3c986009232" +#define TEAMS_CLIENTINFO_NAME "skypeteams" +#define TEAMS_CLIENTINFO_VERSION "49/24062722442" + +#define TEAMS_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0 Teams/24165.1410.2974.6689/49" #define DBKEY_ID "id" #define DBKEY_GROUP "DefaultGroup" @@ -39,7 +43,7 @@ class CTeamsProto : public PROTO<CTeamsProto> CTimer m_heartBeat, m_loginPoll; void OnHeartBeat(CTimer *) { - m_proto.ProcessTimer(); + m_proto.TRouterSendJson("ping"); } void OnLoginPoll(CTimer *) { @@ -141,12 +145,6 @@ public: void __cdecl SearchBasicThread(void *param); ////////////////////////////////////////////////////////////////////////////////////// - // services - - static INT_PTR __cdecl SvcEventGetIcon(WPARAM, LPARAM); - static INT_PTR __cdecl SvcGetEventText(WPARAM, LPARAM); - - ////////////////////////////////////////////////////////////////////////////////////// // settings CMOption<bool> m_bAutoHistorySync; @@ -164,7 +162,7 @@ public: // other data int m_iPollingId, m_iMessageId = 1; - ptrA m_szToken, m_szId, m_szOwnSkypeId; + ptrA m_szToken, m_szEndpoint, m_szOwnSkypeId; CMStringA m_szSkypename, m_szMyname, m_szSkypeToken; MCONTACT m_hMyContact; @@ -211,6 +209,7 @@ public: void LoadProfile(MHttpResponse *response, AsyncHttpRequest *pRequest); static INT_PTR __cdecl GlobalParseSkypeUriService(WPARAM, LPARAM lParam); + private: bool m_bHistorySynced; @@ -224,9 +223,6 @@ private: mir_cs messageSyncLock; mir_cs m_StatusLock; - HANDLE m_hPollingThread; - HNETLIBCONN m_hPollingConn; - // avatars void SetAvatarUrl(MCONTACT hContact, const CMStringW &tszUrl); bool ReceiveAvatar(MCONTACT hContact); @@ -303,18 +299,8 @@ private: void SetChatStatus(MCONTACT hContact, int iStatus); - // polling - void __cdecl PollingThread(void*); - bool ParseMessage(const JSONNode &node, DB::EventInfo &dbei); void ParsePollData(const char*); - - void ProcessNewMessage(const JSONNode &node); - void ProcessUserPresence(const JSONNode &node); - void ProcessThreadUpdate(const JSONNode &node); - void ProcessEndpointPresence(const JSONNode &node); - void ProcessConversationUpdate(const JSONNode &node); - // utils template <typename T> __inline static void FreeList(const LIST<T> &lst) @@ -346,8 +332,6 @@ private: static LRESULT CALLBACK PopupDlgProcCall(HWND hPopup, UINT uMsg, WPARAM wParam, LPARAM lParam); - void ProcessTimer(); - void SetString(MCONTACT hContact, const char *pszSetting, const JSONNode &node); CMStringW ChangeTopicForm(); @@ -369,6 +353,32 @@ private: auto *proto = CMPlugin::getInstance((MCONTACT)wParam); return proto ? (proto->*Service)(wParam, lParam) : 0; } + + // trouter +public: + void TRouterProcess(const char *str); + +private: + CMStringA m_szTrouterUrl, m_szTrouterSurl; + WebSocket<CTeamsProto> *m_ws; + MHttpHeaders m_connectParams; + int iCommandId; + + void __cdecl GatewayThread(void *); + + void TRouterSendJson(const char *szName, const JSONNode *node = 0); + void TRouterSendJson(const JSONNode &node); + + void TRouterSendAuthentication(); + void TRouterSendActive(bool); + void TRouterRegister(); + void TRouterRegister(const char *pszAppId, const char *pszKey, const char *pszPath); + + void StartTrouter(); + void StopTrouter(); + + void OnTrouterInfo(MHttpResponse *response, AsyncHttpRequest *pRequest); + void OnTrouterSession(MHttpResponse *response, AsyncHttpRequest *pRequest); }; typedef CProtoDlgBase<CTeamsProto> CTeamsDlgBase; diff --git a/protocols/Teams/src/teams_search.cpp b/protocols/Teams/src/teams_search.cpp index a88daaae47..5cceab3c3f 100644 --- a/protocols/Teams/src/teams_search.cpp +++ b/protocols/Teams/src/teams_search.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 @@ -34,7 +34,7 @@ void CTeamsProto::OnSearch(MHttpResponse *response, AsyncHttpRequest*) { debugLogA(__FUNCTION__); - SkypeReply reply(response); + TeamsReply reply(response); if (reply.error()) { ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0); return; diff --git a/protocols/Teams/src/teams_trouter.cpp b/protocols/Teams/src/teams_trouter.cpp new file mode 100644 index 0000000000..323c8f63af --- /dev/null +++ b/protocols/Teams/src/teams_trouter.cpp @@ -0,0 +1,224 @@ +/* +Copyright (C) 2025 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/>. +*/ + +#include "stdafx.h" + +#define TEAMS_TROUTER_TTL 86400 +#define TEAMS_TROUTER_TCCV "2024.23.01.2" + +void CTeamsProto::OnTrouterSession(MHttpResponse *response, AsyncHttpRequest *pRequest) +{ + if (response->resultCode != 200) { + LoginError(); + return; + } + + int iStart = 0; + CMStringA szId = response->body.Tokenize(":", iStart); + m_szTrouterUrl = pRequest->m_szUrl; + m_szTrouterUrl.Replace("socket.io/1/", "socket.io/1/websocket/" + szId + "/"); + ForkThread(&CTeamsProto::GatewayThread); +} + +void CTeamsProto::OnTrouterInfo(MHttpResponse *response, AsyncHttpRequest *) +{ + TeamsReply reply(response); + if (reply.error()) { + LoginError(); + return; + } + + auto &root = reply.data(); + m_szTrouterSurl = root["surl"].as_mstring(); + CMStringA ccid = root["ccid"].as_mstring(); + CMStringA szUrl = root["socketio"].as_mstring(); + szUrl += "socket.io/1/"; + + auto *pReq = new AsyncHttpRequest(REQUEST_GET, HOST_OTHER, szUrl, &CTeamsProto::OnTrouterSession); + pReq << CHAR_PARAM("v", "v4"); + + m_connectParams.destroy(); + for (auto &it : root["connectparams"]) { + m_connectParams.AddHeader(it.name(), it.as_string().c_str()); + pReq << CHAR_PARAM(it.name(), it.as_string().c_str()); + } + + pReq << CHAR_PARAM("tc", "{\"cv\":\"" TEAMS_TROUTER_TCCV "\",\"ua\":\"TeamsCDL\",\"hr\":\"\",\"v\":\"" TEAMS_CLIENTINFO_VERSION "\"}") + << CHAR_PARAM("con_num", "1234567890123_1") << CHAR_PARAM("epid", m_szEndpoint) << BOOL_PARAM("auth", true) << INT_PARAM("timeout", 40); + if (!ccid.IsEmpty()) + pReq << CHAR_PARAM("ccid", ccid); + PushRequest(pReq); +} + +void CTeamsProto::StartTrouter() +{ + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_OTHER, "https://go.trouter.teams.microsoft.com/v4/a", &CTeamsProto::OnTrouterInfo); + pReq->m_szUrl.AppendFormat("?epid=%s", m_szEndpoint.get()); + pReq->AddHeader("x-skypetoken", m_szSkypeToken); + pReq->flags |= NLHRF_NODUMPHEADERS; + PushRequest(pReq); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CTeamsProto::StopTrouter() +{ + m_impl.m_heartBeat.StopSafe(); + + if (m_ws) { + m_ws->terminate(); + m_ws = nullptr; + } +} + +void CTeamsProto::GatewayThread(void *) +{ + m_ws = nullptr; + + MHttpHeaders headers; + headers.AddHeader("x-skypetoken", m_szSkypeToken); + headers.AddHeader("User-Agent", TEAMS_USER_AGENT); + + WebSocket<CTeamsProto> ws(this); + NLHR_PTR pReply(ws.connect(m_hNetlibUser, m_szTrouterUrl, &headers)); + if (pReply) { + if (pReply->resultCode == 101) { + m_ws = &ws; + + iCommandId = 1; + m_impl.m_heartBeat.StartSafe(30000); + + debugLogA("Websocket connection succeeded"); + ws.run(); + } + else debugLogA("websocket connection failed: %d", pReply->resultCode); + } + else debugLogA("websocket connection failed"); + + StopTrouter(); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// TRouter send + +void CTeamsProto::TRouterSendJson(const JSONNode &node) +{ + std::string szJson = "5:::" + node.write(); + if (m_ws) { + m_ws->sendText(szJson.c_str()); + } +} + +void CTeamsProto::TRouterSendJson(const char *szName, const JSONNode *node) +{ + JSONNode payload, args(JSON_ARRAY); + payload << CHAR_PARAM("name", szName); + if (node) { + args.set_name("args"); + args << *node; + payload << args; + } + + std::string szJson = payload.write(); + if (m_ws) + m_ws->sendText(szJson.c_str()); +} + +void CTeamsProto::TRouterSendAuthentication() +{ + JSONNode headers, params, payload; + + headers.set_name("headers"); + headers << CHAR_PARAM("X-Ms-Test-User", "False") << CHAR_PARAM("Authorization", "Bearer " + m_szAccessToken) + << CHAR_PARAM("X-MS-Migration", "True"); + + params.set_name("connectparams"); + for (auto &it : m_connectParams) + params << CHAR_PARAM(it->szName, it->szValue); + + payload << headers << params; + TRouterSendJson(payload); +} + +static char szSuffix[4] = { 'A', 'g', 'Q', 'w' }; + +void CTeamsProto::TRouterSendActive(bool bActive) +{ + CMStringA cv; + srand(time(0)); + for (int i = 0; i < 21; i++) + cv.AppendChar('a' + rand() % 26); + cv.AppendChar(szSuffix[rand() % 4]); + cv += ".0.1"; + + JSONNode payload; + payload << CHAR_PARAM("state", bActive ? "active" : "inactive") << CHAR_PARAM("cv", cv); + TRouterSendJson("user.activity", &payload); +} + +void CTeamsProto::TRouterRegister() +{ + TRouterRegister("NextGenCalling", "DesktopNgc_2.3:SkypeNgc", m_szTrouterSurl + "NGCallManagerWin"); + TRouterRegister("SkypeSpacesWeb", "SkypeSpacesWeb_2.3", m_szTrouterSurl + "SkypeSpacesWeb"); + TRouterRegister("TeamsCDLWebWorker", "TeamsCDLWebWorker_1.9", m_szTrouterSurl); +} + +void CTeamsProto::TRouterRegister(const char *pszAppId, const char *pszKey, const char *pszPath) +{ + JSONNode descr, reg, obj, trouter(JSON_ARRAY), transports; + descr.set_name("clientDescription"); + descr << CHAR_PARAM("appId", pszAppId) << CHAR_PARAM("aesKey", "") << CHAR_PARAM("languageId", "en-US") + << CHAR_PARAM("platform", "edge") << CHAR_PARAM("templateKey", pszKey) << CHAR_PARAM("platformUIVersion", TEAMS_CLIENTINFO_VERSION) + << CHAR_PARAM("productContext", "TFL"); + + obj << CHAR_PARAM("context", "") << CHAR_PARAM("path", pszPath) << INT_PARAM("ttl", TEAMS_TROUTER_TTL); + trouter.set_name("TROUTER"); trouter << obj; + transports.set_name("transports"); + + reg.set_name("registration"); + reg << descr << CHAR_PARAM("registrationId", m_szEndpoint) << CHAR_PARAM("nodeId", "") << transports; + + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_OTHER, "https://edge.skype.com/registrar/prod/v2/registrations"); + pReq->flags |= NLHRF_NODUMPHEADERS; + pReq->AddHeader("Content-Type", "application/json"); + pReq->AddHeader("X-Skypetoken", m_szSkypeToken); + pReq->AddHeader("Authorization", "Bearer " + m_szAccessToken); + pReq->m_szParam = mir_urlEncode(reg.write().c_str()); + PushRequest(pReq); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// TRouter receive + +void WebSocket<CTeamsProto>::process(const uint8_t *buf, size_t cbLen) +{ + Netlib_Dump(getConn(), buf, cbLen, false, 0); + + CMStringA payload((const char *)buf, (int)cbLen); + p->TRouterProcess(payload); +} + +void CTeamsProto::TRouterProcess(const char *str) +{ + switch (*str) { + case '1': + TRouterSendAuthentication(); + TRouterSendActive(true); + TRouterRegister(); + break; + } +}
\ No newline at end of file diff --git a/protocols/Teams/src/teams_utils.cpp b/protocols/Teams/src/teams_utils.cpp index 59beeaa894..3d23351468 100644 --- a/protocols/Teams/src/teams_utils.cpp +++ b/protocols/Teams/src/teams_utils.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2015-25 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2025 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 diff --git a/protocols/Teams/src/teams_utils.h b/protocols/Teams/src/teams_utils.h index f7d205da61..58255e53c1 100644 --- a/protocols/Teams/src/teams_utils.h +++ b/protocols/Teams/src/teams_utils.h @@ -60,9 +60,9 @@ struct CFileUploadParam : public MZeroedObject } }; -struct SkypeReply : public JsonReply +struct TeamsReply : public JsonReply { - SkypeReply(MHttpResponse *response) : + TeamsReply(MHttpResponse *response) : JsonReply(response) { if (m_root) |