summaryrefslogtreecommitdiff
path: root/protocols/Teams/src/teams_http.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Teams/src/teams_http.cpp')
-rw-r--r--protocols/Teams/src/teams_http.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/protocols/Teams/src/teams_http.cpp b/protocols/Teams/src/teams_http.cpp
new file mode 100644
index 0000000000..7ac6d3be2d
--- /dev/null
+++ b/protocols/Teams/src/teams_http.cpp
@@ -0,0 +1,198 @@
+/*
+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"
+
+AsyncHttpRequest::AsyncHttpRequest(int type, SkypeHost host, LPCSTR url, MTHttpRequestHandler pFunc) :
+ m_host(host)
+{
+ switch (host) {
+ case HOST_API: m_szUrl = "api.skype.com"; break;
+ case HOST_CONTACTS: m_szUrl = "contacts.skype.com/contacts/v2"; break;
+ case HOST_LOGIN: m_szUrl = "login.microsoftonline.com"; break;
+ case HOST_TEAMS: m_szUrl = TEAMS_BASE_HOST; break;
+ case HOST_TEAMS_API: m_szUrl = TEAMS_BASE_HOST "/api/mt/beta"; break;
+ case HOST_CHATS: m_szUrl = TEAMS_BASE_HOST "/api/chatsvc/consumer/v1"; break;
+ case HOST_GROUPS: m_szUrl = TEAMS_BASE_HOST "/api/groups/v1"; break;
+ case HOST_PRESENCE: m_szUrl = "presence." TEAMS_BASE_HOST "/v1"; break;
+ }
+
+ AddHeader("User-Agent", TEAMS_USER_AGENT);
+
+ if (url)
+ m_szUrl.Append(url);
+ m_pFunc = pFunc;
+ flags = NLHRF_HTTP11 | NLHRF_SSL | NLHRF_DUMPASTEXT;
+ requestType = type;
+}
+
+void AsyncHttpRequest::AddAuthentication(CTeamsProto *ppro)
+{
+ AddHeader("Authentication", CMStringA("skypetoken=") + ppro->m_szSkypeToken);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CTeamsProto::StartQueue()
+{
+ if (!m_isTerminated)
+ return;
+
+ m_isTerminated = false;
+ if (m_hRequestQueueThread == nullptr)
+ ForkThread(&CTeamsProto::WorkerThread);
+}
+
+void CTeamsProto::StopQueue()
+{
+ m_isTerminated = true;
+
+ if (m_hRequestQueueThread)
+ m_hRequestQueueEvent.Set();
+}
+
+void CTeamsProto::PushRequest(AsyncHttpRequest *request)
+{
+ if (m_isTerminated)
+ return;
+ {
+ mir_cslock lock(m_requestQueueLock);
+ m_requests.insert(request);
+ }
+ m_hRequestQueueEvent.Set();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MHttpResponse* CTeamsProto::DoSend(AsyncHttpRequest *pReq)
+{
+ if (pReq->m_host != HOST_OTHER)
+ pReq->m_szUrl.Insert(0, ((pReq->flags & NLHRF_SSL) ? "https://" : "http://"));
+
+ if (!pReq->m_szParam.IsEmpty()) {
+ switch (pReq->requestType) {
+ case REQUEST_PUT:
+ case REQUEST_POST:
+ if (!pReq->FindHeader("Content-Type")) {
+ if (pReq->m_szParam[0] == '[' || pReq->m_szParam[0] == '{')
+ pReq->AddHeader("Content-Type", "application/json");
+ else
+ pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded");
+ }
+ }
+ }
+
+ pReq->AddHeader("X-MS-Client-Consumer-Type", "teams4life");
+
+ switch (pReq->m_host) {
+ case HOST_CHATS:
+ case HOST_CONTACTS:
+ pReq->AddAuthentication(this);
+ pReq->AddHeader("Accept", "application/json");
+ pReq->AddHeader("X-Stratus-Caller", TEAMS_CLIENTINFO_NAME);
+ pReq->AddHeader("X-Stratus-Request", "abcd1234");
+ pReq->AddHeader("Origin", "https://teams.live.com");
+ pReq->AddHeader("Referer", "https://teams.live.com/");
+ pReq->AddHeader("ms-ic3-product", "tfl");
+ pReq->AddHeader("ms-ic3-additional-product", "Sfl");
+ break;
+
+ case HOST_GROUPS:
+ case HOST_TEAMS_API:
+ pReq->AddHeader("X-MS-Client-Type", "maglev");
+ pReq->AddHeader("Origin", "https://teams.live.com");
+ pReq->AddHeader("Referer", "https://teams.live.com/v2/");
+ pReq->AddHeader("Cookie", mir_urlEncode(m_szApiCookie));
+ __fallthrough;
+
+ case HOST_TEAMS:
+ if (!pReq->FindHeader("Authorization"))
+ pReq->AddHeader("Authorization", "Bearer " + m_szAccessToken);
+ if (m_szSkypeToken)
+ pReq->AddHeader("X-Skypetoken", m_szSkypeToken);
+ pReq->AddHeader("Accept", "application/json");
+ pReq->AddHeader("ms-ic3-product", "tfl");
+ pReq->AddHeader("ms-ic3-additional-product", "Sfl");
+ break;
+
+ case HOST_API:
+ if (m_szSkypeToken)
+ pReq->AddHeader("X-Skypetoken", m_szSkypeToken);
+ pReq->AddHeader("Accept", "application/json");
+ break;
+
+ case HOST_PRESENCE:
+ pReq->flags |= NLHRF_REDIRECT;
+
+ if (m_szSkypeToken)
+ pReq->AddHeader("X-Skypetoken", m_szSkypeToken);
+
+ pReq->AddHeader("Accept", "application/json");
+ pReq->AddHeader("x-ms-client-user-agent", "Teams-V2-Desktop");
+ pReq->AddHeader("x-ms-correlation-id", "1");
+ pReq->AddHeader("x-ms-client-version", TEAMS_CLIENTINFO_VERSION);
+ pReq->AddHeader("x-ms-endpoint-id", m_szEndpoint);
+ break;
+
+ case HOST_LOGIN:
+ #ifndef _DEBUG
+ pReq->flags |= NLHRF_NODUMP;
+ #endif
+ break;
+ }
+
+ debugLogA("Send request to %s", pReq->m_szUrl.c_str());
+
+ return Netlib_HttpTransaction(m_hNetlibUser, pReq);
+}
+
+void CTeamsProto::Execute(AsyncHttpRequest *item)
+{
+ NLHR_PTR response(DoSend(item));
+ if (item->m_pFunc != nullptr)
+ (this->*item->m_pFunc)(response, item);
+ m_requests.remove(item);
+ delete item;
+}
+
+void CTeamsProto::WorkerThread(void*)
+{
+ m_hRequestQueueThread = GetCurrentThread();
+
+ while (true) {
+ m_hRequestQueueEvent.Wait();
+ if (m_isTerminated)
+ break;
+
+ while (true) {
+ AsyncHttpRequest *item = nullptr;
+ {
+ mir_cslock lock(m_requestQueueLock);
+
+ if (m_requests.getCount() == 0)
+ break;
+
+ item = m_requests[0];
+ m_requests.remove(0);
+ }
+ if (item != nullptr)
+ Execute(item);
+ }
+ }
+
+ m_hRequestQueueThread = nullptr;
+}