summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/CloudFile/res/dropbox.icobin5430 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/gdrive.icobin5430 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/onedrive.icobin7886 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/upload.icobin103999 -> 5430 bytes
-rw-r--r--protocols/CloudFile/res/yadisk.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/proto_discord/res/Away.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/proto_discord/res/DND.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/proto_discord/res/Invisible.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/proto_discord/res/Offline.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/proto_discord/res/Online.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Discord/res/discord.icobin4150 -> 5430 bytes
-rw-r--r--protocols/Discord/src/gateway.cpp4
-rw-r--r--protocols/Discord/src/voice_client.cpp2
-rw-r--r--protocols/ICQCorp/CMakeLists.txt3
-rw-r--r--protocols/ICQCorp/Proto_icq/CMakeLists.txt2
-rw-r--r--protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj28
-rw-r--r--protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj.filters4
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Away.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/DND.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/FFC.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Invisible.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/NA.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Occupied.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Offline.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Online.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Phone.icobin0 -> 5430 bytes
-rw-r--r--protocols/ICQCorp/Proto_icq/res/Proto_ICQ.rc77
-rw-r--r--protocols/ICQCorp/Proto_icq/src/resource.h24
-rw-r--r--protocols/SkypeWeb/SkypeWeb.vcxproj1
-rw-r--r--protocols/SkypeWeb/SkypeWeb.vcxproj.filters3
-rw-r--r--protocols/SkypeWeb/src/requests/poll.h38
-rw-r--r--protocols/SkypeWeb/src/skype_polling.cpp30
-rw-r--r--protocols/SkypeWeb/src/stdafx.h1
-rw-r--r--protocols/Steam/proto_steam/res/Invisible.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Steam/src/steam_login.cpp4
-rw-r--r--protocols/Teams/Teams.vcxproj2
-rw-r--r--protocols/Teams/Teams.vcxproj.filters6
-rw-r--r--protocols/Teams/proto_teams/res/Away.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Teams/proto_teams/res/DND.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Teams/proto_teams/res/Invisible.icobin5430 -> 5430 bytes
-rw-r--r--protocols/Teams/src/main.cpp17
-rw-r--r--protocols/Teams/src/requests/capabilities.h41
-rw-r--r--protocols/Teams/src/requests/contacts.h89
-rw-r--r--protocols/Teams/src/requests/poll.h38
-rw-r--r--protocols/Teams/src/stdafx.cxx2
-rw-r--r--protocols/Teams/src/stdafx.h7
-rw-r--r--protocols/Teams/src/teams_avatars.cpp4
-rw-r--r--protocols/Teams/src/teams_chatrooms.cpp6
-rw-r--r--protocols/Teams/src/teams_contacts.cpp53
-rw-r--r--protocols/Teams/src/teams_endpoint.cpp71
-rw-r--r--protocols/Teams/src/teams_files.cpp19
-rw-r--r--protocols/Teams/src/teams_history.cpp6
-rw-r--r--protocols/Teams/src/teams_http.cpp4
-rw-r--r--protocols/Teams/src/teams_login.cpp4
-rw-r--r--protocols/Teams/src/teams_menus.cpp2
-rw-r--r--protocols/Teams/src/teams_mood.cpp2
-rw-r--r--protocols/Teams/src/teams_options.cpp2
-rw-r--r--protocols/Teams/src/teams_polling.cpp39
-rw-r--r--protocols/Teams/src/teams_popups.cpp17
-rw-r--r--protocols/Teams/src/teams_profile.cpp4
-rw-r--r--protocols/Teams/src/teams_proto.cpp40
-rw-r--r--protocols/Teams/src/teams_proto.h70
-rw-r--r--protocols/Teams/src/teams_search.cpp4
-rw-r--r--protocols/Teams/src/teams_trouter.cpp367
-rw-r--r--protocols/Teams/src/teams_utils.cpp2
-rw-r--r--protocols/Teams/src/teams_utils.h4
-rw-r--r--protocols/Teams/src/version.h2
-rw-r--r--protocols/Weather/res/resource.rc3
-rw-r--r--protocols/Weather/src/proto.h2
-rw-r--r--protocols/Weather/src/resource.h1
-rw-r--r--protocols/Weather/src/stdafx.h2
-rw-r--r--protocols/Weather/src/weather_addstn.cpp2
-rw-r--r--protocols/Weather/src/weather_contacts.cpp18
-rw-r--r--protocols/Weather/src/weather_conv.cpp59
-rw-r--r--protocols/Weather/src/weather_data.cpp16
-rw-r--r--protocols/Weather/src/weather_mwin.cpp4
-rw-r--r--protocols/Weather/src/weather_opt.cpp98
-rw-r--r--protocols/Weather/src/weather_popup.cpp4
-rw-r--r--protocols/Weather/src/weather_proto.cpp4
-rw-r--r--protocols/Weather/src/weather_update.cpp60
-rw-r--r--protocols/Weather/src/weather_userinfo.cpp20
81 files changed, 928 insertions, 510 deletions
diff --git a/protocols/CloudFile/res/dropbox.ico b/protocols/CloudFile/res/dropbox.ico
index 8a286d7f32..09d2721244 100644
--- a/protocols/CloudFile/res/dropbox.ico
+++ b/protocols/CloudFile/res/dropbox.ico
Binary files differ
diff --git a/protocols/CloudFile/res/gdrive.ico b/protocols/CloudFile/res/gdrive.ico
index a34123e95b..3655f72583 100644
--- a/protocols/CloudFile/res/gdrive.ico
+++ b/protocols/CloudFile/res/gdrive.ico
Binary files differ
diff --git a/protocols/CloudFile/res/onedrive.ico b/protocols/CloudFile/res/onedrive.ico
index 502cee9bb7..94c8ab8240 100644
--- a/protocols/CloudFile/res/onedrive.ico
+++ b/protocols/CloudFile/res/onedrive.ico
Binary files differ
diff --git a/protocols/CloudFile/res/upload.ico b/protocols/CloudFile/res/upload.ico
index b51e87ed35..09f224a20e 100644
--- a/protocols/CloudFile/res/upload.ico
+++ b/protocols/CloudFile/res/upload.ico
Binary files differ
diff --git a/protocols/CloudFile/res/yadisk.ico b/protocols/CloudFile/res/yadisk.ico
index b3a5ac69b4..31d802c51f 100644
--- a/protocols/CloudFile/res/yadisk.ico
+++ b/protocols/CloudFile/res/yadisk.ico
Binary files differ
diff --git a/protocols/Discord/proto_discord/res/Away.ico b/protocols/Discord/proto_discord/res/Away.ico
index 844c1d4b3a..46dccb19ca 100644
--- a/protocols/Discord/proto_discord/res/Away.ico
+++ b/protocols/Discord/proto_discord/res/Away.ico
Binary files differ
diff --git a/protocols/Discord/proto_discord/res/DND.ico b/protocols/Discord/proto_discord/res/DND.ico
index 6341c0e08c..805dd75622 100644
--- a/protocols/Discord/proto_discord/res/DND.ico
+++ b/protocols/Discord/proto_discord/res/DND.ico
Binary files differ
diff --git a/protocols/Discord/proto_discord/res/Invisible.ico b/protocols/Discord/proto_discord/res/Invisible.ico
index 7d34d4ca58..d168845ae6 100644
--- a/protocols/Discord/proto_discord/res/Invisible.ico
+++ b/protocols/Discord/proto_discord/res/Invisible.ico
Binary files differ
diff --git a/protocols/Discord/proto_discord/res/Offline.ico b/protocols/Discord/proto_discord/res/Offline.ico
index f2ec365064..7473a3b968 100644
--- a/protocols/Discord/proto_discord/res/Offline.ico
+++ b/protocols/Discord/proto_discord/res/Offline.ico
Binary files differ
diff --git a/protocols/Discord/proto_discord/res/Online.ico b/protocols/Discord/proto_discord/res/Online.ico
index 94f4d0d8bd..1d3efde242 100644
--- a/protocols/Discord/proto_discord/res/Online.ico
+++ b/protocols/Discord/proto_discord/res/Online.ico
Binary files differ
diff --git a/protocols/Discord/res/discord.ico b/protocols/Discord/res/discord.ico
index c2830ed132..1d3efde242 100644
--- a/protocols/Discord/res/discord.ico
+++ b/protocols/Discord/res/discord.ico
Binary files differ
diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp
index c038234aec..e3bf1b307c 100644
--- a/protocols/Discord/src/gateway.cpp
+++ b/protocols/Discord/src/gateway.cpp
@@ -25,9 +25,7 @@ bool CDiscordProto::GatewaySend(const JSONNode &pRoot)
if (!m_bConnected)
return false;
- json_string szText = pRoot.write();
- debugLogA("Gateway send: %s", szText.c_str());
- m_ws.sendText(szText.c_str());
+ m_ws.sendText(pRoot.write().c_str());
return true;
}
diff --git a/protocols/Discord/src/voice_client.cpp b/protocols/Discord/src/voice_client.cpp
index 1e20a93723..99d7668d74 100644
--- a/protocols/Discord/src/voice_client.cpp
+++ b/protocols/Discord/src/voice_client.cpp
@@ -61,9 +61,7 @@ void CDiscordVoiceCall::write(int op, JSONNode &d)
JSONNode payload;
payload << INT_PARAM("op", op) << d;
-
auto json = payload.write();
- ppro->debugLogA("Voice JSON sent: %s", json.c_str());
mir_cslock lck(m_cs);
m_ws->sendText(json.c_str());
diff --git a/protocols/ICQCorp/CMakeLists.txt b/protocols/ICQCorp/CMakeLists.txt
index 9e3d58ba26..d18898a34e 100644
--- a/protocols/ICQCorp/CMakeLists.txt
+++ b/protocols/ICQCorp/CMakeLists.txt
@@ -12,4 +12,5 @@ file(GLOB SOURCES "src/*.h" "res/*.rc"
"src/user.cpp"
)
set(TARGET ICQCorp)
-include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake) \ No newline at end of file
+include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake)
+add_subdirectory(proto_icq)
diff --git a/protocols/ICQCorp/Proto_icq/CMakeLists.txt b/protocols/ICQCorp/Proto_icq/CMakeLists.txt
new file mode 100644
index 0000000000..596ac21624
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/CMakeLists.txt
@@ -0,0 +1,2 @@
+set(TARGET Proto_ICQ)
+include(${CMAKE_SOURCE_DIR}/cmake/icons.cmake) \ No newline at end of file
diff --git a/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj b/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj
new file mode 100644
index 0000000000..21763bbc0b
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_ICQ</ProjectName>
+ <ProjectGuid>{DB3B0449-E576-4BBB-8B08-AB9E914D39CA}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj.filters b/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/Proto_ICQ.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/ICQCorp/Proto_icq/res/Away.ico b/protocols/ICQCorp/Proto_icq/res/Away.ico
new file mode 100644
index 0000000000..248a3e9916
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Away.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/DND.ico b/protocols/ICQCorp/Proto_icq/res/DND.ico
new file mode 100644
index 0000000000..4833160eac
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/DND.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/FFC.ico b/protocols/ICQCorp/Proto_icq/res/FFC.ico
new file mode 100644
index 0000000000..e7ec4d3ae2
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/FFC.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Invisible.ico b/protocols/ICQCorp/Proto_icq/res/Invisible.ico
new file mode 100644
index 0000000000..6a337c2926
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Invisible.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/NA.ico b/protocols/ICQCorp/Proto_icq/res/NA.ico
new file mode 100644
index 0000000000..ec0621dc9f
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/NA.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Occupied.ico b/protocols/ICQCorp/Proto_icq/res/Occupied.ico
new file mode 100644
index 0000000000..04ea2a5855
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Occupied.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Offline.ico b/protocols/ICQCorp/Proto_icq/res/Offline.ico
new file mode 100644
index 0000000000..af862168cd
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Offline.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Online.ico b/protocols/ICQCorp/Proto_icq/res/Online.ico
new file mode 100644
index 0000000000..2e33305a76
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Online.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Phone.ico b/protocols/ICQCorp/Proto_icq/res/Phone.ico
new file mode 100644
index 0000000000..74c80b66ed
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Phone.ico
Binary files differ
diff --git a/protocols/ICQCorp/Proto_icq/res/Proto_ICQ.rc b/protocols/ICQCorp/Proto_icq/res/Proto_ICQ.rc
new file mode 100644
index 0000000000..33d8faf243
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/res/Proto_ICQ.rc
@@ -0,0 +1,77 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "Offline.ico"
+IDI_ICON2 ICON "Online.ico"
+IDI_ICON3 ICON "Away.ico"
+IDI_ICON4 ICON "Invisible.ico"
+IDI_ICON5 ICON "NA.ico"
+IDI_ICON6 ICON "DND.ico"
+IDI_ICON7 ICON "Occupied.ico"
+IDI_ICON8 ICON "FFC.ico"
+IDI_ICON9 ICON "Phone.ico"
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/ICQCorp/Proto_icq/src/resource.h b/protocols/ICQCorp/Proto_icq/src/resource.h
new file mode 100644
index 0000000000..c74e04f59e
--- /dev/null
+++ b/protocols/ICQCorp/Proto_icq/src/resource.h
@@ -0,0 +1,24 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_ICQ.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+#define IDI_ICON3 128
+#define IDI_ICON4 130
+#define IDI_ICON5 131
+#define IDI_ICON6 158
+#define IDI_ICON7 159
+#define IDI_ICON8 129
+#define IDI_ICON9 1002
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 110
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/SkypeWeb/SkypeWeb.vcxproj b/protocols/SkypeWeb/SkypeWeb.vcxproj
index f44147ab8f..c7cda08954 100644
--- a/protocols/SkypeWeb/SkypeWeb.vcxproj
+++ b/protocols/SkypeWeb/SkypeWeb.vcxproj
@@ -57,7 +57,6 @@
<ClInclude Include="src\requests\history.h" />
<ClInclude Include="src\requests\login.h" />
<ClInclude Include="src\requests\oauth.h" />
- <ClInclude Include="src\requests\poll.h" />
<ClInclude Include="src\requests\profile.h" />
<ClInclude Include="src\requests\search.h" />
<ClInclude Include="src\requests\status.h" />
diff --git a/protocols/SkypeWeb/SkypeWeb.vcxproj.filters b/protocols/SkypeWeb/SkypeWeb.vcxproj.filters
index e6d0bb2fc3..15d9199310 100644
--- a/protocols/SkypeWeb/SkypeWeb.vcxproj.filters
+++ b/protocols/SkypeWeb/SkypeWeb.vcxproj.filters
@@ -96,9 +96,6 @@
<ClInclude Include="src\requests\oauth.h">
<Filter>Header Files\Requests</Filter>
</ClInclude>
- <ClInclude Include="src\requests\poll.h">
- <Filter>Header Files\Requests</Filter>
- </ClInclude>
<ClInclude Include="src\requests\profile.h">
<Filter>Header Files\Requests</Filter>
</ClInclude>
diff --git a/protocols/SkypeWeb/src/requests/poll.h b/protocols/SkypeWeb/src/requests/poll.h
deleted file mode 100644
index bf1850fd27..0000000000
--- a/protocols/SkypeWeb/src/requests/poll.h
+++ /dev/null
@@ -1,38 +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_POLL_H_
-#define _SKYPE_POLL_H_
-
-struct PollRequest : public AsyncHttpRequest
-{
- PollRequest(CSkypeProto *ppro) :
- AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szId) + "/subscriptions/0/poll")
- {
- flags |= NLHRF_PERSISTENT;
- timeout = 120000;
-
- if (ppro->m_iPollingId != -1)
- m_szUrl.AppendFormat("?ackId=%d", ppro->m_iPollingId);
-
- AddHeader("Referer", "https://web.skype.com/main");
- AddHeader("ClientInfo", "os=Windows; osVer=8.1; proc=Win32; lcid=en-us; deviceType=1; country=n/a; clientName=swx-skype.com; clientVer=908/1.85.0.29");
- AddHeader("Accept", "application/json");
- AddHeader("Accept-Language", "en, C");
- }
-};
-#endif //_SKYPE_POLL_H_ \ No newline at end of file
diff --git a/protocols/SkypeWeb/src/skype_polling.cpp b/protocols/SkypeWeb/src/skype_polling.cpp
index ed7b50938e..2821f06d34 100644
--- a/protocols/SkypeWeb/src/skype_polling.cpp
+++ b/protocols/SkypeWeb/src/skype_polling.cpp
@@ -27,14 +27,34 @@ void CSkypeProto::PollingThread(void *)
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()));
+ AsyncHttpRequest req(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(m_szId) + "/subscriptions/0/poll");
+ req.flags |= NLHRF_PERSISTENT;
+ req.timeout = 120000;
+ req.nlc = m_hPollingConn;
+
+ if (m_iPollingId != -1)
+ req.m_szUrl.AppendFormat("?ackId=%d", m_iPollingId);
+
+ req.AddHeader("Referer", "https://web.skype.com/main");
+ req.AddHeader("ClientInfo", "os=Windows; osVer=8.1; proc=Win32; lcid=en-us; deviceType=1; country=n/a; clientName=swx-skype.com; clientVer=908/1.85.0.29");
+ req.AddHeader("Accept", "application/json");
+ req.AddHeader("Accept-Language", "en, C");
+
+ NLHR_PTR response(DoSend(&req));
if (m_isTerminated || m_szId == nullptr)
break;
- if (response == nullptr || response->resultCode != 200) {
- m_hPollingConn = nullptr;
+ // no network?..
+ if (response == nullptr)
+ break;
+
+ if (response->resultCode != 200) {
+ auto reply = JSONNode::parse(response->body);
+ if (reply && reply["message"]["errorCode"] == 729) // endpoint broken, log off
+ break;
+
+ Sleep(200);
+ m_hPollingConn = response->nlc;
continue;
}
diff --git a/protocols/SkypeWeb/src/stdafx.h b/protocols/SkypeWeb/src/stdafx.h
index ef94f3040c..263aefd914 100644
--- a/protocols/SkypeWeb/src/stdafx.h
+++ b/protocols/SkypeWeb/src/stdafx.h
@@ -119,7 +119,6 @@ struct AsyncHttpRequest : public MTHttpRequest<CSkypeProto>
#include "requests/history.h"
#include "requests/login.h"
#include "requests/oauth.h"
-#include "requests/poll.h"
#include "requests/profile.h"
#include "requests/search.h"
#include "requests/status.h"
diff --git a/protocols/Steam/proto_steam/res/Invisible.ico b/protocols/Steam/proto_steam/res/Invisible.ico
index f920c04ed2..68e4a93641 100644
--- a/protocols/Steam/proto_steam/res/Invisible.ico
+++ b/protocols/Steam/proto_steam/res/Invisible.ico
Binary files differ
diff --git a/protocols/Steam/src/steam_login.cpp b/protocols/Steam/src/steam_login.cpp
index 1235130542..669d164351 100644
--- a/protocols/Steam/src/steam_login.cpp
+++ b/protocols/Steam/src/steam_login.cpp
@@ -159,7 +159,7 @@ INT_PTR CALLBACK CSteamProto::EnterEmailCode(void *param)
ppro->SendConfirmationCode(true, T2Utf(es.ptszResult));
mir_free(es.ptszResult);
}
- else ppro->Logout();
+ else ppro->m_ws->terminate();
return 0;
}
@@ -174,7 +174,7 @@ INT_PTR CALLBACK CSteamProto::EnterTotpCode(void *param)
ppro->SendConfirmationCode(false, T2Utf(es.ptszResult));
mir_free(es.ptszResult);
}
- else ppro->Logout();
+ else ppro->m_ws->terminate();
return 0;
}
diff --git a/protocols/Teams/Teams.vcxproj b/protocols/Teams/Teams.vcxproj
index ad579a582d..436f8c746d 100644
--- a/protocols/Teams/Teams.vcxproj
+++ b/protocols/Teams/Teams.vcxproj
@@ -42,11 +42,11 @@
<ClCompile Include="src\teams_messages.cpp" />
<ClCompile Include="src\teams_mood.cpp" />
<ClCompile Include="src\teams_options.cpp" />
- <ClCompile Include="src\teams_polling.cpp" />
<ClCompile Include="src\teams_popups.cpp" />
<ClCompile Include="src\teams_profile.cpp" />
<ClCompile Include="src\teams_proto.cpp" />
<ClCompile Include="src\teams_search.cpp" />
+ <ClCompile Include="src\teams_trouter.cpp" />
<ClCompile Include="src\teams_utils.cpp" />
<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 b2582eb02b..c15ff6085c 100644
--- a/protocols/Teams/Teams.vcxproj.filters
+++ b/protocols/Teams/Teams.vcxproj.filters
@@ -43,9 +43,6 @@
<ClCompile Include="src\teams_mood.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="src\teams_polling.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
<ClCompile Include="src\teams_popups.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -61,6 +58,9 @@
<ClCompile Include="src\teams_search.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\teams_trouter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\resource.h">
diff --git a/protocols/Teams/proto_teams/res/Away.ico b/protocols/Teams/proto_teams/res/Away.ico
index 2faf6635bd..a6b544e597 100644
--- a/protocols/Teams/proto_teams/res/Away.ico
+++ b/protocols/Teams/proto_teams/res/Away.ico
Binary files differ
diff --git a/protocols/Teams/proto_teams/res/DND.ico b/protocols/Teams/proto_teams/res/DND.ico
index b38ab27226..5919b2e563 100644
--- a/protocols/Teams/proto_teams/res/DND.ico
+++ b/protocols/Teams/proto_teams/res/DND.ico
Binary files differ
diff --git a/protocols/Teams/proto_teams/res/Invisible.ico b/protocols/Teams/proto_teams/res/Invisible.ico
index 49b66a79fe..673f13a81a 100644
--- a/protocols/Teams/proto_teams/res/Invisible.ico
+++ b/protocols/Teams/proto_teams/res/Invisible.ico
Binary files differ
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
deleted file mode 100644
index 566d946e3e..0000000000
--- a/protocols/Teams/src/requests/capabilities.h
+++ /dev/null
@@ -1,41 +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_CAPS_H_
-#define _SKYPE_REQUEST_CAPS_H_
-
-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)
- {
- JSONNode privateInfo; privateInfo.set_name("privateInfo");
- privateInfo << CHAR_PARAM("epname", hostname);
-
- JSONNode publicInfo; publicInfo.set_name("publicInfo");
- publicInfo << CHAR_PARAM("capabilities", "Audio|Video") << INT_PARAM("typ", 125)
- << CHAR_PARAM("skypeNameVersion", "Miranda NG Skype") << CHAR_PARAM("nodeInfo", "xx") << CHAR_PARAM("version", g_szMirVer);
-
- JSONNode node;
- node << CHAR_PARAM("id", "messagingService") << CHAR_PARAM("type", "EndpointPresenceDoc")
- << CHAR_PARAM("selfLink", "uri") << privateInfo << publicInfo;
-
- m_szParam = node.write().c_str();
- }
-};
-
-#endif //_SKYPE_REQUEST_CAPS_H_
diff --git a/protocols/Teams/src/requests/contacts.h b/protocols/Teams/src/requests/contacts.h
deleted file mode 100644
index f0614f10b6..0000000000
--- a/protocols/Teams/src/requests/contacts.h
+++ /dev/null
@@ -1,89 +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_CONTACTS_H_
-#define _SKYPE_REQUEST_CONTACTS_H_
-
-struct GetContactListRequest : public AsyncHttpRequest
-{
- GetContactListRequest() :
- AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/contacts", &CTeamsProto::LoadContactList)
- {
- }
-};
-
-struct GetContactsAuthRequest : public AsyncHttpRequest
-{
- GetContactsAuthRequest() :
- AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/invites", &CTeamsProto::LoadContactsAuth)
- {
- }
-};
-
-struct AddContactRequest : public AsyncHttpRequest
-{
- AddContactRequest(const char *who, const char *greeting = "") :
- AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS, "/users/SELF/contacts")
- {
- JSONNode node;
- node << CHAR_PARAM("mri", who) << CHAR_PARAM("greeting", greeting);
- m_szParam = node.write().c_str();
- }
-};
-
-struct AuthAcceptRequest : public AsyncHttpRequest
-{
- AuthAcceptRequest(const char *who) :
- AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS)
- {
- m_szUrl.AppendFormat("/users/SELF/invites/%s/accept", mir_urlEncode(who).c_str());
- }
-};
-
-struct AuthDeclineRequest : public AsyncHttpRequest
-{
- AuthDeclineRequest(const char *who) :
- AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS)
- {
- m_szUrl.AppendFormat("/users/SELF/invites/%s/decline", mir_urlEncode(who).c_str());
- }
-};
-
-struct BlockContactRequest : public AsyncHttpRequest
-{
- BlockContactRequest(CTeamsProto *ppro, MCONTACT hContact) :
- AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS, "/users/SELF/contacts/blocklist/" + ppro->getId(hContact), &CTeamsProto::OnBlockContact)
- {
- m_szParam = "{\"report_abuse\":\"false\",\"ui_version\":\"skype.com\"}";
- pUserInfo = (void *)hContact;
- }
-};
-
-struct UnblockContactRequest : public AsyncHttpRequest
-{
- UnblockContactRequest(CTeamsProto *ppro, MCONTACT hContact) :
- AsyncHttpRequest(REQUEST_DELETE, HOST_CONTACTS, 0, &CTeamsProto::OnUnblockContact)
- {
- m_szUrl.AppendFormat("/users/SELF/contacts/blocklist/%s", ppro->getId(hContact).c_str());
- pUserInfo = (void *)hContact;
-
- // TODO: user ip address
- this << CHAR_PARAM("reporterIp", "123.123.123.123") << CHAR_PARAM("uiVersion", g_szMirVer);
- }
-};
-
-#endif //_SKYPE_REQUEST_CONTACTS_H_ \ No newline at end of file
diff --git a/protocols/Teams/src/requests/poll.h b/protocols/Teams/src/requests/poll.h
deleted file mode 100644
index b2573a43e2..0000000000
--- a/protocols/Teams/src/requests/poll.h
+++ /dev/null
@@ -1,38 +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_POLL_H_
-#define _SKYPE_POLL_H_
-
-struct PollRequest : public AsyncHttpRequest
-{
- PollRequest(CTeamsProto *ppro) :
- AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(ppro->m_szId) + "/subscriptions/0/poll")
- {
- flags |= NLHRF_PERSISTENT;
- timeout = 120000;
-
- if (ppro->m_iPollingId != -1)
- m_szUrl.AppendFormat("?ackId=%d", ppro->m_iPollingId);
-
- AddHeader("Referer", "https://web.skype.com/main");
- AddHeader("ClientInfo", "os=Windows; osVer=8.1; proc=Win32; lcid=en-us; deviceType=1; country=n/a; clientName=swx-skype.com; clientVer=908/1.85.0.29");
- AddHeader("Accept", "application/json");
- AddHeader("Accept-Language", "en, C");
- }
-};
-#endif //_SKYPE_POLL_H_ \ No newline at end of file
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/stdafx.h b/protocols/Teams/src/stdafx.h
index de676dace4..7cbbec2676 100644
--- a/protocols/Teams/src/stdafx.h
+++ b/protocols/Teams/src/stdafx.h
@@ -88,16 +88,11 @@ struct AsyncHttpRequest : public MTHttpRequest<CTeamsProto>
#include "teams_proto.h"
-#include "requests/capabilities.h"
#include "requests/chatrooms.h"
-#include "requests/contacts.h"
#include "requests/history.h"
-#include "requests/poll.h"
#include "requests/profile.h"
#include "requests/search.h"
#include "requests/status.h"
#include "requests/subscriptions.h"
-#define POLLING_ERRORS_LIMIT 3
-
-#endif //_COMMON_H_ \ No newline at end of file
+#endif //_COMMON_H_
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..8579aed3c3 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
@@ -100,9 +100,11 @@ MCONTACT CTeamsProto::AddContact(const char *skypeId, const char *nick, bool isT
return hContact;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CTeamsProto::LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest*)
{
- SkypeReply reply(response);
+ TeamsReply reply(response);
if (reply.error())
return;
@@ -140,7 +142,7 @@ void CTeamsProto::LoadContactsAuth(MHttpResponse *response, AsyncHttpRequest*)
void CTeamsProto::LoadContactList(MHttpResponse *response, AsyncHttpRequest*)
{
- SkypeReply reply(response);
+ TeamsReply reply(response);
if (reply.error())
return;
@@ -220,16 +222,14 @@ void CTeamsProto::LoadContactList(MHttpResponse *response, AsyncHttpRequest*)
}
}
- PushRequest(new GetContactsAuthRequest());
+ PushRequest(new AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/invites", &CTeamsProto::LoadContactsAuth));
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
INT_PTR CTeamsProto::OnRequestAuth(WPARAM hContact, LPARAM)
{
- if (hContact == INVALID_CONTACT_ID)
- return 1;
-
- PushRequest(new AddContactRequest(getId(hContact)));
- return 0;
+ return AuthRequest(hContact, 0);
}
INT_PTR CTeamsProto::OnGrantAuth(WPARAM hContact, LPARAM)
@@ -237,7 +237,7 @@ INT_PTR CTeamsProto::OnGrantAuth(WPARAM hContact, LPARAM)
if (hContact == INVALID_CONTACT_ID)
return 1;
- PushRequest(new AuthAcceptRequest(getId(hContact)));
+ PushRequest(new AsyncHttpRequest(REQUEST_POST, HOST_CONTACTS, "/users/SELF/invites/" + mir_urlEncode(getId(hContact)) + "/accept"));
return 0;
}
@@ -257,15 +257,6 @@ bool CTeamsProto::OnContactDeleted(MCONTACT hContact, uint32_t flags)
/////////////////////////////////////////////////////////////////////////////////////////
-INT_PTR CTeamsProto::BlockContact(WPARAM hContact, LPARAM)
-{
- if (!IsOnline()) return 1;
-
- if (IDYES == MessageBox(NULL, TranslateT("Are you sure?"), TranslateT("Warning"), MB_YESNO | MB_ICONQUESTION))
- PushRequest(new BlockContactRequest(this, hContact));
- return 0;
-}
-
void CTeamsProto::OnBlockContact(MHttpResponse *response, AsyncHttpRequest *pRequest)
{
MCONTACT hContact = (DWORD_PTR)pRequest->pUserInfo;
@@ -273,12 +264,21 @@ void CTeamsProto::OnBlockContact(MHttpResponse *response, AsyncHttpRequest *pReq
Contact::Hide(hContact);
}
-INT_PTR CTeamsProto::UnblockContact(WPARAM hContact, LPARAM)
+INT_PTR CTeamsProto::BlockContact(WPARAM hContact, LPARAM)
{
- PushRequest(new UnblockContactRequest(this, hContact));
+ if (!IsOnline()) return 1;
+
+ if (IDYES == MessageBox(NULL, TranslateT("Are you sure?"), TranslateT("Warning"), MB_YESNO | MB_ICONQUESTION)) {
+ auto *pReq = new AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS, "/users/SELF/contacts/blocklist/" + mir_urlEncode(getId(hContact)), &CTeamsProto::OnBlockContact);
+ pReq->m_szParam = "{\"report_abuse\":\"false\",\"ui_version\":\"skype.com\"}";
+ pReq->pUserInfo = (void *)hContact;
+ PushRequest(pReq);
+ }
return 0;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CTeamsProto::OnUnblockContact(MHttpResponse *response, AsyncHttpRequest *pRequest)
{
if (response == nullptr)
@@ -288,3 +288,14 @@ void CTeamsProto::OnUnblockContact(MHttpResponse *response, AsyncHttpRequest *pR
Contact::Hide(hContact, false);
delSetting(hContact, "IsBlocked");
}
+
+INT_PTR CTeamsProto::UnblockContact(WPARAM hContact, LPARAM)
+{
+ if (!IsOnline()) return 1;
+
+ auto *pReq = new AsyncHttpRequest(REQUEST_DELETE, HOST_CONTACTS, "/users/SELF/contacts/blocklist/" + mir_urlEncode(getId(hContact)), &CTeamsProto::OnUnblockContact);
+ pReq->pUserInfo = (void *)hContact;
+ pReq << CHAR_PARAM("reporterIp", "123.123.123.123") << CHAR_PARAM("uiVersion", g_szMirVer); // TODO: user ip address
+ PushRequest(pReq);
+ return 0;
+}
diff --git a/protocols/Teams/src/teams_endpoint.cpp b/protocols/Teams/src/teams_endpoint.cpp
index 39b6958abb..733008ee75 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;
}
@@ -111,23 +100,9 @@ void CTeamsProto::OnSubscriptionsCreated(MHttpResponse *response, AsyncHttpReque
SendPresence();
}
-void CTeamsProto::SendPresence()
-{
- ptrA epname;
-
- if (!m_bUseHostnameAsPlace && m_wstrPlace && *m_wstrPlace)
- epname = mir_utf8encodeW(m_wstrPlace);
- else {
- wchar_t compName[MAX_COMPUTERNAME_LENGTH + 1];
- DWORD size = _countof(compName);
- GetComputerName(compName, &size);
- epname = mir_utf8encodeW(compName);
- }
-
- PushRequest(new SendCapabilitiesRequest(epname, this));
-}
+/////////////////////////////////////////////////////////////////////////////////////////
-void CTeamsProto::OnCapabilitiesSended(MHttpResponse *response, AsyncHttpRequest*)
+void CTeamsProto::OnCapabilitiesSended(MHttpResponse *response, AsyncHttpRequest *)
{
if (response == nullptr || response->body.IsEmpty()) {
ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, 1001);
@@ -147,7 +122,7 @@ void CTeamsProto::OnCapabilitiesSended(MHttpResponse *response, AsyncHttpRequest
skypenames.destroy();
ReceiveAvatar(0);
- PushRequest(new GetContactListRequest());
+ PushRequest(new AsyncHttpRequest(REQUEST_GET, HOST_CONTACTS, "/users/SELF/contacts", &CTeamsProto::LoadContactList));
PushRequest(new SyncConversations());
JSONNode root = JSONNode::parse(response->body);
@@ -157,6 +132,38 @@ void CTeamsProto::OnCapabilitiesSended(MHttpResponse *response, AsyncHttpRequest
PushRequest(new GetProfileRequest(this, 0));
}
+void CTeamsProto::SendPresence()
+{
+ ptrA epname;
+
+ if (!m_bUseHostnameAsPlace && m_wstrPlace && *m_wstrPlace)
+ epname = mir_utf8encodeW(m_wstrPlace);
+ else {
+ wchar_t compName[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD size = _countof(compName);
+ GetComputerName(compName, &size);
+ epname = mir_utf8encodeW(compName);
+ }
+
+ JSONNode privateInfo; privateInfo.set_name("privateInfo");
+ privateInfo << CHAR_PARAM("epname", epname);
+
+ JSONNode publicInfo; publicInfo.set_name("publicInfo");
+ publicInfo << CHAR_PARAM("capabilities", "Audio|Video") << INT_PARAM("typ", 125)
+ << CHAR_PARAM("skypeNameVersion", "Miranda NG Skype") << CHAR_PARAM("nodeInfo", "xx") << CHAR_PARAM("version", g_szMirVer);
+
+ JSONNode node;
+ node << CHAR_PARAM("id", "messagingService") << CHAR_PARAM("type", "EndpointPresenceDoc")
+ << CHAR_PARAM("selfLink", "uri") << privateInfo << publicInfo;
+
+ auto *pReq = new AsyncHttpRequest(REQUEST_PUT, HOST_DEFAULT, "/users/ME/endpoints/" + mir_urlEncode(m_szEndpoint) + "/presenceDocs/messagingService",
+ &CTeamsProto::OnCapabilitiesSended);
+ pReq->m_szParam = node.write().c_str();
+ PushRequest(pReq);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CTeamsProto::OnStatusChanged(MHttpResponse *response, AsyncHttpRequest*)
{
if (response == nullptr || response->body.IsEmpty()) {
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..a24b44bfbc 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
@@ -23,7 +23,7 @@ AsyncHttpRequest::AsyncHttpRequest(int type, SkypeHost host, LPCSTR url, MTHttpR
switch (host) {
case HOST_API: m_szUrl = "api.skype.com"; break;
case HOST_PEOPLE: m_szUrl = "people.skype.com/v2"; break;
- case HOST_CONTACTS: m_szUrl = "edge.skype.com/pcs/contacts/v2"; break;
+ case HOST_CONTACTS: m_szUrl = "contacts.skype.com/contacts/v2"; break;
case HOST_GRAPH: m_szUrl = "skypegraph.skype.com"; break;
case HOST_LOGIN: m_szUrl = "login.microsoftonline.com"; break;
case HOST_TEAMS: m_szUrl = "teams.live.com"; break;
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_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..9999e41c2e 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) :
@@ -22,6 +39,13 @@ CTeamsProto::CTeamsProto(const char *protoName, const wchar_t *userName) :
nlu.szSettingsModule = m_szModuleName;
m_hNetlibUser = Netlib_RegisterUser(&nlu);
+ CMStringA module(FORMAT, "%s.TRouter", m_szModuleName);
+ CMStringW descr(FORMAT, TranslateT("%s websocket connection"), m_tszUserName);
+ nlu.szSettingsModule = module.GetBuffer();
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_UNICODE;
+ nlu.szDescriptiveName.w = descr.GetBuffer();
+ m_hTrouterNetlibUser = Netlib_RegisterUser(&nlu);
+
CreateProtoService(PS_GETAVATARINFO, &CTeamsProto::SvcGetAvatarInfo);
CreateProtoService(PS_GETAVATARCAPS, &CTeamsProto::SvcGetAvatarCaps);
CreateProtoService(PS_GETMYAVATAR, &CTeamsProto::SvcGetMyAvatar);
@@ -83,6 +107,7 @@ void CTeamsProto::OnModulesLoaded()
void CTeamsProto::OnShutdown()
{
StopQueue();
+ StopTrouter();
}
INT_PTR CTeamsProto::GetCaps(int type, MCONTACT)
@@ -142,7 +167,7 @@ int CTeamsProto::Authorize(MEVENT hDbEvent)
if (hContact == INVALID_CONTACT_ID)
return 1;
- PushRequest(new AuthAcceptRequest(getId(hContact)));
+ PushRequest(new AsyncHttpRequest(REQUEST_POST, HOST_CONTACTS, "/users/SELF/invites/" + mir_urlEncode(getId(hContact)) + "/accept"));
return 0;
}
@@ -152,7 +177,7 @@ int CTeamsProto::AuthDeny(MEVENT hDbEvent, const wchar_t *)
if (hContact == INVALID_CONTACT_ID)
return 1;
- PushRequest(new AuthDeclineRequest(getId(hContact)));
+ PushRequest(new AsyncHttpRequest(REQUEST_POST, HOST_CONTACTS, "/users/SELF/invites/" + mir_urlEncode(getId(hContact)) + "/decline"));
return 0;
}
@@ -166,7 +191,15 @@ int CTeamsProto::AuthRequest(MCONTACT hContact, const wchar_t *szMessage)
if (hContact == INVALID_CONTACT_ID)
return 1;
- PushRequest(new AddContactRequest(getId(hContact), T2Utf(szMessage)));
+ auto *pReq = new AsyncHttpRequest(REQUEST_PUT, HOST_CONTACTS, "/users/SELF/contacts");
+
+ JSONNode node;
+ node << CHAR_PARAM("mri", getId(hContact));
+ if (mir_wstrlen(szMessage))
+ node << WCHAR_PARAM("greeting", szMessage);
+ pReq->m_szParam = node.write().c_str();
+
+ PushRequest(pReq);
return 0;
}
@@ -203,6 +236,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..c6ad876e86 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;
@@ -182,12 +180,6 @@ public:
void OnEndpointCreated(MHttpResponse *response, AsyncHttpRequest *pRequest);
void OnEndpointDeleted(MHttpResponse *response, AsyncHttpRequest *pRequest);
- // oauth
- void OnOAuthStart(MHttpResponse *response, AsyncHttpRequest *pRequest);
- void OnOAuthConfirm(MHttpResponse* response, AsyncHttpRequest* pRequest);
- void OnOAuthAuthorize(MHttpResponse* response, AsyncHttpRequest* pRequest);
- void OnOAuthEnd(MHttpResponse *response, AsyncHttpRequest *pRequest);
-
void OnASMObjectCreated(MHttpResponse *response, AsyncHttpRequest *pRequest);
void OnASMObjectUploaded(MHttpResponse *response, AsyncHttpRequest *pRequest);
@@ -211,6 +203,7 @@ public:
void LoadProfile(MHttpResponse *response, AsyncHttpRequest *pRequest);
static INT_PTR __cdecl GlobalParseSkypeUriService(WPARAM, LPARAM lParam);
+
private:
bool m_bHistorySynced;
@@ -224,9 +217,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,17 +293,7 @@ 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>
@@ -346,8 +326,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 +347,40 @@ private:
auto *proto = CMPlugin::getInstance((MCONTACT)wParam);
return proto ? (proto->*Service)(wParam, lParam) : 0;
}
+
+ // trouter
+public:
+ void TRouterProcess(const char *str);
+
+private:
+ HNETLIBUSER m_hTrouterNetlibUser;
+ CMStringA m_szTrouterUrl, m_szTrouterSurl;
+ WebSocket<CTeamsProto> *m_ws;
+ MHttpHeaders m_connectParams;
+ int iCommandId;
+
+ void ProcessNewMessage(const JSONNode &node);
+ void ProcessUserPresence(const JSONNode &node);
+ void ProcessThreadUpdate(const JSONNode &node);
+ void ProcessServerMessage(const std::string &szName, const JSONNode &args);
+ void ProcessEndpointPresence(const JSONNode &node);
+ void ProcessConversationUpdate(const JSONNode &node);
+
+ 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..e602724c68
--- /dev/null
+++ b/protocols/Teams/src/teams_trouter.cpp
@@ -0,0 +1,367 @@
+/*
+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_hTrouterNetlibUser, 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"); transports << trouter;
+
+ 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 = 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);
+}
+
+static const char* skip3colons(const char *str)
+{
+ int nColons = 3;
+ for (const char *p = str; *p; p++) {
+ if (*p == ':') {
+ if (--nColons == 0)
+ return p + 1;
+ }
+ }
+ return str;
+}
+
+void CTeamsProto::TRouterProcess(const char *str)
+{
+ switch (*str) {
+ case '1':
+ TRouterSendAuthentication();
+ TRouterSendActive(true);
+ TRouterRegister();
+ break;
+
+ case '3':
+ if (auto packet = JSONNode::parse(skip3colons(str))) {
+ std::string szBody(packet["body"].as_string());
+ auto message = JSONNode::parse(szBody.c_str());
+ if (message) {
+ Netlib_Logf(m_hTrouterNetlibUser, "Got event:\n%s", message.write_formatted().c_str());
+
+ const JSONNode &resource = message["resource"];
+
+ std::string resourceType = message["resourceType"].as_string();
+ if (resourceType == "NewMessage")
+ ProcessNewMessage(resource);
+ else if (resourceType == "UserPresence")
+ ProcessUserPresence(resource);
+ else if (resourceType == "EndpointPresence")
+ ProcessEndpointPresence(resource);
+ else if (resourceType == "ConversationUpdate")
+ ProcessConversationUpdate(resource);
+ else if (resourceType == "ThreadUpdate")
+ ProcessThreadUpdate(resource);
+ }
+ }
+ break;
+
+ case '5':
+ if (auto root = JSONNode::parse(skip3colons(str))) {
+ std::string szName(root["name"].as_string());
+ ProcessServerMessage(szName, root["args"]);
+ }
+ break;
+ }
+}
+
+void CTeamsProto::ProcessEndpointPresence(const JSONNode &node)
+{
+ debugLogA(__FUNCTION__);
+ std::string selfLink = node["selfLink"].as_string();
+ CMStringA skypename(UrlToSkypeId(selfLink.c_str()));
+
+ MCONTACT hContact = FindContact(skypename);
+ if (hContact == NULL)
+ return;
+
+ const JSONNode &publicInfo = node["publicInfo"];
+ const JSONNode &privateInfo = node["privateInfo"];
+ CMStringA MirVer;
+ if (publicInfo) {
+ std::string skypeNameVersion = publicInfo["skypeNameVersion"].as_string();
+ std::string version = publicInfo["version"].as_string();
+ std::string typ = publicInfo["typ"].as_string();
+ int iTyp = atoi(typ.c_str());
+ switch (iTyp) {
+ case 0:
+ case 1:
+ MirVer.Append("Skype (Web) " + ParseUrl(version.c_str(), "/"));
+ break;
+ case 10:
+ MirVer.Append("Skype (XBOX) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 17:
+ MirVer.Append("Skype (Android) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 16:
+ MirVer.Append("Skype (iOS) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 12:
+ MirVer.Append("Skype (WinRT) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 15:
+ MirVer.Append("Skype (WP) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 13:
+ MirVer.Append("Skype (OSX) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 11:
+ MirVer.Append("Skype (Windows) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 14:
+ MirVer.Append("Skype (Linux) " + ParseUrl(skypeNameVersion.c_str(), "/"));
+ break;
+ case 125:
+ MirVer.AppendFormat("Miranda NG Skype %s", version.c_str());
+ break;
+ default:
+ MirVer.Append("Skype (Unknown)");
+ }
+ }
+
+ if (privateInfo != NULL) {
+ std::string epname = privateInfo["epname"].as_string();
+ if (!epname.empty())
+ MirVer.AppendFormat(" [%s]", epname.c_str());
+ }
+
+ setString(hContact, "MirVer", MirVer);
+}
+
+void CTeamsProto::ProcessUserPresence(const JSONNode &node)
+{
+ debugLogA(__FUNCTION__);
+
+ std::string selfLink = node["selfLink"].as_string();
+ std::string status = node["availability"].as_string();
+ CMStringA skypename = UrlToSkypeId(selfLink.c_str());
+
+ if (!skypename.IsEmpty()) {
+ if (IsMe(skypename)) {
+ int iNewStatus = SkypeToMirandaStatus(status.c_str());
+ if (iNewStatus == ID_STATUS_OFFLINE) return;
+ int old_status = m_iStatus;
+ m_iDesiredStatus = iNewStatus;
+ m_iStatus = iNewStatus;
+ if (old_status != iNewStatus)
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, iNewStatus);
+ }
+ else {
+ MCONTACT hContact = FindContact(skypename);
+ if (hContact != NULL)
+ SetContactStatus(hContact, SkypeToMirandaStatus(status.c_str()));
+ }
+ }
+}
+
+void CTeamsProto::ProcessServerMessage(const std::string &szName, const JSONNode&)
+{
+ if (szName == "trouter.message_loss") {
+ TRouterRegister("TeamsCDLWebWorker", "TeamsCDLWebWorker_1.9", m_szTrouterSurl);
+ }
+}
+
+void CTeamsProto::ProcessConversationUpdate(const JSONNode &) {}
+void CTeamsProto::ProcessThreadUpdate(const JSONNode &) {}
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)
diff --git a/protocols/Teams/src/version.h b/protocols/Teams/src/version.h
index 711a86277e..3b23908bca 100644
--- a/protocols/Teams/src/version.h
+++ b/protocols/Teams/src/version.h
@@ -7,7 +7,7 @@
#define __PLUGIN_NAME "Teams protocol"
#define __FILENAME "Teams.dll"
-#define __DESCRIPTION "Teams protocol support for Miranda NG."
+#define __DESCRIPTION "Microsoft Teams protocol support for Miranda NG."
#define __AUTHOR "Miranda NG team"
#define __AUTHORWEB "https://miranda-ng.org/p/Teams"
#define __COPYRIGHT "© 2025 Miranda NG team"
diff --git a/protocols/Weather/res/resource.rc b/protocols/Weather/res/resource.rc
index b03db42abc..8c6e6227d8 100644
--- a/protocols/Weather/res/resource.rc
+++ b/protocols/Weather/res/resource.rc
@@ -182,7 +182,8 @@ BEGIN
CONTROL "History Log",IDC_TM7,"MButtonClass",WS_TABSTOP,2,221,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
EDITTEXT IDC_HTEXT,80,219,183,12,ES_AUTOHSCROLL
GROUPBOX "Variable List",IDC_STATIC,207,14,99,191
- LTEXT "",IDC_VARLIST,213,25,86,157
+ CONTROL "",IDC_VARLIST,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,213,25,86,157
+ CONTROL "More Variables",IDC_MORE,"MButtonClass",WS_TABSTOP,216,187,81,15,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
CONTROL "Reset",IDC_RESET,"MButtonClass",WS_TABSTOP,266,208,40,21,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
EDITTEXT IDC_BTITLE2,80,28,125,12,ES_AUTOHSCROLL
CONTROL "Status Message",IDC_TM8,"MButtonClass",WS_TABSTOP | 0x100,2,29,77,9,WS_EX_WINDOWEDGE | WS_EX_NOACTIVATE | 0x10000000L
diff --git a/protocols/Weather/src/proto.h b/protocols/Weather/src/proto.h
index e83fee46eb..e1115b65e3 100644
--- a/protocols/Weather/src/proto.h
+++ b/protocols/Weather/src/proto.h
@@ -151,7 +151,6 @@ class CWeatherProto : public PROTO<CWeatherProto>
// data
void ConvertDataValue(WIDATAITEM *UpdateData);
void EraseAllInfo(void);
- void GetStationID(MCONTACT hContact, wchar_t *id, int idlen);
WEATHERINFO LoadWeatherInfo(MCONTACT hContact);
MHttpResponse* RunQuery(const wchar_t *id, int days);
@@ -182,6 +181,7 @@ class CWeatherProto : public PROTO<CWeatherProto>
int __cdecl OptInit(WPARAM, LPARAM);
CMStringW GetTextValue(int c);
+ void GetVarsDescr(CMStringW &str);
// popups
int WPShowMessage(const wchar_t *lpzText, int kind);
diff --git a/protocols/Weather/src/resource.h b/protocols/Weather/src/resource.h
index e53877d0ee..809c94857b 100644
--- a/protocols/Weather/src/resource.h
+++ b/protocols/Weather/src/resource.h
@@ -109,6 +109,7 @@
#define IDC_INFO10 2091
#define IDC_INFO12 2092
#define IDC_INFO13 2093
+#define IDC_MORE 2094
#define IDC_MOREDETAIL 2095
#define IDC_DATALIST 2096
#define IDC_MUPDATE 2097
diff --git a/protocols/Weather/src/stdafx.h b/protocols/Weather/src/stdafx.h
index eec03bd13e..cf1f3240a3 100644
--- a/protocols/Weather/src/stdafx.h
+++ b/protocols/Weather/src/stdafx.h
@@ -146,7 +146,7 @@ void TrimString(wchar_t *str);
void ConvertBackslashes(char *str);
char *GetSearchStr(char *dis);
-wchar_t *GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t* str);
+CMStringW GetDisplay(WEATHERINFO *w, const wchar_t *dis);
wchar_t *GetError(int code);
diff --git a/protocols/Weather/src/weather_addstn.cpp b/protocols/Weather/src/weather_addstn.cpp
index 1bdfb9b49d..026b9f8c67 100644
--- a/protocols/Weather/src/weather_addstn.cpp
+++ b/protocols/Weather/src/weather_addstn.cpp
@@ -88,7 +88,7 @@ MCONTACT CWeatherProto::AddToList(int, PROTOSEARCHRESULT *psr)
// if no default station is found, set the new contact as default station
if (opt.Default[0] == 0) {
- GetStationID(hContact, opt.Default, _countof(opt.Default));
+ wcsncpy_s(opt.Default, getMStringW(hContact, "ID"), _countof(opt.Default));
opt.DefStn = hContact;
ptrW wszNick(getWStringA(hContact, "Nick"));
diff --git a/protocols/Weather/src/weather_contacts.cpp b/protocols/Weather/src/weather_contacts.cpp
index 2661c1b20e..2f5a08f4ef 100644
--- a/protocols/Weather/src/weather_contacts.cpp
+++ b/protocols/Weather/src/weather_contacts.cpp
@@ -53,13 +53,12 @@ INT_PTR CWeatherProto::ViewLog(WPARAM wParam, LPARAM lParam)
// read complete forecast
// wParam = current contact
-INT_PTR CWeatherProto::LoadForecast(WPARAM wParam, LPARAM)
+INT_PTR CWeatherProto::LoadForecast(WPARAM hContact, LPARAM)
{
- wchar_t id[256];
- GetStationID(wParam, id, _countof(id));
- if (id[0] != 0) {
+ CMStringW wszID(getMStringW(hContact, "ID"));
+ if (!wszID.IsEmpty()) {
// set the url and open the webpage
- CMStringA szUrl("https://www.visualcrossing.com/weather-forecast/" + mir_urlEncode(T2Utf(id)) + "/metric");
+ CMStringA szUrl("https://www.visualcrossing.com/weather-forecast/" + mir_urlEncode(T2Utf(wszID)) + "/metric");
Utils_OpenUrl(szUrl);
}
return 0;
@@ -69,13 +68,12 @@ INT_PTR CWeatherProto::LoadForecast(WPARAM wParam, LPARAM)
// load weather map
// wParam = current contact
-INT_PTR CWeatherProto::WeatherMap(WPARAM wParam, LPARAM)
+INT_PTR CWeatherProto::WeatherMap(WPARAM hContact, LPARAM)
{
- wchar_t id[256];
- GetStationID(wParam, id, _countof(id));
- if (id[0] != 0) {
+ CMStringW wszID(getMStringW(hContact, "ID"));
+ if (!wszID.IsEmpty()) {
// set the url and open the webpage
- CMStringA szUrl("https://www.visualcrossing.com/weather-history/" + mir_urlEncode(T2Utf(id)) + "/metric");
+ CMStringA szUrl("https://www.visualcrossing.com/weather-history/" + mir_urlEncode(T2Utf(wszID)) + "/metric");
Utils_OpenUrl(szUrl);
}
diff --git a/protocols/Weather/src/weather_conv.cpp b/protocols/Weather/src/weather_conv.cpp
index d9f35264b0..4d2c79f0ce 100644
--- a/protocols/Weather/src/weather_conv.cpp
+++ b/protocols/Weather/src/weather_conv.cpp
@@ -399,7 +399,7 @@ char* GetSearchStr(char *dis)
// dis = the string to parse
// return value = the parsed string
-wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str)
+CMStringW GetDisplay(WEATHERINFO *w, const wchar_t *dis)
{
wchar_t lpzDate[32], chr;
char name[256], temp[2];
@@ -407,7 +407,7 @@ wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str)
size_t i;
// Clear the string
- str[0] = 0;
+ CMStringW str;
// looking character by character
for (i = 0; i < mir_wstrlen(dis); i++) {
@@ -416,10 +416,10 @@ wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str)
i++;
chr = dis[i];
switch (chr) {
- case '%': mir_wstrcat(str, L"%"); break;
- case 't': mir_wstrcat(str, L"\t"); break;
- case 'n': mir_wstrcat(str, L"\r\n"); break;
- case '\\': mir_wstrcat(str, L"\\"); break;
+ case '%': str.Append(L"%"); break;
+ case 't': str.Append(L"\t"); break;
+ case 'n': str.Append(L"\r\n"); break;
+ case '\\': str.Append(L"\\"); break;
}
}
@@ -430,29 +430,31 @@ wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str)
// turn capitalized characters to small case
if (chr < 'a' && chr != '[' && chr != '%') chr = (char)((int)chr + 32);
switch (chr) {
- case 'c': mir_wstrcat(str, w->cond); break;
+ case 'c': str.Append(w->cond); break;
case 'd': // get the current date
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, nullptr, nullptr, lpzDate, _countof(lpzDate));
- mir_wstrcat(str, lpzDate); break;
- case 'e': mir_wstrcat(str, w->dewpoint); break;
- case 'f': mir_wstrcat(str, w->feel); break;
- case 'h': mir_wstrcat(str, w->high); break;
- case 'i': mir_wstrcat(str, w->winddir); break;
- case 'l': mir_wstrcat(str, w->low); break;
- case 'm': mir_wstrcat(str, w->humid); break;
- case 'n': mir_wstrcat(str, w->city); break;
- case 'p': mir_wstrcat(str, w->pressure); break;
- case 'r': mir_wstrcat(str, w->sunrise); break;
- case 's': mir_wstrcat(str, w->id); break;
- case 't': mir_wstrcat(str, w->temp); break;
+ str.Append(lpzDate); break;
+ case 'e': str.Append(w->dewpoint); break;
+ case 'f': str.Append(w->feel); break;
+ case 'h': str.Append(w->high); break;
+ case 'i': str.Append(w->winddir); break;
+ case 'l': str.Append(w->low); break;
+ case 'm': str.Append(w->humid); break;
+ case 'n': str.Append(w->city); break;
+ case 'p': str.Append(w->pressure); break;
+ case 'r': str.Append(w->sunrise); break;
+ case 's': str.Append(w->id); break;
+ case 't': str.Append(w->temp); break;
case 'u':
- if (mir_wstrcmp(w->update, NODATA)) mir_wstrcat(str, w->update);
- else mir_wstrcat(str, TranslateT("<unknown time>"));
+ if (mir_wstrcmp(w->update, NODATA))
+ str.Append(w->update);
+ else
+ str.Append(TranslateT("<unknown time>"));
break;
- case 'v': mir_wstrcat(str, w->vis); break;
- case 'w': mir_wstrcat(str, w->wind); break;
- case 'y': mir_wstrcat(str, w->sunset); break;
- case '%': mir_wstrcat(str, L"%"); break;
+ case 'v': str.Append(w->vis); break;
+ case 'w': str.Append(w->wind); break;
+ case 'y': str.Append(w->sunset); break;
+ case '%': str.Append(L"%"); break;
case '[': // custom variables
i++;
name[0] = 0;
@@ -464,17 +466,14 @@ wchar_t* GetDisplay(WEATHERINFO *w, const wchar_t *dis, wchar_t *str)
// access the database to get its value
if (!db_get_ws(w->hContact, WEATHERCONDITION, name, &dbv)) {
if (dbv.pwszVal != TranslateW(NODATA) && dbv.pwszVal != TranslateT("<Error>"))
- mir_wstrcat(str, dbv.pwszVal);
+ str.Append(dbv.pwszVal);
db_free(&dbv);
}
break;
}
}
// if the character is not a variable, write the original character to the new string
- else {
- mir_snwprintf(lpzDate, L"%c", dis[i]);
- mir_wstrcat(str, lpzDate);
- }
+ else str.AppendChar(dis[i]);
}
return str;
diff --git a/protocols/Weather/src/weather_data.cpp b/protocols/Weather/src/weather_data.cpp
index a02ae0dc1f..76e50ca139 100644
--- a/protocols/Weather/src/weather_data.cpp
+++ b/protocols/Weather/src/weather_data.cpp
@@ -26,18 +26,6 @@ saving individual weather data for a weather contact.
#include "stdafx.h"
/////////////////////////////////////////////////////////////////////////////////////////
-// get station ID from DB
-// hContact = the current contact handle
-// return value = the string for station ID
-
-void CWeatherProto::GetStationID(MCONTACT hContact, wchar_t *id, int idlen)
-{
- // accessing the database
- if (db_get_wstatic(hContact, m_szModuleName, "ID", id, idlen))
- id[0] = 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
// initialize weather info by loading values from database
// hContact = current contact handle
// return value = the current weather information in WEATHERINFO struct
@@ -49,7 +37,7 @@ WEATHERINFO CWeatherProto::LoadWeatherInfo(MCONTACT hContact)
// if the string is not found in database, a value of "N/A" is stored in the field
WEATHERINFO winfo;
winfo.hContact = hContact;
- GetStationID(hContact, winfo.id, _countof(winfo.id));
+ wcsncpy_s(winfo.id, getMStringW(hContact, "ID"), _countof(winfo.id));
if (db_get_wstatic(hContact, m_szModuleName, "Nick", winfo.city, _countof(winfo.city)))
wcsncpy(winfo.city, NODATA, _countof(winfo.city) - 1);
@@ -121,7 +109,7 @@ void CWeatherProto::EraseAllInfo()
// if no default station find, assign a new one
if (opt.Default[0] == 0) {
- GetStationID(hContact, opt.Default, _countof(opt.Default));
+ wcsncpy_s(opt.Default, getMStringW(hContact, "ID"), _countof(opt.Default));
opt.DefStn = hContact;
if (!getWString(hContact, "Nick", &dbv)) {
diff --git a/protocols/Weather/src/weather_mwin.cpp b/protocols/Weather/src/weather_mwin.cpp
index 57b775c81b..058c6e56ad 100644
--- a/protocols/Weather/src/weather_mwin.cpp
+++ b/protocols/Weather/src/weather_mwin.cpp
@@ -340,7 +340,7 @@ void CWeatherProto::InitMwin(void)
g_plugin.addFont(&fontid);
for (auto &hContact : AccContacts())
- if (g_plugin.getDword(hContact, "mwin"))
+ if (getDword(hContact, "mwin"))
AddFrameWindow(hContact);
hFontHook = HookEvent(ME_FONT_RELOAD, RedrawFrame);
@@ -349,7 +349,7 @@ void CWeatherProto::InitMwin(void)
void CWeatherProto::DestroyMwin(void)
{
for (auto &hContact : AccContacts()) {
- uint32_t frameId = g_plugin.getDword(hContact, "mwin");
+ uint32_t frameId = getDword(hContact, "mwin");
if (frameId)
CallService(MS_CLIST_FRAMES_REMOVEFRAME, frameId, 0);
}
diff --git a/protocols/Weather/src/weather_opt.cpp b/protocols/Weather/src/weather_opt.cpp
index a0b42e21be..765309e414 100644
--- a/protocols/Weather/src/weather_opt.cpp
+++ b/protocols/Weather/src/weather_opt.cpp
@@ -295,8 +295,6 @@ public:
/////////////////////////////////////////////////////////////////////////////////////////
// text option dialog
-#define VAR_LIST_OPT TranslateT("%c\tcurrent condition\n%d\tcurrent date\n%e\tdewpoint\n%f\tfeel-like temp\n%h\ttoday's high\n%i\twind direction\n%l\ttoday's low\n%m\thumidity\n%n\tstation name\n%p\tpressure\n%r\tsunrise time\n%s\tstation ID\n%t\ttemperature\n%u\tupdate time\n%v\tvisibility\n%w\twind speed\n%y\tsun set\n----------\n\\n\tnew line")
-
struct
{
wchar_t c;
@@ -315,13 +313,40 @@ static controls[] =
{ 'S', IDC_BTITLE2, "StatusText" },
};
+struct
+{
+ wchar_t symbol;
+ const wchar_t *pwszText;
+}
+static variables[] =
+{
+ { 'c', LPGENW("Current condition") },
+ { 'd', LPGENW("Current date") },
+ { 'e', LPGENW("Dewpoint") },
+ { 'f', LPGENW("Feel-like temp") },
+ { 'h', LPGENW("Today's high") },
+ { 'i', LPGENW("Wind direction") },
+ { 'l', LPGENW("Today's low") },
+ { 'm', LPGENW("Humidity") },
+ { 'n', LPGENW("Station name") },
+ { 'p', LPGENW("Pressure") },
+ { 'r', LPGENW("Sunrise") },
+ { 's', LPGENW("Station ID") },
+ { 't', LPGENW("Temperature") },
+ { 'u', LPGENW("Update time") },
+ { 'v', LPGENW("Visibility") },
+ { 'w', LPGENW("Wind speed") },
+ { 'y', LPGENW("Sunset") },
+};
+
class COptionsTextDlg : public CWeatherDlgBase
{
- CCtrlMButton btnReset, tm1, tm2, tm3, tm4, tm5, tm6, tm7, tm8;
+ CCtrlMButton btnMore, btnReset, tm1, tm2, tm3, tm4, tm5, tm6, tm7, tm8;
public:
COptionsTextDlg(CWeatherProto *ppro) :
CWeatherDlgBase(ppro, IDD_TEXTOPT),
+ btnMore(this, IDC_MORE),
btnReset(this, IDC_RESET),
tm1(this, IDC_TM1),
tm2(this, IDC_TM2),
@@ -332,6 +357,7 @@ public:
tm7(this, IDC_TM7),
tm8(this, IDC_TM8)
{
+ btnMore.OnClick = Callback(this, &COptionsTextDlg::onClick_More);
btnReset.OnClick = Callback(this, &COptionsTextDlg::onClick_Reset);
tm1.OnClick = tm2.OnClick = tm3.OnClick = tm4.OnClick = tm5.OnClick = tm6.OnClick = tm7.OnClick = tm8.OnClick =
@@ -346,7 +372,12 @@ public:
SetWindowPos(m_hwnd, HWND_TOPMOST, rc.left, rc.top, 0, 0, SWP_NOSIZE);
// generate the display text for variable list
- SetDlgItemTextW(m_hwnd, IDC_VARLIST, VAR_LIST_OPT);
+ CMStringW str;
+ for (auto &it : variables)
+ str.AppendFormat(L"%%%c\t%s\r\n", it.symbol, TranslateW(it.pwszText));
+ str.Append(L"----------\r\n");
+ str.AppendFormat(L"\\n\t%s\r\n", TranslateT("new line"));
+ SetDlgItemTextW(m_hwnd, IDC_VARLIST, str);
for (auto &it : controls)
SetDlgItemTextW(m_hwnd, it.id, m_proto->GetTextValue(it.c));
@@ -360,6 +391,7 @@ public:
tm6.MakeFlat();
tm7.MakeFlat();
tm8.MakeFlat();
+ btnMore.MakeFlat();
btnReset.MakeFlat();
return true;
}
@@ -367,8 +399,8 @@ public:
bool OnApply() override
{
// save the option
- wchar_t textstr[MAX_TEXT_SIZE];
for (auto &it : controls) {
+ wchar_t textstr[MAX_TEXT_SIZE];
GetDlgItemText(m_hwnd, it.id, textstr, _countof(textstr));
if (!mir_wstrcmpi(textstr, GetDefaultText(it.c)))
m_proto->delSetting(it.setting);
@@ -381,45 +413,55 @@ public:
return true;
}
+ void onClick_More(CCtrlButton *)
+ {
+ // heading
+ CMStringW str(TranslateT("Here is a list of custom variables that are currently available"));
+ str += L"\n\n";
+ m_proto->GetVarsDescr(str);
+
+ // display the list in a message box
+ MessageBox(nullptr, str, TranslateT("More Variables"), MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
+ }
+
void onClick_TM(CCtrlButton *pButton)
{
// display the menu
- RECT pos;
- GetWindowRect(pButton->GetHwnd(), &pos);
HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMMENU));
HMENU hMenu1 = GetSubMenu(hMenu, 0);
TranslateMenu(hMenu1);
- {
- auto &var = controls[pButton->GetCtrlId() - IDC_TM1];
-
- switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr)) {
- case ID_MPREVIEW:
- {
- // show the preview in a message box, using the weather data from the default station
- WEATHERINFO winfo = m_proto->LoadWeatherInfo(m_proto->opt.DefStn);
- wchar_t buf[MAX_TEXT_SIZE], str[4096];
- GetDlgItemTextW(m_hwnd, var.id, buf, _countof(buf));
- GetDisplay(&winfo, buf, str);
- MessageBox(nullptr, str, TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST);
- }
- break;
-
- case ID_MRESET:
- SetDlgItemTextW(m_hwnd, var.id, GetDefaultText(var.c));
- break;
+
+ auto &var = controls[pButton->GetCtrlId() - IDC_TM1];
+
+ RECT pos;
+ GetWindowRect(pButton->GetHwnd(), &pos);
+ switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr)) {
+ case ID_MPREVIEW:
+ {
+ // show the preview in a message box, using the weather data from the default station
+ WEATHERINFO winfo = m_proto->LoadWeatherInfo(m_proto->opt.DefStn);
+ wchar_t buf[MAX_TEXT_SIZE];
+ GetDlgItemTextW(m_hwnd, var.id, buf, _countof(buf));
+ MessageBox(nullptr, GetDisplay(&winfo, buf), TranslateT("Weather Protocol Text Preview"), MB_OK | MB_TOPMOST);
}
- DestroyMenu(hMenu);
+ break;
+
+ case ID_MRESET:
+ SetDlgItemTextW(m_hwnd, var.id, GetDefaultText(var.c));
+ break;
}
+ DestroyMenu(hMenu);
}
void onClick_Reset(CCtrlButton *)
{
// left click action selection menu
- RECT pos;
- GetWindowRect(btnReset.GetHwnd(), &pos);
HMENU hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_TMENU));
HMENU hMenu1 = GetSubMenu(hMenu, 0);
TranslateMenu(hMenu1);
+
+ RECT pos;
+ GetWindowRect(btnReset.GetHwnd(), &pos);
switch (TrackPopupMenu(hMenu1, TPM_LEFTBUTTON | TPM_RETURNCMD, pos.left, pos.bottom, 0, m_hwnd, nullptr)) {
case ID_T1:
// reset to the strings in memory, discard all changes
diff --git a/protocols/Weather/src/weather_popup.cpp b/protocols/Weather/src/weather_popup.cpp
index 91dcf51cb9..b9f938e41d 100644
--- a/protocols/Weather/src/weather_popup.cpp
+++ b/protocols/Weather/src/weather_popup.cpp
@@ -120,8 +120,8 @@ int CWeatherProto::WeatherPopup(MCONTACT hContact, bool bAlways)
POPUPDATAW ppd;
ppd.lchContact = hContact;
ppd.PluginData = ppd.lchIcon = GetStatusIcon(winfo.hContact);
- GetDisplay(&winfo, GetTextValue('P'), ppd.lpwzContactName);
- GetDisplay(&winfo, GetTextValue('p'), ppd.lpwzText);
+ wcsncpy_s(ppd.lpwzContactName, GetDisplay(&winfo, GetTextValue('P')), _TRUNCATE);
+ wcsncpy_s(ppd.lpwzText, GetDisplay(&winfo, GetTextValue('p')), _TRUNCATE);
ppd.PluginWindowProc = PopupDlgProc;
ppd.colorBack = (opt.UseWinColors) ? GetSysColor(COLOR_BTNFACE) : opt.BGColour;
ppd.colorText = (opt.UseWinColors) ? GetSysColor(COLOR_WINDOWTEXT) : opt.TextColour;
diff --git a/protocols/Weather/src/weather_proto.cpp b/protocols/Weather/src/weather_proto.cpp
index 6df768e7ac..3c5f8f1057 100644
--- a/protocols/Weather/src/weather_proto.cpp
+++ b/protocols/Weather/src/weather_proto.cpp
@@ -32,8 +32,6 @@ CWeatherProto::CWeatherProto(const char *protoName, const wchar_t *userName) :
HookProtoEvent(ME_CLIST_DOUBLECLICKED, &CWeatherProto::BriefInfoEvt);
HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CWeatherProto::BuildContactMenu);
- InitMwin();
-
// load options and set defaults
LoadOptions();
@@ -63,6 +61,8 @@ CWeatherProto::~CWeatherProto()
void CWeatherProto::OnModulesLoaded()
{
+ InitMwin();
+
// timer for the first update
m_impl.m_start.Start(5000); // first update is 5 sec after load
diff --git a/protocols/Weather/src/weather_update.cpp b/protocols/Weather/src/weather_update.cpp
index 15713e110e..82437dbb72 100644
--- a/protocols/Weather/src/weather_update.cpp
+++ b/protocols/Weather/src/weather_update.cpp
@@ -32,7 +32,6 @@ menu items).
int CWeatherProto::UpdateWeather(MCONTACT hContact)
{
- wchar_t str2[MAX_TEXT_SIZE];
DBVARIANT dbv;
BOOL Ch = FALSE;
@@ -128,22 +127,18 @@ int CWeatherProto::UpdateWeather(MCONTACT hContact)
setWord(hContact, "Status", iStatus);
AvatarDownloaded(hContact);
- GetDisplay(&winfo, GetTextValue('C'), str2);
- db_set_ws(hContact, "CList", "MyHandle", str2);
+ db_set_ws(hContact, "CList", "MyHandle", GetDisplay(&winfo, GetTextValue('C')));
- GetDisplay(&winfo, GetTextValue('S'), str2);
- if (str2[0])
+ CMStringW str2(GetDisplay(&winfo, GetTextValue('S')));
+ if (!str2.IsEmpty())
db_set_ws(hContact, "CList", "StatusMsg", str2);
else
db_unset(hContact, "CList", "StatusMsg");
-
- ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2[0] ? str2 : nullptr));
+ ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, nullptr, (LPARAM)(str2.IsEmpty() ? nullptr : str2.c_str()));
// save descriptions in MyNotes
- GetDisplay(&winfo, GetTextValue('N'), str2);
- db_set_ws(hContact, "UserInfo", "MyNotes", str2);
- GetDisplay(&winfo, GetTextValue('X'), str2);
- db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", str2);
+ db_set_ws(hContact, "UserInfo", "MyNotes", GetDisplay(&winfo, GetTextValue('N')));
+ db_set_ws(hContact, WEATHERCONDITION, "WeatherInfo", GetDisplay(&winfo, GetTextValue('X')));
// set the update tag
setByte(hContact, "IsUpdated", TRUE);
@@ -174,8 +169,7 @@ int CWeatherProto::UpdateWeather(MCONTACT hContact)
db_free(&dbv);
if (file != nullptr) {
// write data to the file and close
- GetDisplay(&winfo, GetTextValue('E'), str2);
- fputws(str2, file);
+ fputws(GetDisplay(&winfo, GetTextValue('E')), file);
fclose(file);
}
}
@@ -183,9 +177,7 @@ int CWeatherProto::UpdateWeather(MCONTACT hContact)
if (getByte(hContact, "History")) {
// internal log using history
- GetDisplay(&winfo, GetTextValue('H'), str2);
-
- T2Utf szMessage(str2);
+ T2Utf szMessage(GetDisplay(&winfo, GetTextValue('H')));
DBEVENTINFO dbei = {};
dbei.szModule = m_szModuleName;
@@ -381,6 +373,7 @@ static double g_elevation = 0;
static void getData(OBJLIST<WIDATAITEM> &arValues, const JSONNode &node)
{
+ arValues.insert(new WIDATAITEM(LPGENW("Date"), L"", parseConditions(node["datetime"].as_mstring())));
arValues.insert(new WIDATAITEM(LPGENW("Condition"), L"", parseConditions(node["conditions"].as_mstring())));
arValues.insert(new WIDATAITEM(LPGENW("Temperature"), L"C", node["temp"].as_mstring()));
arValues.insert(new WIDATAITEM(LPGENW("High"), L"C", node["tempmax"].as_mstring()));
@@ -403,15 +396,14 @@ static void getData(OBJLIST<WIDATAITEM> &arValues, const JSONNode &node)
int CWeatherProto::GetWeatherData(MCONTACT hContact)
{
// get each part of the id's
- wchar_t id[256];
- GetStationID(hContact, id, _countof(id));
- if (id[0] == 0)
+ CMStringW wszID(getMStringW(hContact, "ID"));
+ if (wszID.IsEmpty())
return INVALID_ID;
uint16_t cond = NA;
// download the html file from the internet
- WeatherReply reply(RunQuery(id, 7));
+ WeatherReply reply(RunQuery(wszID, 7));
if (!reply)
return reply.error();
@@ -478,6 +470,34 @@ int CWeatherProto::GetWeatherData(MCONTACT hContact)
}
/////////////////////////////////////////////////////////////////////////////////////////
+
+static int enumSettings(const char *pszSetting, void *param)
+{
+ auto *pList = (OBJLIST<char>*)param;
+ if (!pList->find((char*)pszSetting))
+ pList->insert(newStr(pszSetting));
+ return 0;
+}
+
+void CWeatherProto::GetVarsDescr(CMStringW &wszDescr)
+{
+ OBJLIST<char> vars(10, strcmp);
+ for (int i = 1; i <= 7; i++)
+ vars.insert(newStr(CMStringA(FORMAT, "Forecast Day %d", i)));
+
+ for (auto &cc : AccContacts())
+ db_enum_settings(cc, &enumSettings, WEATHERCONDITION, &vars);
+
+ CMStringW str;
+ for (auto &it : vars) {
+ if (!str.IsEmpty())
+ str.Append(L", ");
+ str.AppendFormat(L"%%[%S]", it);
+ }
+ wszDescr += str;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
// main auto-update timer
void CWeatherProto::DoUpdate()
diff --git a/protocols/Weather/src/weather_userinfo.cpp b/protocols/Weather/src/weather_userinfo.cpp
index 0679ddf6e9..1207d01b4a 100644
--- a/protocols/Weather/src/weather_userinfo.cpp
+++ b/protocols/Weather/src/weather_userinfo.cpp
@@ -151,8 +151,6 @@ public:
{
m_list.DeleteAllItems();
- wchar_t str[4096];
-
// load weather information from the contact into the WEATHERINFO struct
WEATHERINFO winfo = m_proto->LoadWeatherInfo(hContact);
// check if data exist. If not, display error message box
@@ -160,13 +158,11 @@ public:
SetDlgItemTextW(m_hwnd, IDC_MTEXT, TranslateT("No information available.\r\nPlease update weather condition first."));
else {
// set the display text and show the message box
- GetDisplay(&winfo, m_proto->GetTextValue('B'), str);
- SetDlgItemTextW(m_hwnd, IDC_MTEXT, str);
+ SetDlgItemTextW(m_hwnd, IDC_MTEXT, GetDisplay(&winfo, m_proto->GetTextValue('B')));
}
- GetDisplay(&winfo, L"%c, %t", str);
SetWindowTextW(m_hwnd, winfo.city);
- SetDlgItemTextW(m_hwnd, IDC_HEADERBAR, str);
+ SetDlgItemTextW(m_hwnd, IDC_HEADERBAR, GetDisplay(&winfo, L"%c, %t"));
// get all the settings and store them in a temporary list
LIST<char> arSettings(10);
@@ -311,9 +307,8 @@ public:
ppro = (CWeatherProto *)Proto_GetContactInstance(m_hContact);
// load weather info for the contact
- wchar_t str[MAX_TEXT_SIZE];
WEATHERINFO w = ppro->LoadWeatherInfo(m_hContact);
- SetDlgItemText(m_hwnd, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n"), str));
+ SetDlgItemText(m_hwnd, IDC_INFO1, GetDisplay(&w, TranslateT("Current condition for %n")));
SendDlgItemMessage(m_hwnd, IDC_INFOICON, STM_SETICON, (WPARAM)ppro->GetStatusIconBig(m_hContact), 0);
@@ -327,19 +322,16 @@ public:
SendDlgItemMessage(m_hwnd, IDC_INFO2, WM_SETFONT, (WPARAM)CreateFontIndirect(&lf), 0);
// set the text for displaying other current weather conditions data
- GetDisplay(&w, L"%c %t", str);
- SetDlgItemText(m_hwnd, IDC_INFO2, str);
+ SetDlgItemText(m_hwnd, IDC_INFO2, GetDisplay(&w, L"%c %t"));
SetDlgItemText(m_hwnd, IDC_INFO3, w.feel);
SetDlgItemText(m_hwnd, IDC_INFO4, w.pressure);
- GetDisplay(&w, L"%i %w", str);
- SetDlgItemText(m_hwnd, IDC_INFO5, str);
+ SetDlgItemText(m_hwnd, IDC_INFO5, GetDisplay(&w, L"%i %w"));
SetDlgItemText(m_hwnd, IDC_INFO6, w.dewpoint);
SetDlgItemText(m_hwnd, IDC_INFO7, w.sunrise);
SetDlgItemText(m_hwnd, IDC_INFO8, w.sunset);
SetDlgItemText(m_hwnd, IDC_INFO9, w.high);
SetDlgItemText(m_hwnd, IDC_INFO10, w.low);
- GetDisplay(&w, TranslateT("Last update on: %u"), str);
- SetDlgItemText(m_hwnd, IDC_INFO11, str);
+ SetDlgItemText(m_hwnd, IDC_INFO11, GetDisplay(&w, TranslateT("Last update on: %u")));
SetDlgItemText(m_hwnd, IDC_INFO12, w.humid);
SetDlgItemText(m_hwnd, IDC_INFO13, w.vis);
return true;