diff options
author | dartraiden <wowemuh@gmail.com> | 2023-01-14 01:30:59 +0300 |
---|---|---|
committer | dartraiden <wowemuh@gmail.com> | 2023-01-14 01:30:59 +0300 |
commit | de40f3be3f08487937525c2ef096dad665dda61d (patch) | |
tree | eb1205f8dca7c30b561a2776f9527072bd92eaf1 /protocols | |
parent | dd743899a769120ba2321230afddd6e4f1271872 (diff) |
Convert sources to CR+LF
Diffstat (limited to 'protocols')
96 files changed, 23998 insertions, 23998 deletions
diff --git a/protocols/Discord/CMakeLists.txt b/protocols/Discord/CMakeLists.txt index a227eff6df..d0502167ed 100644 --- a/protocols/Discord/CMakeLists.txt +++ b/protocols/Discord/CMakeLists.txt @@ -1,5 +1,5 @@ -file(GLOB SOURCES "src/*.h" "src/*.cpp" "res/*.rc") -set(TARGET Discord) -include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake) -target_link_libraries(${TARGET} Zlib libjson) +file(GLOB SOURCES "src/*.h" "src/*.cpp" "res/*.rc")
+set(TARGET Discord)
+include(${CMAKE_SOURCE_DIR}/cmake/plugin.cmake)
+target_link_libraries(${TARGET} Zlib libjson)
add_subdirectory(proto_discord)
\ No newline at end of file diff --git a/protocols/Discord/discord.vcxproj b/protocols/Discord/discord.vcxproj index ac4c73bd0f..e2f19b6be9 100644 --- a/protocols/Discord/discord.vcxproj +++ b/protocols/Discord/discord.vcxproj @@ -1,66 +1,66 @@ -<?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"> - <ProjectGuid>{88928401-2CE8-4568-AAA7-226141870CBF}</ProjectGuid> - <ProjectName>Discord</ProjectName> - </PropertyGroup> - <ImportGroup Label="PropertySheets"> - <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> - </ImportGroup> - <ItemGroup> - <ClCompile Include="src\avatars.cpp" /> - <ClCompile Include="src\connection.cpp" /> - <ClCompile Include="src\dispatch.cpp" /> - <ClCompile Include="src\gateway.cpp" /> - <ClCompile Include="src\groupchat.cpp" /> - <ClCompile Include="src\guilds.cpp" /> - <ClCompile Include="src\http.cpp" /> - <ClCompile Include="src\main.cpp" /> - <ClCompile Include="src\menus.cpp" /> - <ClCompile Include="src\options.cpp" /> - <ClCompile Include="src\proto.cpp" /> - <ClCompile Include="src\server.cpp" /> - <ClCompile Include="src\stdafx.cxx"> - <PrecompiledHeader>Create</PrecompiledHeader> - </ClCompile> - <ClCompile Include="src\utils.cpp" /> - <ClCompile Include="src\voice.cpp" /> - <ClInclude Include="src\proto.h" /> - <ClInclude Include="src\resource.h" /> - <ClInclude Include="src\stdafx.h" /> - <ClInclude Include="src\version.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\..\libs\zlib\zlib.vcxproj"> - <Project>{01F9E227-06F5-4BED-907F-402CA7DFAFE6}</Project> - <ReferenceOutputAssembly>false</ReferenceOutputAssembly> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\..\libs\libjson\libjson.vcxproj"> - <Project>{f6a9340e-b8d9-4c75-be30-47dc66d0abc7}</Project> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\discord.rc" /> - <ResourceCompile Include="res\version.rc" /> - </ItemGroup> +<?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">
+ <ProjectGuid>{88928401-2CE8-4568-AAA7-226141870CBF}</ProjectGuid>
+ <ProjectName>Discord</ProjectName>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClCompile Include="src\avatars.cpp" />
+ <ClCompile Include="src\connection.cpp" />
+ <ClCompile Include="src\dispatch.cpp" />
+ <ClCompile Include="src\gateway.cpp" />
+ <ClCompile Include="src\groupchat.cpp" />
+ <ClCompile Include="src\guilds.cpp" />
+ <ClCompile Include="src\http.cpp" />
+ <ClCompile Include="src\main.cpp" />
+ <ClCompile Include="src\menus.cpp" />
+ <ClCompile Include="src\options.cpp" />
+ <ClCompile Include="src\proto.cpp" />
+ <ClCompile Include="src\server.cpp" />
+ <ClCompile Include="src\stdafx.cxx">
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp" />
+ <ClCompile Include="src\voice.cpp" />
+ <ClInclude Include="src\proto.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\stdafx.h" />
+ <ClInclude Include="src\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\libs\zlib\zlib.vcxproj">
+ <Project>{01F9E227-06F5-4BED-907F-402CA7DFAFE6}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\libs\libjson\libjson.vcxproj">
+ <Project>{f6a9340e-b8d9-4c75-be30-47dc66d0abc7}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\discord.rc" />
+ <ResourceCompile Include="res\version.rc" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Discord/discord.vcxproj.filters b/protocols/Discord/discord.vcxproj.filters index 18314b26b0..f8b955739b 100644 --- a/protocols/Discord/discord.vcxproj.filters +++ b/protocols/Discord/discord.vcxproj.filters @@ -1,73 +1,73 @@ -<?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" /> - <ItemGroup> - <ClCompile Include="src\avatars.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\connection.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\dispatch.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\gateway.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\groupchat.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\guilds.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\http.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\main.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\menus.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\options.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\proto.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\server.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\stdafx.cxx"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\utils.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\voice.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="src\proto.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\stdafx.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\version.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\discord.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - <ResourceCompile Include="res\version.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> +<?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" />
+ <ItemGroup>
+ <ClCompile Include="src\avatars.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\connection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\dispatch.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\gateway.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\groupchat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\guilds.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\http.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\menus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\server.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\stdafx.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\voice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\discord.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="res\version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Discord/proto_discord/CMakeLists.txt b/protocols/Discord/proto_discord/CMakeLists.txt index 5ea6891fa1..48da532df6 100644 --- a/protocols/Discord/proto_discord/CMakeLists.txt +++ b/protocols/Discord/proto_discord/CMakeLists.txt @@ -1,2 +1,2 @@ -set(TARGET Proto_Discord) +set(TARGET Proto_Discord)
include(${CMAKE_SOURCE_DIR}/cmake/icons.cmake)
\ No newline at end of file diff --git a/protocols/Discord/proto_discord/Proto_Discord.vcxproj b/protocols/Discord/proto_discord/Proto_Discord.vcxproj index 8ce8962a22..a17e91b938 100644 --- a/protocols/Discord/proto_discord/Proto_Discord.vcxproj +++ b/protocols/Discord/proto_discord/Proto_Discord.vcxproj @@ -1,34 +1,34 @@ -<?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_Discord</ProjectName> - <ProjectGuid>{6B8BA5EE-3815-44A6-A13B-2A22E8B3A311}</ProjectGuid> - </PropertyGroup> - <ImportGroup Label="PropertySheets"> - <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" /> - </ImportGroup> - <ItemGroup> - <ClInclude Include="src\resource.h" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Proto_Discord.rc" /> - </ItemGroup> +<?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_Discord</ProjectName>
+ <ProjectGuid>{6B8BA5EE-3815-44A6-A13B-2A22E8B3A311}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Discord.rc" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Discord/proto_discord/Proto_Discord.vcxproj.filters b/protocols/Discord/proto_discord/Proto_Discord.vcxproj.filters index 3f512b9b20..a86aceb510 100644 --- a/protocols/Discord/proto_discord/Proto_Discord.vcxproj.filters +++ b/protocols/Discord/proto_discord/Proto_Discord.vcxproj.filters @@ -1,14 +1,14 @@ -<?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" /> - <ItemGroup> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Proto_Discord.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> +<?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" />
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Discord.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Discord/proto_discord/res/Proto_Discord.rc b/protocols/Discord/proto_discord/res/Proto_Discord.rc index 13d3153e3e..fb320d064b 100644 --- a/protocols/Discord/proto_discord/res/Proto_Discord.rc +++ b/protocols/Discord/proto_discord/res/Proto_Discord.rc @@ -1,74 +1,74 @@ -// 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" -#endif // Russian (Russia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// 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"
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Discord/proto_discord/src/resource.h b/protocols/Discord/proto_discord/src/resource.h index 70e0dd0372..1a283a2809 100644 --- a/protocols/Discord/proto_discord/src/resource.h +++ b/protocols/Discord/proto_discord/src/resource.h @@ -1,23 +1,23 @@ -//{{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 - -// 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 +//{{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
+
+// 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/Discord/res/discord.rc b/protocols/Discord/res/discord.rc index 6fac650624..780cae5613 100644 --- a/protocols/Discord/res/discord.rc +++ b/protocols/Discord/res/discord.rc @@ -1,159 +1,159 @@ -// Microsoft Visual C++ generated resource script. -// -#include "..\src\resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "..\\src\\resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.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_MAIN ICON "discord.ico" - -IDI_GROUPCHAT ICON "groupchat.ico" - -IDI_VOICE_CALL ICON "voiceCall.ico" - -IDI_VOICE_ENDED ICON "voiceEnded.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_OPTIONS_ACCOUNT DIALOGEX 0, 0, 305, 144 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "User details",IDC_STATIC,7,7,291,46 - LTEXT "E-mail:",IDC_STATIC,17,20,61,8,0,WS_EX_RIGHT - EDITTEXT IDC_USERNAME,84,18,123,13,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,17,36,61,8,0,WS_EX_RIGHT - EDITTEXT IDC_PASSWORD,84,34,123,13,ES_PASSWORD | ES_AUTOHSCROLL - GROUPBOX "Contacts",IDC_STATIC,7,54,291,86 - LTEXT "Default group:",IDC_STATIC,17,73,61,8,0,WS_EX_RIGHT - EDITTEXT IDC_GROUP,84,71,123,13,ES_AUTOHSCROLL - CONTROL "Enable guilds (servers)",IDC_USEGUILDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,90,275,10 - CONTROL "Do not open chat windows on creation",IDC_HIDECHATS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,102,248,10 - CONTROL "Use subgroups for server channels (requires restart)",IDC_USEGROUPS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,114,248,10 - CONTROL "Delete messages in Miranda when they are deleted from server",IDC_DELETE_MSGS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,126,275,10 -END - -IDD_OPTIONS_ACCMGR DIALOGEX 0, 0, 200, 88 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "User details",IDC_STATIC,7,7,178,46 - LTEXT "E-mail:",IDC_STATIC,17,20,69,8,0,WS_EX_RIGHT - EDITTEXT IDC_USERNAME,92,18,86,13,ES_AUTOHSCROLL - LTEXT "Password:",IDC_STATIC,17,36,69,8,0,WS_EX_RIGHT - EDITTEXT IDC_PASSWORD,92,34,86,13,ES_PASSWORD | ES_AUTOHSCROLL - GROUPBOX "Contacts",IDC_STATIC,7,56,178,28 - LTEXT "Default group:",IDC_STATIC,17,67,69,8,0,WS_EX_RIGHT - EDITTEXT IDC_GROUP,92,65,86,13,ES_AUTOHSCROLL -END - -IDD_EXTSEARCH DIALOGEX 0, 0, 114, 55 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU -EXSTYLE WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Nick:",IDC_STATIC,6,7,99,8 - EDITTEXT IDC_NICK,3,18,103,12,0,WS_EX_CLIENTEDGE -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_OPTIONS_ACCOUNT, DIALOG - BEGIN - END - - IDD_OPTIONS_ACCMGR, DIALOG - BEGIN - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_OPTIONS_ACCOUNT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.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_MAIN ICON "discord.ico"
+
+IDI_GROUPCHAT ICON "groupchat.ico"
+
+IDI_VOICE_CALL ICON "voiceCall.ico"
+
+IDI_VOICE_ENDED ICON "voiceEnded.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTIONS_ACCOUNT DIALOGEX 0, 0, 305, 144
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "User details",IDC_STATIC,7,7,291,46
+ LTEXT "E-mail:",IDC_STATIC,17,20,61,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_USERNAME,84,18,123,13,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,17,36,61,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_PASSWORD,84,34,123,13,ES_PASSWORD | ES_AUTOHSCROLL
+ GROUPBOX "Contacts",IDC_STATIC,7,54,291,86
+ LTEXT "Default group:",IDC_STATIC,17,73,61,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_GROUP,84,71,123,13,ES_AUTOHSCROLL
+ CONTROL "Enable guilds (servers)",IDC_USEGUILDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,90,275,10
+ CONTROL "Do not open chat windows on creation",IDC_HIDECHATS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,102,248,10
+ CONTROL "Use subgroups for server channels (requires restart)",IDC_USEGROUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,114,248,10
+ CONTROL "Delete messages in Miranda when they are deleted from server",IDC_DELETE_MSGS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,126,275,10
+END
+
+IDD_OPTIONS_ACCMGR DIALOGEX 0, 0, 200, 88
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "User details",IDC_STATIC,7,7,178,46
+ LTEXT "E-mail:",IDC_STATIC,17,20,69,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_USERNAME,92,18,86,13,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,17,36,69,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_PASSWORD,92,34,86,13,ES_PASSWORD | ES_AUTOHSCROLL
+ GROUPBOX "Contacts",IDC_STATIC,7,56,178,28
+ LTEXT "Default group:",IDC_STATIC,17,67,69,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_GROUP,92,65,86,13,ES_AUTOHSCROLL
+END
+
+IDD_EXTSEARCH DIALOGEX 0, 0, 114, 55
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_TRANSPARENT | WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Nick:",IDC_STATIC,6,7,99,8
+ EDITTEXT IDC_NICK,3,18,103,12,0,WS_EX_CLIENTEDGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPTIONS_ACCOUNT, DIALOG
+ BEGIN
+ END
+
+ IDD_OPTIONS_ACCMGR, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_OPTIONS_ACCOUNT AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Discord/res/version.rc b/protocols/Discord/res/version.rc index 5a5ddd63ed..bd3c22d943 100644 --- a/protocols/Discord/res/version.rc +++ b/protocols/Discord/res/version.rc @@ -1,9 +1,9 @@ -// Microsoft Visual C++ generated resource script. -// -#ifdef APSTUDIO_INVOKED -#error this file is not editable by Microsoft Visual C++ -#endif //APSTUDIO_INVOKED - -#include "..\src\version.h" - -#include "..\..\build\Version.rc" +// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/Discord/src/avatars.cpp b/protocols/Discord/src/avatars.cpp index aef0a76e48..fc49a7ec1a 100644 --- a/protocols/Discord/src/avatars.cpp +++ b/protocols/Discord/src/avatars.cpp @@ -1,205 +1,205 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -CMStringW CDiscordProto::GetAvatarFilename(MCONTACT hContact) -{ - CMStringW wszResult(FORMAT, L"%s\\%S", VARSW(L"%miranda_avatarcache%"), m_szModuleName); - CreateDirectoryTreeW(wszResult); - - wszResult.AppendChar('\\'); - - const wchar_t* szFileType = ProtoGetAvatarExtension(getByte(hContact, "AvatarType", PA_FORMAT_PNG)); - wszResult.AppendFormat(L"%lld%s", getId(hContact, DB_KEY_ID), szFileType); - return wszResult; -} - -INT_PTR CDiscordProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam) -{ - int res = 0; - - switch (wParam) { - case AF_MAXSIZE: - ((POINT*)lParam)->x = ((POINT*)lParam)->y = 128; - break; - - case AF_FORMATSUPPORTED: - res = lParam == PA_FORMAT_PNG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_JPEG; - break; - - case AF_ENABLED: - case AF_DONTNEEDDELAYS: - case AF_FETCHIFPROTONOTVISIBLE: - case AF_FETCHIFCONTACTOFFLINE: - return 1; - } - - return res; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::OnReceiveAvatar(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) -{ - PROTO_AVATAR_INFORMATION ai = { 0 }; - ai.format = PA_FORMAT_UNKNOWN; - ai.hContact = (UINT_PTR)pReq->pUserInfo; - - if (reply->resultCode != 200) { -LBL_Error: - ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai); - return; - } - - if (auto *pszHdr = Netlib_GetHeader(reply, "Content-Type")) - ai.format = ProtoGetAvatarFormatByMimeType(pszHdr); - - if (ai.format == PA_FORMAT_UNKNOWN) { - debugLogA("unknown avatar mime type"); - goto LBL_Error; - } - - setByte(ai.hContact, "AvatarType", ai.format); - mir_wstrncpy(ai.filename, GetAvatarFilename(ai.hContact), _countof(ai.filename)); - - FILE *out = _wfopen(ai.filename, L"wb"); - if (out == nullptr) { - debugLogA("cannot open avatar file %S for writing", ai.filename); - goto LBL_Error; - } - - fwrite(reply->pData, 1, reply->dataLength, out); - fclose(out); - - if (ai.hContact) - ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai); - else - ReportSelfAvatarChanged(); -} - -bool CDiscordProto::RetrieveAvatar(MCONTACT hContact) -{ - ptrA szAvatarHash(getStringA(hContact, DB_KEY_AVHASH)); - SnowFlake id = getId(hContact, DB_KEY_ID); - if (id == 0 || szAvatarHash == nullptr) - return false; - - CMStringA szUrl(FORMAT, "https://cdn.discordapp.com/avatars/%lld/%s.jpg", id, szAvatarHash.get()); - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveAvatar); - pReq->pUserInfo = (void*)hContact; - Push(pReq); - return true; -} - -INT_PTR CDiscordProto::GetAvatarInfo(WPARAM flags, LPARAM lParam) -{ - PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION *)lParam; - - CMStringW wszFileName(GetAvatarFilename(pai->hContact)); - if (!wszFileName.IsEmpty()) { - mir_wstrncpy(pai->filename, wszFileName, _countof(pai->filename)); - - bool bFileExist = _waccess(wszFileName, 0) == 0; - - // if we still need to load an avatar - if ((flags & GAIF_FORCE) || !bFileExist) { - if (RetrieveAvatar(pai->hContact)) - return GAIR_WAITFOR; - } - else if (bFileExist) - return GAIR_SUCCESS; - } - - return GAIR_NOAVATAR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::GetMyAvatar(WPARAM wParam, LPARAM lParam) -{ - if (!wParam || !lParam) - return -3; - - wchar_t* buf = (wchar_t*)wParam; - int size = (int)lParam; - - PROTO_AVATAR_INFORMATION ai = {}; - switch (GetAvatarInfo(0, (LPARAM)&ai)) { - case GAIR_SUCCESS: - wcsncpy_s(buf, size, ai.filename, _TRUNCATE); - return 0; - - case GAIR_WAITFOR: - return -1; - } - - return -2; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::SetMyAvatar(WPARAM, LPARAM lParam) -{ - CMStringW wszFileName(GetAvatarFilename(0)); - - const wchar_t *pwszFilename = (const wchar_t*)lParam; - if (pwszFilename == nullptr) { // remove my avatar file - delSetting(DB_KEY_AVHASH); - DeleteFile(wszFileName); - } - - CMStringA szPayload("data:"); - - const char *szMimeType = ProtoGetAvatarMimeType(ProtoGetAvatarFileFormat(pwszFilename)); - if (szMimeType == nullptr) { - debugLogA("invalid file format for avatar %S", pwszFilename); - return 1; - } - szPayload.AppendFormat("%s;base64,", szMimeType); - FILE *in = _wfopen(pwszFilename, L"rb"); - if (in == nullptr) { - debugLogA("cannot open avatar file %S for reading", pwszFilename); - return 2; - } - - int iFileLength = _filelength(_fileno(in)); - ptrA szFileContents((char*)mir_alloc(iFileLength)); - fread(szFileContents, 1, iFileLength, in); - fclose(in); - szPayload.Append(ptrA(mir_base64_encode(szFileContents.get(), iFileLength))); - - JSONNode root; root << CHAR_PARAM("avatar", szPayload); - Push(new AsyncHttpRequest(this, REQUEST_PATCH, "/users/@me", nullptr, &root)); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::CheckAvatarChange(MCONTACT hContact, const CMStringW &wszNewHash) -{ - if (wszNewHash.IsEmpty()) - return; - - ptrW wszOldAvatar(getWStringA(hContact, DB_KEY_AVHASH)); - - // if avatar's hash changed, we need to request a new one - if (mir_wstrcmp(wszNewHash, wszOldAvatar)) { - setWString(hContact, DB_KEY_AVHASH, wszNewHash); - RetrieveAvatar(hContact); - } -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+CMStringW CDiscordProto::GetAvatarFilename(MCONTACT hContact)
+{
+ CMStringW wszResult(FORMAT, L"%s\\%S", VARSW(L"%miranda_avatarcache%"), m_szModuleName);
+ CreateDirectoryTreeW(wszResult);
+
+ wszResult.AppendChar('\\');
+
+ const wchar_t* szFileType = ProtoGetAvatarExtension(getByte(hContact, "AvatarType", PA_FORMAT_PNG));
+ wszResult.AppendFormat(L"%lld%s", getId(hContact, DB_KEY_ID), szFileType);
+ return wszResult;
+}
+
+INT_PTR CDiscordProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ int res = 0;
+
+ switch (wParam) {
+ case AF_MAXSIZE:
+ ((POINT*)lParam)->x = ((POINT*)lParam)->y = 128;
+ break;
+
+ case AF_FORMATSUPPORTED:
+ res = lParam == PA_FORMAT_PNG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_JPEG;
+ break;
+
+ case AF_ENABLED:
+ case AF_DONTNEEDDELAYS:
+ case AF_FETCHIFPROTONOTVISIBLE:
+ case AF_FETCHIFCONTACTOFFLINE:
+ return 1;
+ }
+
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnReceiveAvatar(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq)
+{
+ PROTO_AVATAR_INFORMATION ai = { 0 };
+ ai.format = PA_FORMAT_UNKNOWN;
+ ai.hContact = (UINT_PTR)pReq->pUserInfo;
+
+ if (reply->resultCode != 200) {
+LBL_Error:
+ ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai);
+ return;
+ }
+
+ if (auto *pszHdr = Netlib_GetHeader(reply, "Content-Type"))
+ ai.format = ProtoGetAvatarFormatByMimeType(pszHdr);
+
+ if (ai.format == PA_FORMAT_UNKNOWN) {
+ debugLogA("unknown avatar mime type");
+ goto LBL_Error;
+ }
+
+ setByte(ai.hContact, "AvatarType", ai.format);
+ mir_wstrncpy(ai.filename, GetAvatarFilename(ai.hContact), _countof(ai.filename));
+
+ FILE *out = _wfopen(ai.filename, L"wb");
+ if (out == nullptr) {
+ debugLogA("cannot open avatar file %S for writing", ai.filename);
+ goto LBL_Error;
+ }
+
+ fwrite(reply->pData, 1, reply->dataLength, out);
+ fclose(out);
+
+ if (ai.hContact)
+ ProtoBroadcastAck(ai.hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai);
+ else
+ ReportSelfAvatarChanged();
+}
+
+bool CDiscordProto::RetrieveAvatar(MCONTACT hContact)
+{
+ ptrA szAvatarHash(getStringA(hContact, DB_KEY_AVHASH));
+ SnowFlake id = getId(hContact, DB_KEY_ID);
+ if (id == 0 || szAvatarHash == nullptr)
+ return false;
+
+ CMStringA szUrl(FORMAT, "https://cdn.discordapp.com/avatars/%lld/%s.jpg", id, szAvatarHash.get());
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveAvatar);
+ pReq->pUserInfo = (void*)hContact;
+ Push(pReq);
+ return true;
+}
+
+INT_PTR CDiscordProto::GetAvatarInfo(WPARAM flags, LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION *)lParam;
+
+ CMStringW wszFileName(GetAvatarFilename(pai->hContact));
+ if (!wszFileName.IsEmpty()) {
+ mir_wstrncpy(pai->filename, wszFileName, _countof(pai->filename));
+
+ bool bFileExist = _waccess(wszFileName, 0) == 0;
+
+ // if we still need to load an avatar
+ if ((flags & GAIF_FORCE) || !bFileExist) {
+ if (RetrieveAvatar(pai->hContact))
+ return GAIR_WAITFOR;
+ }
+ else if (bFileExist)
+ return GAIR_SUCCESS;
+ }
+
+ return GAIR_NOAVATAR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::GetMyAvatar(WPARAM wParam, LPARAM lParam)
+{
+ if (!wParam || !lParam)
+ return -3;
+
+ wchar_t* buf = (wchar_t*)wParam;
+ int size = (int)lParam;
+
+ PROTO_AVATAR_INFORMATION ai = {};
+ switch (GetAvatarInfo(0, (LPARAM)&ai)) {
+ case GAIR_SUCCESS:
+ wcsncpy_s(buf, size, ai.filename, _TRUNCATE);
+ return 0;
+
+ case GAIR_WAITFOR:
+ return -1;
+ }
+
+ return -2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::SetMyAvatar(WPARAM, LPARAM lParam)
+{
+ CMStringW wszFileName(GetAvatarFilename(0));
+
+ const wchar_t *pwszFilename = (const wchar_t*)lParam;
+ if (pwszFilename == nullptr) { // remove my avatar file
+ delSetting(DB_KEY_AVHASH);
+ DeleteFile(wszFileName);
+ }
+
+ CMStringA szPayload("data:");
+
+ const char *szMimeType = ProtoGetAvatarMimeType(ProtoGetAvatarFileFormat(pwszFilename));
+ if (szMimeType == nullptr) {
+ debugLogA("invalid file format for avatar %S", pwszFilename);
+ return 1;
+ }
+ szPayload.AppendFormat("%s;base64,", szMimeType);
+ FILE *in = _wfopen(pwszFilename, L"rb");
+ if (in == nullptr) {
+ debugLogA("cannot open avatar file %S for reading", pwszFilename);
+ return 2;
+ }
+
+ int iFileLength = _filelength(_fileno(in));
+ ptrA szFileContents((char*)mir_alloc(iFileLength));
+ fread(szFileContents, 1, iFileLength, in);
+ fclose(in);
+ szPayload.Append(ptrA(mir_base64_encode(szFileContents.get(), iFileLength)));
+
+ JSONNode root; root << CHAR_PARAM("avatar", szPayload);
+ Push(new AsyncHttpRequest(this, REQUEST_PATCH, "/users/@me", nullptr, &root));
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::CheckAvatarChange(MCONTACT hContact, const CMStringW &wszNewHash)
+{
+ if (wszNewHash.IsEmpty())
+ return;
+
+ ptrW wszOldAvatar(getWStringA(hContact, DB_KEY_AVHASH));
+
+ // if avatar's hash changed, we need to request a new one
+ if (mir_wstrcmp(wszNewHash, wszOldAvatar)) {
+ setWString(hContact, DB_KEY_AVHASH, wszNewHash);
+ RetrieveAvatar(hContact);
+ }
+}
diff --git a/protocols/Discord/src/connection.cpp b/protocols/Discord/src/connection.cpp index a85d5738a0..d98d6e4ec8 100644 --- a/protocols/Discord/src/connection.cpp +++ b/protocols/Discord/src/connection.cpp @@ -1,123 +1,123 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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 CDiscordProto::ExecuteRequest(AsyncHttpRequest *pReq) -{ - CMStringA str; - - pReq->szUrl = pReq->m_szUrl.GetBuffer(); - if (!pReq->m_szParam.IsEmpty()) { - if (pReq->requestType == REQUEST_GET) { - str.Format("%s?%s", pReq->m_szUrl.c_str(), pReq->m_szParam.c_str()); - pReq->szUrl = str.GetBuffer(); - } - else { - pReq->pData = mir_strdup(pReq->m_szParam); - pReq->dataLength = pReq->m_szParam.GetLength(); - } - } - - if (pReq->m_bMainSite) { - pReq->flags |= NLHRF_PERSISTENT; - pReq->nlc = m_hAPIConnection; - pReq->AddHeader("Cookie", m_szCookie); - } - - bool bRetryable = pReq->nlc != nullptr; - debugLogA("Executing request #%d:\n%s", pReq->m_iReqNum, pReq->szUrl); - -LBL_Retry: - NLHR_PTR reply(Netlib_HttpTransaction(m_hNetlibUser, pReq)); - if (reply == nullptr) { - debugLogA("Request %d failed", pReq->m_iReqNum); - - if (pReq->m_bMainSite) { - if (IsStatusConnecting(m_iStatus)) - ConnectionFailed(LOGINERR_NONETWORK); - m_hAPIConnection = nullptr; - } - - if (bRetryable) { - debugLogA("Attempt to retry request #%d", pReq->m_iReqNum); - pReq->nlc = nullptr; - bRetryable = false; - goto LBL_Retry; - } - } - else { - if (pReq->m_pFunc != nullptr) - (this->*(pReq->m_pFunc))(reply, pReq); - - if (pReq->m_bMainSite) - m_hAPIConnection = reply->nlc; - } - delete pReq; -} - -void CDiscordProto::OnLoggedIn() -{ - debugLogA("CDiscordProto::OnLoggedIn"); - m_bOnline = true; - SetServerStatus(m_iDesiredStatus); -} - -void CDiscordProto::OnLoggedOut() -{ - debugLogA("CDiscordProto::OnLoggedOut"); - m_bOnline = false; - m_bTerminated = true; - m_iGatewaySeq = 0; - m_szTempToken = nullptr; - m_szCookie.Empty(); - m_szWSCookie.Empty(); - - m_impl.m_heartBeat.StopSafe(); - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - - setAllContactStatuses(ID_STATUS_OFFLINE, false); -} - -void CDiscordProto::ShutdownSession() -{ - if (m_bTerminated) - return; - - debugLogA("CDiscordProto::ShutdownSession"); - - // shutdown all resources - if (m_hWorkerThread) - SetEvent(m_evRequestsQueue); - if (m_hGatewayConnection) - Netlib_Shutdown(m_hGatewayConnection); - if (m_hAPIConnection) - Netlib_Shutdown(m_hAPIConnection); - - OnLoggedOut(); -} - -void CDiscordProto::ConnectionFailed(int iReason) -{ - debugLogA("CDiscordProto::ConnectionFailed -> reason %d", iReason); - delSetting("AccessToken"); - - ProtoBroadcastAck(0, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, iReason); - ShutdownSession(); -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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 CDiscordProto::ExecuteRequest(AsyncHttpRequest *pReq)
+{
+ CMStringA str;
+
+ pReq->szUrl = pReq->m_szUrl.GetBuffer();
+ if (!pReq->m_szParam.IsEmpty()) {
+ if (pReq->requestType == REQUEST_GET) {
+ str.Format("%s?%s", pReq->m_szUrl.c_str(), pReq->m_szParam.c_str());
+ pReq->szUrl = str.GetBuffer();
+ }
+ else {
+ pReq->pData = mir_strdup(pReq->m_szParam);
+ pReq->dataLength = pReq->m_szParam.GetLength();
+ }
+ }
+
+ if (pReq->m_bMainSite) {
+ pReq->flags |= NLHRF_PERSISTENT;
+ pReq->nlc = m_hAPIConnection;
+ pReq->AddHeader("Cookie", m_szCookie);
+ }
+
+ bool bRetryable = pReq->nlc != nullptr;
+ debugLogA("Executing request #%d:\n%s", pReq->m_iReqNum, pReq->szUrl);
+
+LBL_Retry:
+ NLHR_PTR reply(Netlib_HttpTransaction(m_hNetlibUser, pReq));
+ if (reply == nullptr) {
+ debugLogA("Request %d failed", pReq->m_iReqNum);
+
+ if (pReq->m_bMainSite) {
+ if (IsStatusConnecting(m_iStatus))
+ ConnectionFailed(LOGINERR_NONETWORK);
+ m_hAPIConnection = nullptr;
+ }
+
+ if (bRetryable) {
+ debugLogA("Attempt to retry request #%d", pReq->m_iReqNum);
+ pReq->nlc = nullptr;
+ bRetryable = false;
+ goto LBL_Retry;
+ }
+ }
+ else {
+ if (pReq->m_pFunc != nullptr)
+ (this->*(pReq->m_pFunc))(reply, pReq);
+
+ if (pReq->m_bMainSite)
+ m_hAPIConnection = reply->nlc;
+ }
+ delete pReq;
+}
+
+void CDiscordProto::OnLoggedIn()
+{
+ debugLogA("CDiscordProto::OnLoggedIn");
+ m_bOnline = true;
+ SetServerStatus(m_iDesiredStatus);
+}
+
+void CDiscordProto::OnLoggedOut()
+{
+ debugLogA("CDiscordProto::OnLoggedOut");
+ m_bOnline = false;
+ m_bTerminated = true;
+ m_iGatewaySeq = 0;
+ m_szTempToken = nullptr;
+ m_szCookie.Empty();
+ m_szWSCookie.Empty();
+
+ m_impl.m_heartBeat.StopSafe();
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE);
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+
+ setAllContactStatuses(ID_STATUS_OFFLINE, false);
+}
+
+void CDiscordProto::ShutdownSession()
+{
+ if (m_bTerminated)
+ return;
+
+ debugLogA("CDiscordProto::ShutdownSession");
+
+ // shutdown all resources
+ if (m_hWorkerThread)
+ SetEvent(m_evRequestsQueue);
+ if (m_hGatewayConnection)
+ Netlib_Shutdown(m_hGatewayConnection);
+ if (m_hAPIConnection)
+ Netlib_Shutdown(m_hAPIConnection);
+
+ OnLoggedOut();
+}
+
+void CDiscordProto::ConnectionFailed(int iReason)
+{
+ debugLogA("CDiscordProto::ConnectionFailed -> reason %d", iReason);
+ delSetting("AccessToken");
+
+ ProtoBroadcastAck(0, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr, iReason);
+ ShutdownSession();
+}
diff --git a/protocols/Discord/src/dispatch.cpp b/protocols/Discord/src/dispatch.cpp index 5d79feb9fe..7554fa669c 100644 --- a/protocols/Discord/src/dispatch.cpp +++ b/protocols/Discord/src/dispatch.cpp @@ -1,592 +1,592 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -#pragma pack(4) - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CDiscordCommand -{ - const wchar_t *szCommandId; - GatewayHandlerFunc pFunc; -} -static handlers[] = // these structures must me sorted alphabetically -{ - { L"CALL_CREATE", &CDiscordProto::OnCommandCallCreated }, - { L"CALL_DELETE", &CDiscordProto::OnCommandCallDeleted }, - { L"CALL_UPDATE", &CDiscordProto::OnCommandCallUpdated }, - - { L"CHANNEL_CREATE", &CDiscordProto::OnCommandChannelCreated }, - { L"CHANNEL_DELETE", &CDiscordProto::OnCommandChannelDeleted }, - { L"CHANNEL_UPDATE", &CDiscordProto::OnCommandChannelUpdated }, - - { L"GUILD_CREATE", &CDiscordProto::OnCommandGuildCreated }, - { L"GUILD_DELETE", &CDiscordProto::OnCommandGuildDeleted }, - { L"GUILD_MEMBER_ADD", &CDiscordProto::OnCommandGuildMemberAdded }, - { L"GUILD_MEMBER_LIST_UPDATE", &CDiscordProto::OnCommandGuildMemberListUpdate }, - { L"GUILD_MEMBER_REMOVE", &CDiscordProto::OnCommandGuildMemberRemoved }, - { L"GUILD_MEMBER_UPDATE", &CDiscordProto::OnCommandGuildMemberUpdated }, - { L"GUILD_ROLE_CREATE", &CDiscordProto::OnCommandRoleCreated }, - { L"GUILD_ROLE_DELETE", &CDiscordProto::OnCommandRoleDeleted }, - { L"GUILD_ROLE_UPDATE", &CDiscordProto::OnCommandRoleCreated }, - - { L"MESSAGE_ACK", &CDiscordProto::OnCommandMessageAck }, - { L"MESSAGE_CREATE", &CDiscordProto::OnCommandMessageCreate }, - { L"MESSAGE_DELETE", &CDiscordProto::OnCommandMessageDelete }, - { L"MESSAGE_UPDATE", &CDiscordProto::OnCommandMessageUpdate }, - - { L"PRESENCE_UPDATE", &CDiscordProto::OnCommandPresence }, - - { L"READY", &CDiscordProto::OnCommandReady }, - - { L"RELATIONSHIP_ADD", &CDiscordProto::OnCommandFriendAdded }, - { L"RELATIONSHIP_REMOVE", &CDiscordProto::OnCommandFriendRemoved }, - - { L"TYPING_START", &CDiscordProto::OnCommandTyping }, - - { L"USER_SETTINGS_UPDATE", &CDiscordProto::OnCommandUserSettingsUpdate }, - { L"USER_UPDATE", &CDiscordProto::OnCommandUserUpdate }, -}; - -static int __cdecl pSearchFunc(const void *p1, const void *p2) -{ - return wcscmp(((CDiscordCommand*)p1)->szCommandId, ((CDiscordCommand*)p2)->szCommandId); -} - -GatewayHandlerFunc CDiscordProto::GetHandler(const wchar_t *pwszCommand) -{ - CDiscordCommand tmp = { pwszCommand, nullptr }; - CDiscordCommand *p = (CDiscordCommand*)bsearch(&tmp, handlers, _countof(handlers), sizeof(handlers[0]), pSearchFunc); - return (p != nullptr) ? p->pFunc : nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// channel operations - -void CDiscordProto::OnCommandChannelCreated(const JSONNode &pRoot) -{ - SnowFlake guildId = ::getId(pRoot["guild_id"]); - if (guildId == 0) - PreparePrivateChannel(pRoot); - else { - // group channel for a guild - CDiscordGuild *pGuild = FindGuild(guildId); - if (pGuild && m_bUseGroupchats) { - CDiscordUser *pUser = ProcessGuildChannel(pGuild, pRoot); - if (pUser) - CreateChat(pGuild, pUser); - } - } -} - -void CDiscordProto::OnCommandChannelDeleted(const JSONNode &pRoot) -{ - CDiscordUser *pUser = FindUserByChannel(::getId(pRoot["id"])); - if (pUser == nullptr) - return; - - SnowFlake guildId = ::getId(pRoot["guild_id"]); - if (guildId == 0) { - pUser->channelId = pUser->lastMsgId = 0; - delSetting(pUser->hContact, DB_KEY_CHANNELID); - } - else { - CDiscordGuild *pGuild = FindGuild(guildId); - if (pGuild != nullptr) - Chat_Terminate(m_szModuleName, pUser->wszUsername, true); - } -} - -void CDiscordProto::OnCommandChannelUpdated(const JSONNode &pRoot) -{ - CDiscordUser *pUser = FindUserByChannel(::getId(pRoot["id"])); - if (pUser == nullptr) - return; - - pUser->lastMsgId = ::getId(pRoot["last_message_id"]); - - SnowFlake guildId = ::getId(pRoot["guild_id"]); - if (guildId != 0) { - CDiscordGuild *pGuild = FindGuild(guildId); - if (pGuild == nullptr) - return; - - CMStringW wszName = pRoot["name"].as_mstring(); - if (!wszName.IsEmpty()) { - CMStringW wszNewName = pGuild->wszName + L"#" + wszName; - Chat_ChangeSessionName(m_szModuleName, pUser->wszUsername, wszNewName); - } - - CMStringW wszTopic = pRoot["topic"].as_mstring(); - Chat_SetStatusbarText(m_szModuleName, pUser->wszUsername, wszTopic); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC }; - gce.pszID.w = pUser->wszUsername; - gce.pszText.w = wszTopic; - gce.time = time(0); - Chat_Event(&gce); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// reading a new message - -void CDiscordProto::OnCommandFriendAdded(const JSONNode &pRoot) -{ - CDiscordUser *pUser = PrepareUser(pRoot["user"]); - pUser->bIsPrivate = true; - ProcessType(pUser, pRoot); -} - -void CDiscordProto::OnCommandFriendRemoved(const JSONNode &pRoot) -{ - SnowFlake id = ::getId(pRoot["id"]); - CDiscordUser *pUser = FindUser(id); - if (pUser != nullptr) { - if (pUser->hContact) - if (pUser->bIsPrivate) - db_delete_contact(pUser->hContact); - - arUsers.remove(pUser); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// guild synchronization - -void CDiscordProto::OnCommandGuildCreated(const JSONNode &pRoot) -{ - if (m_bUseGroupchats) - ProcessGuild(pRoot); -} - -void CDiscordProto::OnCommandGuildDeleted(const JSONNode &pRoot) -{ - CDiscordGuild *pGuild = FindGuild(::getId(pRoot["id"])); - if (pGuild == nullptr) - return; - - for (auto &it : arUsers.rev_iter()) - if (it->pGuild == pGuild) { - Chat_Terminate(m_szModuleName, it->wszUsername, true); - arUsers.removeItem(&it); - } - - Chat_Terminate(m_szModuleName, pRoot["name"].as_mstring(), true); - - arGuilds.remove(pGuild); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// guild members - -void CDiscordProto::OnCommandGuildMemberAdded(const JSONNode&) -{ -} - -void CDiscordProto::OnCommandGuildMemberListUpdate(const JSONNode &pRoot) -{ - auto *pGuild = FindGuild(::getId(pRoot["guild_id"])); - if (pGuild == nullptr) - return; - - int iStatus = 0; - - for (auto &ops: pRoot["ops"]) { - for (auto &it : ops["items"]) { - auto &item = it.at((size_t)0); - if (!mir_strcmp(item .name(), "group")) { - iStatus = item ["id"].as_string() == "online" ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE; - continue; - } - - if (!mir_strcmp(item .name(), "member")) { - bool bNew = false; - auto *pm = ProcessGuildUser(pGuild, item, &bNew); - pm->iStatus = iStatus; - - if (bNew) - AddGuildUser(pGuild, *pm); - else if (iStatus) { - CMStringW wszUserId(FORMAT, L"%lld", pm->userId); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_SETCONTACTSTATUS }; - gce.time = time(0); - gce.pszUID.w = wszUserId; - - for (auto &cc : pGuild->arChannels) { - if (!cc->bIsGroup) - continue; - - gce.pszID.w = cc->wszChannelName; - gce.dwItemData = iStatus; - Chat_Event(&gce); - } - } - } - } - } - - pGuild->bSynced = true; -} - -void CDiscordProto::OnCommandGuildMemberRemoved(const JSONNode &pRoot) -{ - CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"])); - if (pGuild == nullptr) - return; - - CMStringW wszUserId = pRoot["user"]["id"].as_mstring(); - - for (auto &pUser : arUsers) { - if (pUser->pGuild != pGuild) - continue; - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_PART }; - gce.pszUID.w = pUser->wszUsername; - gce.time = time(0); - gce.pszUID.w = wszUserId; - Chat_Event(&gce); - } -} - -void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot) -{ - CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"])); - if (pGuild == nullptr) - return; - - CMStringW wszUserId = pRoot["user"]["id"].as_mstring(); - CDiscordGuildMember *gm = pGuild->FindUser(_wtoi64(wszUserId)); - if (gm == nullptr) - return; - - gm->wszDiscordId = pRoot["user"]["username"].as_mstring() + L"#" + pRoot["user"]["discriminator"].as_mstring(); - gm->wszNick = pRoot["nick"].as_mstring(); - if (gm->wszNick.IsEmpty()) - gm->wszNick = pRoot["user"]["username"].as_mstring(); - - for (auto &it : arUsers) { - if (it->pGuild != pGuild) - continue; - - CMStringW wszOldNick; - SESSION_INFO *si = g_chatApi.SM_FindSession(it->wszUsername, m_szModuleName); - if (si != nullptr) { - USERINFO *ui = g_chatApi.UM_FindUser(si, wszUserId); - if (ui != nullptr) - wszOldNick = ui->pszNick; - } - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_NICK }; - gce.pszID.w = it->wszUsername; - gce.time = time(0); - gce.pszUID.w = wszUserId; - gce.pszNick.w = wszOldNick; - gce.pszText.w = gm->wszNick; - Chat_Event(&gce); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// roles - -void CDiscordProto::OnCommandRoleCreated(const JSONNode &pRoot) -{ - CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"])); - if (pGuild != nullptr) - ProcessRole(pGuild, pRoot["role"]); -} - -void CDiscordProto::OnCommandRoleDeleted(const JSONNode &pRoot) -{ - CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"])); - if (pGuild == nullptr) - return; - - SnowFlake id = ::getId(pRoot["role_id"]); - CDiscordRole *pRole = pGuild->arRoles.find((CDiscordRole*)&id); - if (pRole == nullptr) - return; - - int iOldPosition = pRole->position; - pGuild->arRoles.remove(pRole); - - for (auto &it : pGuild->arRoles) - if (it->position > iOldPosition) - it->position--; - - for (auto &it : arUsers) { - if (it->pGuild != pGuild) - continue; - - SESSION_INFO *si = g_chatApi.SM_FindSession(it->wszUsername, m_szModuleName); - if (si != nullptr) { - g_chatApi.TM_RemoveAll(&si->pStatuses); - BuildStatusList(pGuild, si); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// reading a new message - -void CDiscordProto::OnCommandMessageCreate(const JSONNode &pRoot) -{ - OnCommandMessage(pRoot, true); -} - -void CDiscordProto::OnCommandMessageUpdate(const JSONNode &pRoot) -{ - OnCommandMessage(pRoot, false); -} - -void CDiscordProto::OnCommandMessage(const JSONNode &pRoot, bool bIsNew) -{ - CMStringW wszMessageId = pRoot["id"].as_mstring(); - CMStringW wszUserId = pRoot["author"]["id"].as_mstring(); - SnowFlake userId = _wtoi64(wszUserId); - SnowFlake msgId = _wtoi64(wszMessageId); - - // try to find a sender by his channel - SnowFlake channelId = ::getId(pRoot["channel_id"]); - CDiscordUser *pUser = FindUserByChannel(channelId); - if (pUser == nullptr) { - debugLogA("skipping message with unknown channel id=%lld", channelId); - return; - } - - char szMsgId[100]; - _i64toa_s(msgId, szMsgId, _countof(szMsgId), 10); - - COwnMessage ownMsg(::getId(pRoot["nonce"]), 0); - COwnMessage *p = arOwnMessages.find(&ownMsg); - if (p != nullptr) { // own message? skip it - ProtoBroadcastAck(pUser->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)p->reqId, (LPARAM)szMsgId); - debugLogA("skipping own message with nonce=%lld, id=%lld", ownMsg.nonce, msgId); - } - else { - CMStringW wszText = PrepareMessageText(pRoot); - if (wszText.IsEmpty()) - return; - - // old message? try to restore it from database - bool bOurMessage = userId == m_ownId; - if (!bIsNew) { - MEVENT hOldEvent = db_event_getById(m_szModuleName, szMsgId); - if (hOldEvent) { - DB::EventInfo dbei; - dbei.cbBlob = -1; - if (!db_event_get(hOldEvent, &dbei)) { - ptrW wszOldText(DbEvent_GetTextW(&dbei, CP_UTF8)); - if (wszOldText) - wszText.Insert(0, wszOldText); - if (dbei.flags & DBEF_SENT) - bOurMessage = true; - } - } - } - - const JSONNode &edited = pRoot["edited_timestamp"]; - if (!edited.isnull()) - wszText.AppendFormat(L" (%s %s)", TranslateT("edited at"), edited.as_mstring().c_str()); - - if (pUser->bIsPrivate && !pUser->bIsGroup) { - // if a message has myself as an author, add some flags - PROTORECVEVENT recv = {}; - if (bOurMessage) - recv.flags = PREF_CREATEREAD | PREF_SENT; - - debugLogA("store a message from private user %lld, channel id %lld", pUser->id, pUser->channelId); - ptrA buf(mir_utf8encodeW(wszText)); - - recv.timestamp = (uint32_t)StringToDate(pRoot["timestamp"].as_mstring()); - recv.szMessage = buf; - recv.szMsgId = szMsgId; - ProtoChainRecvMsg(pUser->hContact, &recv); - } - else { - debugLogA("store a message into the group channel id %lld", channelId); - - SESSION_INFO *si = g_chatApi.SM_FindSession(pUser->wszUsername, m_szModuleName); - if (si == nullptr) { - debugLogA("message to unknown channel %lld ignored", channelId); - return; - } - - ProcessChatUser(pUser, wszUserId, pRoot); - - ParseSpecialChars(si, wszText); - wszText.Replace(L"%", L"%%"); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_MESSAGE }; - gce.pszID.w = pUser->wszUsername; - gce.dwFlags = GCEF_ADDTOLOG; - gce.pszUID.w = wszUserId; - gce.pszText.w = wszText; - gce.time = (uint32_t)StringToDate(pRoot["timestamp"].as_mstring()); - gce.bIsMe = bOurMessage; - Chat_Event(&gce); - - debugLogW(L"New channel %s message from %s: %s", si->ptszID, gce.pszUID.w, gce.pszText.w); - } - } - - pUser->lastMsgId = msgId; - - SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database - if (lastId < msgId) - setId(pUser->hContact, DB_KEY_LASTMSGID, msgId); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// someone changed its status - -void CDiscordProto::OnCommandMessageAck(const JSONNode &pRoot) -{ - CDiscordUser *pUser = FindUserByChannel(pRoot["channel_id"]); - if (pUser != nullptr) - pUser->lastMsgId = ::getId(pRoot["message_id"]); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// message deleted - -void CDiscordProto::OnCommandMessageDelete(const JSONNode &pRoot) -{ - if (!m_bSyncDeleteMsgs) - return; - - CMStringA msgid(pRoot["id"].as_mstring()); - if (!msgid.IsEmpty()) { - MEVENT hEvent = db_event_getById(m_szModuleName, msgid); - if (hEvent) - db_event_delete(hEvent); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// someone changed its status - -void CDiscordProto::OnCommandPresence(const JSONNode &pRoot) -{ - auto *pGuild = FindGuild(::getId(pRoot["user"]["guild_id"])); - if (pGuild == nullptr) - ProcessPresence(pRoot); - // else - // pGuild->ProcessPresence(pRoot); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// gateway session start - -void CDiscordProto::OnCommandReady(const JSONNode &pRoot) -{ - OnLoggedIn(); - - GatewaySendHeartbeat(); - m_impl.m_heartBeat.StartSafe(m_iHartbeatInterval); - - m_szGatewaySessionId = pRoot["session_id"].as_mstring(); - - if (m_bUseGroupchats) - for (auto &it : pRoot["guilds"]) - ProcessGuild(it); - - for (auto &it : pRoot["relationships"]) { - CDiscordUser *pUser = PrepareUser(it["user"]); - ProcessType(pUser, it); - } - - for (auto &it : pRoot["presences"]) - ProcessPresence(it); - - for (auto &it : pRoot["private_channels"]) - PreparePrivateChannel(it); - - for (auto &it : pRoot["read_state"]) { - CDiscordUser *pUser = FindUserByChannel(::getId(it["id"])); - if (pUser != nullptr) - pUser->lastReadId = ::getId(it["last_message_id"]); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// UTN support - -void CDiscordProto::OnCommandTyping(const JSONNode &pRoot) -{ - SnowFlake channelId = ::getId(pRoot["channel_id"]); - debugLogA("user typing notification: channelid=%lld", channelId); - - CDiscordUser *pChannel = FindUserByChannel(channelId); - if (pChannel == nullptr) { - debugLogA("channel with id=%lld is not found", channelId); - return; - } - - // both private groupchats & guild channels are chat rooms for Miranda - if (pChannel->pGuild) { - debugLogA("user is typing in a group channel"); - - CMStringW wszUerId = pRoot["user_id"].as_mstring(); - ProcessGuildUser(pChannel->pGuild, pRoot); // never returns null - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TYPING }; - gce.pszID.w = pChannel->wszUsername; - gce.pszUID.w = wszUerId; - gce.dwItemData = 1; - gce.time = time(0); - Chat_Event(&gce); - } - else { - debugLogA("user is typing in his private channel"); - CallService(MS_PROTO_CONTACTISTYPING, pChannel->hContact, 20); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// User info update - -void CDiscordProto::OnCommandUserUpdate(const JSONNode &pRoot) -{ - SnowFlake id = ::getId(pRoot["id"]); - - MCONTACT hContact; - if (id != m_ownId) { - CDiscordUser *pUser = FindUser(id); - if (pUser == nullptr) - return; - - hContact = pUser->hContact; - } - else hContact = 0; - - // force rereading avatar - CheckAvatarChange(hContact, pRoot["avatar"].as_mstring()); -} - -void CDiscordProto::OnCommandUserSettingsUpdate(const JSONNode &pRoot) -{ - int iStatus = StrToStatus(pRoot["status"].as_mstring()); - if (iStatus != 0) { - int iOldStatus = m_iStatus; m_iStatus = iStatus; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); - } -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+#pragma pack(4)
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CDiscordCommand
+{
+ const wchar_t *szCommandId;
+ GatewayHandlerFunc pFunc;
+}
+static handlers[] = // these structures must me sorted alphabetically
+{
+ { L"CALL_CREATE", &CDiscordProto::OnCommandCallCreated },
+ { L"CALL_DELETE", &CDiscordProto::OnCommandCallDeleted },
+ { L"CALL_UPDATE", &CDiscordProto::OnCommandCallUpdated },
+
+ { L"CHANNEL_CREATE", &CDiscordProto::OnCommandChannelCreated },
+ { L"CHANNEL_DELETE", &CDiscordProto::OnCommandChannelDeleted },
+ { L"CHANNEL_UPDATE", &CDiscordProto::OnCommandChannelUpdated },
+
+ { L"GUILD_CREATE", &CDiscordProto::OnCommandGuildCreated },
+ { L"GUILD_DELETE", &CDiscordProto::OnCommandGuildDeleted },
+ { L"GUILD_MEMBER_ADD", &CDiscordProto::OnCommandGuildMemberAdded },
+ { L"GUILD_MEMBER_LIST_UPDATE", &CDiscordProto::OnCommandGuildMemberListUpdate },
+ { L"GUILD_MEMBER_REMOVE", &CDiscordProto::OnCommandGuildMemberRemoved },
+ { L"GUILD_MEMBER_UPDATE", &CDiscordProto::OnCommandGuildMemberUpdated },
+ { L"GUILD_ROLE_CREATE", &CDiscordProto::OnCommandRoleCreated },
+ { L"GUILD_ROLE_DELETE", &CDiscordProto::OnCommandRoleDeleted },
+ { L"GUILD_ROLE_UPDATE", &CDiscordProto::OnCommandRoleCreated },
+
+ { L"MESSAGE_ACK", &CDiscordProto::OnCommandMessageAck },
+ { L"MESSAGE_CREATE", &CDiscordProto::OnCommandMessageCreate },
+ { L"MESSAGE_DELETE", &CDiscordProto::OnCommandMessageDelete },
+ { L"MESSAGE_UPDATE", &CDiscordProto::OnCommandMessageUpdate },
+
+ { L"PRESENCE_UPDATE", &CDiscordProto::OnCommandPresence },
+
+ { L"READY", &CDiscordProto::OnCommandReady },
+
+ { L"RELATIONSHIP_ADD", &CDiscordProto::OnCommandFriendAdded },
+ { L"RELATIONSHIP_REMOVE", &CDiscordProto::OnCommandFriendRemoved },
+
+ { L"TYPING_START", &CDiscordProto::OnCommandTyping },
+
+ { L"USER_SETTINGS_UPDATE", &CDiscordProto::OnCommandUserSettingsUpdate },
+ { L"USER_UPDATE", &CDiscordProto::OnCommandUserUpdate },
+};
+
+static int __cdecl pSearchFunc(const void *p1, const void *p2)
+{
+ return wcscmp(((CDiscordCommand*)p1)->szCommandId, ((CDiscordCommand*)p2)->szCommandId);
+}
+
+GatewayHandlerFunc CDiscordProto::GetHandler(const wchar_t *pwszCommand)
+{
+ CDiscordCommand tmp = { pwszCommand, nullptr };
+ CDiscordCommand *p = (CDiscordCommand*)bsearch(&tmp, handlers, _countof(handlers), sizeof(handlers[0]), pSearchFunc);
+ return (p != nullptr) ? p->pFunc : nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// channel operations
+
+void CDiscordProto::OnCommandChannelCreated(const JSONNode &pRoot)
+{
+ SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ if (guildId == 0)
+ PreparePrivateChannel(pRoot);
+ else {
+ // group channel for a guild
+ CDiscordGuild *pGuild = FindGuild(guildId);
+ if (pGuild && m_bUseGroupchats) {
+ CDiscordUser *pUser = ProcessGuildChannel(pGuild, pRoot);
+ if (pUser)
+ CreateChat(pGuild, pUser);
+ }
+ }
+}
+
+void CDiscordProto::OnCommandChannelDeleted(const JSONNode &pRoot)
+{
+ CDiscordUser *pUser = FindUserByChannel(::getId(pRoot["id"]));
+ if (pUser == nullptr)
+ return;
+
+ SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ if (guildId == 0) {
+ pUser->channelId = pUser->lastMsgId = 0;
+ delSetting(pUser->hContact, DB_KEY_CHANNELID);
+ }
+ else {
+ CDiscordGuild *pGuild = FindGuild(guildId);
+ if (pGuild != nullptr)
+ Chat_Terminate(m_szModuleName, pUser->wszUsername, true);
+ }
+}
+
+void CDiscordProto::OnCommandChannelUpdated(const JSONNode &pRoot)
+{
+ CDiscordUser *pUser = FindUserByChannel(::getId(pRoot["id"]));
+ if (pUser == nullptr)
+ return;
+
+ pUser->lastMsgId = ::getId(pRoot["last_message_id"]);
+
+ SnowFlake guildId = ::getId(pRoot["guild_id"]);
+ if (guildId != 0) {
+ CDiscordGuild *pGuild = FindGuild(guildId);
+ if (pGuild == nullptr)
+ return;
+
+ CMStringW wszName = pRoot["name"].as_mstring();
+ if (!wszName.IsEmpty()) {
+ CMStringW wszNewName = pGuild->wszName + L"#" + wszName;
+ Chat_ChangeSessionName(m_szModuleName, pUser->wszUsername, wszNewName);
+ }
+
+ CMStringW wszTopic = pRoot["topic"].as_mstring();
+ Chat_SetStatusbarText(m_szModuleName, pUser->wszUsername, wszTopic);
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC };
+ gce.pszID.w = pUser->wszUsername;
+ gce.pszText.w = wszTopic;
+ gce.time = time(0);
+ Chat_Event(&gce);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// reading a new message
+
+void CDiscordProto::OnCommandFriendAdded(const JSONNode &pRoot)
+{
+ CDiscordUser *pUser = PrepareUser(pRoot["user"]);
+ pUser->bIsPrivate = true;
+ ProcessType(pUser, pRoot);
+}
+
+void CDiscordProto::OnCommandFriendRemoved(const JSONNode &pRoot)
+{
+ SnowFlake id = ::getId(pRoot["id"]);
+ CDiscordUser *pUser = FindUser(id);
+ if (pUser != nullptr) {
+ if (pUser->hContact)
+ if (pUser->bIsPrivate)
+ db_delete_contact(pUser->hContact);
+
+ arUsers.remove(pUser);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// guild synchronization
+
+void CDiscordProto::OnCommandGuildCreated(const JSONNode &pRoot)
+{
+ if (m_bUseGroupchats)
+ ProcessGuild(pRoot);
+}
+
+void CDiscordProto::OnCommandGuildDeleted(const JSONNode &pRoot)
+{
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["id"]));
+ if (pGuild == nullptr)
+ return;
+
+ for (auto &it : arUsers.rev_iter())
+ if (it->pGuild == pGuild) {
+ Chat_Terminate(m_szModuleName, it->wszUsername, true);
+ arUsers.removeItem(&it);
+ }
+
+ Chat_Terminate(m_szModuleName, pRoot["name"].as_mstring(), true);
+
+ arGuilds.remove(pGuild);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// guild members
+
+void CDiscordProto::OnCommandGuildMemberAdded(const JSONNode&)
+{
+}
+
+void CDiscordProto::OnCommandGuildMemberListUpdate(const JSONNode &pRoot)
+{
+ auto *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
+ int iStatus = 0;
+
+ for (auto &ops: pRoot["ops"]) {
+ for (auto &it : ops["items"]) {
+ auto &item = it.at((size_t)0);
+ if (!mir_strcmp(item .name(), "group")) {
+ iStatus = item ["id"].as_string() == "online" ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ continue;
+ }
+
+ if (!mir_strcmp(item .name(), "member")) {
+ bool bNew = false;
+ auto *pm = ProcessGuildUser(pGuild, item, &bNew);
+ pm->iStatus = iStatus;
+
+ if (bNew)
+ AddGuildUser(pGuild, *pm);
+ else if (iStatus) {
+ CMStringW wszUserId(FORMAT, L"%lld", pm->userId);
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_SETCONTACTSTATUS };
+ gce.time = time(0);
+ gce.pszUID.w = wszUserId;
+
+ for (auto &cc : pGuild->arChannels) {
+ if (!cc->bIsGroup)
+ continue;
+
+ gce.pszID.w = cc->wszChannelName;
+ gce.dwItemData = iStatus;
+ Chat_Event(&gce);
+ }
+ }
+ }
+ }
+ }
+
+ pGuild->bSynced = true;
+}
+
+void CDiscordProto::OnCommandGuildMemberRemoved(const JSONNode &pRoot)
+{
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
+ CMStringW wszUserId = pRoot["user"]["id"].as_mstring();
+
+ for (auto &pUser : arUsers) {
+ if (pUser->pGuild != pGuild)
+ continue;
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_PART };
+ gce.pszUID.w = pUser->wszUsername;
+ gce.time = time(0);
+ gce.pszUID.w = wszUserId;
+ Chat_Event(&gce);
+ }
+}
+
+void CDiscordProto::OnCommandGuildMemberUpdated(const JSONNode &pRoot)
+{
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
+ CMStringW wszUserId = pRoot["user"]["id"].as_mstring();
+ CDiscordGuildMember *gm = pGuild->FindUser(_wtoi64(wszUserId));
+ if (gm == nullptr)
+ return;
+
+ gm->wszDiscordId = pRoot["user"]["username"].as_mstring() + L"#" + pRoot["user"]["discriminator"].as_mstring();
+ gm->wszNick = pRoot["nick"].as_mstring();
+ if (gm->wszNick.IsEmpty())
+ gm->wszNick = pRoot["user"]["username"].as_mstring();
+
+ for (auto &it : arUsers) {
+ if (it->pGuild != pGuild)
+ continue;
+
+ CMStringW wszOldNick;
+ SESSION_INFO *si = g_chatApi.SM_FindSession(it->wszUsername, m_szModuleName);
+ if (si != nullptr) {
+ USERINFO *ui = g_chatApi.UM_FindUser(si, wszUserId);
+ if (ui != nullptr)
+ wszOldNick = ui->pszNick;
+ }
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_NICK };
+ gce.pszID.w = it->wszUsername;
+ gce.time = time(0);
+ gce.pszUID.w = wszUserId;
+ gce.pszNick.w = wszOldNick;
+ gce.pszText.w = gm->wszNick;
+ Chat_Event(&gce);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// roles
+
+void CDiscordProto::OnCommandRoleCreated(const JSONNode &pRoot)
+{
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild != nullptr)
+ ProcessRole(pGuild, pRoot["role"]);
+}
+
+void CDiscordProto::OnCommandRoleDeleted(const JSONNode &pRoot)
+{
+ CDiscordGuild *pGuild = FindGuild(::getId(pRoot["guild_id"]));
+ if (pGuild == nullptr)
+ return;
+
+ SnowFlake id = ::getId(pRoot["role_id"]);
+ CDiscordRole *pRole = pGuild->arRoles.find((CDiscordRole*)&id);
+ if (pRole == nullptr)
+ return;
+
+ int iOldPosition = pRole->position;
+ pGuild->arRoles.remove(pRole);
+
+ for (auto &it : pGuild->arRoles)
+ if (it->position > iOldPosition)
+ it->position--;
+
+ for (auto &it : arUsers) {
+ if (it->pGuild != pGuild)
+ continue;
+
+ SESSION_INFO *si = g_chatApi.SM_FindSession(it->wszUsername, m_szModuleName);
+ if (si != nullptr) {
+ g_chatApi.TM_RemoveAll(&si->pStatuses);
+ BuildStatusList(pGuild, si);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// reading a new message
+
+void CDiscordProto::OnCommandMessageCreate(const JSONNode &pRoot)
+{
+ OnCommandMessage(pRoot, true);
+}
+
+void CDiscordProto::OnCommandMessageUpdate(const JSONNode &pRoot)
+{
+ OnCommandMessage(pRoot, false);
+}
+
+void CDiscordProto::OnCommandMessage(const JSONNode &pRoot, bool bIsNew)
+{
+ CMStringW wszMessageId = pRoot["id"].as_mstring();
+ CMStringW wszUserId = pRoot["author"]["id"].as_mstring();
+ SnowFlake userId = _wtoi64(wszUserId);
+ SnowFlake msgId = _wtoi64(wszMessageId);
+
+ // try to find a sender by his channel
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ CDiscordUser *pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ debugLogA("skipping message with unknown channel id=%lld", channelId);
+ return;
+ }
+
+ char szMsgId[100];
+ _i64toa_s(msgId, szMsgId, _countof(szMsgId), 10);
+
+ COwnMessage ownMsg(::getId(pRoot["nonce"]), 0);
+ COwnMessage *p = arOwnMessages.find(&ownMsg);
+ if (p != nullptr) { // own message? skip it
+ ProtoBroadcastAck(pUser->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)p->reqId, (LPARAM)szMsgId);
+ debugLogA("skipping own message with nonce=%lld, id=%lld", ownMsg.nonce, msgId);
+ }
+ else {
+ CMStringW wszText = PrepareMessageText(pRoot);
+ if (wszText.IsEmpty())
+ return;
+
+ // old message? try to restore it from database
+ bool bOurMessage = userId == m_ownId;
+ if (!bIsNew) {
+ MEVENT hOldEvent = db_event_getById(m_szModuleName, szMsgId);
+ if (hOldEvent) {
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (!db_event_get(hOldEvent, &dbei)) {
+ ptrW wszOldText(DbEvent_GetTextW(&dbei, CP_UTF8));
+ if (wszOldText)
+ wszText.Insert(0, wszOldText);
+ if (dbei.flags & DBEF_SENT)
+ bOurMessage = true;
+ }
+ }
+ }
+
+ const JSONNode &edited = pRoot["edited_timestamp"];
+ if (!edited.isnull())
+ wszText.AppendFormat(L" (%s %s)", TranslateT("edited at"), edited.as_mstring().c_str());
+
+ if (pUser->bIsPrivate && !pUser->bIsGroup) {
+ // if a message has myself as an author, add some flags
+ PROTORECVEVENT recv = {};
+ if (bOurMessage)
+ recv.flags = PREF_CREATEREAD | PREF_SENT;
+
+ debugLogA("store a message from private user %lld, channel id %lld", pUser->id, pUser->channelId);
+ ptrA buf(mir_utf8encodeW(wszText));
+
+ recv.timestamp = (uint32_t)StringToDate(pRoot["timestamp"].as_mstring());
+ recv.szMessage = buf;
+ recv.szMsgId = szMsgId;
+ ProtoChainRecvMsg(pUser->hContact, &recv);
+ }
+ else {
+ debugLogA("store a message into the group channel id %lld", channelId);
+
+ SESSION_INFO *si = g_chatApi.SM_FindSession(pUser->wszUsername, m_szModuleName);
+ if (si == nullptr) {
+ debugLogA("message to unknown channel %lld ignored", channelId);
+ return;
+ }
+
+ ProcessChatUser(pUser, wszUserId, pRoot);
+
+ ParseSpecialChars(si, wszText);
+ wszText.Replace(L"%", L"%%");
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_MESSAGE };
+ gce.pszID.w = pUser->wszUsername;
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.pszUID.w = wszUserId;
+ gce.pszText.w = wszText;
+ gce.time = (uint32_t)StringToDate(pRoot["timestamp"].as_mstring());
+ gce.bIsMe = bOurMessage;
+ Chat_Event(&gce);
+
+ debugLogW(L"New channel %s message from %s: %s", si->ptszID, gce.pszUID.w, gce.pszText.w);
+ }
+ }
+
+ pUser->lastMsgId = msgId;
+
+ SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database
+ if (lastId < msgId)
+ setId(pUser->hContact, DB_KEY_LASTMSGID, msgId);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// someone changed its status
+
+void CDiscordProto::OnCommandMessageAck(const JSONNode &pRoot)
+{
+ CDiscordUser *pUser = FindUserByChannel(pRoot["channel_id"]);
+ if (pUser != nullptr)
+ pUser->lastMsgId = ::getId(pRoot["message_id"]);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// message deleted
+
+void CDiscordProto::OnCommandMessageDelete(const JSONNode &pRoot)
+{
+ if (!m_bSyncDeleteMsgs)
+ return;
+
+ CMStringA msgid(pRoot["id"].as_mstring());
+ if (!msgid.IsEmpty()) {
+ MEVENT hEvent = db_event_getById(m_szModuleName, msgid);
+ if (hEvent)
+ db_event_delete(hEvent);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// someone changed its status
+
+void CDiscordProto::OnCommandPresence(const JSONNode &pRoot)
+{
+ auto *pGuild = FindGuild(::getId(pRoot["user"]["guild_id"]));
+ if (pGuild == nullptr)
+ ProcessPresence(pRoot);
+ // else
+ // pGuild->ProcessPresence(pRoot);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// gateway session start
+
+void CDiscordProto::OnCommandReady(const JSONNode &pRoot)
+{
+ OnLoggedIn();
+
+ GatewaySendHeartbeat();
+ m_impl.m_heartBeat.StartSafe(m_iHartbeatInterval);
+
+ m_szGatewaySessionId = pRoot["session_id"].as_mstring();
+
+ if (m_bUseGroupchats)
+ for (auto &it : pRoot["guilds"])
+ ProcessGuild(it);
+
+ for (auto &it : pRoot["relationships"]) {
+ CDiscordUser *pUser = PrepareUser(it["user"]);
+ ProcessType(pUser, it);
+ }
+
+ for (auto &it : pRoot["presences"])
+ ProcessPresence(it);
+
+ for (auto &it : pRoot["private_channels"])
+ PreparePrivateChannel(it);
+
+ for (auto &it : pRoot["read_state"]) {
+ CDiscordUser *pUser = FindUserByChannel(::getId(it["id"]));
+ if (pUser != nullptr)
+ pUser->lastReadId = ::getId(it["last_message_id"]);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// UTN support
+
+void CDiscordProto::OnCommandTyping(const JSONNode &pRoot)
+{
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ debugLogA("user typing notification: channelid=%lld", channelId);
+
+ CDiscordUser *pChannel = FindUserByChannel(channelId);
+ if (pChannel == nullptr) {
+ debugLogA("channel with id=%lld is not found", channelId);
+ return;
+ }
+
+ // both private groupchats & guild channels are chat rooms for Miranda
+ if (pChannel->pGuild) {
+ debugLogA("user is typing in a group channel");
+
+ CMStringW wszUerId = pRoot["user_id"].as_mstring();
+ ProcessGuildUser(pChannel->pGuild, pRoot); // never returns null
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TYPING };
+ gce.pszID.w = pChannel->wszUsername;
+ gce.pszUID.w = wszUerId;
+ gce.dwItemData = 1;
+ gce.time = time(0);
+ Chat_Event(&gce);
+ }
+ else {
+ debugLogA("user is typing in his private channel");
+ CallService(MS_PROTO_CONTACTISTYPING, pChannel->hContact, 20);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// User info update
+
+void CDiscordProto::OnCommandUserUpdate(const JSONNode &pRoot)
+{
+ SnowFlake id = ::getId(pRoot["id"]);
+
+ MCONTACT hContact;
+ if (id != m_ownId) {
+ CDiscordUser *pUser = FindUser(id);
+ if (pUser == nullptr)
+ return;
+
+ hContact = pUser->hContact;
+ }
+ else hContact = 0;
+
+ // force rereading avatar
+ CheckAvatarChange(hContact, pRoot["avatar"].as_mstring());
+}
+
+void CDiscordProto::OnCommandUserSettingsUpdate(const JSONNode &pRoot)
+{
+ int iStatus = StrToStatus(pRoot["status"].as_mstring());
+ if (iStatus != 0) {
+ int iOldStatus = m_iStatus; m_iStatus = iStatus;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
+ }
+}
diff --git a/protocols/Discord/src/gateway.cpp b/protocols/Discord/src/gateway.cpp index 82c3b70eb5..0530945c3e 100644 --- a/protocols/Discord/src/gateway.cpp +++ b/protocols/Discord/src/gateway.cpp @@ -1,346 +1,346 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -////////////////////////////////////////////////////////////////////////////////////// -// sends a piece of JSON to a server via a websocket, masked - -bool CDiscordProto::GatewaySend(const JSONNode &pRoot) -{ - if (m_hGatewayConnection == nullptr) - return false; - - json_string szText = pRoot.write(); - debugLogA("Gateway send: %s", szText.c_str()); - WebSocket_SendText(m_hGatewayConnection, szText.c_str()); - return true; -} - -////////////////////////////////////////////////////////////////////////////////////// -// gateway worker thread - -void CDiscordProto::GatewayThread(void*) -{ - while (GatewayThreadWorker()) - ; - ShutdownSession(); -} - -bool CDiscordProto::GatewayThreadWorker() -{ - NETLIBHTTPHEADER hdrs[] = - { - { "Origin", "https://discord.com" }, - { 0, 0 }, - { 0, 0 }, - }; - - if (!m_szWSCookie.IsEmpty()) { - hdrs[1].szName = "Cookie"; - hdrs[1].szValue = m_szWSCookie.GetBuffer(); - } - - NLHR_PTR pReply(WebSocket_Connect(m_hGatewayNetlibUser, m_szGateway + "/?encoding=json&v=8", hdrs)); - if (pReply == nullptr) { - debugLogA("Gateway connection failed, exiting"); - return false; - } - - if (auto *pszNewCookie = Netlib_GetHeader(pReply, "Set-Cookie")) { - char *p = strchr(pszNewCookie, ';'); - if (p) *p = 0; - - m_szWSCookie = pszNewCookie; - } - - if (pReply->resultCode != 101) { - // if there's no cookie & Miranda is bounced with error 404, simply apply the cookie and try again - if (pReply->resultCode == 404) { - if (hdrs[1].szName == nullptr) - return true; - - m_szWSCookie.Empty(); // don't use the same cookie twice - } - return false; - } - - // succeeded! - debugLogA("Gateway connection succeeded"); - m_hGatewayConnection = pReply->nlc; - - bool bExit = false; - int offset = 0; - MBinBuffer netbuf; - - while (!bExit) { - if (m_bTerminated) - break; - - unsigned char buf[2048]; - int bufSize = Netlib_Recv(m_hGatewayConnection, (char*)buf + offset, _countof(buf) - offset, MSG_NODUMP); - if (bufSize == 0) { - debugLogA("Gateway connection gracefully closed"); - bExit = !m_bTerminated; - break; - } - if (bufSize < 0) { - debugLogA("Gateway connection error, exiting"); - break; - } - - WSHeader hdr; - if (!WebSocket_InitHeader(hdr, buf, bufSize)) { - offset += bufSize; - continue; - } - offset = 0; - - debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, final = %d, masked = %d", bufSize, hdr.opCode, hdr.headerSize, hdr.bIsFinal, hdr.bIsMasked); - - // we have some additional data, not only opcode - if ((size_t)bufSize > hdr.headerSize) { - size_t currPacketSize = bufSize - hdr.headerSize; - netbuf.append(buf, bufSize); - while (currPacketSize < hdr.payloadSize) { - int result = Netlib_Recv(m_hGatewayConnection, (char*)buf, _countof(buf), MSG_NODUMP); - if (result == 0) { - debugLogA("Gateway connection gracefully closed"); - bExit = !m_bTerminated; - break; - } - if (result < 0) { - debugLogA("Gateway connection error, exiting"); - break; - } - currPacketSize += result; - netbuf.append(buf, result); - } - } - - // read all payloads from the current buffer, one by one - size_t prevSize = 0; - while (true) { - switch (hdr.opCode) { - case 0: // text packet - case 1: // binary packet - case 2: // continuation - if (hdr.bIsFinal) { - // process a packet here - CMStringA szJson((char*)netbuf.data() + hdr.headerSize, (int)hdr.payloadSize); - debugLogA("JSON received:\n%s", szJson.c_str()); - JSONNode root = JSONNode::parse(szJson); - if (root) - bExit = GatewayProcess(root); - } - break; - - case 8: // close - debugLogA("server required to exit"); - bExit = true; // simply reconnect, don't exit - break; - - case 9: // ping - debugLogA("ping received"); - Netlib_Send(m_hGatewayConnection, (char*)buf + hdr.headerSize, bufSize - int(hdr.headerSize), 0); - break; - } - - if (hdr.bIsFinal) - netbuf.remove(hdr.headerSize + hdr.payloadSize); - - if (netbuf.length() == 0) - break; - - // if we have not enough data for header, continue reading - if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) - break; - - // if we have not enough data for data, continue reading - if (hdr.headerSize + hdr.payloadSize > netbuf.length()) - break; - - debugLogA("Got inner packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); - if (prevSize == netbuf.length()) { - netbuf.remove(prevSize); - debugLogA("dropping current packet, exiting"); - break; - } - - prevSize = netbuf.length(); - } - } - - Netlib_CloseHandle(m_hGatewayConnection); - m_hGatewayConnection = nullptr; - return bExit; -} - -////////////////////////////////////////////////////////////////////////////////////// -// handles server commands - -bool CDiscordProto::GatewayProcess(const JSONNode &pRoot) -{ - int opCode = pRoot["op"].as_int(); - switch (opCode) { - case OPCODE_DISPATCH: // process incoming command - { - int iSeq = pRoot["s"].as_int(); - if (iSeq != 0) - m_iGatewaySeq = iSeq; - - CMStringW wszCommand = pRoot["t"].as_mstring(); - debugLogA("got a server command to dispatch: %S", wszCommand.c_str()); - - GatewayHandlerFunc pFunc = GetHandler(wszCommand); - if (pFunc) - (this->*pFunc)(pRoot["d"]); - } - break; - - case OPCODE_RECONNECT: // we need to reconnect asap - debugLogA("we need to reconnect, leaving worker thread"); - return true; - - case OPCODE_INVALID_SESSION: // session invalidated - if (pRoot["d"].as_bool()) // session can be resumed - GatewaySendResume(); - else { - Sleep(5000); // 5 seconds - recommended timeout - GatewaySendIdentify(); - } - break; - - case OPCODE_HELLO: // hello - m_iHartbeatInterval = pRoot["d"]["heartbeat_interval"].as_int(); - - GatewaySendIdentify(); - break; - - case OPCODE_HEARTBEAT_ACK: // heartbeat ack - break; - - default: - debugLogA("ACHTUNG! Unknown opcode: %d, report it to developer", opCode); - } - - return false; -} - -////////////////////////////////////////////////////////////////////////////////////// -// requests to be sent to a gateway - -void CDiscordProto::GatewaySendGuildInfo(CDiscordGuild *pGuild) -{ - if (!pGuild->arChannels.getCount()) - return; - - JSONNode a1(JSON_ARRAY); a1 << INT_PARAM("", 0) << INT_PARAM("", 99); - - CMStringA szId(FORMAT, "%lld", pGuild->arChannels[0]->id); - JSONNode chl(JSON_ARRAY); chl.set_name(szId.c_str()); chl << a1; - - JSONNode channels; channels.set_name("channels"); channels << chl; - - JSONNode payload; payload.set_name("d"); - payload << SINT64_PARAM("guild_id", pGuild->id) << BOOL_PARAM("typing", true) << BOOL_PARAM("activities", true) << BOOL_PARAM("presences", true) << channels; - - JSONNode root; - root << INT_PARAM("op", OPCODE_REQUEST_SYNC_CHANNEL) << payload; - GatewaySend(root); -} - -void CDiscordProto::GatewaySendHeartbeat() -{ - // we don't send heartbeat packets until we get logged in - if (!m_iHartbeatInterval || !m_iGatewaySeq) - return; - - JSONNode root; - root << INT_PARAM("op", OPCODE_HEARTBEAT) << INT_PARAM("d", m_iGatewaySeq); - GatewaySend(root); -} - -void CDiscordProto::GatewaySendIdentify() -{ - if (m_szAccessToken == nullptr) { - ConnectionFailed(LOGINERR_WRONGPASSWORD); - return; - } - - char szOs[256]; - OS_GetDisplayString(szOs, _countof(szOs)); - - char szVersion[256]; - Miranda_GetVersionText(szVersion, _countof(szVersion)); - - JSONNode props; props.set_name("properties"); - props << CHAR_PARAM("os", szOs) << CHAR_PARAM("browser", "Chrome") << CHAR_PARAM("device", szVersion) - << CHAR_PARAM("referrer", "https://miranda-ng.org") << CHAR_PARAM("referring_domain", "miranda-ng.org"); - - JSONNode payload; payload.set_name("d"); - payload << CHAR_PARAM("token", m_szAccessToken) << props << BOOL_PARAM("compress", false) << INT_PARAM("large_threshold", 250); - - JSONNode root; - root << INT_PARAM("op", OPCODE_IDENTIFY) << payload; - GatewaySend(root); -} - -void CDiscordProto::GatewaySendResume() -{ - char szRandom[40]; - uint8_t random[16]; - Utils_GetRandom(random, _countof(random)); - bin2hex(random, _countof(random), szRandom); - - JSONNode root; - root << CHAR_PARAM("token", szRandom) << CHAR_PARAM("session_id", m_szGatewaySessionId) << INT_PARAM("seq", m_iGatewaySeq); - GatewaySend(root); -} - -bool CDiscordProto::GatewaySendStatus(int iStatus, const wchar_t *pwszStatusText) -{ - if (iStatus == ID_STATUS_OFFLINE) { - Push(new AsyncHttpRequest(this, REQUEST_POST, "/auth/logout", nullptr)); - return true; - } - - const char *pszStatus; - switch (iStatus) { - case ID_STATUS_AWAY: - case ID_STATUS_NA: - pszStatus = "idle"; break; - case ID_STATUS_DND: - pszStatus = "dnd"; break; - case ID_STATUS_INVISIBLE: - pszStatus = "invisible"; break; - default: - pszStatus = "online"; break; - } - - JSONNode payload; payload.set_name("d"); - payload << INT64_PARAM("since", __int64(time(0)) * 1000) << BOOL_PARAM("afk", true) << CHAR_PARAM("status", pszStatus); - if (pwszStatusText == nullptr) - payload << CHAR_PARAM("game", nullptr); - else { - JSONNode game; game.set_name("game"); game << WCHAR_PARAM("name", pwszStatusText) << INT_PARAM("type", 0); - payload << game; - } - - JSONNode root; root << INT_PARAM("op", OPCODE_STATUS_UPDATE) << payload; - return GatewaySend(root); -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+//////////////////////////////////////////////////////////////////////////////////////
+// sends a piece of JSON to a server via a websocket, masked
+
+bool CDiscordProto::GatewaySend(const JSONNode &pRoot)
+{
+ if (m_hGatewayConnection == nullptr)
+ return false;
+
+ json_string szText = pRoot.write();
+ debugLogA("Gateway send: %s", szText.c_str());
+ WebSocket_SendText(m_hGatewayConnection, szText.c_str());
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// gateway worker thread
+
+void CDiscordProto::GatewayThread(void*)
+{
+ while (GatewayThreadWorker())
+ ;
+ ShutdownSession();
+}
+
+bool CDiscordProto::GatewayThreadWorker()
+{
+ NETLIBHTTPHEADER hdrs[] =
+ {
+ { "Origin", "https://discord.com" },
+ { 0, 0 },
+ { 0, 0 },
+ };
+
+ if (!m_szWSCookie.IsEmpty()) {
+ hdrs[1].szName = "Cookie";
+ hdrs[1].szValue = m_szWSCookie.GetBuffer();
+ }
+
+ NLHR_PTR pReply(WebSocket_Connect(m_hGatewayNetlibUser, m_szGateway + "/?encoding=json&v=8", hdrs));
+ if (pReply == nullptr) {
+ debugLogA("Gateway connection failed, exiting");
+ return false;
+ }
+
+ if (auto *pszNewCookie = Netlib_GetHeader(pReply, "Set-Cookie")) {
+ char *p = strchr(pszNewCookie, ';');
+ if (p) *p = 0;
+
+ m_szWSCookie = pszNewCookie;
+ }
+
+ if (pReply->resultCode != 101) {
+ // if there's no cookie & Miranda is bounced with error 404, simply apply the cookie and try again
+ if (pReply->resultCode == 404) {
+ if (hdrs[1].szName == nullptr)
+ return true;
+
+ m_szWSCookie.Empty(); // don't use the same cookie twice
+ }
+ return false;
+ }
+
+ // succeeded!
+ debugLogA("Gateway connection succeeded");
+ m_hGatewayConnection = pReply->nlc;
+
+ bool bExit = false;
+ int offset = 0;
+ MBinBuffer netbuf;
+
+ while (!bExit) {
+ if (m_bTerminated)
+ break;
+
+ unsigned char buf[2048];
+ int bufSize = Netlib_Recv(m_hGatewayConnection, (char*)buf + offset, _countof(buf) - offset, MSG_NODUMP);
+ if (bufSize == 0) {
+ debugLogA("Gateway connection gracefully closed");
+ bExit = !m_bTerminated;
+ break;
+ }
+ if (bufSize < 0) {
+ debugLogA("Gateway connection error, exiting");
+ break;
+ }
+
+ WSHeader hdr;
+ if (!WebSocket_InitHeader(hdr, buf, bufSize)) {
+ offset += bufSize;
+ continue;
+ }
+ offset = 0;
+
+ debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, final = %d, masked = %d", bufSize, hdr.opCode, hdr.headerSize, hdr.bIsFinal, hdr.bIsMasked);
+
+ // we have some additional data, not only opcode
+ if ((size_t)bufSize > hdr.headerSize) {
+ size_t currPacketSize = bufSize - hdr.headerSize;
+ netbuf.append(buf, bufSize);
+ while (currPacketSize < hdr.payloadSize) {
+ int result = Netlib_Recv(m_hGatewayConnection, (char*)buf, _countof(buf), MSG_NODUMP);
+ if (result == 0) {
+ debugLogA("Gateway connection gracefully closed");
+ bExit = !m_bTerminated;
+ break;
+ }
+ if (result < 0) {
+ debugLogA("Gateway connection error, exiting");
+ break;
+ }
+ currPacketSize += result;
+ netbuf.append(buf, result);
+ }
+ }
+
+ // read all payloads from the current buffer, one by one
+ size_t prevSize = 0;
+ while (true) {
+ switch (hdr.opCode) {
+ case 0: // text packet
+ case 1: // binary packet
+ case 2: // continuation
+ if (hdr.bIsFinal) {
+ // process a packet here
+ CMStringA szJson((char*)netbuf.data() + hdr.headerSize, (int)hdr.payloadSize);
+ debugLogA("JSON received:\n%s", szJson.c_str());
+ JSONNode root = JSONNode::parse(szJson);
+ if (root)
+ bExit = GatewayProcess(root);
+ }
+ break;
+
+ case 8: // close
+ debugLogA("server required to exit");
+ bExit = true; // simply reconnect, don't exit
+ break;
+
+ case 9: // ping
+ debugLogA("ping received");
+ Netlib_Send(m_hGatewayConnection, (char*)buf + hdr.headerSize, bufSize - int(hdr.headerSize), 0);
+ break;
+ }
+
+ if (hdr.bIsFinal)
+ netbuf.remove(hdr.headerSize + hdr.payloadSize);
+
+ if (netbuf.length() == 0)
+ break;
+
+ // if we have not enough data for header, continue reading
+ if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length()))
+ break;
+
+ // if we have not enough data for data, continue reading
+ if (hdr.headerSize + hdr.payloadSize > netbuf.length())
+ break;
+
+ debugLogA("Got inner packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked);
+ if (prevSize == netbuf.length()) {
+ netbuf.remove(prevSize);
+ debugLogA("dropping current packet, exiting");
+ break;
+ }
+
+ prevSize = netbuf.length();
+ }
+ }
+
+ Netlib_CloseHandle(m_hGatewayConnection);
+ m_hGatewayConnection = nullptr;
+ return bExit;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// handles server commands
+
+bool CDiscordProto::GatewayProcess(const JSONNode &pRoot)
+{
+ int opCode = pRoot["op"].as_int();
+ switch (opCode) {
+ case OPCODE_DISPATCH: // process incoming command
+ {
+ int iSeq = pRoot["s"].as_int();
+ if (iSeq != 0)
+ m_iGatewaySeq = iSeq;
+
+ CMStringW wszCommand = pRoot["t"].as_mstring();
+ debugLogA("got a server command to dispatch: %S", wszCommand.c_str());
+
+ GatewayHandlerFunc pFunc = GetHandler(wszCommand);
+ if (pFunc)
+ (this->*pFunc)(pRoot["d"]);
+ }
+ break;
+
+ case OPCODE_RECONNECT: // we need to reconnect asap
+ debugLogA("we need to reconnect, leaving worker thread");
+ return true;
+
+ case OPCODE_INVALID_SESSION: // session invalidated
+ if (pRoot["d"].as_bool()) // session can be resumed
+ GatewaySendResume();
+ else {
+ Sleep(5000); // 5 seconds - recommended timeout
+ GatewaySendIdentify();
+ }
+ break;
+
+ case OPCODE_HELLO: // hello
+ m_iHartbeatInterval = pRoot["d"]["heartbeat_interval"].as_int();
+
+ GatewaySendIdentify();
+ break;
+
+ case OPCODE_HEARTBEAT_ACK: // heartbeat ack
+ break;
+
+ default:
+ debugLogA("ACHTUNG! Unknown opcode: %d, report it to developer", opCode);
+ }
+
+ return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+// requests to be sent to a gateway
+
+void CDiscordProto::GatewaySendGuildInfo(CDiscordGuild *pGuild)
+{
+ if (!pGuild->arChannels.getCount())
+ return;
+
+ JSONNode a1(JSON_ARRAY); a1 << INT_PARAM("", 0) << INT_PARAM("", 99);
+
+ CMStringA szId(FORMAT, "%lld", pGuild->arChannels[0]->id);
+ JSONNode chl(JSON_ARRAY); chl.set_name(szId.c_str()); chl << a1;
+
+ JSONNode channels; channels.set_name("channels"); channels << chl;
+
+ JSONNode payload; payload.set_name("d");
+ payload << SINT64_PARAM("guild_id", pGuild->id) << BOOL_PARAM("typing", true) << BOOL_PARAM("activities", true) << BOOL_PARAM("presences", true) << channels;
+
+ JSONNode root;
+ root << INT_PARAM("op", OPCODE_REQUEST_SYNC_CHANNEL) << payload;
+ GatewaySend(root);
+}
+
+void CDiscordProto::GatewaySendHeartbeat()
+{
+ // we don't send heartbeat packets until we get logged in
+ if (!m_iHartbeatInterval || !m_iGatewaySeq)
+ return;
+
+ JSONNode root;
+ root << INT_PARAM("op", OPCODE_HEARTBEAT) << INT_PARAM("d", m_iGatewaySeq);
+ GatewaySend(root);
+}
+
+void CDiscordProto::GatewaySendIdentify()
+{
+ if (m_szAccessToken == nullptr) {
+ ConnectionFailed(LOGINERR_WRONGPASSWORD);
+ return;
+ }
+
+ char szOs[256];
+ OS_GetDisplayString(szOs, _countof(szOs));
+
+ char szVersion[256];
+ Miranda_GetVersionText(szVersion, _countof(szVersion));
+
+ JSONNode props; props.set_name("properties");
+ props << CHAR_PARAM("os", szOs) << CHAR_PARAM("browser", "Chrome") << CHAR_PARAM("device", szVersion)
+ << CHAR_PARAM("referrer", "https://miranda-ng.org") << CHAR_PARAM("referring_domain", "miranda-ng.org");
+
+ JSONNode payload; payload.set_name("d");
+ payload << CHAR_PARAM("token", m_szAccessToken) << props << BOOL_PARAM("compress", false) << INT_PARAM("large_threshold", 250);
+
+ JSONNode root;
+ root << INT_PARAM("op", OPCODE_IDENTIFY) << payload;
+ GatewaySend(root);
+}
+
+void CDiscordProto::GatewaySendResume()
+{
+ char szRandom[40];
+ uint8_t random[16];
+ Utils_GetRandom(random, _countof(random));
+ bin2hex(random, _countof(random), szRandom);
+
+ JSONNode root;
+ root << CHAR_PARAM("token", szRandom) << CHAR_PARAM("session_id", m_szGatewaySessionId) << INT_PARAM("seq", m_iGatewaySeq);
+ GatewaySend(root);
+}
+
+bool CDiscordProto::GatewaySendStatus(int iStatus, const wchar_t *pwszStatusText)
+{
+ if (iStatus == ID_STATUS_OFFLINE) {
+ Push(new AsyncHttpRequest(this, REQUEST_POST, "/auth/logout", nullptr));
+ return true;
+ }
+
+ const char *pszStatus;
+ switch (iStatus) {
+ case ID_STATUS_AWAY:
+ case ID_STATUS_NA:
+ pszStatus = "idle"; break;
+ case ID_STATUS_DND:
+ pszStatus = "dnd"; break;
+ case ID_STATUS_INVISIBLE:
+ pszStatus = "invisible"; break;
+ default:
+ pszStatus = "online"; break;
+ }
+
+ JSONNode payload; payload.set_name("d");
+ payload << INT64_PARAM("since", __int64(time(0)) * 1000) << BOOL_PARAM("afk", true) << CHAR_PARAM("status", pszStatus);
+ if (pwszStatusText == nullptr)
+ payload << CHAR_PARAM("game", nullptr);
+ else {
+ JSONNode game; game.set_name("game"); game << WCHAR_PARAM("name", pwszStatusText) << INT_PARAM("type", 0);
+ payload << game;
+ }
+
+ JSONNode root; root << INT_PARAM("op", OPCODE_STATUS_UPDATE) << payload;
+ return GatewaySend(root);
+}
diff --git a/protocols/Discord/src/groupchat.cpp b/protocols/Discord/src/groupchat.cpp index f34e35c93a..146f8de1fe 100644 --- a/protocols/Discord/src/groupchat.cpp +++ b/protocols/Discord/src/groupchat.cpp @@ -1,235 +1,235 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -enum { - IDM_CANCEL, - IDM_COPY_ID, - - IDM_CHANGENICK, IDM_CHANGETOPIC, IDM_RENAME, IDM_DESTROY -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si) -{ - Chat_AddGroup(si, L"@owner"); - - for (auto &it : pGuild->arRoles) - Chat_AddGroup(si, it->wszName); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static gc_item sttLogListItems[] = -{ - { LPGENW("Change &nickname"), IDM_CHANGENICK, MENU_ITEM }, - { LPGENW("Channel control"), FALSE, MENU_NEWPOPUP }, - { LPGENW("Change &topic"), IDM_CHANGETOPIC, MENU_POPUPITEM }, - { LPGENW("&Rename channel"), IDM_RENAME, MENU_POPUPITEM }, - { nullptr, 0, MENU_POPUPSEPARATOR }, - { LPGENW("&Destroy channel"), IDM_DESTROY, MENU_POPUPITEM }, -}; - -static gc_item sttNicklistItems[] = -{ - { LPGENW("Copy ID"), IDM_COPY_ID, MENU_ITEM }, -}; - -int CDiscordProto::GroupchatMenuHook(WPARAM, LPARAM lParam) -{ - GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam; - if (gcmi == nullptr) - return 0; - - if (mir_strcmpi(gcmi->pszModule, m_szModuleName)) - return 0; - - CDiscordUser *pChat = FindUserByChannel(_wtoi64(gcmi->pszID)); - if (pChat == nullptr) - return 0; - - if (gcmi->Type == MENU_ON_LOG) - Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin); - else if (gcmi->Type == MENU_ON_NICKLIST) - Chat_AddMenuItems(gcmi->hMenu, _countof(sttNicklistItems), sttNicklistItems, &g_plugin); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::Chat_SendPrivateMessage(GCHOOK *gch) -{ - SnowFlake userId = _wtoi64(gch->ptszUID); - - MCONTACT hContact; - CDiscordUser *pUser = FindUser(userId); - if (pUser == nullptr) { - PROTOSEARCHRESULT psr = { sizeof(psr) }; - psr.id.w = (wchar_t*)gch->ptszUID; - psr.nick.w = (wchar_t*)gch->ptszNick; - if ((hContact = AddToList(PALF_TEMPORARY, &psr)) == 0) - return; - - setId(hContact, DB_KEY_ID, userId); - setId(hContact, DB_KEY_CHANNELID, _wtoi64(gch->si->ptszID)); - setWString(hContact, DB_KEY_NICK, gch->ptszNick); - Contact::Hide(hContact); - db_set_dw(hContact, "Ignore", "Mask1", 0); - } - else hContact = pUser->hContact; - - CallService(MS_MSG_SENDMESSAGE, hContact, 0); -} - -void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch) -{ - CDiscordUser *pUser = FindUserByChannel(_wtoi64(gch->si->ptszID)); - if (pUser == nullptr) - return; - - ENTER_STRING es = {}; - es.szModuleName = m_szModuleName; - - switch (gch->dwData) { - case IDM_DESTROY: - if (IDYES == MessageBox(nullptr, TranslateT("Do you really want to destroy this channel? This action is non-revertable."), m_tszUserName, MB_YESNO | MB_ICONQUESTION)) { - CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str()); - Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr)); - } - break; - - case IDM_RENAME: - es.caption = TranslateT("Enter new channel name:"); - es.type = ESF_COMBO; - es.szDataPrefix = "chat_rename"; - if (EnterString(&es)) { - JSONNode root; root << WCHAR_PARAM("name", es.ptszResult); - CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str()); - Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root)); - mir_free(es.ptszResult); - } - break; - - case IDM_CHANGETOPIC: - es.caption = TranslateT("Enter new topic:"); - es.type = ESF_RICHEDIT; - es.szDataPrefix = "chat_topic"; - if (EnterString(&es)) { - JSONNode root; root << WCHAR_PARAM("topic", es.ptszResult); - CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str()); - Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root)); - mir_free(es.ptszResult); - } - break; - - case IDM_CHANGENICK: - es.caption = TranslateT("Enter your new nick name:"); - es.type = ESF_COMBO; - es.szDataPrefix = "chat_nick"; - es.recentCount = 5; - if (EnterString(&es)) { - JSONNode root; root << WCHAR_PARAM("nick", es.ptszResult); - CMStringA szUrl(FORMAT, "/guilds/%lld/members/@me/nick", pUser->pGuild->id); - Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root)); - mir_free(es.ptszResult); - } - break; - } -} - -void CDiscordProto::Chat_ProcessNickMenu(GCHOOK* gch) -{ - auto *pChannel = FindUserByChannel(_wtoi64(gch->si->ptszID)); - if (pChannel == nullptr || pChannel->pGuild == nullptr) - return; - - auto* pUser = pChannel->pGuild->FindUser(_wtoi64(gch->ptszUID)); - if (pUser == nullptr) - return; - - switch (gch->dwData) { - case IDM_COPY_ID: - CopyId(pUser->wszDiscordId); - break; - } -} - -int CDiscordProto::GroupchatEventHook(WPARAM, LPARAM lParam) -{ - GCHOOK *gch = (GCHOOK*)lParam; - if (gch == nullptr) - return 0; - - if (mir_strcmpi(gch->si->pszModule, m_szModuleName)) - return 0; - - switch (gch->iType) { - case GC_USER_MESSAGE: - if (m_bOnline && mir_wstrlen(gch->ptszText) > 0) { - CMStringW wszText(gch->ptszText); - wszText.TrimRight(); - - int pos = wszText.Find(':'); - if (pos != -1) { - auto wszWord = wszText.Left(pos); - wszWord.Trim(); - if (auto *si = g_chatApi.SM_FindSession(gch->si->ptszID, gch->si->pszModule)) { - USERINFO *pUser = nullptr; - - for (auto &U : si->getUserList()) - if (wszWord == U->pszNick) { - pUser = U; - break; - } - - if (pUser) { - wszText.Delete(0, pos); - wszText.Insert(0, L"<@" + CMStringW(pUser->pszUID) + L">"); - } - } - } - - Chat_UnescapeTags(wszText.GetBuffer()); - - JSONNode body; body << WCHAR_PARAM("content", wszText); - CMStringA szUrl(FORMAT, "/channels/%S/messages", gch->si->ptszID); - Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr, &body)); - } - break; - - case GC_USER_PRIVMESS: - Chat_SendPrivateMessage(gch); - break; - - case GC_USER_LOGMENU: - Chat_ProcessLogMenu(gch); - break; - - case GC_USER_NICKLISTMENU: - Chat_ProcessNickMenu(gch); - break; - - case GC_USER_TYPNOTIFY: - UserIsTyping(gch->si->hContact, (int)gch->dwData); - break; - } - - return 1; -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+enum {
+ IDM_CANCEL,
+ IDM_COPY_ID,
+
+ IDM_CHANGENICK, IDM_CHANGETOPIC, IDM_RENAME, IDM_DESTROY
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si)
+{
+ Chat_AddGroup(si, L"@owner");
+
+ for (auto &it : pGuild->arRoles)
+ Chat_AddGroup(si, it->wszName);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static gc_item sttLogListItems[] =
+{
+ { LPGENW("Change &nickname"), IDM_CHANGENICK, MENU_ITEM },
+ { LPGENW("Channel control"), FALSE, MENU_NEWPOPUP },
+ { LPGENW("Change &topic"), IDM_CHANGETOPIC, MENU_POPUPITEM },
+ { LPGENW("&Rename channel"), IDM_RENAME, MENU_POPUPITEM },
+ { nullptr, 0, MENU_POPUPSEPARATOR },
+ { LPGENW("&Destroy channel"), IDM_DESTROY, MENU_POPUPITEM },
+};
+
+static gc_item sttNicklistItems[] =
+{
+ { LPGENW("Copy ID"), IDM_COPY_ID, MENU_ITEM },
+};
+
+int CDiscordProto::GroupchatMenuHook(WPARAM, LPARAM lParam)
+{
+ GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam;
+ if (gcmi == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gcmi->pszModule, m_szModuleName))
+ return 0;
+
+ CDiscordUser *pChat = FindUserByChannel(_wtoi64(gcmi->pszID));
+ if (pChat == nullptr)
+ return 0;
+
+ if (gcmi->Type == MENU_ON_LOG)
+ Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin);
+ else if (gcmi->Type == MENU_ON_NICKLIST)
+ Chat_AddMenuItems(gcmi->hMenu, _countof(sttNicklistItems), sttNicklistItems, &g_plugin);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::Chat_SendPrivateMessage(GCHOOK *gch)
+{
+ SnowFlake userId = _wtoi64(gch->ptszUID);
+
+ MCONTACT hContact;
+ CDiscordUser *pUser = FindUser(userId);
+ if (pUser == nullptr) {
+ PROTOSEARCHRESULT psr = { sizeof(psr) };
+ psr.id.w = (wchar_t*)gch->ptszUID;
+ psr.nick.w = (wchar_t*)gch->ptszNick;
+ if ((hContact = AddToList(PALF_TEMPORARY, &psr)) == 0)
+ return;
+
+ setId(hContact, DB_KEY_ID, userId);
+ setId(hContact, DB_KEY_CHANNELID, _wtoi64(gch->si->ptszID));
+ setWString(hContact, DB_KEY_NICK, gch->ptszNick);
+ Contact::Hide(hContact);
+ db_set_dw(hContact, "Ignore", "Mask1", 0);
+ }
+ else hContact = pUser->hContact;
+
+ CallService(MS_MSG_SENDMESSAGE, hContact, 0);
+}
+
+void CDiscordProto::Chat_ProcessLogMenu(GCHOOK *gch)
+{
+ CDiscordUser *pUser = FindUserByChannel(_wtoi64(gch->si->ptszID));
+ if (pUser == nullptr)
+ return;
+
+ ENTER_STRING es = {};
+ es.szModuleName = m_szModuleName;
+
+ switch (gch->dwData) {
+ case IDM_DESTROY:
+ if (IDYES == MessageBox(nullptr, TranslateT("Do you really want to destroy this channel? This action is non-revertable."), m_tszUserName, MB_YESNO | MB_ICONQUESTION)) {
+ CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
+ Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr));
+ }
+ break;
+
+ case IDM_RENAME:
+ es.caption = TranslateT("Enter new channel name:");
+ es.type = ESF_COMBO;
+ es.szDataPrefix = "chat_rename";
+ if (EnterString(&es)) {
+ JSONNode root; root << WCHAR_PARAM("name", es.ptszResult);
+ CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
+ Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
+ mir_free(es.ptszResult);
+ }
+ break;
+
+ case IDM_CHANGETOPIC:
+ es.caption = TranslateT("Enter new topic:");
+ es.type = ESF_RICHEDIT;
+ es.szDataPrefix = "chat_topic";
+ if (EnterString(&es)) {
+ JSONNode root; root << WCHAR_PARAM("topic", es.ptszResult);
+ CMStringA szUrl(FORMAT, "/channels/%S", pUser->wszUsername.c_str());
+ Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
+ mir_free(es.ptszResult);
+ }
+ break;
+
+ case IDM_CHANGENICK:
+ es.caption = TranslateT("Enter your new nick name:");
+ es.type = ESF_COMBO;
+ es.szDataPrefix = "chat_nick";
+ es.recentCount = 5;
+ if (EnterString(&es)) {
+ JSONNode root; root << WCHAR_PARAM("nick", es.ptszResult);
+ CMStringA szUrl(FORMAT, "/guilds/%lld/members/@me/nick", pUser->pGuild->id);
+ Push(new AsyncHttpRequest(this, REQUEST_PATCH, szUrl, nullptr, &root));
+ mir_free(es.ptszResult);
+ }
+ break;
+ }
+}
+
+void CDiscordProto::Chat_ProcessNickMenu(GCHOOK* gch)
+{
+ auto *pChannel = FindUserByChannel(_wtoi64(gch->si->ptszID));
+ if (pChannel == nullptr || pChannel->pGuild == nullptr)
+ return;
+
+ auto* pUser = pChannel->pGuild->FindUser(_wtoi64(gch->ptszUID));
+ if (pUser == nullptr)
+ return;
+
+ switch (gch->dwData) {
+ case IDM_COPY_ID:
+ CopyId(pUser->wszDiscordId);
+ break;
+ }
+}
+
+int CDiscordProto::GroupchatEventHook(WPARAM, LPARAM lParam)
+{
+ GCHOOK *gch = (GCHOOK*)lParam;
+ if (gch == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gch->si->pszModule, m_szModuleName))
+ return 0;
+
+ switch (gch->iType) {
+ case GC_USER_MESSAGE:
+ if (m_bOnline && mir_wstrlen(gch->ptszText) > 0) {
+ CMStringW wszText(gch->ptszText);
+ wszText.TrimRight();
+
+ int pos = wszText.Find(':');
+ if (pos != -1) {
+ auto wszWord = wszText.Left(pos);
+ wszWord.Trim();
+ if (auto *si = g_chatApi.SM_FindSession(gch->si->ptszID, gch->si->pszModule)) {
+ USERINFO *pUser = nullptr;
+
+ for (auto &U : si->getUserList())
+ if (wszWord == U->pszNick) {
+ pUser = U;
+ break;
+ }
+
+ if (pUser) {
+ wszText.Delete(0, pos);
+ wszText.Insert(0, L"<@" + CMStringW(pUser->pszUID) + L">");
+ }
+ }
+ }
+
+ Chat_UnescapeTags(wszText.GetBuffer());
+
+ JSONNode body; body << WCHAR_PARAM("content", wszText);
+ CMStringA szUrl(FORMAT, "/channels/%S/messages", gch->si->ptszID);
+ Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr, &body));
+ }
+ break;
+
+ case GC_USER_PRIVMESS:
+ Chat_SendPrivateMessage(gch);
+ break;
+
+ case GC_USER_LOGMENU:
+ Chat_ProcessLogMenu(gch);
+ break;
+
+ case GC_USER_NICKLISTMENU:
+ Chat_ProcessNickMenu(gch);
+ break;
+
+ case GC_USER_TYPNOTIFY:
+ UserIsTyping(gch->si->hContact, (int)gch->dwData);
+ break;
+ }
+
+ return 1;
+}
diff --git a/protocols/Discord/src/guilds.cpp b/protocols/Discord/src/guilds.cpp index d05ff80863..760437ceb0 100644 --- a/protocols/Discord/src/guilds.cpp +++ b/protocols/Discord/src/guilds.cpp @@ -1,413 +1,413 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2); - -static int compareRoles(const CDiscordRole *p1, const CDiscordRole *p2) -{ - return compareInt64(p1->id, p2->id); -} - -static int compareChatUsers(const CDiscordGuildMember *p1, const CDiscordGuildMember *p2) -{ - return compareInt64(p1->userId, p2->userId); -} - -CDiscordGuild::CDiscordGuild(SnowFlake _id) : - id(_id), - arChannels(10, compareUsers), - arChatUsers(30, compareChatUsers), - arRoles(10, compareRoles) -{ -} - -CDiscordGuild::~CDiscordGuild() -{ -} - -CDiscordUser::~CDiscordUser() -{ - if (pGuild != nullptr) - pGuild->arChannels.remove(this); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// reads a presence block from json - -void CDiscordProto::ProcessPresence(const JSONNode &root) -{ - auto userId = ::getId(root["user"]["id"]); - CDiscordUser *pUser = FindUser(userId); - if (pUser == nullptr) { - debugLogA("Presence from unknown user id %lld ignored", userId); - return; - } - - setWord(pUser->hContact, "Status", StrToStatus(root["status"].as_mstring())); - - CheckAvatarChange(pUser->hContact, root["user"]["avatar"].as_mstring()); - - for (auto &act : root["activities"]) { - CMStringW wszStatus(act["state"].as_mstring()); - if (!wszStatus.IsEmpty()) - db_set_ws(pUser->hContact, "CList", "StatusMsg", wszStatus); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// reads a role from json - -void CDiscordProto::ProcessRole(CDiscordGuild *guild, const JSONNode &role) -{ - SnowFlake id = ::getId(role["id"]); - CDiscordRole *p = guild->arRoles.find((CDiscordRole*)&id); - if (p == nullptr) { - p = new CDiscordRole(); - p->id = id; - guild->arRoles.insert(p); - } - - p->color = role["color"].as_int(); - p->position = role["position"].as_int(); - p->permissions = role["permissions"].as_int(); - p->wszName = role["name"].as_mstring(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void sttSetGroupName(MCONTACT hContact, const wchar_t *pwszGroupName) -{ - ptrW wszOldName(Clist_GetGroup(hContact)); - if (wszOldName != nullptr) { - ptrW wszChatGroup(Chat_GetGroup()); - if (mir_wstrcmpi(wszOldName, wszChatGroup)) - return; // custom group, don't touch it - } - - Clist_SetGroup(hContact, pwszGroupName); -} - -void CDiscordProto::BatchChatCreate(void *param) -{ - CDiscordGuild *pGuild = (CDiscordGuild*)param; - - for (auto &it : pGuild->arChannels) - if (!it->bIsPrivate && !it->bIsGroup) - CreateChat(pGuild, it); -} - -void CDiscordProto::CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser) -{ - SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, pUser->wszUsername, pUser->wszChannelName); - si->pParent = pGuild->pParentSi; - pUser->hContact = si->hContact; - setId(pUser->hContact, DB_KEY_ID, pUser->channelId); - setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId); - - SnowFlake oldMsgId = getId(pUser->hContact, DB_KEY_LASTMSGID); - if (oldMsgId == 0) - RetrieveHistory(pUser, MSG_BEFORE, pUser->lastMsgId, 20); - else if (!pUser->bSynced && pUser->lastMsgId > oldMsgId) { - pUser->bSynced = true; - RetrieveHistory(pUser, MSG_AFTER, oldMsgId, 99); - } - - if (m_bUseGuildGroups) { - if (pUser->parentId) { - CDiscordUser *pParent = FindUserByChannel(pUser->parentId); - if (pParent != nullptr) - sttSetGroupName(pUser->hContact, pParent->wszChannelName); - } - else sttSetGroupName(pUser->hContact, Clist_GroupGetName(pGuild->groupId)); - } - - BuildStatusList(pGuild, si); - - Chat_Control(m_szModuleName, pUser->wszUsername, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); - Chat_Control(m_szModuleName, pUser->wszUsername, SESSION_ONLINE); - - if (!pUser->wszTopic.IsEmpty()) { - Chat_SetStatusbarText(m_szModuleName, pUser->wszUsername, pUser->wszTopic); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC }; - gce.pszID.w = pUser->wszUsername; - gce.time = time(0); - gce.pszText.w = pUser->wszTopic; - Chat_Event(&gce); - } -} - -void CDiscordProto::ProcessGuild(const JSONNode &pRoot) -{ - SnowFlake guildId = ::getId(pRoot["id"]); - - CDiscordGuild *pGuild = FindGuild(guildId); - if (pGuild == nullptr) { - pGuild = new CDiscordGuild(guildId); - pGuild->LoadFromFile(); - arGuilds.insert(pGuild); - } - - pGuild->ownerId = ::getId(pRoot["owner_id"]); - pGuild->wszName = pRoot["name"].as_mstring(); - if (m_bUseGuildGroups) - pGuild->groupId = Clist_GroupCreate(Clist_GroupExists(m_wszDefaultGroup), pGuild->wszName); - - SESSION_INFO *si = Chat_NewSession(GCW_SERVER, m_szModuleName, pGuild->wszName, pGuild->wszName, pGuild); - if (si == nullptr) - return; - - pGuild->pParentSi = (SESSION_INFO*)si; - pGuild->hContact = si->hContact; - setId(pGuild->hContact, DB_KEY_CHANNELID, guildId); - - Chat_Control(m_szModuleName, pGuild->wszName, WINDOW_HIDDEN); - Chat_Control(m_szModuleName, pGuild->wszName, SESSION_ONLINE); - - for (auto &it : pRoot["roles"]) - ProcessRole(pGuild, it); - - BuildStatusList(pGuild, si); - - for (auto &it : pRoot["channels"]) - ProcessGuildChannel(pGuild, it); - - if (!pGuild->bSynced && getByte(si->hContact, "EnableSync")) - GatewaySendGuildInfo(pGuild); - - // store all guild members - for (auto &it : pRoot["members"]) { - auto *pm = ProcessGuildUser(pGuild, it); - - CMStringW wszNick = it["nick"].as_mstring(); - if (!wszNick.IsEmpty()) - pm->wszNick = wszNick; - - pm->iStatus = ID_STATUS_OFFLINE; - } - - // parse online statuses - for (auto &it : pRoot["presences"]) { - CDiscordGuildMember *gm = pGuild->FindUser(::getId(it["user"]["id"])); - if (gm != nullptr) - gm->iStatus = StrToStatus(it["status"].as_mstring()); - } - - for (auto &it : pGuild->arChatUsers) - AddGuildUser(pGuild, *it); - - if (!m_bTerminated) - ForkThread(&CDiscordProto::BatchChatCreate, pGuild); - - pGuild->bSynced = true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CDiscordUser* CDiscordProto::ProcessGuildChannel(CDiscordGuild *pGuild, const JSONNode &pch) -{ - CMStringW wszChannelId = pch["id"].as_mstring(); - SnowFlake channelId = _wtoi64(wszChannelId); - CMStringW wszName = pch["name"].as_mstring(); - CDiscordUser *pUser; - - // filter our all channels but the text ones - switch (pch["type"].as_int()) { - case 4: // channel group - if (!m_bUseGuildGroups) // ignore groups when they aren't enabled - return nullptr; - - pUser = FindUserByChannel(channelId); - if (pUser == nullptr) { - // missing channel - create it - pUser = new CDiscordUser(channelId); - pUser->bIsPrivate = false; - pUser->channelId = channelId; - pUser->bIsGroup = true; - arUsers.insert(pUser); - - pGuild->arChannels.insert(pUser); - - MGROUP grpId = Clist_GroupCreate(pGuild->groupId, wszName); - pUser->wszChannelName = Clist_GroupGetName(grpId); - } - return pUser; - - case 0: // text channel - pUser = FindUserByChannel(channelId); - if (pUser == nullptr) { - // missing channel - create it - pUser = new CDiscordUser(channelId); - pUser->bIsPrivate = false; - pUser->channelId = channelId; - arUsers.insert(pUser); - } - - if (pGuild->arChannels.find(pUser) == nullptr) - pGuild->arChannels.insert(pUser); - - pUser->wszUsername = wszChannelId; - if (m_bUseGuildGroups) - pUser->wszChannelName = L"#" + wszName; - else - pUser->wszChannelName = pGuild->wszName + L"#" + wszName; - pUser->wszTopic = pch["topic"].as_mstring(); - pUser->pGuild = pGuild; - pUser->lastMsgId = ::getId(pch["last_message_id"]); - pUser->parentId = _wtoi64(pch["parent_id"].as_mstring()); - return pUser; - } - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CDiscordGuildMember* CDiscordProto::ProcessGuildUser(CDiscordGuild *pGuild, const JSONNode &pRoot, bool *pbNew) -{ - auto& pUser = pRoot["user"]; - - bool bNew = false; - CMStringW wszUserId = pUser["id"].as_mstring(); - SnowFlake userId = _wtoi64(wszUserId); - CDiscordGuildMember *pm = pGuild->FindUser(userId); - if (pm == nullptr) { - pm = new CDiscordGuildMember(userId); - pGuild->arChatUsers.insert(pm); - bNew = true; - } - - pm->wszDiscordId = pUser["username"].as_mstring() + L"#" + pUser["discriminator"].as_mstring(); - pm->wszNick = pRoot["nick"].as_mstring(); - if (pm->wszNick.IsEmpty()) - pm->wszNick = pUser["username"].as_mstring(); - else - bNew = true; - - if (userId == pGuild->ownerId) - pm->wszRole = L"@owner"; - else { - CDiscordRole *pRole = nullptr; - for (auto &itr : pRoot["roles"]) { - SnowFlake roleId = ::getId(itr); - if (pRole = pGuild->arRoles.find((CDiscordRole *)&roleId)) - break; - } - pm->wszRole = (pRole == nullptr) ? L"@everyone" : pRole->wszName; - } - - if (pbNew) - *pbNew = bNew; - return pm; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::ProcessChatUser(CDiscordUser *pChat, const CMStringW &wszUserId, const JSONNode &pRoot) -{ - // input data control - SnowFlake userId = _wtoi64(wszUserId); - CDiscordGuild *pGuild = pChat->pGuild; - if (pGuild == nullptr || userId == 0) - return; - - // does user exist? if yes, there's nothing to do - auto *pm = pGuild->FindUser(userId); - if (pm != nullptr) - return; - - // otherwise let's create a user and insert him into all guild's chats - pm = new CDiscordGuildMember(userId); - pm->wszDiscordId = pRoot["author"]["username"].as_mstring() + L"#" + pRoot["author"]["discriminator"].as_mstring(); - pm->wszNick = pRoot["nick"].as_mstring(); - if (pm->wszNick.IsEmpty()) - pm->wszNick = pRoot["author"]["username"].as_mstring(); - pGuild->arChatUsers.insert(pm); - - debugLogA("add missing user to chat: id=%lld, nick=%S", userId, pm->wszNick.c_str()); - AddGuildUser(pGuild, *pm); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::AddGuildUser(CDiscordGuild *pGuild, const CDiscordGuildMember &pUser) -{ - int flags = 0; - switch (pUser.iStatus) { - case ID_STATUS_ONLINE: case ID_STATUS_NA: case ID_STATUS_DND: - flags = 1; - break; - } - - auto *pStatus = g_chatApi.TM_FindStatus(pGuild->pParentSi->pStatuses, pUser.wszRole); - - wchar_t wszUserId[100]; - _i64tow_s(pUser.userId, wszUserId, _countof(wszUserId), 10); - - auto *pu = g_chatApi.UM_AddUser(pGuild->pParentSi, wszUserId, pUser.wszNick, (pStatus) ? pStatus->iStatus : 0); - pu->iStatusEx = flags; - if (pUser.userId == m_ownId) - pGuild->pParentSi->pMe = pu; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordGuild::LoadFromFile() -{ - int fileNo = _wopen(GetCacheFile(), O_TEXT | O_RDONLY); - if (fileNo == -1) - return; - - int fSize = ::filelength(fileNo); - ptrA json((char*)mir_alloc(fSize + 1)); - read(fileNo, json, fSize); - close(fileNo); - - JSONNode cached = JSONNode::parse(json); - for (auto &it : cached) { - SnowFlake userId = getId(it["id"]); - auto *pUser = FindUser(userId); - if (pUser == nullptr) { - pUser = new CDiscordGuildMember(userId); - arChatUsers.insert(pUser); - } - - pUser->wszNick = it["n"].as_mstring(); - pUser->wszRole = it["r"].as_mstring(); - } -} - -void CDiscordGuild ::SaveToFile() -{ - JSONNode members(JSON_ARRAY); - for (auto &it : arChatUsers) { - JSONNode member; - member << INT64_PARAM("id", it->userId) << WCHAR_PARAM("n", it->wszNick) << WCHAR_PARAM("r", it->wszRole); - members << member; - } - - CMStringW wszFileName(GetCacheFile()); - CreatePathToFileW(wszFileName); - int fileNo = _wopen(wszFileName, O_CREAT | O_TRUNC | O_TEXT | O_WRONLY); - if (fileNo != -1) { - std::string json = members.write_formatted(); - write(fileNo, json.c_str(), (int)json.size()); - close(fileNo); - } -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2);
+
+static int compareRoles(const CDiscordRole *p1, const CDiscordRole *p2)
+{
+ return compareInt64(p1->id, p2->id);
+}
+
+static int compareChatUsers(const CDiscordGuildMember *p1, const CDiscordGuildMember *p2)
+{
+ return compareInt64(p1->userId, p2->userId);
+}
+
+CDiscordGuild::CDiscordGuild(SnowFlake _id) :
+ id(_id),
+ arChannels(10, compareUsers),
+ arChatUsers(30, compareChatUsers),
+ arRoles(10, compareRoles)
+{
+}
+
+CDiscordGuild::~CDiscordGuild()
+{
+}
+
+CDiscordUser::~CDiscordUser()
+{
+ if (pGuild != nullptr)
+ pGuild->arChannels.remove(this);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// reads a presence block from json
+
+void CDiscordProto::ProcessPresence(const JSONNode &root)
+{
+ auto userId = ::getId(root["user"]["id"]);
+ CDiscordUser *pUser = FindUser(userId);
+ if (pUser == nullptr) {
+ debugLogA("Presence from unknown user id %lld ignored", userId);
+ return;
+ }
+
+ setWord(pUser->hContact, "Status", StrToStatus(root["status"].as_mstring()));
+
+ CheckAvatarChange(pUser->hContact, root["user"]["avatar"].as_mstring());
+
+ for (auto &act : root["activities"]) {
+ CMStringW wszStatus(act["state"].as_mstring());
+ if (!wszStatus.IsEmpty())
+ db_set_ws(pUser->hContact, "CList", "StatusMsg", wszStatus);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// reads a role from json
+
+void CDiscordProto::ProcessRole(CDiscordGuild *guild, const JSONNode &role)
+{
+ SnowFlake id = ::getId(role["id"]);
+ CDiscordRole *p = guild->arRoles.find((CDiscordRole*)&id);
+ if (p == nullptr) {
+ p = new CDiscordRole();
+ p->id = id;
+ guild->arRoles.insert(p);
+ }
+
+ p->color = role["color"].as_int();
+ p->position = role["position"].as_int();
+ p->permissions = role["permissions"].as_int();
+ p->wszName = role["name"].as_mstring();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void sttSetGroupName(MCONTACT hContact, const wchar_t *pwszGroupName)
+{
+ ptrW wszOldName(Clist_GetGroup(hContact));
+ if (wszOldName != nullptr) {
+ ptrW wszChatGroup(Chat_GetGroup());
+ if (mir_wstrcmpi(wszOldName, wszChatGroup))
+ return; // custom group, don't touch it
+ }
+
+ Clist_SetGroup(hContact, pwszGroupName);
+}
+
+void CDiscordProto::BatchChatCreate(void *param)
+{
+ CDiscordGuild *pGuild = (CDiscordGuild*)param;
+
+ for (auto &it : pGuild->arChannels)
+ if (!it->bIsPrivate && !it->bIsGroup)
+ CreateChat(pGuild, it);
+}
+
+void CDiscordProto::CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser)
+{
+ SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, pUser->wszUsername, pUser->wszChannelName);
+ si->pParent = pGuild->pParentSi;
+ pUser->hContact = si->hContact;
+ setId(pUser->hContact, DB_KEY_ID, pUser->channelId);
+ setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
+
+ SnowFlake oldMsgId = getId(pUser->hContact, DB_KEY_LASTMSGID);
+ if (oldMsgId == 0)
+ RetrieveHistory(pUser, MSG_BEFORE, pUser->lastMsgId, 20);
+ else if (!pUser->bSynced && pUser->lastMsgId > oldMsgId) {
+ pUser->bSynced = true;
+ RetrieveHistory(pUser, MSG_AFTER, oldMsgId, 99);
+ }
+
+ if (m_bUseGuildGroups) {
+ if (pUser->parentId) {
+ CDiscordUser *pParent = FindUserByChannel(pUser->parentId);
+ if (pParent != nullptr)
+ sttSetGroupName(pUser->hContact, pParent->wszChannelName);
+ }
+ else sttSetGroupName(pUser->hContact, Clist_GroupGetName(pGuild->groupId));
+ }
+
+ BuildStatusList(pGuild, si);
+
+ Chat_Control(m_szModuleName, pUser->wszUsername, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE);
+ Chat_Control(m_szModuleName, pUser->wszUsername, SESSION_ONLINE);
+
+ if (!pUser->wszTopic.IsEmpty()) {
+ Chat_SetStatusbarText(m_szModuleName, pUser->wszUsername, pUser->wszTopic);
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC };
+ gce.pszID.w = pUser->wszUsername;
+ gce.time = time(0);
+ gce.pszText.w = pUser->wszTopic;
+ Chat_Event(&gce);
+ }
+}
+
+void CDiscordProto::ProcessGuild(const JSONNode &pRoot)
+{
+ SnowFlake guildId = ::getId(pRoot["id"]);
+
+ CDiscordGuild *pGuild = FindGuild(guildId);
+ if (pGuild == nullptr) {
+ pGuild = new CDiscordGuild(guildId);
+ pGuild->LoadFromFile();
+ arGuilds.insert(pGuild);
+ }
+
+ pGuild->ownerId = ::getId(pRoot["owner_id"]);
+ pGuild->wszName = pRoot["name"].as_mstring();
+ if (m_bUseGuildGroups)
+ pGuild->groupId = Clist_GroupCreate(Clist_GroupExists(m_wszDefaultGroup), pGuild->wszName);
+
+ SESSION_INFO *si = Chat_NewSession(GCW_SERVER, m_szModuleName, pGuild->wszName, pGuild->wszName, pGuild);
+ if (si == nullptr)
+ return;
+
+ pGuild->pParentSi = (SESSION_INFO*)si;
+ pGuild->hContact = si->hContact;
+ setId(pGuild->hContact, DB_KEY_CHANNELID, guildId);
+
+ Chat_Control(m_szModuleName, pGuild->wszName, WINDOW_HIDDEN);
+ Chat_Control(m_szModuleName, pGuild->wszName, SESSION_ONLINE);
+
+ for (auto &it : pRoot["roles"])
+ ProcessRole(pGuild, it);
+
+ BuildStatusList(pGuild, si);
+
+ for (auto &it : pRoot["channels"])
+ ProcessGuildChannel(pGuild, it);
+
+ if (!pGuild->bSynced && getByte(si->hContact, "EnableSync"))
+ GatewaySendGuildInfo(pGuild);
+
+ // store all guild members
+ for (auto &it : pRoot["members"]) {
+ auto *pm = ProcessGuildUser(pGuild, it);
+
+ CMStringW wszNick = it["nick"].as_mstring();
+ if (!wszNick.IsEmpty())
+ pm->wszNick = wszNick;
+
+ pm->iStatus = ID_STATUS_OFFLINE;
+ }
+
+ // parse online statuses
+ for (auto &it : pRoot["presences"]) {
+ CDiscordGuildMember *gm = pGuild->FindUser(::getId(it["user"]["id"]));
+ if (gm != nullptr)
+ gm->iStatus = StrToStatus(it["status"].as_mstring());
+ }
+
+ for (auto &it : pGuild->arChatUsers)
+ AddGuildUser(pGuild, *it);
+
+ if (!m_bTerminated)
+ ForkThread(&CDiscordProto::BatchChatCreate, pGuild);
+
+ pGuild->bSynced = true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CDiscordUser* CDiscordProto::ProcessGuildChannel(CDiscordGuild *pGuild, const JSONNode &pch)
+{
+ CMStringW wszChannelId = pch["id"].as_mstring();
+ SnowFlake channelId = _wtoi64(wszChannelId);
+ CMStringW wszName = pch["name"].as_mstring();
+ CDiscordUser *pUser;
+
+ // filter our all channels but the text ones
+ switch (pch["type"].as_int()) {
+ case 4: // channel group
+ if (!m_bUseGuildGroups) // ignore groups when they aren't enabled
+ return nullptr;
+
+ pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ // missing channel - create it
+ pUser = new CDiscordUser(channelId);
+ pUser->bIsPrivate = false;
+ pUser->channelId = channelId;
+ pUser->bIsGroup = true;
+ arUsers.insert(pUser);
+
+ pGuild->arChannels.insert(pUser);
+
+ MGROUP grpId = Clist_GroupCreate(pGuild->groupId, wszName);
+ pUser->wszChannelName = Clist_GroupGetName(grpId);
+ }
+ return pUser;
+
+ case 0: // text channel
+ pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ // missing channel - create it
+ pUser = new CDiscordUser(channelId);
+ pUser->bIsPrivate = false;
+ pUser->channelId = channelId;
+ arUsers.insert(pUser);
+ }
+
+ if (pGuild->arChannels.find(pUser) == nullptr)
+ pGuild->arChannels.insert(pUser);
+
+ pUser->wszUsername = wszChannelId;
+ if (m_bUseGuildGroups)
+ pUser->wszChannelName = L"#" + wszName;
+ else
+ pUser->wszChannelName = pGuild->wszName + L"#" + wszName;
+ pUser->wszTopic = pch["topic"].as_mstring();
+ pUser->pGuild = pGuild;
+ pUser->lastMsgId = ::getId(pch["last_message_id"]);
+ pUser->parentId = _wtoi64(pch["parent_id"].as_mstring());
+ return pUser;
+ }
+
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CDiscordGuildMember* CDiscordProto::ProcessGuildUser(CDiscordGuild *pGuild, const JSONNode &pRoot, bool *pbNew)
+{
+ auto& pUser = pRoot["user"];
+
+ bool bNew = false;
+ CMStringW wszUserId = pUser["id"].as_mstring();
+ SnowFlake userId = _wtoi64(wszUserId);
+ CDiscordGuildMember *pm = pGuild->FindUser(userId);
+ if (pm == nullptr) {
+ pm = new CDiscordGuildMember(userId);
+ pGuild->arChatUsers.insert(pm);
+ bNew = true;
+ }
+
+ pm->wszDiscordId = pUser["username"].as_mstring() + L"#" + pUser["discriminator"].as_mstring();
+ pm->wszNick = pRoot["nick"].as_mstring();
+ if (pm->wszNick.IsEmpty())
+ pm->wszNick = pUser["username"].as_mstring();
+ else
+ bNew = true;
+
+ if (userId == pGuild->ownerId)
+ pm->wszRole = L"@owner";
+ else {
+ CDiscordRole *pRole = nullptr;
+ for (auto &itr : pRoot["roles"]) {
+ SnowFlake roleId = ::getId(itr);
+ if (pRole = pGuild->arRoles.find((CDiscordRole *)&roleId))
+ break;
+ }
+ pm->wszRole = (pRole == nullptr) ? L"@everyone" : pRole->wszName;
+ }
+
+ if (pbNew)
+ *pbNew = bNew;
+ return pm;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::ProcessChatUser(CDiscordUser *pChat, const CMStringW &wszUserId, const JSONNode &pRoot)
+{
+ // input data control
+ SnowFlake userId = _wtoi64(wszUserId);
+ CDiscordGuild *pGuild = pChat->pGuild;
+ if (pGuild == nullptr || userId == 0)
+ return;
+
+ // does user exist? if yes, there's nothing to do
+ auto *pm = pGuild->FindUser(userId);
+ if (pm != nullptr)
+ return;
+
+ // otherwise let's create a user and insert him into all guild's chats
+ pm = new CDiscordGuildMember(userId);
+ pm->wszDiscordId = pRoot["author"]["username"].as_mstring() + L"#" + pRoot["author"]["discriminator"].as_mstring();
+ pm->wszNick = pRoot["nick"].as_mstring();
+ if (pm->wszNick.IsEmpty())
+ pm->wszNick = pRoot["author"]["username"].as_mstring();
+ pGuild->arChatUsers.insert(pm);
+
+ debugLogA("add missing user to chat: id=%lld, nick=%S", userId, pm->wszNick.c_str());
+ AddGuildUser(pGuild, *pm);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::AddGuildUser(CDiscordGuild *pGuild, const CDiscordGuildMember &pUser)
+{
+ int flags = 0;
+ switch (pUser.iStatus) {
+ case ID_STATUS_ONLINE: case ID_STATUS_NA: case ID_STATUS_DND:
+ flags = 1;
+ break;
+ }
+
+ auto *pStatus = g_chatApi.TM_FindStatus(pGuild->pParentSi->pStatuses, pUser.wszRole);
+
+ wchar_t wszUserId[100];
+ _i64tow_s(pUser.userId, wszUserId, _countof(wszUserId), 10);
+
+ auto *pu = g_chatApi.UM_AddUser(pGuild->pParentSi, wszUserId, pUser.wszNick, (pStatus) ? pStatus->iStatus : 0);
+ pu->iStatusEx = flags;
+ if (pUser.userId == m_ownId)
+ pGuild->pParentSi->pMe = pu;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordGuild::LoadFromFile()
+{
+ int fileNo = _wopen(GetCacheFile(), O_TEXT | O_RDONLY);
+ if (fileNo == -1)
+ return;
+
+ int fSize = ::filelength(fileNo);
+ ptrA json((char*)mir_alloc(fSize + 1));
+ read(fileNo, json, fSize);
+ close(fileNo);
+
+ JSONNode cached = JSONNode::parse(json);
+ for (auto &it : cached) {
+ SnowFlake userId = getId(it["id"]);
+ auto *pUser = FindUser(userId);
+ if (pUser == nullptr) {
+ pUser = new CDiscordGuildMember(userId);
+ arChatUsers.insert(pUser);
+ }
+
+ pUser->wszNick = it["n"].as_mstring();
+ pUser->wszRole = it["r"].as_mstring();
+ }
+}
+
+void CDiscordGuild ::SaveToFile()
+{
+ JSONNode members(JSON_ARRAY);
+ for (auto &it : arChatUsers) {
+ JSONNode member;
+ member << INT64_PARAM("id", it->userId) << WCHAR_PARAM("n", it->wszNick) << WCHAR_PARAM("r", it->wszRole);
+ members << member;
+ }
+
+ CMStringW wszFileName(GetCacheFile());
+ CreatePathToFileW(wszFileName);
+ int fileNo = _wopen(wszFileName, O_CREAT | O_TRUNC | O_TEXT | O_WRONLY);
+ if (fileNo != -1) {
+ std::string json = members.write_formatted();
+ write(fileNo, json.c_str(), (int)json.size());
+ close(fileNo);
+ }
+}
diff --git a/protocols/Discord/src/http.cpp b/protocols/Discord/src/http.cpp index 2facf00af7..f65451f9ce 100644 --- a/protocols/Discord/src/http.cpp +++ b/protocols/Discord/src/http.cpp @@ -1,155 +1,155 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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 CDiscordProto::Push(AsyncHttpRequest *pReq, int iTimeout) -{ - pReq->timeout = iTimeout; - { - mir_cslock lck(m_csHttpQueue); - m_arHttpQueue.insert(pReq); - } - SetEvent(m_evRequestsQueue); -} - -void CDiscordProto::SaveToken(const JSONNode &data) -{ - CMStringA szToken = data["token"].as_mstring(); - if (!szToken.IsEmpty()) - m_szTempToken = szToken.Detach(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static LONG g_reqNum = 0; - -AsyncHttpRequest::AsyncHttpRequest(CDiscordProto *ppro, int iRequestType, LPCSTR _url, MTHttpRequestHandler pFunc, JSONNode *pRoot) -{ - if (*_url == '/') { // relative url leads to a site - m_szUrl = "https://discord.com/api/v8"; - m_szUrl += _url; - m_bMainSite = true; - } - else { - m_szUrl = _url; - m_bMainSite = false; - } - - flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_SSL; - if (ppro->m_szAccessToken != nullptr) { - AddHeader("Authorization", ppro->m_szAccessToken); - flags |= NLHRF_DUMPASTEXT | NLHRF_NODUMPHEADERS; - } - else flags |= NLHRF_NODUMPSEND; - - if (pRoot != nullptr) { - ptrW text(json_write(pRoot)); - pData = mir_utf8encodeW(text); - dataLength = (int)mir_strlen(pData); - - AddHeader("Content-Type", "application/json"); - } - - m_pFunc = pFunc; - requestType = iRequestType; - m_iErrorCode = 0; - m_iReqNum = ::InterlockedIncrement(&g_reqNum); -} - -JsonReply::JsonReply(NETLIBHTTPREQUEST *pReply) -{ - if (pReply == nullptr) { - m_errorCode = 500; - return; - } - - m_errorCode = pReply->resultCode; - - m_root = json_parse(pReply->pData); - if (m_root == nullptr) - m_errorCode = 500; -} - -JsonReply::~JsonReply() -{ - json_delete(m_root); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::ServerThread(void*) -{ - m_szAccessToken = getStringA("AccessToken"); - m_hAPIConnection = nullptr; - m_bTerminated = false; - - debugLogA("CDiscordProto::WorkerThread: %s", "entering"); - - if (m_szAccessToken != nullptr) - RetrieveMyInfo(); // try to receive a response from server - else { - if (mir_wstrlen(m_wszEmail) == 0) { - ConnectionFailed(LOGINERR_BADUSERID); - return; - } - - ptrW wszPassword(getWStringA(DB_KEY_PASSWORD)); - if (wszPassword == nullptr) { - ConnectionFailed(LOGINERR_WRONGPASSWORD); - return; - } - - JSONNode root; root << WCHAR_PARAM("email", m_wszEmail) << WCHAR_PARAM("password", wszPassword); - Push(new AsyncHttpRequest(this, REQUEST_POST, "/auth/login", &CDiscordProto::OnReceiveToken, &root)); - } - - while (true) { - WaitForSingleObject(m_evRequestsQueue, 1000); - if (m_bTerminated) - break; - - AsyncHttpRequest *pReq; - bool need_sleep = false; - while (true) { - { - mir_cslock lck(m_csHttpQueue); - if (m_arHttpQueue.getCount() == 0) - break; - - pReq = m_arHttpQueue[0]; - m_arHttpQueue.remove(0); - need_sleep = (m_arHttpQueue.getCount() > 1); - } - if (m_bTerminated) - break; - ExecuteRequest(pReq); - if (need_sleep) { - Sleep(330); - debugLogA("CDiscordProto::WorkerThread: %s", "need to sleep"); - } - } - } - - m_hWorkerThread = nullptr; - if (m_hAPIConnection) { - Netlib_CloseHandle(m_hAPIConnection); - m_hAPIConnection = nullptr; - } - - debugLogA("CDiscordProto::WorkerThread: %s", "leaving"); -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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 CDiscordProto::Push(AsyncHttpRequest *pReq, int iTimeout)
+{
+ pReq->timeout = iTimeout;
+ {
+ mir_cslock lck(m_csHttpQueue);
+ m_arHttpQueue.insert(pReq);
+ }
+ SetEvent(m_evRequestsQueue);
+}
+
+void CDiscordProto::SaveToken(const JSONNode &data)
+{
+ CMStringA szToken = data["token"].as_mstring();
+ if (!szToken.IsEmpty())
+ m_szTempToken = szToken.Detach();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static LONG g_reqNum = 0;
+
+AsyncHttpRequest::AsyncHttpRequest(CDiscordProto *ppro, int iRequestType, LPCSTR _url, MTHttpRequestHandler pFunc, JSONNode *pRoot)
+{
+ if (*_url == '/') { // relative url leads to a site
+ m_szUrl = "https://discord.com/api/v8";
+ m_szUrl += _url;
+ m_bMainSite = true;
+ }
+ else {
+ m_szUrl = _url;
+ m_bMainSite = false;
+ }
+
+ flags = NLHRF_HTTP11 | NLHRF_REDIRECT | NLHRF_SSL;
+ if (ppro->m_szAccessToken != nullptr) {
+ AddHeader("Authorization", ppro->m_szAccessToken);
+ flags |= NLHRF_DUMPASTEXT | NLHRF_NODUMPHEADERS;
+ }
+ else flags |= NLHRF_NODUMPSEND;
+
+ if (pRoot != nullptr) {
+ ptrW text(json_write(pRoot));
+ pData = mir_utf8encodeW(text);
+ dataLength = (int)mir_strlen(pData);
+
+ AddHeader("Content-Type", "application/json");
+ }
+
+ m_pFunc = pFunc;
+ requestType = iRequestType;
+ m_iErrorCode = 0;
+ m_iReqNum = ::InterlockedIncrement(&g_reqNum);
+}
+
+JsonReply::JsonReply(NETLIBHTTPREQUEST *pReply)
+{
+ if (pReply == nullptr) {
+ m_errorCode = 500;
+ return;
+ }
+
+ m_errorCode = pReply->resultCode;
+
+ m_root = json_parse(pReply->pData);
+ if (m_root == nullptr)
+ m_errorCode = 500;
+}
+
+JsonReply::~JsonReply()
+{
+ json_delete(m_root);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::ServerThread(void*)
+{
+ m_szAccessToken = getStringA("AccessToken");
+ m_hAPIConnection = nullptr;
+ m_bTerminated = false;
+
+ debugLogA("CDiscordProto::WorkerThread: %s", "entering");
+
+ if (m_szAccessToken != nullptr)
+ RetrieveMyInfo(); // try to receive a response from server
+ else {
+ if (mir_wstrlen(m_wszEmail) == 0) {
+ ConnectionFailed(LOGINERR_BADUSERID);
+ return;
+ }
+
+ ptrW wszPassword(getWStringA(DB_KEY_PASSWORD));
+ if (wszPassword == nullptr) {
+ ConnectionFailed(LOGINERR_WRONGPASSWORD);
+ return;
+ }
+
+ JSONNode root; root << WCHAR_PARAM("email", m_wszEmail) << WCHAR_PARAM("password", wszPassword);
+ Push(new AsyncHttpRequest(this, REQUEST_POST, "/auth/login", &CDiscordProto::OnReceiveToken, &root));
+ }
+
+ while (true) {
+ WaitForSingleObject(m_evRequestsQueue, 1000);
+ if (m_bTerminated)
+ break;
+
+ AsyncHttpRequest *pReq;
+ bool need_sleep = false;
+ while (true) {
+ {
+ mir_cslock lck(m_csHttpQueue);
+ if (m_arHttpQueue.getCount() == 0)
+ break;
+
+ pReq = m_arHttpQueue[0];
+ m_arHttpQueue.remove(0);
+ need_sleep = (m_arHttpQueue.getCount() > 1);
+ }
+ if (m_bTerminated)
+ break;
+ ExecuteRequest(pReq);
+ if (need_sleep) {
+ Sleep(330);
+ debugLogA("CDiscordProto::WorkerThread: %s", "need to sleep");
+ }
+ }
+ }
+
+ m_hWorkerThread = nullptr;
+ if (m_hAPIConnection) {
+ Netlib_CloseHandle(m_hAPIConnection);
+ m_hAPIConnection = nullptr;
+ }
+
+ debugLogA("CDiscordProto::WorkerThread: %s", "leaving");
+}
diff --git a/protocols/Discord/src/main.cpp b/protocols/Discord/src/main.cpp index c615047d00..98f0b120de 100644 --- a/protocols/Discord/src/main.cpp +++ b/protocols/Discord/src/main.cpp @@ -1,71 +1,71 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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; - -///////////////////////////////////////////////////////////////////////////////////////// - -PLUGININFOEX pluginInfoEx = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {88928401-2CE8-4568-AAA7-226141870CBF} - { 0x88928401, 0x2ce8, 0x4568, { 0xaa, 0xa7, 0x22, 0x61, 0x41, 0x87, 0x0c, 0xbf } } -}; - -CMPlugin::CMPlugin() : - ACCPROTOPLUGIN<CDiscordProto>("Discord", pluginInfoEx) -{ - SetUniqueId(DB_KEY_ID); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Interface information - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST }; - -///////////////////////////////////////////////////////////////////////////////////////// -// Load - -IconItem g_iconList[] = -{ - { LPGEN("Main icon"), "main", IDI_MAIN }, - { LPGEN("Group chats"), "groupchat", IDI_GROUPCHAT }, - { LPGEN("Call"), "voicecall", IDI_VOICE_CALL }, - { LPGEN("Call ended"), "voiceend", IDI_VOICE_ENDED } -}; - -static int OnModulesLoaded(WPARAM, LPARAM) -{ - g_plugin.bVoiceService = ServiceExists(MS_VOICESERVICE_REGISTER); - return 0; -} - -int CMPlugin::Load() -{ - HookEvent(ME_SYSTEM_MODULESLOADED, &OnModulesLoaded); - - g_plugin.registerIcon("Protocols/Discord", g_iconList); - return 0; -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {88928401-2CE8-4568-AAA7-226141870CBF}
+ { 0x88928401, 0x2ce8, 0x4568, { 0xaa, 0xa7, 0x22, 0x61, 0x41, 0x87, 0x0c, 0xbf } }
+};
+
+CMPlugin::CMPlugin() :
+ ACCPROTOPLUGIN<CDiscordProto>("Discord", pluginInfoEx)
+{
+ SetUniqueId(DB_KEY_ID);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Interface information
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load
+
+IconItem g_iconList[] =
+{
+ { LPGEN("Main icon"), "main", IDI_MAIN },
+ { LPGEN("Group chats"), "groupchat", IDI_GROUPCHAT },
+ { LPGEN("Call"), "voicecall", IDI_VOICE_CALL },
+ { LPGEN("Call ended"), "voiceend", IDI_VOICE_ENDED }
+};
+
+static int OnModulesLoaded(WPARAM, LPARAM)
+{
+ g_plugin.bVoiceService = ServiceExists(MS_VOICESERVICE_REGISTER);
+ return 0;
+}
+
+int CMPlugin::Load()
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, &OnModulesLoaded);
+
+ g_plugin.registerIcon("Protocols/Discord", g_iconList);
+ return 0;
+}
diff --git a/protocols/Discord/src/menus.cpp b/protocols/Discord/src/menus.cpp index e88d91aa43..cc928221f3 100644 --- a/protocols/Discord/src/menus.cpp +++ b/protocols/Discord/src/menus.cpp @@ -1,172 +1,172 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -INT_PTR CDiscordProto::OnMenuCopyId(WPARAM hContact, LPARAM) -{ - CopyId(CMStringW(FORMAT, L"%s#%d", getMStringW(hContact, DB_KEY_NICK).c_str(), getDword(hContact, DB_KEY_DISCR))); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::OnMenuCreateChannel(WPARAM hContact, LPARAM) -{ - ENTER_STRING es = { m_szModuleName, "channel_name", TranslateT("Enter channel name"), nullptr, ESF_COMBO, 5 }; - if (EnterString(&es)) { - JSONNode roles(JSON_ARRAY); roles.set_name("permission_overwrites"); - JSONNode root; root << INT_PARAM("type", 0) << WCHAR_PARAM("name", es.ptszResult) << roles; - CMStringA szUrl(FORMAT, "/guilds/%lld/channels", getId(hContact, DB_KEY_CHANNELID)); - Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr, &root)); - mir_free(es.ptszResult); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::OnMenuJoinGuild(WPARAM, LPARAM) -{ - ENTER_STRING es = { m_szModuleName, "guild_name", TranslateT("Enter invitation code you received"), nullptr, ESF_COMBO, 5 }; - if (EnterString(&es)) { - CMStringA szUrl(FORMAT, "/invite/%S", es.ptszResult); - Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr)); - mir_free(es.ptszResult); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::OnMenuLeaveGuild(WPARAM hContact, LPARAM) -{ - if (IDYES == MessageBox(nullptr, TranslateT("Do you really want to leave the guild?"), m_tszUserName, MB_ICONQUESTION | MB_YESNOCANCEL)) { - CMStringA szUrl(FORMAT, "/users/@me/guilds/%lld", getId(hContact, DB_KEY_CHANNELID)); - Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr)); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::OnMenuLoadHistory(WPARAM hContact, LPARAM) -{ - auto *pUser = FindUser(getId(hContact, DB_KEY_ID)); - if (pUser) { - RetrieveHistory(pUser, MSG_AFTER, 0, 100); - delSetting(hContact, DB_KEY_LASTMSGID); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::OnMenuToggleSync(WPARAM hContact, LPARAM) -{ - bool bEnabled = !getBool(hContact, "EnableSync"); - setByte(hContact, "EnableSync", bEnabled); - - if (bEnabled) - if (auto *pGuild = FindGuild(getId(hContact, DB_KEY_CHANNELID))) - GatewaySendGuildInfo(pGuild); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CDiscordProto::OnMenuPrebuild(WPARAM hContact, LPARAM) -{ - // "Leave guild" menu item should be visible only for the guild contacts - bool bIsGuild = getByte(hContact, "ChatRoom") == 2; - Menu_ShowItem(m_hMenuLeaveGuild, bIsGuild); - Menu_ShowItem(m_hMenuCreateChannel, bIsGuild); - Menu_ShowItem(m_hMenuToggleSync, bIsGuild); - - if (!bIsGuild && getWord(hContact, "ApparentMode") != 0) - Menu_ShowItem(GetMenuItem(PROTO_MENU_REQ_AUTH), true); - - if (getByte(hContact, "EnableSync")) - Menu_ModifyItem(m_hMenuToggleSync, LPGENW("Disable sync"), Skin_GetIconHandle(SKINICON_CHAT_LEAVE)); - else - Menu_ModifyItem(m_hMenuToggleSync, LPGENW("Enable sync"), Skin_GetIconHandle(SKINICON_CHAT_JOIN)); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Protocol menu items - -void CDiscordProto::OnBuildProtoMenu() -{ - CMenuItem mi(&g_plugin); - mi.root = Menu_GetProtocolRoot(this); - mi.flags = CMIF_UNMOVABLE; - - mi.pszService = "/JoinGuild"; - CreateProtoService(mi.pszService, &CDiscordProto::OnMenuJoinGuild); - mi.name.a = LPGEN("Join guild"); - mi.position = 200001; - mi.hIcolibItem = g_iconList[1].hIcolib; - Menu_AddProtoMenuItem(&mi, m_szModuleName); - - mi.pszService = "/CopyId"; - CreateProtoService(mi.pszService, &CDiscordProto::OnMenuCopyId); - mi.name.a = LPGEN("Copy my Discord ID"); - mi.position = 200002; - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_USERONLINE); - Menu_AddProtoMenuItem(&mi, m_szModuleName); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Contact menu items - -void CDiscordProto::InitMenus() -{ - CMenuItem mi(&g_plugin); - mi.pszService = "/LeaveGuild"; - CreateProtoService(mi.pszService, &CDiscordProto::OnMenuLeaveGuild); - SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8C); - mi.name.a = LPGEN("Leave guild"); - mi.position = -200001000; - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_CHAT_LEAVE); - m_hMenuLeaveGuild = Menu_AddContactMenuItem(&mi, m_szModuleName); - - mi.pszService = "/CreateChannel"; - CreateProtoService(mi.pszService, &CDiscordProto::OnMenuCreateChannel); - SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8D); - mi.name.a = LPGEN("Create new channel"); - mi.position = -200001001; - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_ADDCONTACT); - m_hMenuCreateChannel = Menu_AddContactMenuItem(&mi, m_szModuleName); - - SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8E); - mi.pszService = "/CopyId"; - mi.name.a = LPGEN("Copy ID"); - mi.position = -200001002; - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_USERONLINE); - Menu_AddContactMenuItem(&mi, m_szModuleName); - - mi.pszService = "/ToggleSync"; - CreateProtoService(mi.pszService, &CDiscordProto::OnMenuToggleSync); - SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8F); - mi.name.a = LPGEN("Enable guild sync"); - mi.position = -200001003; - mi.hIcolibItem = Skin_GetIconHandle(SKINICON_CHAT_JOIN); - m_hMenuToggleSync = Menu_AddContactMenuItem(&mi, m_szModuleName); - - HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CDiscordProto::OnMenuPrebuild); -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+INT_PTR CDiscordProto::OnMenuCopyId(WPARAM hContact, LPARAM)
+{
+ CopyId(CMStringW(FORMAT, L"%s#%d", getMStringW(hContact, DB_KEY_NICK).c_str(), getDword(hContact, DB_KEY_DISCR)));
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::OnMenuCreateChannel(WPARAM hContact, LPARAM)
+{
+ ENTER_STRING es = { m_szModuleName, "channel_name", TranslateT("Enter channel name"), nullptr, ESF_COMBO, 5 };
+ if (EnterString(&es)) {
+ JSONNode roles(JSON_ARRAY); roles.set_name("permission_overwrites");
+ JSONNode root; root << INT_PARAM("type", 0) << WCHAR_PARAM("name", es.ptszResult) << roles;
+ CMStringA szUrl(FORMAT, "/guilds/%lld/channels", getId(hContact, DB_KEY_CHANNELID));
+ Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr, &root));
+ mir_free(es.ptszResult);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::OnMenuJoinGuild(WPARAM, LPARAM)
+{
+ ENTER_STRING es = { m_szModuleName, "guild_name", TranslateT("Enter invitation code you received"), nullptr, ESF_COMBO, 5 };
+ if (EnterString(&es)) {
+ CMStringA szUrl(FORMAT, "/invite/%S", es.ptszResult);
+ Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr));
+ mir_free(es.ptszResult);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::OnMenuLeaveGuild(WPARAM hContact, LPARAM)
+{
+ if (IDYES == MessageBox(nullptr, TranslateT("Do you really want to leave the guild?"), m_tszUserName, MB_ICONQUESTION | MB_YESNOCANCEL)) {
+ CMStringA szUrl(FORMAT, "/users/@me/guilds/%lld", getId(hContact, DB_KEY_CHANNELID));
+ Push(new AsyncHttpRequest(this, REQUEST_DELETE, szUrl, nullptr));
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::OnMenuLoadHistory(WPARAM hContact, LPARAM)
+{
+ auto *pUser = FindUser(getId(hContact, DB_KEY_ID));
+ if (pUser) {
+ RetrieveHistory(pUser, MSG_AFTER, 0, 100);
+ delSetting(hContact, DB_KEY_LASTMSGID);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::OnMenuToggleSync(WPARAM hContact, LPARAM)
+{
+ bool bEnabled = !getBool(hContact, "EnableSync");
+ setByte(hContact, "EnableSync", bEnabled);
+
+ if (bEnabled)
+ if (auto *pGuild = FindGuild(getId(hContact, DB_KEY_CHANNELID)))
+ GatewaySendGuildInfo(pGuild);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDiscordProto::OnMenuPrebuild(WPARAM hContact, LPARAM)
+{
+ // "Leave guild" menu item should be visible only for the guild contacts
+ bool bIsGuild = getByte(hContact, "ChatRoom") == 2;
+ Menu_ShowItem(m_hMenuLeaveGuild, bIsGuild);
+ Menu_ShowItem(m_hMenuCreateChannel, bIsGuild);
+ Menu_ShowItem(m_hMenuToggleSync, bIsGuild);
+
+ if (!bIsGuild && getWord(hContact, "ApparentMode") != 0)
+ Menu_ShowItem(GetMenuItem(PROTO_MENU_REQ_AUTH), true);
+
+ if (getByte(hContact, "EnableSync"))
+ Menu_ModifyItem(m_hMenuToggleSync, LPGENW("Disable sync"), Skin_GetIconHandle(SKINICON_CHAT_LEAVE));
+ else
+ Menu_ModifyItem(m_hMenuToggleSync, LPGENW("Enable sync"), Skin_GetIconHandle(SKINICON_CHAT_JOIN));
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Protocol menu items
+
+void CDiscordProto::OnBuildProtoMenu()
+{
+ CMenuItem mi(&g_plugin);
+ mi.root = Menu_GetProtocolRoot(this);
+ mi.flags = CMIF_UNMOVABLE;
+
+ mi.pszService = "/JoinGuild";
+ CreateProtoService(mi.pszService, &CDiscordProto::OnMenuJoinGuild);
+ mi.name.a = LPGEN("Join guild");
+ mi.position = 200001;
+ mi.hIcolibItem = g_iconList[1].hIcolib;
+ Menu_AddProtoMenuItem(&mi, m_szModuleName);
+
+ mi.pszService = "/CopyId";
+ CreateProtoService(mi.pszService, &CDiscordProto::OnMenuCopyId);
+ mi.name.a = LPGEN("Copy my Discord ID");
+ mi.position = 200002;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_USERONLINE);
+ Menu_AddProtoMenuItem(&mi, m_szModuleName);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Contact menu items
+
+void CDiscordProto::InitMenus()
+{
+ CMenuItem mi(&g_plugin);
+ mi.pszService = "/LeaveGuild";
+ CreateProtoService(mi.pszService, &CDiscordProto::OnMenuLeaveGuild);
+ SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8C);
+ mi.name.a = LPGEN("Leave guild");
+ mi.position = -200001000;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_CHAT_LEAVE);
+ m_hMenuLeaveGuild = Menu_AddContactMenuItem(&mi, m_szModuleName);
+
+ mi.pszService = "/CreateChannel";
+ CreateProtoService(mi.pszService, &CDiscordProto::OnMenuCreateChannel);
+ SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8D);
+ mi.name.a = LPGEN("Create new channel");
+ mi.position = -200001001;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_ADDCONTACT);
+ m_hMenuCreateChannel = Menu_AddContactMenuItem(&mi, m_szModuleName);
+
+ SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8E);
+ mi.pszService = "/CopyId";
+ mi.name.a = LPGEN("Copy ID");
+ mi.position = -200001002;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_OTHER_USERONLINE);
+ Menu_AddContactMenuItem(&mi, m_szModuleName);
+
+ mi.pszService = "/ToggleSync";
+ CreateProtoService(mi.pszService, &CDiscordProto::OnMenuToggleSync);
+ SET_UID(mi, 0x6EF11AD6, 0x6111, 0x4E29, 0xBA, 0x8B, 0xA7, 0xB2, 0xE0, 0x22, 0xE1, 0x8F);
+ mi.name.a = LPGEN("Enable guild sync");
+ mi.position = -200001003;
+ mi.hIcolibItem = Skin_GetIconHandle(SKINICON_CHAT_JOIN);
+ m_hMenuToggleSync = Menu_AddContactMenuItem(&mi, m_szModuleName);
+
+ HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CDiscordProto::OnMenuPrebuild);
+}
diff --git a/protocols/Discord/src/options.cpp b/protocols/Discord/src/options.cpp index 86f3519df8..3ced623311 100644 --- a/protocols/Discord/src/options.cpp +++ b/protocols/Discord/src/options.cpp @@ -1,100 +1,100 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -///////////////////////////////////////////////////////////////////////////////////////// - -class CDiscardAccountOptions : public CProtoDlgBase<CDiscordProto> -{ - CCtrlCheck chkUseChats, chkHideChats, chkUseGroups, chkDeleteMsgs; - CCtrlEdit m_edGroup, m_edUserName, m_edPassword; - ptrW m_wszOldGroup; - -public: - CDiscardAccountOptions(CDiscordProto *ppro, int iDlgID, bool bFullDlg) : - CProtoDlgBase<CDiscordProto>(ppro, iDlgID), - m_edGroup(this, IDC_GROUP), - m_edUserName(this, IDC_USERNAME), - m_edPassword(this, IDC_PASSWORD), - chkUseChats(this, IDC_USEGUILDS), - chkHideChats(this, IDC_HIDECHATS), - chkUseGroups(this, IDC_USEGROUPS), - chkDeleteMsgs(this, IDC_DELETE_MSGS), - m_wszOldGroup(mir_wstrdup(ppro->m_wszDefaultGroup)) - { - CreateLink(m_edGroup, ppro->m_wszDefaultGroup); - CreateLink(m_edUserName, ppro->m_wszEmail); - if (bFullDlg) { - CreateLink(chkUseChats, ppro->m_bUseGroupchats); - CreateLink(chkHideChats, ppro->m_bHideGroupchats); - CreateLink(chkUseGroups, ppro->m_bUseGuildGroups); - CreateLink(chkDeleteMsgs, ppro->m_bSyncDeleteMsgs); - - chkUseChats.OnChange = Callback(this, &CDiscardAccountOptions::onChange_GroupChats); - } - } - - bool OnInitDialog() override - { - ptrW buf(m_proto->getWStringA(DB_KEY_PASSWORD)); - if (buf) - m_edPassword.SetText(buf); - return true; - } - - bool OnApply() override - { - if (mir_wstrcmp(m_proto->m_wszDefaultGroup, m_wszOldGroup)) - Clist_GroupCreate(0, m_proto->m_wszDefaultGroup); - - ptrW buf(m_edPassword.GetText()); - m_proto->setWString(DB_KEY_PASSWORD, buf); - return true; - } - - void onChange_GroupChats(CCtrlCheck*) - { - bool bEnabled = chkUseChats.GetState(); - chkHideChats.Enable(bEnabled); - chkUseGroups.Enable(bEnabled); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::SvcCreateAccMgrUI(WPARAM, LPARAM hwndParent) -{ - CDiscardAccountOptions *pDlg = new CDiscardAccountOptions(this, IDD_OPTIONS_ACCMGR, false); - pDlg->SetParent((HWND)hwndParent); - pDlg->Create(); - return (INT_PTR)pDlg->GetHwnd(); -} - -int CDiscordProto::OnOptionsInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.szTitle.w = m_tszUserName; - odp.flags = ODPF_UNICODE; - odp.szGroup.w = LPGENW("Network"); - - odp.position = 1; - odp.szTab.w = LPGENW("Account"); - odp.pDialog = new CDiscardAccountOptions(this, IDD_OPTIONS_ACCOUNT, true); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class CDiscardAccountOptions : public CProtoDlgBase<CDiscordProto>
+{
+ CCtrlCheck chkUseChats, chkHideChats, chkUseGroups, chkDeleteMsgs;
+ CCtrlEdit m_edGroup, m_edUserName, m_edPassword;
+ ptrW m_wszOldGroup;
+
+public:
+ CDiscardAccountOptions(CDiscordProto *ppro, int iDlgID, bool bFullDlg) :
+ CProtoDlgBase<CDiscordProto>(ppro, iDlgID),
+ m_edGroup(this, IDC_GROUP),
+ m_edUserName(this, IDC_USERNAME),
+ m_edPassword(this, IDC_PASSWORD),
+ chkUseChats(this, IDC_USEGUILDS),
+ chkHideChats(this, IDC_HIDECHATS),
+ chkUseGroups(this, IDC_USEGROUPS),
+ chkDeleteMsgs(this, IDC_DELETE_MSGS),
+ m_wszOldGroup(mir_wstrdup(ppro->m_wszDefaultGroup))
+ {
+ CreateLink(m_edGroup, ppro->m_wszDefaultGroup);
+ CreateLink(m_edUserName, ppro->m_wszEmail);
+ if (bFullDlg) {
+ CreateLink(chkUseChats, ppro->m_bUseGroupchats);
+ CreateLink(chkHideChats, ppro->m_bHideGroupchats);
+ CreateLink(chkUseGroups, ppro->m_bUseGuildGroups);
+ CreateLink(chkDeleteMsgs, ppro->m_bSyncDeleteMsgs);
+
+ chkUseChats.OnChange = Callback(this, &CDiscardAccountOptions::onChange_GroupChats);
+ }
+ }
+
+ bool OnInitDialog() override
+ {
+ ptrW buf(m_proto->getWStringA(DB_KEY_PASSWORD));
+ if (buf)
+ m_edPassword.SetText(buf);
+ return true;
+ }
+
+ bool OnApply() override
+ {
+ if (mir_wstrcmp(m_proto->m_wszDefaultGroup, m_wszOldGroup))
+ Clist_GroupCreate(0, m_proto->m_wszDefaultGroup);
+
+ ptrW buf(m_edPassword.GetText());
+ m_proto->setWString(DB_KEY_PASSWORD, buf);
+ return true;
+ }
+
+ void onChange_GroupChats(CCtrlCheck*)
+ {
+ bool bEnabled = chkUseChats.GetState();
+ chkHideChats.Enable(bEnabled);
+ chkUseGroups.Enable(bEnabled);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::SvcCreateAccMgrUI(WPARAM, LPARAM hwndParent)
+{
+ CDiscardAccountOptions *pDlg = new CDiscardAccountOptions(this, IDD_OPTIONS_ACCMGR, false);
+ pDlg->SetParent((HWND)hwndParent);
+ pDlg->Create();
+ return (INT_PTR)pDlg->GetHwnd();
+}
+
+int CDiscordProto::OnOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szTitle.w = m_tszUserName;
+ odp.flags = ODPF_UNICODE;
+ odp.szGroup.w = LPGENW("Network");
+
+ odp.position = 1;
+ odp.szTab.w = LPGENW("Account");
+ odp.pDialog = new CDiscardAccountOptions(this, IDD_OPTIONS_ACCOUNT, true);
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/Discord/src/proto.cpp b/protocols/Discord/src/proto.cpp index 972c6ec312..2bd02f704d 100644 --- a/protocols/Discord/src/proto.cpp +++ b/protocols/Discord/src/proto.cpp @@ -1,768 +1,768 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -static int compareMessages(const COwnMessage *p1, const COwnMessage *p2) -{ - return compareInt64(p1->nonce, p2->nonce); -} - -static int compareRequests(const AsyncHttpRequest *p1, const AsyncHttpRequest *p2) -{ - return p1->m_iReqNum - p2->m_iReqNum; -} - -int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2) -{ - return compareInt64(p1->id, p2->id); -} - -static int compareGuilds(const CDiscordGuild *p1, const CDiscordGuild *p2) -{ - return compareInt64(p1->id, p2->id); -} - -CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) : - PROTO<CDiscordProto>(proto_name, username), - m_impl(*this), - m_arHttpQueue(10, compareRequests), - m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)), - arUsers(10, compareUsers), - arGuilds(1, compareGuilds), - arMarkReadQueue(1, compareUsers), - arOwnMessages(1, compareMessages), - arVoiceCalls(1), - - m_wszEmail(this, "Email", L""), - m_wszDefaultGroup(this, "GroupName", DB_KEYVAL_GROUP), - m_bUseGroupchats(this, "UseGroupChats", true), - m_bHideGroupchats(this, "HideChats", true), - m_bUseGuildGroups(this, "UseGuildGroups", false), - m_bSyncDeleteMsgs(this, "DeleteServerMsgs", true) -{ - // Services - CreateProtoService(PS_CREATEACCMGRUI, &CDiscordProto::SvcCreateAccMgrUI); - - CreateProtoService(PS_GETAVATARINFO, &CDiscordProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &CDiscordProto::GetAvatarCaps); - CreateProtoService(PS_GETMYAVATAR, &CDiscordProto::GetMyAvatar); - CreateProtoService(PS_SETMYAVATAR, &CDiscordProto::SetMyAvatar); - - CreateProtoService(PS_MENU_REQAUTH, &CDiscordProto::RequestFriendship); - CreateProtoService(PS_MENU_LOADHISTORY, &CDiscordProto::OnMenuLoadHistory); - - CreateProtoService(PS_VOICE_CAPS, &CDiscordProto::VoiceCaps); - - // Events - HookProtoEvent(ME_OPT_INITIALISE, &CDiscordProto::OnOptionsInit); - HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CDiscordProto::OnDbEventRead); - HookProtoEvent(ME_PROTO_ACCLISTCHANGED, &CDiscordProto::OnAccountChanged); - - HookProtoEvent(PE_VOICE_CALL_STATE, &CDiscordProto::OnVoiceState); - - // database - db_set_resident(m_szModuleName, "XStatusMsg"); - - // custom events - DBEVENTTYPEDESCR dbEventType = {}; - dbEventType.module = m_szModuleName; - dbEventType.flags = DETF_HISTORY | DETF_MSGWINDOW; - - dbEventType.eventType = EVENT_INCOMING_CALL; - dbEventType.descr = Translate("Incoming call"); - dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_CALL); - DbEvent_RegisterType(&dbEventType); - - dbEventType.eventType = EVENT_CALL_FINISHED; - dbEventType.descr = Translate("Call ended"); - dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_ENDED); - DbEvent_RegisterType(&dbEventType); - - // Groupchat initialization - GCREGISTER gcr = {}; - gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR; - gcr.ptszDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - Chat_Register(&gcr); - - // Network initialization - CMStringW descr; - NETLIBUSER nlu = {}; - - nlu.szSettingsModule = m_szModuleName; - nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; - descr.Format(TranslateT("%s server connection"), m_tszUserName); - nlu.szDescriptiveName.w = descr.GetBuffer(); - m_hNetlibUser = Netlib_RegisterUser(&nlu); - - CMStringA module(FORMAT, "%s.Gateway", m_szModuleName); - nlu.szSettingsModule = module.GetBuffer(); - nlu.flags = NUF_OUTGOING | NUF_UNICODE; - descr.Format(TranslateT("%s gateway connection"), m_tszUserName); - nlu.szDescriptiveName.w = descr.GetBuffer(); - m_hGatewayNetlibUser = Netlib_RegisterUser(&nlu); -} - -CDiscordProto::~CDiscordProto() -{ - debugLogA("CDiscordProto::~CDiscordProto"); - - for (auto &msg : m_wszStatusMsg) - mir_free(msg); - - arUsers.destroy(); - - m_arHttpQueue.destroy(); - ::CloseHandle(m_evRequestsQueue); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::OnModulesLoaded() -{ - std::vector<MCONTACT> lostIds; - - // Fill users list - for (auto &hContact : AccContacts()) { - CDiscordUser *pNew = new CDiscordUser(getId(hContact, DB_KEY_ID)); - pNew->hContact = hContact; - pNew->lastMsgId = getId(hContact, DB_KEY_LASTMSGID); - pNew->wszUsername = ptrW(getWStringA(hContact, DB_KEY_NICK)); - pNew->iDiscriminator = getDword(hContact, DB_KEY_DISCR); - - // set EnableSync = 1 by default for all existing guilds - switch (getByte(hContact, "ChatRoom")) { - case 2: // guild - delSetting(hContact, DB_KEY_CHANNELID); - if (getDword(hContact, "EnableSync", -1) == -1) - setDword(hContact, "EnableSync", 1); - break; - - case 1: // group chat - pNew->channelId = getId(hContact, DB_KEY_CHANNELID); - if (!pNew->channelId) { - lostIds.push_back(hContact); - delete pNew; - continue; - } - break; - - default: - pNew->channelId = getId(hContact, DB_KEY_CHANNELID); - break; - } - arUsers.insert(pNew); - } - - for (auto &hContact: lostIds) - db_delete_contact(hContact); - - // Clist - Clist_GroupCreate(0, m_wszDefaultGroup); - - HookProtoEvent(ME_GC_EVENT, &CDiscordProto::GroupchatEventHook); - HookProtoEvent(ME_GC_BUILDMENU, &CDiscordProto::GroupchatMenuHook); - - InitMenus(); - - // Voice support - if (g_plugin.bVoiceService) { - VOICE_MODULE voice = {}; - voice.cbSize = sizeof(voice); - voice.name = m_szModuleName; - voice.description = TranslateT("Discord voice call"); - voice.icon = m_hProtoIcon; - voice.flags = VOICE_CAPS_CALL_CONTACT | VOICE_CAPS_VOICE; - CallService(MS_VOICESERVICE_REGISTER, (WPARAM)&voice, 0); - } -} - -void CDiscordProto::OnShutdown() -{ - debugLogA("CDiscordProto::OnPreShutdown"); - - m_bTerminated = true; - SetEvent(m_evRequestsQueue); - - for (auto &it : arGuilds) - it->SaveToFile(); - - if (m_hGatewayConnection) - Netlib_Shutdown(m_hGatewayConnection); - - if (g_plugin.bVoiceService) - CallService(MS_VOICESERVICE_UNREGISTER, (WPARAM)m_szModuleName, 0); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::GetCaps(int type, MCONTACT) -{ - switch (type) { - case PFLAGNUM_1: - return PF1_IM | PF1_MODEMSG | PF1_MODEMSGRECV | PF1_SERVERCLIST | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_ADDSEARCHRES | PF1_FILESEND; - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_INVISIBLE; - case PFLAGNUM_3: - return PF2_ONLINE | PF2_LONGAWAY | PF2_HEAVYDND | PF2_INVISIBLE; - case PFLAGNUM_4: - return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_SUPPORTTYPING | PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDOFFLINE | PF4_SERVERMSGID | PF4_OFFLINEFILES; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)TranslateT("User ID"); - } - return 0; -} - -int CDiscordProto::SetStatus(int iNewStatus) -{ - debugLogA("CDiscordProto::SetStatus iNewStatus = %d, m_iStatus = %d, m_iDesiredStatus = %d m_hWorkerThread = %p", iNewStatus, m_iStatus, m_iDesiredStatus, m_hWorkerThread); - - if (iNewStatus == m_iStatus) - return 0; - - m_iDesiredStatus = iNewStatus; - int iOldStatus = m_iStatus; - - // go offline - if (iNewStatus == ID_STATUS_OFFLINE) { - if (m_bOnline) { - SetServerStatus(ID_STATUS_OFFLINE); - ShutdownSession(); - } - m_iStatus = m_iDesiredStatus; - setAllContactStatuses(ID_STATUS_OFFLINE, false); - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); - } - // not logged in? come on - else if (m_hWorkerThread == nullptr && !IsStatusConnecting(m_iStatus)) { - m_iStatus = ID_STATUS_CONNECTING; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); - m_hWorkerThread = ForkThreadEx(&CDiscordProto::ServerThread, nullptr, nullptr); - } - else if (m_bOnline) { - debugLogA("setting server online status to %d", iNewStatus); - SetServerStatus(iNewStatus); - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM) -{ - switch (msg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - SetFocus(GetDlgItem(hwndDlg, IDC_NICK)); - return TRUE; - - case WM_COMMAND: - if (HIWORD(wParam) == EN_SETFOCUS) - PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg); - } - return FALSE; -} - -HWND CDiscordProto::CreateExtendedSearchUI(HWND hwndParent) -{ - if (hwndParent) - return CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_EXTSEARCH), hwndParent, AdvancedSearchDlgProc, 0); - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::SearchThread(void *param) -{ - Sleep(100); - - PROTOSEARCHRESULT psr = { 0 }; - psr.cbSize = sizeof(psr); - psr.flags = PSR_UNICODE; - psr.nick.w = (wchar_t*)param; - psr.firstName.w = L""; - psr.lastName.w = L""; - psr.id.w = L""; - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)&psr); - - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0); - mir_free(param); -} - -HWND CDiscordProto::SearchAdvanced(HWND hwndDlg) -{ - if (!m_bOnline || !IsWindow(hwndDlg)) - return nullptr; - - wchar_t wszNick[200]; - GetDlgItemTextW(hwndDlg, IDC_NICK, wszNick, _countof(wszNick)); - if (wszNick[0] == 0) // empty string? reject - return nullptr; - - wchar_t *p = wcschr(wszNick, '#'); - if (p == nullptr) // wrong user id - return nullptr; - - ForkThread(&CDiscordProto::SearchThread, mir_wstrdup(wszNick)); - return (HWND)1; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Basic search - by SnowFlake - -void CDiscordProto::OnReceiveUserinfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - JsonReply root(pReply); - if (!root) { - ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)1); - return; - } - - auto &data = root.data(); - CMStringW wszUserId(data["username"].as_mstring() + L"#" + data["discriminator"].as_mstring()); - ForkThread(&CDiscordProto::SearchThread, wszUserId.Detach()); -} - -HANDLE CDiscordProto::SearchBasic(const wchar_t *wszId) -{ - if (!m_bOnline) - return nullptr; - - CMStringA szUrl = "/users/"; - szUrl.AppendFormat(ptrA(mir_utf8encodeW(wszId))); - Push(new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveUserinfo)); - return (HANDLE)1; // Success -} - -//////////////////////////////////////////////////////////////////////////////////////// -// Authorization - -int CDiscordProto::AuthRequest(MCONTACT hContact, const wchar_t*) -{ - ptrW wszUsername(getWStringA(hContact, DB_KEY_NICK)); - int iDiscriminator(getDword(hContact, DB_KEY_DISCR, -1)); - if (wszUsername == nullptr || iDiscriminator == -1) - return 1; // error - - JSONNode root; root << WCHAR_PARAM("username", wszUsername) << INT_PARAM("discriminator", iDiscriminator); - Push(new AsyncHttpRequest(this, REQUEST_POST, "/users/@me/relationships", nullptr, &root)); - return 0; -} - -int CDiscordProto::AuthRecv(MCONTACT, PROTORECVEVENT *pre) -{ - return Proto_AuthRecv(m_szModuleName, pre); -} - -int CDiscordProto::Authorize(MEVENT hDbEvent) -{ - DB::EventInfo dbei; - dbei.cbBlob = -1; - if (db_event_get(hDbEvent, &dbei)) return 1; - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1; - if (mir_strcmp(dbei.szModule, m_szModuleName)) return 1; - - JSONNode root; - MCONTACT hContact = DbGetAuthEventContact(&dbei); - CMStringA szUrl(FORMAT, "/users/@me/relationships/%lld", getId(hContact, DB_KEY_ID)); - Push(new AsyncHttpRequest(this, REQUEST_PUT, szUrl, nullptr, &root)); - return 0; -} - -int CDiscordProto::AuthDeny(MEVENT hDbEvent, const wchar_t*) -{ - DB::EventInfo dbei; - dbei.cbBlob = -1; - if (db_event_get(hDbEvent, &dbei)) return 1; - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1; - if (mir_strcmp(dbei.szModule, m_szModuleName)) return 1; - - MCONTACT hContact = DbGetAuthEventContact(&dbei); - RemoveFriend(getId(hContact, DB_KEY_ID)); - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////// - -MCONTACT CDiscordProto::AddToList(int flags, PROTOSEARCHRESULT *psr) -{ - if (mir_wstrlen(psr->nick.w) == 0) - return 0; - - wchar_t *p = wcschr(psr->nick.w, '#'); - if (p == nullptr) - return 0; - - MCONTACT hContact = db_add_contact(); - Proto_AddToContact(hContact, m_szModuleName); - if (flags & PALF_TEMPORARY) - Contact::RemoveFromList(hContact); - - *p = 0; - CDiscordUser *pUser = new CDiscordUser(0); - pUser->hContact = hContact; - pUser->wszUsername = psr->nick.w; - pUser->iDiscriminator = _wtoi(p + 1); - *p = '#'; - - if (mir_wstrlen(psr->id.w)) { - pUser->id = _wtoi64(psr->id.w); - setId(hContact, DB_KEY_ID, pUser->id); - } - - Clist_SetGroup(hContact, m_wszDefaultGroup); - setWString(hContact, DB_KEY_NICK, pUser->wszUsername); - setDword(hContact, DB_KEY_DISCR, pUser->iDiscriminator); - arUsers.insert(pUser); - - return hContact; -} - -MCONTACT CDiscordProto::AddToListByEvent(int flags, int, MEVENT hDbEvent) -{ - DB::EventInfo dbei; - dbei.cbBlob = -1; - if (db_event_get(hDbEvent, &dbei)) - return 0; - if (mir_strcmp(dbei.szModule, m_szModuleName)) - return 0; - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) - return 0; - - DB::AUTH_BLOB blob(dbei.pBlob); - if (flags & PALF_TEMPORARY) - Contact::RemoveFromList(blob.get_contact()); - else - Contact::PutOnList(blob.get_contact()); - return blob.get_contact(); -} - -//////////////////////////////////////////////////////////////////////////////////////// -// SendMsg - -void CDiscordProto::OnSendMsg(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) -{ - JsonReply root(pReply); - if (!root) { - int iReqNum = -1; - for (auto &it : arOwnMessages) - if (it->reqId == pReq->m_iReqNum) { - iReqNum = it->reqId; - arOwnMessages.removeItem(&it); - break; - } - - if (iReqNum != -1) { - CMStringW wszErrorMsg(root.data()["message"].as_mstring()); - if (wszErrorMsg.IsEmpty()) - wszErrorMsg = TranslateT("Message send failed"); - ProtoBroadcastAck(pReq->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)iReqNum, (LPARAM)wszErrorMsg.c_str()); - } - } -} - -int CDiscordProto::SendMsg(MCONTACT hContact, int /*flags*/, const char *pszSrc) -{ - if (!m_bOnline) { - ProtoBroadcastAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)1, (LPARAM)TranslateT("Protocol is offline or user isn't authorized yet")); - return 1; - } - - ptrW wszText(mir_utf8decodeW(pszSrc)); - if (wszText == nullptr) - return 0; - - CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID)); - if (pUser == nullptr || pUser->id == 0) - return 0; - - // no channel - we need to create one - if (pUser->channelId == 0) { - JSONNode list(JSON_ARRAY); list.set_name("recipients"); list << SINT64_PARAM("", pUser->id); - JSONNode body; body << list; - CMStringA szUrl(FORMAT, "/users/%lld/channels", m_ownId); - - // theoretically we get the same data from the gateway thread, but there could be a delay - // so we bind data analysis to the http packet reply - mir_cslock lck(m_csHttpQueue); - ExecuteRequest(new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveCreateChannel, &body)); - if (pUser->channelId == 0) - return 0; - } - - // we generate a random 64-bit integer and pass it to the server - // to distinguish our own messages from these generated by another clients - SnowFlake nonce; Utils_GetRandom(&nonce, sizeof(nonce)); nonce = abs(nonce); - JSONNode body; body << WCHAR_PARAM("content", wszText) << SINT64_PARAM("nonce", nonce); - - CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId); - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnSendMsg, &body); - pReq->hContact = hContact; - arOwnMessages.insert(new COwnMessage(nonce, pReq->m_iReqNum)); - Push(pReq); - return pReq->m_iReqNum; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void __cdecl CDiscordProto::GetAwayMsgThread(void *param) -{ - Thread_SetName("Jabber: GetAwayMsgThread"); - - auto *pUser = (CDiscordUser *)param; - if (pUser == nullptr) - return; - - if (pUser->wszTopic.IsEmpty()) - ProtoBroadcastAck(pUser->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, 0); - else - ProtoBroadcastAck(pUser->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pUser->wszTopic.c_str()); -} - -HANDLE CDiscordProto::GetAwayMsg(MCONTACT hContact) -{ - ForkThread(&CDiscordProto::GetAwayMsgThread, FindUser(getId(hContact, DB_KEY_ID))); - return (HANDLE)1; -} - -int CDiscordProto::SetAwayMsg(int iStatus, const wchar_t *msg) -{ - if (iStatus < ID_STATUS_MIN || iStatus > ID_STATUS_MAX) - return 0; - - wchar_t *&pwszMessage = m_wszStatusMsg[iStatus - ID_STATUS_MIN]; - if (!mir_wstrcmp(msg, pwszMessage)) - return 0; - - replaceStrW(pwszMessage, msg); - - if (m_bOnline) { - JSONNode status; status.set_name("custom_status"); status << WCHAR_PARAM("text", (msg) ? msg : L""); - JSONNode root; root << status; - Push(new AsyncHttpRequest(this, REQUEST_PATCH, "/users/@me/settings", nullptr, &root)); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CDiscordProto::UserIsTyping(MCONTACT hContact, int type) -{ - if (type == PROTOTYPE_SELFTYPING_ON) { - CMStringA szUrl(FORMAT, "/channels/%lld/typing", getId(hContact, DB_KEY_CHANNELID)); - Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr)); - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::OnReceiveMarkRead(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *) -{ - JsonReply root(pReply); - if (root) - SaveToken(root.data()); -} - -void CDiscordProto::SendMarkRead() -{ - mir_cslock lck(csMarkReadQueue); - while (arMarkReadQueue.getCount()) { - CDiscordUser *pUser = arMarkReadQueue[0]; - JSONNode payload; payload << CHAR_PARAM("token", m_szTempToken); - CMStringA szUrl(FORMAT, "/channels/%lld/messages/%lld/ack", pUser->channelId, pUser->lastMsgId); - auto *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveMarkRead, &payload); - Push(pReq); - arMarkReadQueue.remove(0); - } -} - -int CDiscordProto::OnDbEventRead(WPARAM, LPARAM hDbEvent) -{ - MCONTACT hContact = db_event_getContact(hDbEvent); - if (!hContact) - return 0; - - // filter out only events of my protocol - const char *szProto = Proto_GetBaseAccountName(hContact); - if (mir_strcmp(szProto, m_szModuleName)) - return 0; - - if (m_bOnline) { - m_impl.m_markRead.Start(200); - - CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID)); - if (pUser != nullptr) { - mir_cslock lck(csMarkReadQueue); - if (arMarkReadQueue.indexOf(pUser) == -1) - arMarkReadQueue.insert(pUser); - } - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CDiscordProto::OnAccountChanged(WPARAM iAction, LPARAM lParam) -{ - if (iAction == PRAC_ADDED) { - PROTOACCOUNT *pa = (PROTOACCOUNT*)lParam; - if (pa && pa->ppro == this) { - m_bUseGroupchats = false; - m_bUseGuildGroups = true; - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::OnContactDeleted(MCONTACT hContact) -{ - CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID)); - if (pUser == nullptr || !m_bOnline) - return; - - if (pUser->channelId) - Push(new AsyncHttpRequest(this, REQUEST_DELETE, CMStringA(FORMAT, "/channels/%lld", pUser->channelId), nullptr)); - - if (pUser->id) - RemoveFriend(pUser->id); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CDiscordProto::RequestFriendship(WPARAM hContact, LPARAM) -{ - AuthRequest(hContact, 0); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -struct SendFileThreadParam -{ - MCONTACT hContact; - CMStringW wszDescr, wszFileName; - - SendFileThreadParam(MCONTACT _p1, LPCWSTR _p2, LPCWSTR _p3) : - hContact(_p1), - wszFileName(_p2), - wszDescr(_p3) - {} -}; - -void CDiscordProto::SendFileThread(void *param) -{ - SendFileThreadParam *p = (SendFileThreadParam*)param; - - FILE *in = _wfopen(p->wszFileName, L"rb"); - if (in == nullptr) { - debugLogA("cannot open file %S for reading", p->wszFileName.c_str()); - LBL_Error: - ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, param); - delete p; - return; - } - - ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, param); - - char szRandom[16], szRandomText[33]; - Utils_GetRandom(szRandom, _countof(szRandom)); - bin2hex(szRandom, _countof(szRandom), szRandomText); - CMStringA szBoundary(FORMAT, "----Boundary%s", szRandomText); - - CMStringA szUrl(FORMAT, "/channels/%lld/messages", getId(p->hContact, DB_KEY_CHANNELID)); - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveFile); - pReq->AddHeader("Content-Type", CMStringA("multipart/form-data; boundary=" + szBoundary)); - pReq->AddHeader("Accept", "*/*"); - - szBoundary.Insert(0, "--"); - - CMStringA szBody; - szBody.Append(szBoundary + "\r\n"); - szBody.Append("Content-Disposition: form-data; name=\"content\"\r\n\r\n"); - szBody.Append(ptrA(mir_utf8encodeW(p->wszDescr))); - szBody.Append("\r\n"); - - szBody.Append(szBoundary + "\r\n"); - szBody.Append("Content-Disposition: form-data; name=\"tts\"\r\n\r\nfalse\r\n"); - - wchar_t *pFileName = wcsrchr(p->wszFileName.GetBuffer(), '\\'); - if (pFileName != nullptr) - pFileName++; - else - pFileName = p->wszFileName.GetBuffer(); - - szBody.Append(szBoundary + "\r\n"); - szBody.AppendFormat("Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", ptrA(mir_utf8encodeW(pFileName)).get()); - szBody.AppendFormat("Content-Type: %S\r\n", ProtoGetAvatarMimeType(ProtoGetAvatarFileFormat(p->wszFileName))); - szBody.Append("\r\n"); - - size_t cbBytes = filelength(fileno(in)); - - szBoundary.Insert(0, "\r\n"); - szBoundary.Append("--\r\n"); - pReq->dataLength = int(szBody.GetLength() + szBoundary.GetLength() + cbBytes); - pReq->pData = (char*)mir_alloc(pReq->dataLength+1); - memcpy(pReq->pData, szBody.c_str(), szBody.GetLength()); - size_t cbRead = fread(pReq->pData + szBody.GetLength(), 1, cbBytes, in); - fclose(in); - if (cbBytes != cbRead) { - debugLogA("cannot read file %S: %d bytes read instead of %d", p->wszFileName.c_str(), cbRead, cbBytes); - delete pReq; - goto LBL_Error; - } - - memcpy(pReq->pData + szBody.GetLength() + cbBytes, szBoundary, szBoundary.GetLength()); - pReq->pUserInfo = p; - Push(pReq); - - ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, param); -} - -void CDiscordProto::OnReceiveFile(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) -{ - SendFileThreadParam *p = (SendFileThreadParam*)pReq->pUserInfo; - if (pReply->resultCode != 200) { - ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, p); - debugLogA("CDiscordProto::SendFile failed: %d", pReply->resultCode); - } - else { - ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, p); - debugLogA("CDiscordProto::SendFile succeeded"); - } - - delete p; -} - -HANDLE CDiscordProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) -{ - SnowFlake id = getId(hContact, DB_KEY_CHANNELID); - if (id == 0) - return nullptr; - - // we don't wanna block the main thread, right? - SendFileThreadParam *param = new SendFileThreadParam(hContact, ppszFiles[0], szDescription); - ForkThread(&CDiscordProto::SendFileThread, param); - return param; -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+static int compareMessages(const COwnMessage *p1, const COwnMessage *p2)
+{
+ return compareInt64(p1->nonce, p2->nonce);
+}
+
+static int compareRequests(const AsyncHttpRequest *p1, const AsyncHttpRequest *p2)
+{
+ return p1->m_iReqNum - p2->m_iReqNum;
+}
+
+int compareUsers(const CDiscordUser *p1, const CDiscordUser *p2)
+{
+ return compareInt64(p1->id, p2->id);
+}
+
+static int compareGuilds(const CDiscordGuild *p1, const CDiscordGuild *p2)
+{
+ return compareInt64(p1->id, p2->id);
+}
+
+CDiscordProto::CDiscordProto(const char *proto_name, const wchar_t *username) :
+ PROTO<CDiscordProto>(proto_name, username),
+ m_impl(*this),
+ m_arHttpQueue(10, compareRequests),
+ m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)),
+ arUsers(10, compareUsers),
+ arGuilds(1, compareGuilds),
+ arMarkReadQueue(1, compareUsers),
+ arOwnMessages(1, compareMessages),
+ arVoiceCalls(1),
+
+ m_wszEmail(this, "Email", L""),
+ m_wszDefaultGroup(this, "GroupName", DB_KEYVAL_GROUP),
+ m_bUseGroupchats(this, "UseGroupChats", true),
+ m_bHideGroupchats(this, "HideChats", true),
+ m_bUseGuildGroups(this, "UseGuildGroups", false),
+ m_bSyncDeleteMsgs(this, "DeleteServerMsgs", true)
+{
+ // Services
+ CreateProtoService(PS_CREATEACCMGRUI, &CDiscordProto::SvcCreateAccMgrUI);
+
+ CreateProtoService(PS_GETAVATARINFO, &CDiscordProto::GetAvatarInfo);
+ CreateProtoService(PS_GETAVATARCAPS, &CDiscordProto::GetAvatarCaps);
+ CreateProtoService(PS_GETMYAVATAR, &CDiscordProto::GetMyAvatar);
+ CreateProtoService(PS_SETMYAVATAR, &CDiscordProto::SetMyAvatar);
+
+ CreateProtoService(PS_MENU_REQAUTH, &CDiscordProto::RequestFriendship);
+ CreateProtoService(PS_MENU_LOADHISTORY, &CDiscordProto::OnMenuLoadHistory);
+
+ CreateProtoService(PS_VOICE_CAPS, &CDiscordProto::VoiceCaps);
+
+ // Events
+ HookProtoEvent(ME_OPT_INITIALISE, &CDiscordProto::OnOptionsInit);
+ HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CDiscordProto::OnDbEventRead);
+ HookProtoEvent(ME_PROTO_ACCLISTCHANGED, &CDiscordProto::OnAccountChanged);
+
+ HookProtoEvent(PE_VOICE_CALL_STATE, &CDiscordProto::OnVoiceState);
+
+ // database
+ db_set_resident(m_szModuleName, "XStatusMsg");
+
+ // custom events
+ DBEVENTTYPEDESCR dbEventType = {};
+ dbEventType.module = m_szModuleName;
+ dbEventType.flags = DETF_HISTORY | DETF_MSGWINDOW;
+
+ dbEventType.eventType = EVENT_INCOMING_CALL;
+ dbEventType.descr = Translate("Incoming call");
+ dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_CALL);
+ DbEvent_RegisterType(&dbEventType);
+
+ dbEventType.eventType = EVENT_CALL_FINISHED;
+ dbEventType.descr = Translate("Call ended");
+ dbEventType.eventIcon = g_plugin.getIconHandle(IDI_VOICE_ENDED);
+ DbEvent_RegisterType(&dbEventType);
+
+ // Groupchat initialization
+ GCREGISTER gcr = {};
+ gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR;
+ gcr.ptszDispName = m_tszUserName;
+ gcr.pszModule = m_szModuleName;
+ Chat_Register(&gcr);
+
+ // Network initialization
+ CMStringW descr;
+ NETLIBUSER nlu = {};
+
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ descr.Format(TranslateT("%s server connection"), m_tszUserName);
+ nlu.szDescriptiveName.w = descr.GetBuffer();
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ CMStringA module(FORMAT, "%s.Gateway", m_szModuleName);
+ nlu.szSettingsModule = module.GetBuffer();
+ nlu.flags = NUF_OUTGOING | NUF_UNICODE;
+ descr.Format(TranslateT("%s gateway connection"), m_tszUserName);
+ nlu.szDescriptiveName.w = descr.GetBuffer();
+ m_hGatewayNetlibUser = Netlib_RegisterUser(&nlu);
+}
+
+CDiscordProto::~CDiscordProto()
+{
+ debugLogA("CDiscordProto::~CDiscordProto");
+
+ for (auto &msg : m_wszStatusMsg)
+ mir_free(msg);
+
+ arUsers.destroy();
+
+ m_arHttpQueue.destroy();
+ ::CloseHandle(m_evRequestsQueue);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnModulesLoaded()
+{
+ std::vector<MCONTACT> lostIds;
+
+ // Fill users list
+ for (auto &hContact : AccContacts()) {
+ CDiscordUser *pNew = new CDiscordUser(getId(hContact, DB_KEY_ID));
+ pNew->hContact = hContact;
+ pNew->lastMsgId = getId(hContact, DB_KEY_LASTMSGID);
+ pNew->wszUsername = ptrW(getWStringA(hContact, DB_KEY_NICK));
+ pNew->iDiscriminator = getDword(hContact, DB_KEY_DISCR);
+
+ // set EnableSync = 1 by default for all existing guilds
+ switch (getByte(hContact, "ChatRoom")) {
+ case 2: // guild
+ delSetting(hContact, DB_KEY_CHANNELID);
+ if (getDword(hContact, "EnableSync", -1) == -1)
+ setDword(hContact, "EnableSync", 1);
+ break;
+
+ case 1: // group chat
+ pNew->channelId = getId(hContact, DB_KEY_CHANNELID);
+ if (!pNew->channelId) {
+ lostIds.push_back(hContact);
+ delete pNew;
+ continue;
+ }
+ break;
+
+ default:
+ pNew->channelId = getId(hContact, DB_KEY_CHANNELID);
+ break;
+ }
+ arUsers.insert(pNew);
+ }
+
+ for (auto &hContact: lostIds)
+ db_delete_contact(hContact);
+
+ // Clist
+ Clist_GroupCreate(0, m_wszDefaultGroup);
+
+ HookProtoEvent(ME_GC_EVENT, &CDiscordProto::GroupchatEventHook);
+ HookProtoEvent(ME_GC_BUILDMENU, &CDiscordProto::GroupchatMenuHook);
+
+ InitMenus();
+
+ // Voice support
+ if (g_plugin.bVoiceService) {
+ VOICE_MODULE voice = {};
+ voice.cbSize = sizeof(voice);
+ voice.name = m_szModuleName;
+ voice.description = TranslateT("Discord voice call");
+ voice.icon = m_hProtoIcon;
+ voice.flags = VOICE_CAPS_CALL_CONTACT | VOICE_CAPS_VOICE;
+ CallService(MS_VOICESERVICE_REGISTER, (WPARAM)&voice, 0);
+ }
+}
+
+void CDiscordProto::OnShutdown()
+{
+ debugLogA("CDiscordProto::OnPreShutdown");
+
+ m_bTerminated = true;
+ SetEvent(m_evRequestsQueue);
+
+ for (auto &it : arGuilds)
+ it->SaveToFile();
+
+ if (m_hGatewayConnection)
+ Netlib_Shutdown(m_hGatewayConnection);
+
+ if (g_plugin.bVoiceService)
+ CallService(MS_VOICESERVICE_UNREGISTER, (WPARAM)m_szModuleName, 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_MODEMSG | PF1_MODEMSGRECV | PF1_SERVERCLIST | PF1_BASICSEARCH | PF1_EXTSEARCH | PF1_ADDSEARCHRES | PF1_FILESEND;
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_INVISIBLE;
+ case PFLAGNUM_3:
+ return PF2_ONLINE | PF2_LONGAWAY | PF2_HEAVYDND | PF2_INVISIBLE;
+ case PFLAGNUM_4:
+ return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_SUPPORTTYPING | PF4_SUPPORTIDLE | PF4_AVATARS | PF4_IMSENDOFFLINE | PF4_SERVERMSGID | PF4_OFFLINEFILES;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)TranslateT("User ID");
+ }
+ return 0;
+}
+
+int CDiscordProto::SetStatus(int iNewStatus)
+{
+ debugLogA("CDiscordProto::SetStatus iNewStatus = %d, m_iStatus = %d, m_iDesiredStatus = %d m_hWorkerThread = %p", iNewStatus, m_iStatus, m_iDesiredStatus, m_hWorkerThread);
+
+ if (iNewStatus == m_iStatus)
+ return 0;
+
+ m_iDesiredStatus = iNewStatus;
+ int iOldStatus = m_iStatus;
+
+ // go offline
+ if (iNewStatus == ID_STATUS_OFFLINE) {
+ if (m_bOnline) {
+ SetServerStatus(ID_STATUS_OFFLINE);
+ ShutdownSession();
+ }
+ m_iStatus = m_iDesiredStatus;
+ setAllContactStatuses(ID_STATUS_OFFLINE, false);
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
+ }
+ // not logged in? come on
+ else if (m_hWorkerThread == nullptr && !IsStatusConnecting(m_iStatus)) {
+ m_iStatus = ID_STATUS_CONNECTING;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
+ m_hWorkerThread = ForkThreadEx(&CDiscordProto::ServerThread, nullptr, nullptr);
+ }
+ else if (m_bOnline) {
+ debugLogA("setting server online status to %d", iNewStatus);
+ SetServerStatus(iNewStatus);
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR CALLBACK AdvancedSearchDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetFocus(GetDlgItem(hwndDlg, IDC_NICK));
+ return TRUE;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == EN_SETFOCUS)
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ }
+ return FALSE;
+}
+
+HWND CDiscordProto::CreateExtendedSearchUI(HWND hwndParent)
+{
+ if (hwndParent)
+ return CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_EXTSEARCH), hwndParent, AdvancedSearchDlgProc, 0);
+
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::SearchThread(void *param)
+{
+ Sleep(100);
+
+ PROTOSEARCHRESULT psr = { 0 };
+ psr.cbSize = sizeof(psr);
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = (wchar_t*)param;
+ psr.firstName.w = L"";
+ psr.lastName.w = L"";
+ psr.id.w = L"";
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)&psr);
+
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+ mir_free(param);
+}
+
+HWND CDiscordProto::SearchAdvanced(HWND hwndDlg)
+{
+ if (!m_bOnline || !IsWindow(hwndDlg))
+ return nullptr;
+
+ wchar_t wszNick[200];
+ GetDlgItemTextW(hwndDlg, IDC_NICK, wszNick, _countof(wszNick));
+ if (wszNick[0] == 0) // empty string? reject
+ return nullptr;
+
+ wchar_t *p = wcschr(wszNick, '#');
+ if (p == nullptr) // wrong user id
+ return nullptr;
+
+ ForkThread(&CDiscordProto::SearchThread, mir_wstrdup(wszNick));
+ return (HWND)1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Basic search - by SnowFlake
+
+void CDiscordProto::OnReceiveUserinfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (!root) {
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_FAILED, (HANDLE)1);
+ return;
+ }
+
+ auto &data = root.data();
+ CMStringW wszUserId(data["username"].as_mstring() + L"#" + data["discriminator"].as_mstring());
+ ForkThread(&CDiscordProto::SearchThread, wszUserId.Detach());
+}
+
+HANDLE CDiscordProto::SearchBasic(const wchar_t *wszId)
+{
+ if (!m_bOnline)
+ return nullptr;
+
+ CMStringA szUrl = "/users/";
+ szUrl.AppendFormat(ptrA(mir_utf8encodeW(wszId)));
+ Push(new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveUserinfo));
+ return (HANDLE)1; // Success
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Authorization
+
+int CDiscordProto::AuthRequest(MCONTACT hContact, const wchar_t*)
+{
+ ptrW wszUsername(getWStringA(hContact, DB_KEY_NICK));
+ int iDiscriminator(getDword(hContact, DB_KEY_DISCR, -1));
+ if (wszUsername == nullptr || iDiscriminator == -1)
+ return 1; // error
+
+ JSONNode root; root << WCHAR_PARAM("username", wszUsername) << INT_PARAM("discriminator", iDiscriminator);
+ Push(new AsyncHttpRequest(this, REQUEST_POST, "/users/@me/relationships", nullptr, &root));
+ return 0;
+}
+
+int CDiscordProto::AuthRecv(MCONTACT, PROTORECVEVENT *pre)
+{
+ return Proto_AuthRecv(m_szModuleName, pre);
+}
+
+int CDiscordProto::Authorize(MEVENT hDbEvent)
+{
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (db_event_get(hDbEvent, &dbei)) return 1;
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1;
+ if (mir_strcmp(dbei.szModule, m_szModuleName)) return 1;
+
+ JSONNode root;
+ MCONTACT hContact = DbGetAuthEventContact(&dbei);
+ CMStringA szUrl(FORMAT, "/users/@me/relationships/%lld", getId(hContact, DB_KEY_ID));
+ Push(new AsyncHttpRequest(this, REQUEST_PUT, szUrl, nullptr, &root));
+ return 0;
+}
+
+int CDiscordProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
+{
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (db_event_get(hDbEvent, &dbei)) return 1;
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1;
+ if (mir_strcmp(dbei.szModule, m_szModuleName)) return 1;
+
+ MCONTACT hContact = DbGetAuthEventContact(&dbei);
+ RemoveFriend(getId(hContact, DB_KEY_ID));
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+MCONTACT CDiscordProto::AddToList(int flags, PROTOSEARCHRESULT *psr)
+{
+ if (mir_wstrlen(psr->nick.w) == 0)
+ return 0;
+
+ wchar_t *p = wcschr(psr->nick.w, '#');
+ if (p == nullptr)
+ return 0;
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+ if (flags & PALF_TEMPORARY)
+ Contact::RemoveFromList(hContact);
+
+ *p = 0;
+ CDiscordUser *pUser = new CDiscordUser(0);
+ pUser->hContact = hContact;
+ pUser->wszUsername = psr->nick.w;
+ pUser->iDiscriminator = _wtoi(p + 1);
+ *p = '#';
+
+ if (mir_wstrlen(psr->id.w)) {
+ pUser->id = _wtoi64(psr->id.w);
+ setId(hContact, DB_KEY_ID, pUser->id);
+ }
+
+ Clist_SetGroup(hContact, m_wszDefaultGroup);
+ setWString(hContact, DB_KEY_NICK, pUser->wszUsername);
+ setDword(hContact, DB_KEY_DISCR, pUser->iDiscriminator);
+ arUsers.insert(pUser);
+
+ return hContact;
+}
+
+MCONTACT CDiscordProto::AddToListByEvent(int flags, int, MEVENT hDbEvent)
+{
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (db_event_get(hDbEvent, &dbei))
+ return 0;
+ if (mir_strcmp(dbei.szModule, m_szModuleName))
+ return 0;
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
+ return 0;
+
+ DB::AUTH_BLOB blob(dbei.pBlob);
+ if (flags & PALF_TEMPORARY)
+ Contact::RemoveFromList(blob.get_contact());
+ else
+ Contact::PutOnList(blob.get_contact());
+ return blob.get_contact();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// SendMsg
+
+void CDiscordProto::OnSendMsg(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ JsonReply root(pReply);
+ if (!root) {
+ int iReqNum = -1;
+ for (auto &it : arOwnMessages)
+ if (it->reqId == pReq->m_iReqNum) {
+ iReqNum = it->reqId;
+ arOwnMessages.removeItem(&it);
+ break;
+ }
+
+ if (iReqNum != -1) {
+ CMStringW wszErrorMsg(root.data()["message"].as_mstring());
+ if (wszErrorMsg.IsEmpty())
+ wszErrorMsg = TranslateT("Message send failed");
+ ProtoBroadcastAck(pReq->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)iReqNum, (LPARAM)wszErrorMsg.c_str());
+ }
+ }
+}
+
+int CDiscordProto::SendMsg(MCONTACT hContact, int /*flags*/, const char *pszSrc)
+{
+ if (!m_bOnline) {
+ ProtoBroadcastAsync(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)1, (LPARAM)TranslateT("Protocol is offline or user isn't authorized yet"));
+ return 1;
+ }
+
+ ptrW wszText(mir_utf8decodeW(pszSrc));
+ if (wszText == nullptr)
+ return 0;
+
+ CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID));
+ if (pUser == nullptr || pUser->id == 0)
+ return 0;
+
+ // no channel - we need to create one
+ if (pUser->channelId == 0) {
+ JSONNode list(JSON_ARRAY); list.set_name("recipients"); list << SINT64_PARAM("", pUser->id);
+ JSONNode body; body << list;
+ CMStringA szUrl(FORMAT, "/users/%lld/channels", m_ownId);
+
+ // theoretically we get the same data from the gateway thread, but there could be a delay
+ // so we bind data analysis to the http packet reply
+ mir_cslock lck(m_csHttpQueue);
+ ExecuteRequest(new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveCreateChannel, &body));
+ if (pUser->channelId == 0)
+ return 0;
+ }
+
+ // we generate a random 64-bit integer and pass it to the server
+ // to distinguish our own messages from these generated by another clients
+ SnowFlake nonce; Utils_GetRandom(&nonce, sizeof(nonce)); nonce = abs(nonce);
+ JSONNode body; body << WCHAR_PARAM("content", wszText) << SINT64_PARAM("nonce", nonce);
+
+ CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId);
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnSendMsg, &body);
+ pReq->hContact = hContact;
+ arOwnMessages.insert(new COwnMessage(nonce, pReq->m_iReqNum));
+ Push(pReq);
+ return pReq->m_iReqNum;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void __cdecl CDiscordProto::GetAwayMsgThread(void *param)
+{
+ Thread_SetName("Jabber: GetAwayMsgThread");
+
+ auto *pUser = (CDiscordUser *)param;
+ if (pUser == nullptr)
+ return;
+
+ if (pUser->wszTopic.IsEmpty())
+ ProtoBroadcastAck(pUser->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, 0);
+ else
+ ProtoBroadcastAck(pUser->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)pUser->wszTopic.c_str());
+}
+
+HANDLE CDiscordProto::GetAwayMsg(MCONTACT hContact)
+{
+ ForkThread(&CDiscordProto::GetAwayMsgThread, FindUser(getId(hContact, DB_KEY_ID)));
+ return (HANDLE)1;
+}
+
+int CDiscordProto::SetAwayMsg(int iStatus, const wchar_t *msg)
+{
+ if (iStatus < ID_STATUS_MIN || iStatus > ID_STATUS_MAX)
+ return 0;
+
+ wchar_t *&pwszMessage = m_wszStatusMsg[iStatus - ID_STATUS_MIN];
+ if (!mir_wstrcmp(msg, pwszMessage))
+ return 0;
+
+ replaceStrW(pwszMessage, msg);
+
+ if (m_bOnline) {
+ JSONNode status; status.set_name("custom_status"); status << WCHAR_PARAM("text", (msg) ? msg : L"");
+ JSONNode root; root << status;
+ Push(new AsyncHttpRequest(this, REQUEST_PATCH, "/users/@me/settings", nullptr, &root));
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDiscordProto::UserIsTyping(MCONTACT hContact, int type)
+{
+ if (type == PROTOTYPE_SELFTYPING_ON) {
+ CMStringA szUrl(FORMAT, "/channels/%lld/typing", getId(hContact, DB_KEY_CHANNELID));
+ Push(new AsyncHttpRequest(this, REQUEST_POST, szUrl, nullptr));
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnReceiveMarkRead(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *)
+{
+ JsonReply root(pReply);
+ if (root)
+ SaveToken(root.data());
+}
+
+void CDiscordProto::SendMarkRead()
+{
+ mir_cslock lck(csMarkReadQueue);
+ while (arMarkReadQueue.getCount()) {
+ CDiscordUser *pUser = arMarkReadQueue[0];
+ JSONNode payload; payload << CHAR_PARAM("token", m_szTempToken);
+ CMStringA szUrl(FORMAT, "/channels/%lld/messages/%lld/ack", pUser->channelId, pUser->lastMsgId);
+ auto *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveMarkRead, &payload);
+ Push(pReq);
+ arMarkReadQueue.remove(0);
+ }
+}
+
+int CDiscordProto::OnDbEventRead(WPARAM, LPARAM hDbEvent)
+{
+ MCONTACT hContact = db_event_getContact(hDbEvent);
+ if (!hContact)
+ return 0;
+
+ // filter out only events of my protocol
+ const char *szProto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(szProto, m_szModuleName))
+ return 0;
+
+ if (m_bOnline) {
+ m_impl.m_markRead.Start(200);
+
+ CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID));
+ if (pUser != nullptr) {
+ mir_cslock lck(csMarkReadQueue);
+ if (arMarkReadQueue.indexOf(pUser) == -1)
+ arMarkReadQueue.insert(pUser);
+ }
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CDiscordProto::OnAccountChanged(WPARAM iAction, LPARAM lParam)
+{
+ if (iAction == PRAC_ADDED) {
+ PROTOACCOUNT *pa = (PROTOACCOUNT*)lParam;
+ if (pa && pa->ppro == this) {
+ m_bUseGroupchats = false;
+ m_bUseGuildGroups = true;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnContactDeleted(MCONTACT hContact)
+{
+ CDiscordUser *pUser = FindUser(getId(hContact, DB_KEY_ID));
+ if (pUser == nullptr || !m_bOnline)
+ return;
+
+ if (pUser->channelId)
+ Push(new AsyncHttpRequest(this, REQUEST_DELETE, CMStringA(FORMAT, "/channels/%lld", pUser->channelId), nullptr));
+
+ if (pUser->id)
+ RemoveFriend(pUser->id);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CDiscordProto::RequestFriendship(WPARAM hContact, LPARAM)
+{
+ AuthRequest(hContact, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct SendFileThreadParam
+{
+ MCONTACT hContact;
+ CMStringW wszDescr, wszFileName;
+
+ SendFileThreadParam(MCONTACT _p1, LPCWSTR _p2, LPCWSTR _p3) :
+ hContact(_p1),
+ wszFileName(_p2),
+ wszDescr(_p3)
+ {}
+};
+
+void CDiscordProto::SendFileThread(void *param)
+{
+ SendFileThreadParam *p = (SendFileThreadParam*)param;
+
+ FILE *in = _wfopen(p->wszFileName, L"rb");
+ if (in == nullptr) {
+ debugLogA("cannot open file %S for reading", p->wszFileName.c_str());
+ LBL_Error:
+ ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, param);
+ delete p;
+ return;
+ }
+
+ ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, param);
+
+ char szRandom[16], szRandomText[33];
+ Utils_GetRandom(szRandom, _countof(szRandom));
+ bin2hex(szRandom, _countof(szRandom), szRandomText);
+ CMStringA szBoundary(FORMAT, "----Boundary%s", szRandomText);
+
+ CMStringA szUrl(FORMAT, "/channels/%lld/messages", getId(p->hContact, DB_KEY_CHANNELID));
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, szUrl, &CDiscordProto::OnReceiveFile);
+ pReq->AddHeader("Content-Type", CMStringA("multipart/form-data; boundary=" + szBoundary));
+ pReq->AddHeader("Accept", "*/*");
+
+ szBoundary.Insert(0, "--");
+
+ CMStringA szBody;
+ szBody.Append(szBoundary + "\r\n");
+ szBody.Append("Content-Disposition: form-data; name=\"content\"\r\n\r\n");
+ szBody.Append(ptrA(mir_utf8encodeW(p->wszDescr)));
+ szBody.Append("\r\n");
+
+ szBody.Append(szBoundary + "\r\n");
+ szBody.Append("Content-Disposition: form-data; name=\"tts\"\r\n\r\nfalse\r\n");
+
+ wchar_t *pFileName = wcsrchr(p->wszFileName.GetBuffer(), '\\');
+ if (pFileName != nullptr)
+ pFileName++;
+ else
+ pFileName = p->wszFileName.GetBuffer();
+
+ szBody.Append(szBoundary + "\r\n");
+ szBody.AppendFormat("Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", ptrA(mir_utf8encodeW(pFileName)).get());
+ szBody.AppendFormat("Content-Type: %S\r\n", ProtoGetAvatarMimeType(ProtoGetAvatarFileFormat(p->wszFileName)));
+ szBody.Append("\r\n");
+
+ size_t cbBytes = filelength(fileno(in));
+
+ szBoundary.Insert(0, "\r\n");
+ szBoundary.Append("--\r\n");
+ pReq->dataLength = int(szBody.GetLength() + szBoundary.GetLength() + cbBytes);
+ pReq->pData = (char*)mir_alloc(pReq->dataLength+1);
+ memcpy(pReq->pData, szBody.c_str(), szBody.GetLength());
+ size_t cbRead = fread(pReq->pData + szBody.GetLength(), 1, cbBytes, in);
+ fclose(in);
+ if (cbBytes != cbRead) {
+ debugLogA("cannot read file %S: %d bytes read instead of %d", p->wszFileName.c_str(), cbRead, cbBytes);
+ delete pReq;
+ goto LBL_Error;
+ }
+
+ memcpy(pReq->pData + szBody.GetLength() + cbBytes, szBoundary, szBoundary.GetLength());
+ pReq->pUserInfo = p;
+ Push(pReq);
+
+ ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, param);
+}
+
+void CDiscordProto::OnReceiveFile(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ SendFileThreadParam *p = (SendFileThreadParam*)pReq->pUserInfo;
+ if (pReply->resultCode != 200) {
+ ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, p);
+ debugLogA("CDiscordProto::SendFile failed: %d", pReply->resultCode);
+ }
+ else {
+ ProtoBroadcastAck(p->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, p);
+ debugLogA("CDiscordProto::SendFile succeeded");
+ }
+
+ delete p;
+}
+
+HANDLE CDiscordProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles)
+{
+ SnowFlake id = getId(hContact, DB_KEY_CHANNELID);
+ if (id == 0)
+ return nullptr;
+
+ // we don't wanna block the main thread, right?
+ SendFileThreadParam *param = new SendFileThreadParam(hContact, ppszFiles[0], szDescription);
+ ForkThread(&CDiscordProto::SendFileThread, param);
+ return param;
+}
diff --git a/protocols/Discord/src/proto.h b/protocols/Discord/src/proto.h index bf3929fd55..b5262f4e0a 100644 --- a/protocols/Discord/src/proto.h +++ b/protocols/Discord/src/proto.h @@ -1,476 +1,476 @@ -#pragma once - -#define EVENT_INCOMING_CALL 10001 -#define EVENT_CALL_FINISHED 10002 - -typedef __int64 SnowFlake; - -__forceinline int compareInt64(const SnowFlake i1, const SnowFlake i2) -{ - return (i1 == i2) ? 0 : (i1 < i2) ? -1 : 1; -} - -class CDiscordProto; -typedef void (CDiscordProto::*GatewayHandlerFunc)(const JSONNode&); - -struct AsyncHttpRequest : public MTHttpRequest<CDiscordProto> -{ - AsyncHttpRequest(CDiscordProto*, int iRequestType, LPCSTR szUrl, MTHttpRequestHandler pFunc, JSONNode *pNode = nullptr); - - int m_iErrorCode, m_iReqNum; - bool m_bMainSite; - MCONTACT hContact; -}; - -class JsonReply -{ - JSONNode *m_root = nullptr; - int m_errorCode = 0; - -public: - JsonReply(NETLIBHTTPREQUEST *); - ~JsonReply(); - - __forceinline int error() const { return m_errorCode; } - __forceinline JSONNode& data() const { return *m_root; } - __forceinline operator bool() const { return m_errorCode == 200; } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CDiscordRole : public MZeroedObject -{ - SnowFlake id; - COLORREF color; - uint32_t permissions; - int position; - CMStringW wszName; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct COwnMessage -{ - SnowFlake nonce; - int reqId; - - COwnMessage(SnowFlake _id, int _reqId) : - nonce(_id), - reqId(_reqId) - {} -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -enum CDiscordHistoryOp -{ - MSG_NOFILTER, MSG_AFTER, MSG_BEFORE -}; - -struct CDiscordUser : public MZeroedObject -{ - CDiscordUser(SnowFlake _id) : - id(_id) - {} - - ~CDiscordUser(); - - SnowFlake id; - MCONTACT hContact; - - SnowFlake channelId; - SnowFlake lastReadId, lastMsgId; - SnowFlake parentId; - bool bIsPrivate; - bool bIsGroup; - bool bSynced; - - struct CDiscordGuild *pGuild; - - CMStringW wszUsername, wszChannelName, wszTopic; - int iDiscriminator; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CDiscordGuildMember : public MZeroedObject -{ - CDiscordGuildMember(SnowFlake id) : - userId(id) - {} - - ~CDiscordGuildMember() - {} - - SnowFlake userId; - CMStringW wszDiscordId, wszNick, wszRole; - int iStatus; -}; - -struct CDiscordGuild : public MZeroedObject -{ - CDiscordGuild(SnowFlake _id); - ~CDiscordGuild(); - - __forceinline CDiscordGuildMember* FindUser(SnowFlake userId) - { - return arChatUsers.find((CDiscordGuildMember *)&userId); - } - - __inline CMStringW GetCacheFile() const - { - return CMStringW(FORMAT, L"%s\\DiscordCache\\%lld.json", VARSW(L"%miranda_userdata%").get(), id); - } - - SnowFlake id, ownerId; - CMStringW wszName; - MCONTACT hContact; - MGROUP groupId; - bool bSynced = false; - LIST<CDiscordUser> arChannels; - - SESSION_INFO *pParentSi; - OBJLIST<CDiscordGuildMember> arChatUsers; - OBJLIST<CDiscordRole> arRoles; // guild roles - - void LoadFromFile(); - void SaveToFile(); -}; - -struct CDiscordVoiceCall -{ - CMStringA szId; - SnowFlake channelId; - time_t startTime; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#define OPCODE_DISPATCH 0 -#define OPCODE_HEARTBEAT 1 -#define OPCODE_IDENTIFY 2 -#define OPCODE_STATUS_UPDATE 3 -#define OPCODE_VOICE_UPDATE 4 -#define OPCODE_VOICE_PING 5 -#define OPCODE_RESUME 6 -#define OPCODE_RECONNECT 7 -#define OPCODE_REQUEST_MEMBERS 8 -#define OPCODE_INVALID_SESSION 9 -#define OPCODE_HELLO 10 -#define OPCODE_HEARTBEAT_ACK 11 -#define OPCODE_REQUEST_SYNC 12 -#define OPCODE_REQUEST_SYNC_GROUP 13 -#define OPCODE_REQUEST_SYNC_CHANNEL 14 - -class CDiscordProto : public PROTO<CDiscordProto> -{ - friend struct AsyncHttpRequest; - friend class CDiscardAccountOptions; - - class CDiscordProtoImpl - { - friend class CDiscordProto; - CDiscordProto &m_proto; - - CTimer m_heartBeat, m_markRead; - void OnHeartBeat(CTimer *) { - m_proto.GatewaySendHeartbeat(); - } - - void OnMarkRead(CTimer *pTimer) { - m_proto.SendMarkRead(); - pTimer->Stop(); - } - - CDiscordProtoImpl(CDiscordProto &pro) : - m_proto(pro), - m_markRead(Miranda_GetSystemWindow(), UINT_PTR(this)), - m_heartBeat(Miranda_GetSystemWindow(), UINT_PTR(this) + 1) - { - m_markRead.OnEvent = Callback(this, &CDiscordProtoImpl::OnMarkRead); - m_heartBeat.OnEvent = Callback(this, &CDiscordProtoImpl::OnHeartBeat); - } - } m_impl; - - ////////////////////////////////////////////////////////////////////////////////////// - // threads - - void __cdecl SendFileThread(void*); - void __cdecl ServerThread(void*); - void __cdecl SearchThread(void *param); - void __cdecl BatchChatCreate(void* param); - void __cdecl GetAwayMsgThread(void *param); - - ////////////////////////////////////////////////////////////////////////////////////// - // session control - - void ConnectionFailed(int iReason); - void ShutdownSession(void); - - wchar_t *m_wszStatusMsg[MAX_STATUS_COUNT]; - - ptrA m_szAccessToken, m_szTempToken; - - mir_cs m_csHttpQueue; - HANDLE m_evRequestsQueue; - LIST<AsyncHttpRequest> m_arHttpQueue; - - void ExecuteRequest(AsyncHttpRequest *pReq); - void Push(AsyncHttpRequest *pReq, int iTimeout = 10000); - void SaveToken(const JSONNode &data); - - HANDLE m_hWorkerThread; // worker thread handle - HNETLIBCONN m_hAPIConnection; // working connection - - bool - m_bOnline, // protocol is online - m_bTerminated; // Miranda's going down - - ////////////////////////////////////////////////////////////////////////////////////// - // gateway - - CMStringA - m_szGateway, // gateway url - m_szGatewaySessionId, // current session id - m_szCookie, // cookie used for all http queries - m_szWSCookie; // cookie used for establishing websocket connection - - HNETLIBUSER m_hGatewayNetlibUser; // the separate netlib user handle for gateways - HNETLIBCONN m_hGatewayConnection; // gateway connection - - void __cdecl GatewayThread(void*); - bool GatewayThreadWorker(void); - - bool GatewaySend(const JSONNode &pNode); - bool GatewayProcess(const JSONNode &pNode); - - void GatewaySendGuildInfo(CDiscordGuild *pGuild); - void GatewaySendHeartbeat(void); - void GatewaySendIdentify(void); - void GatewaySendResume(void); - bool GatewaySendStatus(int iStatus, const wchar_t *pwszStatusText); - - GatewayHandlerFunc GetHandler(const wchar_t*); - - int m_iHartbeatInterval; // in milliseconds - int m_iGatewaySeq; // gateway sequence number - - ////////////////////////////////////////////////////////////////////////////////////// - // options - - CMOption<wchar_t*> m_wszEmail; // my own email - CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts - CMOption<uint8_t> m_bUseGroupchats; // Shall we connect Guilds at all? - CMOption<uint8_t> m_bHideGroupchats; // Do not open chat windows on creation - CMOption<uint8_t> m_bUseGuildGroups; // use special subgroups for guilds - CMOption<uint8_t> m_bSyncDeleteMsgs; // delete messages from Miranda if they are deleted at the server - - ////////////////////////////////////////////////////////////////////////////////////// - // common data - - SnowFlake m_ownId; - - mir_cs csMarkReadQueue; - LIST<CDiscordUser> arMarkReadQueue; - - OBJLIST<CDiscordUser> arUsers; - OBJLIST<COwnMessage> arOwnMessages; - OBJLIST<CDiscordVoiceCall> arVoiceCalls; - - CDiscordUser* FindUser(SnowFlake id); - CDiscordUser* FindUser(const wchar_t *pwszUsername, int iDiscriminator); - CDiscordUser* FindUserByChannel(SnowFlake channelId); - - void PreparePrivateChannel(const JSONNode &); - CDiscordUser* PrepareUser(const JSONNode &); - - ////////////////////////////////////////////////////////////////////////////////////// - // menu items - - void InitMenus(void); - - int __cdecl OnMenuPrebuild(WPARAM, LPARAM); - - INT_PTR __cdecl OnMenuCopyId(WPARAM, LPARAM); - INT_PTR __cdecl OnMenuCreateChannel(WPARAM, LPARAM); - INT_PTR __cdecl OnMenuJoinGuild(WPARAM, LPARAM); - INT_PTR __cdecl OnMenuLeaveGuild(WPARAM, LPARAM); - INT_PTR __cdecl OnMenuLoadHistory(WPARAM, LPARAM); - INT_PTR __cdecl OnMenuToggleSync(WPARAM, LPARAM); - - HGENMENU m_hMenuLeaveGuild, m_hMenuCreateChannel, m_hMenuToggleSync; - - ////////////////////////////////////////////////////////////////////////////////////// - // guilds - - OBJLIST<CDiscordGuild> arGuilds; - - __forceinline CDiscordGuild* FindGuild(SnowFlake id) const - { - return arGuilds.find((CDiscordGuild*)&id); - } - - void AddGuildUser(CDiscordGuild *guild, const CDiscordGuildMember &pUser); - void ProcessGuild(const JSONNode &json); - void ProcessPresence(const JSONNode &json); - void ProcessRole(CDiscordGuild *guild, const JSONNode &json); - void ProcessType(CDiscordUser *pUser, const JSONNode &json); - - CDiscordUser* ProcessGuildChannel(CDiscordGuild *guild, const JSONNode &json); - CDiscordGuildMember* ProcessGuildUser(CDiscordGuild *pGuild, const JSONNode &json, bool *bNew = nullptr); - - ////////////////////////////////////////////////////////////////////////////////////// - // group chats - - int __cdecl GroupchatEventHook(WPARAM, LPARAM); - int __cdecl GroupchatMenuHook(WPARAM, LPARAM); - - void Chat_SendPrivateMessage(GCHOOK *gch); - void Chat_ProcessLogMenu(GCHOOK *gch); - void Chat_ProcessNickMenu(GCHOOK* gch); - - void CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser); - void ProcessChatUser(CDiscordUser *pChat, const CMStringW &wszUserId, const JSONNode &pRoot); - void ParseSpecialChars(SESSION_INFO *si, CMStringW &str); - - ////////////////////////////////////////////////////////////////////////////////////// - // misc methods - - SnowFlake getId(const char *szName); - SnowFlake getId(MCONTACT hContact, const char *szName); - - void setId(const char *szName, SnowFlake iValue); - void setId(MCONTACT hContact, const char *szName, SnowFlake iValue); - -public: - CDiscordProto(const char*,const wchar_t*); - ~CDiscordProto(); - - ////////////////////////////////////////////////////////////////////////////////////// - // PROTO_INTERFACE - - INT_PTR GetCaps(int, MCONTACT = 0) override; - - HWND CreateExtendedSearchUI(HWND owner) override; - HWND SearchAdvanced(HWND owner) override; - - HANDLE SearchBasic(const wchar_t *id) override; - MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override; - MCONTACT AddToListByEvent(int flags, int, MEVENT hDbEvent) override; - - int AuthRecv(MCONTACT, PROTORECVEVENT *pre) override; - int Authorize(MEVENT hDbEvent) override; - int AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) override; - int AuthRequest(MCONTACT hContact, const wchar_t*) override; - - HANDLE GetAwayMsg(MCONTACT hContact) override; - int SetAwayMsg(int iStatus, const wchar_t *msg) override; - - int SendMsg(MCONTACT hContact, int flags, const char *pszSrc) override; - - HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; - - int UserIsTyping(MCONTACT hContact, int type) override; - - int SetStatus(int iNewStatus) override; - - void OnBuildProtoMenu() override; - void OnContactDeleted(MCONTACT) override; - void OnModulesLoaded() override; - void OnShutdown() override; - - ////////////////////////////////////////////////////////////////////////////////////// - // Services - - INT_PTR __cdecl RequestFriendship(WPARAM, LPARAM); - INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); - - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); - INT_PTR __cdecl SetMyAvatar(WPARAM, LPARAM); - - INT_PTR __cdecl VoiceCaps(WPARAM, LPARAM); - - ////////////////////////////////////////////////////////////////////////////////////// - // Events - - int __cdecl OnOptionsInit(WPARAM, LPARAM); - int __cdecl OnAccountChanged(WPARAM, LPARAM); - int __cdecl OnDbEventRead(WPARAM, LPARAM); - - int __cdecl OnVoiceState(WPARAM, LPARAM); - - ////////////////////////////////////////////////////////////////////////////////////// - // dispatch commands - - void OnCommandCallCreated(const JSONNode &json); - void OnCommandCallDeleted(const JSONNode &json); - void OnCommandCallUpdated(const JSONNode &json); - void OnCommandChannelCreated(const JSONNode &json); - void OnCommandChannelDeleted(const JSONNode &json); - void OnCommandChannelUpdated(const JSONNode &json); - void OnCommandGuildCreated(const JSONNode &json); - void OnCommandGuildDeleted(const JSONNode &json); - void OnCommandGuildMemberAdded(const JSONNode &json); - void OnCommandGuildMemberListUpdate(const JSONNode &json); - void OnCommandGuildMemberRemoved(const JSONNode &json); - void OnCommandGuildMemberUpdated(const JSONNode &json); - void OnCommandFriendAdded(const JSONNode &json); - void OnCommandFriendRemoved(const JSONNode &json); - void OnCommandMessage(const JSONNode&, bool); - void OnCommandMessageCreate(const JSONNode &json); - void OnCommandMessageDelete(const JSONNode &json); - void OnCommandMessageUpdate(const JSONNode &json); - void OnCommandMessageAck(const JSONNode &json); - void OnCommandPresence(const JSONNode &json); - void OnCommandReady(const JSONNode &json); - void OnCommandRoleCreated(const JSONNode &json); - void OnCommandRoleDeleted(const JSONNode &json); - void OnCommandTyping(const JSONNode &json); - void OnCommandUserUpdate(const JSONNode &json); - void OnCommandUserSettingsUpdate(const JSONNode &json); - - void OnLoggedIn(); - void OnLoggedOut(); - - void OnReceiveCreateChannel(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveFile(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveGateway(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveMarkRead(NETLIBHTTPREQUEST *, AsyncHttpRequest *); - void OnReceiveMessageAck(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveToken(NETLIBHTTPREQUEST *, AsyncHttpRequest *); - void OnReceiveUserinfo(NETLIBHTTPREQUEST *, AsyncHttpRequest *); - - void RetrieveMyInfo(); - void OnReceiveMyInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - - void RetrieveHistory(CDiscordUser *pUser, CDiscordHistoryOp iOp = MSG_NOFILTER, SnowFlake msgid = 0, int iLimit = 50); - void OnReceiveHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - - bool RetrieveAvatar(MCONTACT hContact); - void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - - void OnSendMsg(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - - ////////////////////////////////////////////////////////////////////////////////////// - // Misc - - void SendMarkRead(void); - void SetServerStatus(int iStatus); - void RemoveFriend(SnowFlake id); - - CMStringW GetAvatarFilename(MCONTACT hContact); - void CheckAvatarChange(MCONTACT hContact, const CMStringW &wszNewHash); -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CMPlugin : public ACCPROTOPLUGIN<CDiscordProto> -{ - CMPlugin(); - - bool bVoiceService = false; - - int Load() override; -}; +#pragma once
+
+#define EVENT_INCOMING_CALL 10001
+#define EVENT_CALL_FINISHED 10002
+
+typedef __int64 SnowFlake;
+
+__forceinline int compareInt64(const SnowFlake i1, const SnowFlake i2)
+{
+ return (i1 == i2) ? 0 : (i1 < i2) ? -1 : 1;
+}
+
+class CDiscordProto;
+typedef void (CDiscordProto::*GatewayHandlerFunc)(const JSONNode&);
+
+struct AsyncHttpRequest : public MTHttpRequest<CDiscordProto>
+{
+ AsyncHttpRequest(CDiscordProto*, int iRequestType, LPCSTR szUrl, MTHttpRequestHandler pFunc, JSONNode *pNode = nullptr);
+
+ int m_iErrorCode, m_iReqNum;
+ bool m_bMainSite;
+ MCONTACT hContact;
+};
+
+class JsonReply
+{
+ JSONNode *m_root = nullptr;
+ int m_errorCode = 0;
+
+public:
+ JsonReply(NETLIBHTTPREQUEST *);
+ ~JsonReply();
+
+ __forceinline int error() const { return m_errorCode; }
+ __forceinline JSONNode& data() const { return *m_root; }
+ __forceinline operator bool() const { return m_errorCode == 200; }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CDiscordRole : public MZeroedObject
+{
+ SnowFlake id;
+ COLORREF color;
+ uint32_t permissions;
+ int position;
+ CMStringW wszName;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct COwnMessage
+{
+ SnowFlake nonce;
+ int reqId;
+
+ COwnMessage(SnowFlake _id, int _reqId) :
+ nonce(_id),
+ reqId(_reqId)
+ {}
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+enum CDiscordHistoryOp
+{
+ MSG_NOFILTER, MSG_AFTER, MSG_BEFORE
+};
+
+struct CDiscordUser : public MZeroedObject
+{
+ CDiscordUser(SnowFlake _id) :
+ id(_id)
+ {}
+
+ ~CDiscordUser();
+
+ SnowFlake id;
+ MCONTACT hContact;
+
+ SnowFlake channelId;
+ SnowFlake lastReadId, lastMsgId;
+ SnowFlake parentId;
+ bool bIsPrivate;
+ bool bIsGroup;
+ bool bSynced;
+
+ struct CDiscordGuild *pGuild;
+
+ CMStringW wszUsername, wszChannelName, wszTopic;
+ int iDiscriminator;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CDiscordGuildMember : public MZeroedObject
+{
+ CDiscordGuildMember(SnowFlake id) :
+ userId(id)
+ {}
+
+ ~CDiscordGuildMember()
+ {}
+
+ SnowFlake userId;
+ CMStringW wszDiscordId, wszNick, wszRole;
+ int iStatus;
+};
+
+struct CDiscordGuild : public MZeroedObject
+{
+ CDiscordGuild(SnowFlake _id);
+ ~CDiscordGuild();
+
+ __forceinline CDiscordGuildMember* FindUser(SnowFlake userId)
+ {
+ return arChatUsers.find((CDiscordGuildMember *)&userId);
+ }
+
+ __inline CMStringW GetCacheFile() const
+ {
+ return CMStringW(FORMAT, L"%s\\DiscordCache\\%lld.json", VARSW(L"%miranda_userdata%").get(), id);
+ }
+
+ SnowFlake id, ownerId;
+ CMStringW wszName;
+ MCONTACT hContact;
+ MGROUP groupId;
+ bool bSynced = false;
+ LIST<CDiscordUser> arChannels;
+
+ SESSION_INFO *pParentSi;
+ OBJLIST<CDiscordGuildMember> arChatUsers;
+ OBJLIST<CDiscordRole> arRoles; // guild roles
+
+ void LoadFromFile();
+ void SaveToFile();
+};
+
+struct CDiscordVoiceCall
+{
+ CMStringA szId;
+ SnowFlake channelId;
+ time_t startTime;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define OPCODE_DISPATCH 0
+#define OPCODE_HEARTBEAT 1
+#define OPCODE_IDENTIFY 2
+#define OPCODE_STATUS_UPDATE 3
+#define OPCODE_VOICE_UPDATE 4
+#define OPCODE_VOICE_PING 5
+#define OPCODE_RESUME 6
+#define OPCODE_RECONNECT 7
+#define OPCODE_REQUEST_MEMBERS 8
+#define OPCODE_INVALID_SESSION 9
+#define OPCODE_HELLO 10
+#define OPCODE_HEARTBEAT_ACK 11
+#define OPCODE_REQUEST_SYNC 12
+#define OPCODE_REQUEST_SYNC_GROUP 13
+#define OPCODE_REQUEST_SYNC_CHANNEL 14
+
+class CDiscordProto : public PROTO<CDiscordProto>
+{
+ friend struct AsyncHttpRequest;
+ friend class CDiscardAccountOptions;
+
+ class CDiscordProtoImpl
+ {
+ friend class CDiscordProto;
+ CDiscordProto &m_proto;
+
+ CTimer m_heartBeat, m_markRead;
+ void OnHeartBeat(CTimer *) {
+ m_proto.GatewaySendHeartbeat();
+ }
+
+ void OnMarkRead(CTimer *pTimer) {
+ m_proto.SendMarkRead();
+ pTimer->Stop();
+ }
+
+ CDiscordProtoImpl(CDiscordProto &pro) :
+ m_proto(pro),
+ m_markRead(Miranda_GetSystemWindow(), UINT_PTR(this)),
+ m_heartBeat(Miranda_GetSystemWindow(), UINT_PTR(this) + 1)
+ {
+ m_markRead.OnEvent = Callback(this, &CDiscordProtoImpl::OnMarkRead);
+ m_heartBeat.OnEvent = Callback(this, &CDiscordProtoImpl::OnHeartBeat);
+ }
+ } m_impl;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // threads
+
+ void __cdecl SendFileThread(void*);
+ void __cdecl ServerThread(void*);
+ void __cdecl SearchThread(void *param);
+ void __cdecl BatchChatCreate(void* param);
+ void __cdecl GetAwayMsgThread(void *param);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // session control
+
+ void ConnectionFailed(int iReason);
+ void ShutdownSession(void);
+
+ wchar_t *m_wszStatusMsg[MAX_STATUS_COUNT];
+
+ ptrA m_szAccessToken, m_szTempToken;
+
+ mir_cs m_csHttpQueue;
+ HANDLE m_evRequestsQueue;
+ LIST<AsyncHttpRequest> m_arHttpQueue;
+
+ void ExecuteRequest(AsyncHttpRequest *pReq);
+ void Push(AsyncHttpRequest *pReq, int iTimeout = 10000);
+ void SaveToken(const JSONNode &data);
+
+ HANDLE m_hWorkerThread; // worker thread handle
+ HNETLIBCONN m_hAPIConnection; // working connection
+
+ bool
+ m_bOnline, // protocol is online
+ m_bTerminated; // Miranda's going down
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // gateway
+
+ CMStringA
+ m_szGateway, // gateway url
+ m_szGatewaySessionId, // current session id
+ m_szCookie, // cookie used for all http queries
+ m_szWSCookie; // cookie used for establishing websocket connection
+
+ HNETLIBUSER m_hGatewayNetlibUser; // the separate netlib user handle for gateways
+ HNETLIBCONN m_hGatewayConnection; // gateway connection
+
+ void __cdecl GatewayThread(void*);
+ bool GatewayThreadWorker(void);
+
+ bool GatewaySend(const JSONNode &pNode);
+ bool GatewayProcess(const JSONNode &pNode);
+
+ void GatewaySendGuildInfo(CDiscordGuild *pGuild);
+ void GatewaySendHeartbeat(void);
+ void GatewaySendIdentify(void);
+ void GatewaySendResume(void);
+ bool GatewaySendStatus(int iStatus, const wchar_t *pwszStatusText);
+
+ GatewayHandlerFunc GetHandler(const wchar_t*);
+
+ int m_iHartbeatInterval; // in milliseconds
+ int m_iGatewaySeq; // gateway sequence number
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // options
+
+ CMOption<wchar_t*> m_wszEmail; // my own email
+ CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts
+ CMOption<uint8_t> m_bUseGroupchats; // Shall we connect Guilds at all?
+ CMOption<uint8_t> m_bHideGroupchats; // Do not open chat windows on creation
+ CMOption<uint8_t> m_bUseGuildGroups; // use special subgroups for guilds
+ CMOption<uint8_t> m_bSyncDeleteMsgs; // delete messages from Miranda if they are deleted at the server
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // common data
+
+ SnowFlake m_ownId;
+
+ mir_cs csMarkReadQueue;
+ LIST<CDiscordUser> arMarkReadQueue;
+
+ OBJLIST<CDiscordUser> arUsers;
+ OBJLIST<COwnMessage> arOwnMessages;
+ OBJLIST<CDiscordVoiceCall> arVoiceCalls;
+
+ CDiscordUser* FindUser(SnowFlake id);
+ CDiscordUser* FindUser(const wchar_t *pwszUsername, int iDiscriminator);
+ CDiscordUser* FindUserByChannel(SnowFlake channelId);
+
+ void PreparePrivateChannel(const JSONNode &);
+ CDiscordUser* PrepareUser(const JSONNode &);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // menu items
+
+ void InitMenus(void);
+
+ int __cdecl OnMenuPrebuild(WPARAM, LPARAM);
+
+ INT_PTR __cdecl OnMenuCopyId(WPARAM, LPARAM);
+ INT_PTR __cdecl OnMenuCreateChannel(WPARAM, LPARAM);
+ INT_PTR __cdecl OnMenuJoinGuild(WPARAM, LPARAM);
+ INT_PTR __cdecl OnMenuLeaveGuild(WPARAM, LPARAM);
+ INT_PTR __cdecl OnMenuLoadHistory(WPARAM, LPARAM);
+ INT_PTR __cdecl OnMenuToggleSync(WPARAM, LPARAM);
+
+ HGENMENU m_hMenuLeaveGuild, m_hMenuCreateChannel, m_hMenuToggleSync;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // guilds
+
+ OBJLIST<CDiscordGuild> arGuilds;
+
+ __forceinline CDiscordGuild* FindGuild(SnowFlake id) const
+ {
+ return arGuilds.find((CDiscordGuild*)&id);
+ }
+
+ void AddGuildUser(CDiscordGuild *guild, const CDiscordGuildMember &pUser);
+ void ProcessGuild(const JSONNode &json);
+ void ProcessPresence(const JSONNode &json);
+ void ProcessRole(CDiscordGuild *guild, const JSONNode &json);
+ void ProcessType(CDiscordUser *pUser, const JSONNode &json);
+
+ CDiscordUser* ProcessGuildChannel(CDiscordGuild *guild, const JSONNode &json);
+ CDiscordGuildMember* ProcessGuildUser(CDiscordGuild *pGuild, const JSONNode &json, bool *bNew = nullptr);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // group chats
+
+ int __cdecl GroupchatEventHook(WPARAM, LPARAM);
+ int __cdecl GroupchatMenuHook(WPARAM, LPARAM);
+
+ void Chat_SendPrivateMessage(GCHOOK *gch);
+ void Chat_ProcessLogMenu(GCHOOK *gch);
+ void Chat_ProcessNickMenu(GCHOOK* gch);
+
+ void CreateChat(CDiscordGuild *pGuild, CDiscordUser *pUser);
+ void ProcessChatUser(CDiscordUser *pChat, const CMStringW &wszUserId, const JSONNode &pRoot);
+ void ParseSpecialChars(SESSION_INFO *si, CMStringW &str);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // misc methods
+
+ SnowFlake getId(const char *szName);
+ SnowFlake getId(MCONTACT hContact, const char *szName);
+
+ void setId(const char *szName, SnowFlake iValue);
+ void setId(MCONTACT hContact, const char *szName, SnowFlake iValue);
+
+public:
+ CDiscordProto(const char*,const wchar_t*);
+ ~CDiscordProto();
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // PROTO_INTERFACE
+
+ INT_PTR GetCaps(int, MCONTACT = 0) override;
+
+ HWND CreateExtendedSearchUI(HWND owner) override;
+ HWND SearchAdvanced(HWND owner) override;
+
+ HANDLE SearchBasic(const wchar_t *id) override;
+ MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override;
+ MCONTACT AddToListByEvent(int flags, int, MEVENT hDbEvent) override;
+
+ int AuthRecv(MCONTACT, PROTORECVEVENT *pre) override;
+ int Authorize(MEVENT hDbEvent) override;
+ int AuthDeny(MEVENT hDbEvent, const wchar_t* szReason) override;
+ int AuthRequest(MCONTACT hContact, const wchar_t*) override;
+
+ HANDLE GetAwayMsg(MCONTACT hContact) override;
+ int SetAwayMsg(int iStatus, const wchar_t *msg) override;
+
+ int SendMsg(MCONTACT hContact, int flags, const char *pszSrc) override;
+
+ HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override;
+
+ int UserIsTyping(MCONTACT hContact, int type) override;
+
+ int SetStatus(int iNewStatus) override;
+
+ void OnBuildProtoMenu() override;
+ void OnContactDeleted(MCONTACT) override;
+ void OnModulesLoaded() override;
+ void OnShutdown() override;
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Services
+
+ INT_PTR __cdecl RequestFriendship(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
+
+ INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
+ INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
+ INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM);
+ INT_PTR __cdecl SetMyAvatar(WPARAM, LPARAM);
+
+ INT_PTR __cdecl VoiceCaps(WPARAM, LPARAM);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Events
+
+ int __cdecl OnOptionsInit(WPARAM, LPARAM);
+ int __cdecl OnAccountChanged(WPARAM, LPARAM);
+ int __cdecl OnDbEventRead(WPARAM, LPARAM);
+
+ int __cdecl OnVoiceState(WPARAM, LPARAM);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // dispatch commands
+
+ void OnCommandCallCreated(const JSONNode &json);
+ void OnCommandCallDeleted(const JSONNode &json);
+ void OnCommandCallUpdated(const JSONNode &json);
+ void OnCommandChannelCreated(const JSONNode &json);
+ void OnCommandChannelDeleted(const JSONNode &json);
+ void OnCommandChannelUpdated(const JSONNode &json);
+ void OnCommandGuildCreated(const JSONNode &json);
+ void OnCommandGuildDeleted(const JSONNode &json);
+ void OnCommandGuildMemberAdded(const JSONNode &json);
+ void OnCommandGuildMemberListUpdate(const JSONNode &json);
+ void OnCommandGuildMemberRemoved(const JSONNode &json);
+ void OnCommandGuildMemberUpdated(const JSONNode &json);
+ void OnCommandFriendAdded(const JSONNode &json);
+ void OnCommandFriendRemoved(const JSONNode &json);
+ void OnCommandMessage(const JSONNode&, bool);
+ void OnCommandMessageCreate(const JSONNode &json);
+ void OnCommandMessageDelete(const JSONNode &json);
+ void OnCommandMessageUpdate(const JSONNode &json);
+ void OnCommandMessageAck(const JSONNode &json);
+ void OnCommandPresence(const JSONNode &json);
+ void OnCommandReady(const JSONNode &json);
+ void OnCommandRoleCreated(const JSONNode &json);
+ void OnCommandRoleDeleted(const JSONNode &json);
+ void OnCommandTyping(const JSONNode &json);
+ void OnCommandUserUpdate(const JSONNode &json);
+ void OnCommandUserSettingsUpdate(const JSONNode &json);
+
+ void OnLoggedIn();
+ void OnLoggedOut();
+
+ void OnReceiveCreateChannel(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveFile(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveGateway(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveMarkRead(NETLIBHTTPREQUEST *, AsyncHttpRequest *);
+ void OnReceiveMessageAck(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnReceiveToken(NETLIBHTTPREQUEST *, AsyncHttpRequest *);
+ void OnReceiveUserinfo(NETLIBHTTPREQUEST *, AsyncHttpRequest *);
+
+ void RetrieveMyInfo();
+ void OnReceiveMyInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+
+ void RetrieveHistory(CDiscordUser *pUser, CDiscordHistoryOp iOp = MSG_NOFILTER, SnowFlake msgid = 0, int iLimit = 50);
+ void OnReceiveHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+
+ bool RetrieveAvatar(MCONTACT hContact);
+ void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+
+ void OnSendMsg(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Misc
+
+ void SendMarkRead(void);
+ void SetServerStatus(int iStatus);
+ void RemoveFriend(SnowFlake id);
+
+ CMStringW GetAvatarFilename(MCONTACT hContact);
+ void CheckAvatarChange(MCONTACT hContact, const CMStringW &wszNewHash);
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct CMPlugin : public ACCPROTOPLUGIN<CDiscordProto>
+{
+ CMPlugin();
+
+ bool bVoiceService = false;
+
+ int Load() override;
+};
diff --git a/protocols/Discord/src/resource.h b/protocols/Discord/src/resource.h index d0326e6857..099a4af3af 100644 --- a/protocols/Discord/src/resource.h +++ b/protocols/Discord/src/resource.h @@ -1,30 +1,30 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by w:\miranda-ng\protocols\Discord\res\discord.rc -// -#define IDI_MAIN 101 -#define IDI_GROUPCHAT 102 -#define IDD_OPTIONS_ACCOUNT 103 -#define IDD_EXTSEARCH 104 -#define IDD_OPTIONS_ACCMGR 105 -#define IDI_VOICE_CALL 106 -#define IDI_VOICE_ENDED 107 -#define IDC_PASSWORD 1001 -#define IDC_USERNAME 1002 -#define IDC_GROUP 1003 -#define IDC_NICK 1004 -#define IDC_HIDECHATS 1005 -#define IDC_USEGROUPS 1006 -#define IDC_USEGUILDS 1007 -#define IDC_DELETE_MSGS 1009 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 104 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1008 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by w:\miranda-ng\protocols\Discord\res\discord.rc
+//
+#define IDI_MAIN 101
+#define IDI_GROUPCHAT 102
+#define IDD_OPTIONS_ACCOUNT 103
+#define IDD_EXTSEARCH 104
+#define IDD_OPTIONS_ACCMGR 105
+#define IDI_VOICE_CALL 106
+#define IDI_VOICE_ENDED 107
+#define IDC_PASSWORD 1001
+#define IDC_USERNAME 1002
+#define IDC_GROUP 1003
+#define IDC_NICK 1004
+#define IDC_HIDECHATS 1005
+#define IDC_USEGROUPS 1006
+#define IDC_USEGUILDS 1007
+#define IDC_DELETE_MSGS 1009
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 104
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1008
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Discord/src/server.cpp b/protocols/Discord/src/server.cpp index cc6dfe2280..16f716e89f 100644 --- a/protocols/Discord/src/server.cpp +++ b/protocols/Discord/src/server.cpp @@ -1,307 +1,307 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -///////////////////////////////////////////////////////////////////////////////////////// -// removes a friend from the server - -void CDiscordProto::RemoveFriend(SnowFlake id) -{ - Push(new AsyncHttpRequest(this, REQUEST_DELETE, CMStringA(FORMAT, "/users/@me/relationships/%lld", id), nullptr)); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// retrieves server history - -void CDiscordProto::RetrieveHistory(CDiscordUser *pUser, CDiscordHistoryOp iOp, SnowFlake msgid, int iLimit) -{ - if (!pUser->hContact || getByte(pUser->hContact, DB_KEY_DONT_FETCH)) - return; - - CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId); - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveHistory); - pReq << INT_PARAM("limit", iLimit); - - if (msgid) { - switch (iOp) { - case MSG_AFTER: - pReq << INT64_PARAM("after", msgid); break; - case MSG_BEFORE: - pReq << INT64_PARAM("before", msgid); break; - } - } - pReq->pUserInfo = pUser; - Push(pReq); -} - -static int compareMsgHistory(const JSONNode *p1, const JSONNode *p2) -{ - return wcscmp((*p1)["id"].as_mstring(), (*p2)["id"].as_mstring()); -} - -void CDiscordProto::OnReceiveHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) -{ - CDiscordUser *pUser = (CDiscordUser*)pReq->pUserInfo; - - JsonReply root(pReply); - if (!root) { - if (root.error() == 403) // forbidden, don't try to read it anymore - setByte(pUser->hContact, DB_KEY_DONT_FETCH, true); - return; - } - - SESSION_INFO *si = nullptr; - if (!pUser->bIsPrivate) { - si = g_chatApi.SM_FindSession(pUser->wszUsername, m_szModuleName); - if (si == nullptr) { - debugLogA("message to unknown channel %lld ignored", pUser->channelId); - return; - } - } - - SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database - - LIST<JSONNode> arNodes(10, compareMsgHistory); - int iNumMessages = 0; - for (auto &it : root.data()) { - arNodes.insert(&it); - iNumMessages++; - } - - for (auto &it : arNodes) { - auto &pNode = *it; - CMStringW wszText = PrepareMessageText(pNode); - CMStringW wszUserId = pNode["author"]["id"].as_mstring(); - SnowFlake msgid = ::getId(pNode["id"]); - SnowFlake authorid = _wtoi64(wszUserId); - uint32_t dwTimeStamp = StringToDate(pNode["timestamp"].as_mstring()); - - if (pUser->bIsPrivate) { - DBEVENTINFO dbei = {}; - dbei.szModule = m_szModuleName; - dbei.flags = DBEF_UTF; - dbei.eventType = EVENTTYPE_MESSAGE; - - if (authorid == m_ownId) - dbei.flags |= DBEF_SENT; - else - dbei.flags &= ~DBEF_SENT; - - if (msgid <= pUser->lastReadId) - dbei.flags |= DBEF_READ; - else - dbei.flags &= ~DBEF_READ; - - ptrA szBody(mir_utf8encodeW(wszText)); - dbei.timestamp = dwTimeStamp; - dbei.pBlob = (uint8_t*)szBody.get(); - dbei.cbBlob = (uint32_t)mir_strlen(szBody); - - bool bSucceeded = false; - char szMsgId[100]; - _i64toa_s(msgid, szMsgId, _countof(szMsgId), 10); - MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId); - if (hDbEvent != 0) - bSucceeded = 0 == db_event_edit(pUser->hContact, hDbEvent, &dbei); - - if (!bSucceeded) { - dbei.szId = szMsgId; - db_event_add(pUser->hContact, &dbei); - } - } - else { - ProcessChatUser(pUser, wszUserId, pNode); - - ParseSpecialChars(si, wszText); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_MESSAGE }; - gce.pszID.w = pUser->wszUsername; - gce.dwFlags = GCEF_ADDTOLOG; - gce.pszUID.w = wszUserId; - gce.pszText.w = wszText; - gce.time = dwTimeStamp; - gce.bIsMe = authorid == m_ownId; - Chat_Event(&gce); - } - - if (lastId < msgid) - lastId = msgid; - } - - setId(pUser->hContact, DB_KEY_LASTMSGID, lastId); - - // if we fetched 99 messages, but have smth more to go, continue fetching - if (iNumMessages == 99 && lastId < pUser->lastMsgId) - RetrieveHistory(pUser, MSG_AFTER, lastId, 99); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// retrieves user info - -void CDiscordProto::RetrieveMyInfo() -{ - Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveMyInfo)); -} - -void CDiscordProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - JsonReply root(pReply); - if (!root) { - ConnectionFailed(LOGINERR_WRONGPASSWORD); - return; - } - - auto &data = root.data(); - SnowFlake id = ::getId(data["id"]); - setId(0, DB_KEY_ID, id); - - setByte(0, DB_KEY_MFA, data["mfa_enabled"].as_bool()); - setDword(0, DB_KEY_DISCR, _wtoi(data["discriminator"].as_mstring())); - setWString(0, DB_KEY_NICK, data["username"].as_mstring()); - m_wszEmail = data["email"].as_mstring(); - - m_ownId = id; - - m_szCookie.Empty(); - for (int i=0; i < pReply->headersCount; i++) { - if (!mir_strcmpi(pReply->headers[i].szName, "Set-Cookie")) { - char *p = strchr(pReply->headers[i].szValue, ';'); - if (p) *p = 0; - if (!m_szCookie.IsEmpty()) - m_szCookie.Append("; "); - - m_szCookie.Append(pReply->headers[i].szValue); - } - } - - // launch gateway thread - if (m_szGateway.IsEmpty()) - Push(new AsyncHttpRequest(this, REQUEST_GET, "/gateway", &CDiscordProto::OnReceiveGateway)); - else - ForkThread(&CDiscordProto::GatewayThread, nullptr); - - CheckAvatarChange(0, data["avatar"].as_mstring()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// finds a gateway address - -void CDiscordProto::OnReceiveGateway(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - JsonReply root(pReply); - if (!root) { - ShutdownSession(); - return; - } - - auto &data = root.data(); - m_szGateway = data["url"].as_mstring(); - ForkThread(&CDiscordProto::GatewayThread, nullptr); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::SetServerStatus(int iStatus) -{ - if (GatewaySendStatus(iStatus, nullptr)) { - int iOldStatus = m_iStatus; m_iStatus = iStatus; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// channels - -void CDiscordProto::OnReceiveCreateChannel(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - JsonReply root(pReply); - if (root) - OnCommandChannelCreated(root.data()); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::OnReceiveMessageAck(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - JsonReply root(pReply); - if (!root) - return; - - auto &data = root.data(); - CMStringW wszToken(data["token"].as_mstring()); - if (!wszToken.IsEmpty()) { - JSONNode props; props.set_name("properties"); - JSONNode reply; reply << props; - reply << CHAR_PARAM("event", "ack_messages") << WCHAR_PARAM("token", data["token"].as_mstring()); - Push(new AsyncHttpRequest(this, REQUEST_POST, "/track", nullptr, &reply)); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -#define RECAPTCHA_API_KEY "6Lef5iQTAAAAAKeIvIY-DeexoO3gj7ryl9rLMEnn" -#define RECAPTCHA_SITE_URL "https://discord.com" - -void CDiscordProto::OnReceiveToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) -{ - if (pReply->resultCode != 200) { - JSONNode root = JSONNode::parse(pReply->pData); - if (root) { - const JSONNode &captcha = root["captcha_key"].as_array(); - if (captcha) { - for (auto &it : captcha) { - if (it.as_mstring() == "captcha-required") { - MessageBoxW(NULL, TranslateT("The server requires you to enter the captcha. Miranda will redirect you to a browser now"), L"Discord", MB_OK | MB_ICONINFORMATION); - Utils_OpenUrl("https://discord.com/app"); - } - } - } - - for (auto &err: root["errors"]["email"]["_errors"]) { - CMStringW code(err["code"].as_mstring()); - CMStringW message(err["message"].as_mstring()); - if (!code.IsEmpty() || !message.IsEmpty()) { - POPUPDATAW popup; - popup.lchIcon = IcoLib_GetIconByHandle(Skin_GetIconHandle(SKINICON_ERROR), true); - wcscpy_s(popup.lpwzContactName, m_tszUserName); - mir_snwprintf(popup.lpwzText, TranslateT("Connection failed.\n%s (%s)."), message.c_str(), code.c_str()); - PUAddPopupW(&popup); - } - } - } - ConnectionFailed(LOGINERR_WRONGPASSWORD); - return; - } - - JsonReply root(pReply); - if (!root) { - ConnectionFailed(LOGINERR_NOSERVER); - return; - } - - auto &data = root.data(); - CMStringA szToken = data["token"].as_mstring(); - if (szToken.IsEmpty()) { - debugLogA("Strange empty token received, exiting"); - return; - } - - m_szAccessToken = szToken.Detach(); - setString("AccessToken", m_szAccessToken); - RetrieveMyInfo(); -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// removes a friend from the server
+
+void CDiscordProto::RemoveFriend(SnowFlake id)
+{
+ Push(new AsyncHttpRequest(this, REQUEST_DELETE, CMStringA(FORMAT, "/users/@me/relationships/%lld", id), nullptr));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// retrieves server history
+
+void CDiscordProto::RetrieveHistory(CDiscordUser *pUser, CDiscordHistoryOp iOp, SnowFlake msgid, int iLimit)
+{
+ if (!pUser->hContact || getByte(pUser->hContact, DB_KEY_DONT_FETCH))
+ return;
+
+ CMStringA szUrl(FORMAT, "/channels/%lld/messages", pUser->channelId);
+ AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, szUrl, &CDiscordProto::OnReceiveHistory);
+ pReq << INT_PARAM("limit", iLimit);
+
+ if (msgid) {
+ switch (iOp) {
+ case MSG_AFTER:
+ pReq << INT64_PARAM("after", msgid); break;
+ case MSG_BEFORE:
+ pReq << INT64_PARAM("before", msgid); break;
+ }
+ }
+ pReq->pUserInfo = pUser;
+ Push(pReq);
+}
+
+static int compareMsgHistory(const JSONNode *p1, const JSONNode *p2)
+{
+ return wcscmp((*p1)["id"].as_mstring(), (*p2)["id"].as_mstring());
+}
+
+void CDiscordProto::OnReceiveHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ CDiscordUser *pUser = (CDiscordUser*)pReq->pUserInfo;
+
+ JsonReply root(pReply);
+ if (!root) {
+ if (root.error() == 403) // forbidden, don't try to read it anymore
+ setByte(pUser->hContact, DB_KEY_DONT_FETCH, true);
+ return;
+ }
+
+ SESSION_INFO *si = nullptr;
+ if (!pUser->bIsPrivate) {
+ si = g_chatApi.SM_FindSession(pUser->wszUsername, m_szModuleName);
+ if (si == nullptr) {
+ debugLogA("message to unknown channel %lld ignored", pUser->channelId);
+ return;
+ }
+ }
+
+ SnowFlake lastId = getId(pUser->hContact, DB_KEY_LASTMSGID); // as stored in a database
+
+ LIST<JSONNode> arNodes(10, compareMsgHistory);
+ int iNumMessages = 0;
+ for (auto &it : root.data()) {
+ arNodes.insert(&it);
+ iNumMessages++;
+ }
+
+ for (auto &it : arNodes) {
+ auto &pNode = *it;
+ CMStringW wszText = PrepareMessageText(pNode);
+ CMStringW wszUserId = pNode["author"]["id"].as_mstring();
+ SnowFlake msgid = ::getId(pNode["id"]);
+ SnowFlake authorid = _wtoi64(wszUserId);
+ uint32_t dwTimeStamp = StringToDate(pNode["timestamp"].as_mstring());
+
+ if (pUser->bIsPrivate) {
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_szModuleName;
+ dbei.flags = DBEF_UTF;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+
+ if (authorid == m_ownId)
+ dbei.flags |= DBEF_SENT;
+ else
+ dbei.flags &= ~DBEF_SENT;
+
+ if (msgid <= pUser->lastReadId)
+ dbei.flags |= DBEF_READ;
+ else
+ dbei.flags &= ~DBEF_READ;
+
+ ptrA szBody(mir_utf8encodeW(wszText));
+ dbei.timestamp = dwTimeStamp;
+ dbei.pBlob = (uint8_t*)szBody.get();
+ dbei.cbBlob = (uint32_t)mir_strlen(szBody);
+
+ bool bSucceeded = false;
+ char szMsgId[100];
+ _i64toa_s(msgid, szMsgId, _countof(szMsgId), 10);
+ MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId);
+ if (hDbEvent != 0)
+ bSucceeded = 0 == db_event_edit(pUser->hContact, hDbEvent, &dbei);
+
+ if (!bSucceeded) {
+ dbei.szId = szMsgId;
+ db_event_add(pUser->hContact, &dbei);
+ }
+ }
+ else {
+ ProcessChatUser(pUser, wszUserId, pNode);
+
+ ParseSpecialChars(si, wszText);
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_MESSAGE };
+ gce.pszID.w = pUser->wszUsername;
+ gce.dwFlags = GCEF_ADDTOLOG;
+ gce.pszUID.w = wszUserId;
+ gce.pszText.w = wszText;
+ gce.time = dwTimeStamp;
+ gce.bIsMe = authorid == m_ownId;
+ Chat_Event(&gce);
+ }
+
+ if (lastId < msgid)
+ lastId = msgid;
+ }
+
+ setId(pUser->hContact, DB_KEY_LASTMSGID, lastId);
+
+ // if we fetched 99 messages, but have smth more to go, continue fetching
+ if (iNumMessages == 99 && lastId < pUser->lastMsgId)
+ RetrieveHistory(pUser, MSG_AFTER, lastId, 99);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// retrieves user info
+
+void CDiscordProto::RetrieveMyInfo()
+{
+ Push(new AsyncHttpRequest(this, REQUEST_GET, "/users/@me", &CDiscordProto::OnReceiveMyInfo));
+}
+
+void CDiscordProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (!root) {
+ ConnectionFailed(LOGINERR_WRONGPASSWORD);
+ return;
+ }
+
+ auto &data = root.data();
+ SnowFlake id = ::getId(data["id"]);
+ setId(0, DB_KEY_ID, id);
+
+ setByte(0, DB_KEY_MFA, data["mfa_enabled"].as_bool());
+ setDword(0, DB_KEY_DISCR, _wtoi(data["discriminator"].as_mstring()));
+ setWString(0, DB_KEY_NICK, data["username"].as_mstring());
+ m_wszEmail = data["email"].as_mstring();
+
+ m_ownId = id;
+
+ m_szCookie.Empty();
+ for (int i=0; i < pReply->headersCount; i++) {
+ if (!mir_strcmpi(pReply->headers[i].szName, "Set-Cookie")) {
+ char *p = strchr(pReply->headers[i].szValue, ';');
+ if (p) *p = 0;
+ if (!m_szCookie.IsEmpty())
+ m_szCookie.Append("; ");
+
+ m_szCookie.Append(pReply->headers[i].szValue);
+ }
+ }
+
+ // launch gateway thread
+ if (m_szGateway.IsEmpty())
+ Push(new AsyncHttpRequest(this, REQUEST_GET, "/gateway", &CDiscordProto::OnReceiveGateway));
+ else
+ ForkThread(&CDiscordProto::GatewayThread, nullptr);
+
+ CheckAvatarChange(0, data["avatar"].as_mstring());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// finds a gateway address
+
+void CDiscordProto::OnReceiveGateway(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (!root) {
+ ShutdownSession();
+ return;
+ }
+
+ auto &data = root.data();
+ m_szGateway = data["url"].as_mstring();
+ ForkThread(&CDiscordProto::GatewayThread, nullptr);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::SetServerStatus(int iStatus)
+{
+ if (GatewaySendStatus(iStatus, nullptr)) {
+ int iOldStatus = m_iStatus; m_iStatus = iStatus;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)iOldStatus, m_iStatus);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// channels
+
+void CDiscordProto::OnReceiveCreateChannel(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (root)
+ OnCommandChannelCreated(root.data());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::OnReceiveMessageAck(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ JsonReply root(pReply);
+ if (!root)
+ return;
+
+ auto &data = root.data();
+ CMStringW wszToken(data["token"].as_mstring());
+ if (!wszToken.IsEmpty()) {
+ JSONNode props; props.set_name("properties");
+ JSONNode reply; reply << props;
+ reply << CHAR_PARAM("event", "ack_messages") << WCHAR_PARAM("token", data["token"].as_mstring());
+ Push(new AsyncHttpRequest(this, REQUEST_POST, "/track", nullptr, &reply));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#define RECAPTCHA_API_KEY "6Lef5iQTAAAAAKeIvIY-DeexoO3gj7ryl9rLMEnn"
+#define RECAPTCHA_SITE_URL "https://discord.com"
+
+void CDiscordProto::OnReceiveToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
+{
+ if (pReply->resultCode != 200) {
+ JSONNode root = JSONNode::parse(pReply->pData);
+ if (root) {
+ const JSONNode &captcha = root["captcha_key"].as_array();
+ if (captcha) {
+ for (auto &it : captcha) {
+ if (it.as_mstring() == "captcha-required") {
+ MessageBoxW(NULL, TranslateT("The server requires you to enter the captcha. Miranda will redirect you to a browser now"), L"Discord", MB_OK | MB_ICONINFORMATION);
+ Utils_OpenUrl("https://discord.com/app");
+ }
+ }
+ }
+
+ for (auto &err: root["errors"]["email"]["_errors"]) {
+ CMStringW code(err["code"].as_mstring());
+ CMStringW message(err["message"].as_mstring());
+ if (!code.IsEmpty() || !message.IsEmpty()) {
+ POPUPDATAW popup;
+ popup.lchIcon = IcoLib_GetIconByHandle(Skin_GetIconHandle(SKINICON_ERROR), true);
+ wcscpy_s(popup.lpwzContactName, m_tszUserName);
+ mir_snwprintf(popup.lpwzText, TranslateT("Connection failed.\n%s (%s)."), message.c_str(), code.c_str());
+ PUAddPopupW(&popup);
+ }
+ }
+ }
+ ConnectionFailed(LOGINERR_WRONGPASSWORD);
+ return;
+ }
+
+ JsonReply root(pReply);
+ if (!root) {
+ ConnectionFailed(LOGINERR_NOSERVER);
+ return;
+ }
+
+ auto &data = root.data();
+ CMStringA szToken = data["token"].as_mstring();
+ if (szToken.IsEmpty()) {
+ debugLogA("Strange empty token received, exiting");
+ return;
+ }
+
+ m_szAccessToken = szToken.Detach();
+ setString("AccessToken", m_szAccessToken);
+ RetrieveMyInfo();
+}
diff --git a/protocols/Discord/src/stdafx.cxx b/protocols/Discord/src/stdafx.cxx index 4b7f53343f..52b06cb953 100644 --- a/protocols/Discord/src/stdafx.cxx +++ b/protocols/Discord/src/stdafx.cxx @@ -1,18 +1,18 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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/>. -*/ - +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
\ No newline at end of file diff --git a/protocols/Discord/src/stdafx.h b/protocols/Discord/src/stdafx.h index 6cba015cc3..48d68292dd 100644 --- a/protocols/Discord/src/stdafx.h +++ b/protocols/Discord/src/stdafx.h @@ -1,80 +1,80 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#pragma once - -#include <Windows.h> -#include <Shlwapi.h> -#include <Wincrypt.h> - -#include <malloc.h> -#include <stdio.h> -#include <io.h> -#include <fcntl.h> -#include <direct.h> -#include <time.h> - -#include <vector> - -#include "resource.h" - -#include <m_system.h> -#include <newpluginapi.h> -#include <m_avatars.h> -#include <m_chat_int.h> -#include <m_clist.h> -#include <m_contacts.h> -#include <m_database.h> -#include <m_folders.h> -#include <m_gui.h> -#include <m_history.h> -#include <m_hotkeys.h> -#include <m_icolib.h> -#include <m_json.h> -#include <m_langpack.h> -#include <m_message.h> -#include <m_netlib.h> -#include <m_options.h> -#include <m_popup.h> -#include <m_protocols.h> -#include <m_protosvc.h> -#include <m_protoint.h> -#include <m_skin.h> -#include <m_srmm_int.h> -#include <m_userinfo.h> -#include <m_utils.h> -#include <m_voice.h> -#include <m_voiceservice.h> - -#include "../../libs/zlib/src/zlib.h" - -extern IconItem g_iconList[]; - -#define DB_KEY_ID "id" -#define DB_KEY_PASSWORD "Password" -#define DB_KEY_DISCR "Discriminator" -#define DB_KEY_MFA "MfaEnabled" -#define DB_KEY_NICK "Nick" -#define DB_KEY_AVHASH "AvatarHash" -#define DB_KEY_CHANNELID "ChannelID" -#define DB_KEY_LASTMSGID "LastMessageID" -#define DB_KEY_REQAUTH "ReqAuth" -#define DB_KEY_DONT_FETCH "DontFetch" - -#define DB_KEYVAL_GROUP L"Discord" - -#include "version.h" -#include "proto.h" - -///////////////////////////////////////////////////////////////////////////////////////// - -void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si); - -void CopyId(const CMStringW &nick); -SnowFlake getId(const JSONNode &pNode); -CMStringW PrepareMessageText(const JSONNode &pRoot); -int StrToStatus(const CMStringW &str); -time_t StringToDate(const CMStringW &str); -int SerialNext(void); +// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include <Windows.h>
+#include <Shlwapi.h>
+#include <Wincrypt.h>
+
+#include <malloc.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <direct.h>
+#include <time.h>
+
+#include <vector>
+
+#include "resource.h"
+
+#include <m_system.h>
+#include <newpluginapi.h>
+#include <m_avatars.h>
+#include <m_chat_int.h>
+#include <m_clist.h>
+#include <m_contacts.h>
+#include <m_database.h>
+#include <m_folders.h>
+#include <m_gui.h>
+#include <m_history.h>
+#include <m_hotkeys.h>
+#include <m_icolib.h>
+#include <m_json.h>
+#include <m_langpack.h>
+#include <m_message.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_protoint.h>
+#include <m_skin.h>
+#include <m_srmm_int.h>
+#include <m_userinfo.h>
+#include <m_utils.h>
+#include <m_voice.h>
+#include <m_voiceservice.h>
+
+#include "../../libs/zlib/src/zlib.h"
+
+extern IconItem g_iconList[];
+
+#define DB_KEY_ID "id"
+#define DB_KEY_PASSWORD "Password"
+#define DB_KEY_DISCR "Discriminator"
+#define DB_KEY_MFA "MfaEnabled"
+#define DB_KEY_NICK "Nick"
+#define DB_KEY_AVHASH "AvatarHash"
+#define DB_KEY_CHANNELID "ChannelID"
+#define DB_KEY_LASTMSGID "LastMessageID"
+#define DB_KEY_REQAUTH "ReqAuth"
+#define DB_KEY_DONT_FETCH "DontFetch"
+
+#define DB_KEYVAL_GROUP L"Discord"
+
+#include "version.h"
+#include "proto.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void BuildStatusList(const CDiscordGuild *pGuild, SESSION_INFO *si);
+
+void CopyId(const CMStringW &nick);
+SnowFlake getId(const JSONNode &pNode);
+CMStringW PrepareMessageText(const JSONNode &pRoot);
+int StrToStatus(const CMStringW &str);
+time_t StringToDate(const CMStringW &str);
+int SerialNext(void);
diff --git a/protocols/Discord/src/utils.cpp b/protocols/Discord/src/utils.cpp index ac40407c69..ce12a81443 100644 --- a/protocols/Discord/src/utils.cpp +++ b/protocols/Discord/src/utils.cpp @@ -1,376 +1,376 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -int StrToStatus(const CMStringW &str) -{ - if (str == L"idle") - return ID_STATUS_NA; - if (str == L"dnd") - return ID_STATUS_DND; - if (str == L"online") - return ID_STATUS_ONLINE; - if (str == L"offline") - return ID_STATUS_OFFLINE; - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -time_t StringToDate(const CMStringW &str) -{ - struct tm T = { 0 }; - int boo; - if (swscanf(str, L"%04d-%02d-%02dT%02d:%02d:%02d.%d", &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, &boo) != 7) - return time(0); - - T.tm_year -= 1900; - T.tm_mon--; - time_t t = mktime(&T); - - _tzset(); - t -= _timezone; - return (t >= 0) ? t : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static LONG volatile g_counter = 1; - -int SerialNext() -{ - return InterlockedIncrement(&g_counter); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -SnowFlake getId(const JSONNode &pNode) -{ - return _wtoi64(pNode.as_mstring()); -} - -SnowFlake CDiscordProto::getId(const char *szSetting) -{ - DBVARIANT dbv; - dbv.type = DBVT_BLOB; - if (db_get(0, m_szModuleName, szSetting, &dbv)) - return 0; - - SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0; - db_free(&dbv); - return result; -} - -SnowFlake CDiscordProto::getId(MCONTACT hContact, const char *szSetting) -{ - DBVARIANT dbv; - dbv.type = DBVT_BLOB; - if (db_get(hContact, m_szModuleName, szSetting, &dbv)) - return 0; - - SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0; - db_free(&dbv); - return result; -} - -void CDiscordProto::setId(const char *szSetting, SnowFlake iValue) -{ - SnowFlake oldVal = getId(szSetting); - if (oldVal != iValue) - db_set_blob(0, m_szModuleName, szSetting, &iValue, sizeof(iValue)); -} - -void CDiscordProto::setId(MCONTACT hContact, const char *szSetting, SnowFlake iValue) -{ - SnowFlake oldVal = getId(hContact, szSetting); - if (oldVal != iValue) - db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue)); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CopyId(const CMStringW &nick) -{ - if (!OpenClipboard(nullptr)) - return; - - EmptyClipboard(); - - int length = nick.GetLength() + 1; - if (HGLOBAL hMemory = GlobalAlloc(GMEM_FIXED, length * sizeof(wchar_t))) { - mir_wstrncpy((wchar_t*)GlobalLock(hMemory), nick, length); - GlobalUnlock(hMemory); - SetClipboardData(CF_UNICODETEXT, hMemory); - } - CloseClipboard(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static CDiscordUser *g_myUser = new CDiscordUser(0); - -CDiscordUser* CDiscordProto::FindUser(SnowFlake id) -{ - return arUsers.find((CDiscordUser*)&id); -} - -CDiscordUser* CDiscordProto::FindUser(const wchar_t *pwszUsername, int iDiscriminator) -{ - for (auto &p : arUsers) - if (p->wszUsername == pwszUsername && p->iDiscriminator == iDiscriminator) - return p; - - return nullptr; -} - -CDiscordUser* CDiscordProto::FindUserByChannel(SnowFlake channelId) -{ - for (auto &p : arUsers) - if (p->channelId == channelId) - return p; - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Common JSON processing routines - -void CDiscordProto::PreparePrivateChannel(const JSONNode &root) -{ - CDiscordUser *pUser = nullptr; - - CMStringW wszChannelId = root["id"].as_mstring(); - SnowFlake channelId = _wtoi64(wszChannelId); - - int type = root["type"].as_int(); - switch (type) { - case 1: // single channel - for (auto &it : root["recipients"]) - pUser = PrepareUser(it); - if (pUser == nullptr) { - debugLogA("Invalid recipients list, exiting"); - return; - } - break; - - case 3: // private groupchat - if ((pUser = FindUserByChannel(channelId)) == nullptr) { - pUser = new CDiscordUser(channelId); - arUsers.insert(pUser); - } - pUser->bIsGroup = true; - pUser->wszUsername = wszChannelId; - pUser->wszChannelName = root["name"].as_mstring(); - { - SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, pUser->wszUsername, pUser->wszChannelName); - pUser->hContact = si->hContact; - - Chat_AddGroup(si, LPGENW("Owners")); - Chat_AddGroup(si, LPGENW("Participants")); - - SnowFlake ownerId = _wtoi64(root["owner_id"].as_mstring()); - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_JOIN }; - gce.pszID.w = pUser->wszUsername; - for (auto &it : root["recipients"]) { - CMStringW wszId = it["id"].as_mstring(); - CMStringW wszNick = it["nick"].as_mstring(); - if (wszNick.IsEmpty()) - wszNick = it["username"].as_mstring() + L"#" + it["discriminator"].as_mstring(); - - gce.pszUID.w = wszId; - gce.pszNick.w = wszNick; - gce.pszStatus.w = (_wtoi64(wszId) == ownerId) ? L"Owners" : L"Participants"; - Chat_Event(&gce); - } - - CMStringW wszId(FORMAT, L"%lld", getId(DB_KEY_ID)); - CMStringW wszNick(FORMAT, L"%s#%d", getMStringW(DB_KEY_NICK).c_str(), getDword(DB_KEY_DISCR)); - gce.bIsMe = true; - gce.pszUID.w = wszId; - gce.pszNick.w = wszNick; - gce.pszStatus.w = (_wtoi64(wszId) == ownerId) ? L"Owners" : L"Participants"; - Chat_Event(&gce); - - Chat_Control(m_szModuleName, pUser->wszUsername, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); - Chat_Control(m_szModuleName, pUser->wszUsername, SESSION_ONLINE); - } - break; - - default: - debugLogA("Invalid channel type: %d, exiting", type); - return; - } - - pUser->channelId = channelId; - pUser->lastMsgId = ::getId(root["last_message_id"]); - pUser->bIsPrivate = true; - - setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId); - - SnowFlake oldMsgId = getId(pUser->hContact, DB_KEY_LASTMSGID); - if (pUser->lastMsgId > oldMsgId) - RetrieveHistory(pUser, MSG_AFTER, oldMsgId, 99); -} - -CDiscordUser* CDiscordProto::PrepareUser(const JSONNode &user) -{ - SnowFlake id = ::getId(user["id"]); - if (id == m_ownId) - return g_myUser; - - int iDiscriminator = _wtoi(user["discriminator"].as_mstring()); - CMStringW username = user["username"].as_mstring(); - - CDiscordUser *pUser = FindUser(id); - if (pUser == nullptr) { - MCONTACT tmp = INVALID_CONTACT_ID; - - // no user found by userid, try to find him via username+discriminator - pUser = FindUser(username, iDiscriminator); - if (pUser != nullptr) { - // if found, remove the object from list to resort it (its userid==0) - if (pUser->hContact != 0) - tmp = pUser->hContact; - arUsers.remove(pUser); - } - pUser = new CDiscordUser(id); - pUser->wszUsername = username; - pUser->iDiscriminator = iDiscriminator; - if (tmp != INVALID_CONTACT_ID) { - // if we previously had a recently added contact without userid, write it down - pUser->hContact = tmp; - setId(pUser->hContact, DB_KEY_ID, id); - } - arUsers.insert(pUser); - } - - if (pUser->hContact == 0) { - MCONTACT hContact = db_add_contact(); - Proto_AddToContact(hContact, m_szModuleName); - - Clist_SetGroup(hContact, m_wszDefaultGroup); - setId(hContact, DB_KEY_ID, id); - setWString(hContact, DB_KEY_NICK, username); - setDword(hContact, DB_KEY_DISCR, iDiscriminator); - - pUser->hContact = hContact; - } - - CheckAvatarChange(pUser->hContact, user["avatar"].as_mstring()); - return pUser; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CMStringW PrepareMessageText(const JSONNode &pRoot) -{ - CMStringW wszText = pRoot["content"].as_mstring(); - - bool bDelimiterAdded = false; - for (auto &it : pRoot["attachments"]) { - CMStringW wszUrl = it["url"].as_mstring(); - if (!wszUrl.IsEmpty()) { - if (!bDelimiterAdded) { - bDelimiterAdded = true; - wszText.Append(L"\n-----------------"); - } - wszText.AppendFormat(L"\n%s: %s", TranslateT("Attachment"), wszUrl.c_str()); - } - } - - for (auto &it : pRoot["embeds"]) { - wszText.Append(L"\n-----------------"); - - CMStringW str = it["url"].as_mstring(); - wszText.AppendFormat(L"\n%s: %s", TranslateT("Embed"), str.c_str()); - - str = it["provider"]["name"].as_mstring() + L" " + it["type"].as_mstring(); - if (str.GetLength() > 1) - wszText.AppendFormat(L"\n\t%s", str.c_str()); - - str = it["description"].as_mstring(); - if (!str.IsEmpty()) - wszText.AppendFormat(L"\n\t%s", str.c_str()); - - str = it["thumbnail"]["url"].as_mstring(); - if (!str.IsEmpty()) - wszText.AppendFormat(L"\n%s: %s", TranslateT("Preview"), str.c_str()); - } - - return wszText; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::ProcessType(CDiscordUser *pUser, const JSONNode &pRoot) -{ - switch (pRoot["type"].as_int()) { - case 1: // confirmed - Contact::PutOnList(pUser->hContact); - delSetting(pUser->hContact, DB_KEY_REQAUTH); - delSetting(pUser->hContact, "ApparentMode"); - break; - - case 3: // expecting authorization - Contact::RemoveFromList(pUser->hContact); - if (!getByte(pUser->hContact, DB_KEY_REQAUTH, 0)) { - setByte(pUser->hContact, DB_KEY_REQAUTH, 1); - - CMStringA szId(FORMAT, "%lld", pUser->id); - DB::AUTH_BLOB blob(pUser->hContact, T2Utf(pUser->wszUsername), nullptr, nullptr, szId, nullptr); - - PROTORECVEVENT pre = { 0 }; - pre.timestamp = (uint32_t)time(0); - pre.lParam = blob.size(); - pre.szMessage = blob; - ProtoChainRecv(pUser->hContact, PSR_AUTH, 0, (LPARAM)&pre); - } - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CDiscordProto::ParseSpecialChars(SESSION_INFO *si, CMStringW &str) -{ - for (int i = 0; (i = str.Find('<', i)) != -1; i++) { - int iEnd = str.Find('>', i + 1); - if (iEnd == -1) - return; - - CMStringW wszWord = str.Mid(i + 1, iEnd - i - 1); - if (wszWord[0] == '@') { // member highlight - int iStart = 1; - if (wszWord[1] == '!') - iStart++; - - USERINFO *ui = g_chatApi.UM_FindUser(si, wszWord.c_str() + iStart); - if (ui != nullptr) - str.Replace(L"<" + wszWord + L">", CMStringW(ui->pszNick) + L": "); - } - else if (wszWord[0] == '#') { - CDiscordUser *pUser = FindUserByChannel(_wtoi64(wszWord.c_str() + 1)); - if (pUser != nullptr) { - ptrW wszNick(getWStringA(pUser->hContact, DB_KEY_NICK)); - if (wszNick != nullptr) - str.Replace(L"<" + wszWord + L">", wszNick); - } - } - } -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+int StrToStatus(const CMStringW &str)
+{
+ if (str == L"idle")
+ return ID_STATUS_NA;
+ if (str == L"dnd")
+ return ID_STATUS_DND;
+ if (str == L"online")
+ return ID_STATUS_ONLINE;
+ if (str == L"offline")
+ return ID_STATUS_OFFLINE;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+time_t StringToDate(const CMStringW &str)
+{
+ struct tm T = { 0 };
+ int boo;
+ if (swscanf(str, L"%04d-%02d-%02dT%02d:%02d:%02d.%d", &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, &boo) != 7)
+ return time(0);
+
+ T.tm_year -= 1900;
+ T.tm_mon--;
+ time_t t = mktime(&T);
+
+ _tzset();
+ t -= _timezone;
+ return (t >= 0) ? t : 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static LONG volatile g_counter = 1;
+
+int SerialNext()
+{
+ return InterlockedIncrement(&g_counter);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+SnowFlake getId(const JSONNode &pNode)
+{
+ return _wtoi64(pNode.as_mstring());
+}
+
+SnowFlake CDiscordProto::getId(const char *szSetting)
+{
+ DBVARIANT dbv;
+ dbv.type = DBVT_BLOB;
+ if (db_get(0, m_szModuleName, szSetting, &dbv))
+ return 0;
+
+ SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0;
+ db_free(&dbv);
+ return result;
+}
+
+SnowFlake CDiscordProto::getId(MCONTACT hContact, const char *szSetting)
+{
+ DBVARIANT dbv;
+ dbv.type = DBVT_BLOB;
+ if (db_get(hContact, m_szModuleName, szSetting, &dbv))
+ return 0;
+
+ SnowFlake result = (dbv.cpbVal == sizeof(SnowFlake)) ? *(SnowFlake*)dbv.pbVal : 0;
+ db_free(&dbv);
+ return result;
+}
+
+void CDiscordProto::setId(const char *szSetting, SnowFlake iValue)
+{
+ SnowFlake oldVal = getId(szSetting);
+ if (oldVal != iValue)
+ db_set_blob(0, m_szModuleName, szSetting, &iValue, sizeof(iValue));
+}
+
+void CDiscordProto::setId(MCONTACT hContact, const char *szSetting, SnowFlake iValue)
+{
+ SnowFlake oldVal = getId(hContact, szSetting);
+ if (oldVal != iValue)
+ db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CopyId(const CMStringW &nick)
+{
+ if (!OpenClipboard(nullptr))
+ return;
+
+ EmptyClipboard();
+
+ int length = nick.GetLength() + 1;
+ if (HGLOBAL hMemory = GlobalAlloc(GMEM_FIXED, length * sizeof(wchar_t))) {
+ mir_wstrncpy((wchar_t*)GlobalLock(hMemory), nick, length);
+ GlobalUnlock(hMemory);
+ SetClipboardData(CF_UNICODETEXT, hMemory);
+ }
+ CloseClipboard();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static CDiscordUser *g_myUser = new CDiscordUser(0);
+
+CDiscordUser* CDiscordProto::FindUser(SnowFlake id)
+{
+ return arUsers.find((CDiscordUser*)&id);
+}
+
+CDiscordUser* CDiscordProto::FindUser(const wchar_t *pwszUsername, int iDiscriminator)
+{
+ for (auto &p : arUsers)
+ if (p->wszUsername == pwszUsername && p->iDiscriminator == iDiscriminator)
+ return p;
+
+ return nullptr;
+}
+
+CDiscordUser* CDiscordProto::FindUserByChannel(SnowFlake channelId)
+{
+ for (auto &p : arUsers)
+ if (p->channelId == channelId)
+ return p;
+
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Common JSON processing routines
+
+void CDiscordProto::PreparePrivateChannel(const JSONNode &root)
+{
+ CDiscordUser *pUser = nullptr;
+
+ CMStringW wszChannelId = root["id"].as_mstring();
+ SnowFlake channelId = _wtoi64(wszChannelId);
+
+ int type = root["type"].as_int();
+ switch (type) {
+ case 1: // single channel
+ for (auto &it : root["recipients"])
+ pUser = PrepareUser(it);
+ if (pUser == nullptr) {
+ debugLogA("Invalid recipients list, exiting");
+ return;
+ }
+ break;
+
+ case 3: // private groupchat
+ if ((pUser = FindUserByChannel(channelId)) == nullptr) {
+ pUser = new CDiscordUser(channelId);
+ arUsers.insert(pUser);
+ }
+ pUser->bIsGroup = true;
+ pUser->wszUsername = wszChannelId;
+ pUser->wszChannelName = root["name"].as_mstring();
+ {
+ SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, pUser->wszUsername, pUser->wszChannelName);
+ pUser->hContact = si->hContact;
+
+ Chat_AddGroup(si, LPGENW("Owners"));
+ Chat_AddGroup(si, LPGENW("Participants"));
+
+ SnowFlake ownerId = _wtoi64(root["owner_id"].as_mstring());
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_JOIN };
+ gce.pszID.w = pUser->wszUsername;
+ for (auto &it : root["recipients"]) {
+ CMStringW wszId = it["id"].as_mstring();
+ CMStringW wszNick = it["nick"].as_mstring();
+ if (wszNick.IsEmpty())
+ wszNick = it["username"].as_mstring() + L"#" + it["discriminator"].as_mstring();
+
+ gce.pszUID.w = wszId;
+ gce.pszNick.w = wszNick;
+ gce.pszStatus.w = (_wtoi64(wszId) == ownerId) ? L"Owners" : L"Participants";
+ Chat_Event(&gce);
+ }
+
+ CMStringW wszId(FORMAT, L"%lld", getId(DB_KEY_ID));
+ CMStringW wszNick(FORMAT, L"%s#%d", getMStringW(DB_KEY_NICK).c_str(), getDword(DB_KEY_DISCR));
+ gce.bIsMe = true;
+ gce.pszUID.w = wszId;
+ gce.pszNick.w = wszNick;
+ gce.pszStatus.w = (_wtoi64(wszId) == ownerId) ? L"Owners" : L"Participants";
+ Chat_Event(&gce);
+
+ Chat_Control(m_szModuleName, pUser->wszUsername, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE);
+ Chat_Control(m_szModuleName, pUser->wszUsername, SESSION_ONLINE);
+ }
+ break;
+
+ default:
+ debugLogA("Invalid channel type: %d, exiting", type);
+ return;
+ }
+
+ pUser->channelId = channelId;
+ pUser->lastMsgId = ::getId(root["last_message_id"]);
+ pUser->bIsPrivate = true;
+
+ setId(pUser->hContact, DB_KEY_CHANNELID, pUser->channelId);
+
+ SnowFlake oldMsgId = getId(pUser->hContact, DB_KEY_LASTMSGID);
+ if (pUser->lastMsgId > oldMsgId)
+ RetrieveHistory(pUser, MSG_AFTER, oldMsgId, 99);
+}
+
+CDiscordUser* CDiscordProto::PrepareUser(const JSONNode &user)
+{
+ SnowFlake id = ::getId(user["id"]);
+ if (id == m_ownId)
+ return g_myUser;
+
+ int iDiscriminator = _wtoi(user["discriminator"].as_mstring());
+ CMStringW username = user["username"].as_mstring();
+
+ CDiscordUser *pUser = FindUser(id);
+ if (pUser == nullptr) {
+ MCONTACT tmp = INVALID_CONTACT_ID;
+
+ // no user found by userid, try to find him via username+discriminator
+ pUser = FindUser(username, iDiscriminator);
+ if (pUser != nullptr) {
+ // if found, remove the object from list to resort it (its userid==0)
+ if (pUser->hContact != 0)
+ tmp = pUser->hContact;
+ arUsers.remove(pUser);
+ }
+ pUser = new CDiscordUser(id);
+ pUser->wszUsername = username;
+ pUser->iDiscriminator = iDiscriminator;
+ if (tmp != INVALID_CONTACT_ID) {
+ // if we previously had a recently added contact without userid, write it down
+ pUser->hContact = tmp;
+ setId(pUser->hContact, DB_KEY_ID, id);
+ }
+ arUsers.insert(pUser);
+ }
+
+ if (pUser->hContact == 0) {
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+
+ Clist_SetGroup(hContact, m_wszDefaultGroup);
+ setId(hContact, DB_KEY_ID, id);
+ setWString(hContact, DB_KEY_NICK, username);
+ setDword(hContact, DB_KEY_DISCR, iDiscriminator);
+
+ pUser->hContact = hContact;
+ }
+
+ CheckAvatarChange(pUser->hContact, user["avatar"].as_mstring());
+ return pUser;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CMStringW PrepareMessageText(const JSONNode &pRoot)
+{
+ CMStringW wszText = pRoot["content"].as_mstring();
+
+ bool bDelimiterAdded = false;
+ for (auto &it : pRoot["attachments"]) {
+ CMStringW wszUrl = it["url"].as_mstring();
+ if (!wszUrl.IsEmpty()) {
+ if (!bDelimiterAdded) {
+ bDelimiterAdded = true;
+ wszText.Append(L"\n-----------------");
+ }
+ wszText.AppendFormat(L"\n%s: %s", TranslateT("Attachment"), wszUrl.c_str());
+ }
+ }
+
+ for (auto &it : pRoot["embeds"]) {
+ wszText.Append(L"\n-----------------");
+
+ CMStringW str = it["url"].as_mstring();
+ wszText.AppendFormat(L"\n%s: %s", TranslateT("Embed"), str.c_str());
+
+ str = it["provider"]["name"].as_mstring() + L" " + it["type"].as_mstring();
+ if (str.GetLength() > 1)
+ wszText.AppendFormat(L"\n\t%s", str.c_str());
+
+ str = it["description"].as_mstring();
+ if (!str.IsEmpty())
+ wszText.AppendFormat(L"\n\t%s", str.c_str());
+
+ str = it["thumbnail"]["url"].as_mstring();
+ if (!str.IsEmpty())
+ wszText.AppendFormat(L"\n%s: %s", TranslateT("Preview"), str.c_str());
+ }
+
+ return wszText;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::ProcessType(CDiscordUser *pUser, const JSONNode &pRoot)
+{
+ switch (pRoot["type"].as_int()) {
+ case 1: // confirmed
+ Contact::PutOnList(pUser->hContact);
+ delSetting(pUser->hContact, DB_KEY_REQAUTH);
+ delSetting(pUser->hContact, "ApparentMode");
+ break;
+
+ case 3: // expecting authorization
+ Contact::RemoveFromList(pUser->hContact);
+ if (!getByte(pUser->hContact, DB_KEY_REQAUTH, 0)) {
+ setByte(pUser->hContact, DB_KEY_REQAUTH, 1);
+
+ CMStringA szId(FORMAT, "%lld", pUser->id);
+ DB::AUTH_BLOB blob(pUser->hContact, T2Utf(pUser->wszUsername), nullptr, nullptr, szId, nullptr);
+
+ PROTORECVEVENT pre = { 0 };
+ pre.timestamp = (uint32_t)time(0);
+ pre.lParam = blob.size();
+ pre.szMessage = blob;
+ ProtoChainRecv(pUser->hContact, PSR_AUTH, 0, (LPARAM)&pre);
+ }
+ break;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CDiscordProto::ParseSpecialChars(SESSION_INFO *si, CMStringW &str)
+{
+ for (int i = 0; (i = str.Find('<', i)) != -1; i++) {
+ int iEnd = str.Find('>', i + 1);
+ if (iEnd == -1)
+ return;
+
+ CMStringW wszWord = str.Mid(i + 1, iEnd - i - 1);
+ if (wszWord[0] == '@') { // member highlight
+ int iStart = 1;
+ if (wszWord[1] == '!')
+ iStart++;
+
+ USERINFO *ui = g_chatApi.UM_FindUser(si, wszWord.c_str() + iStart);
+ if (ui != nullptr)
+ str.Replace(L"<" + wszWord + L">", CMStringW(ui->pszNick) + L": ");
+ }
+ else if (wszWord[0] == '#') {
+ CDiscordUser *pUser = FindUserByChannel(_wtoi64(wszWord.c_str() + 1));
+ if (pUser != nullptr) {
+ ptrW wszNick(getWStringA(pUser->hContact, DB_KEY_NICK));
+ if (wszNick != nullptr)
+ str.Replace(L"<" + wszWord + L">", wszNick);
+ }
+ }
+ }
+}
diff --git a/protocols/Discord/src/version.h b/protocols/Discord/src/version.h index 138a7eaaec..1a33efa401 100644 --- a/protocols/Discord/src/version.h +++ b/protocols/Discord/src/version.h @@ -1,13 +1,13 @@ -#define __MAJOR_VERSION 0 -#define __MINOR_VERSION 6 -#define __RELEASE_NUM 2 -#define __BUILD_NUM 11 - -#include <stdver.h> - -#define __PLUGIN_NAME "Discord protocol" -#define __FILENAME "Discord.dll" -#define __DESCRIPTION "Discord support for Miranda NG." -#define __AUTHOR "George Hazan" -#define __AUTHORWEB "https://miranda-ng.org/p/Discord/" -#define __COPYRIGHT "© 2016-22 Miranda NG team" +#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 6
+#define __RELEASE_NUM 2
+#define __BUILD_NUM 11
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Discord protocol"
+#define __FILENAME "Discord.dll"
+#define __DESCRIPTION "Discord support for Miranda NG."
+#define __AUTHOR "George Hazan"
+#define __AUTHORWEB "https://miranda-ng.org/p/Discord/"
+#define __COPYRIGHT "© 2016-22 Miranda NG team"
diff --git a/protocols/Discord/src/voice.cpp b/protocols/Discord/src/voice.cpp index 6e41bde300..5d1ccf1ea7 100644 --- a/protocols/Discord/src/voice.cpp +++ b/protocols/Discord/src/voice.cpp @@ -1,116 +1,116 @@ -/* -Copyright © 2016-22 Miranda NG team - -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, either version 2 of the License, or -(at your option) any later version. - -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" - -///////////////////////////////////////////////////////////////////////////////////////// -// call operations (voice & video) - -void CDiscordProto::OnCommandCallCreated(const JSONNode &pRoot) -{ - for (auto &it : pRoot["voice_states"]) { - SnowFlake channelId = ::getId(pRoot["channel_id"]); - auto *pUser = FindUserByChannel(channelId); - if (pUser == nullptr) { - debugLogA("Call from unknown channel %lld, skipping", channelId); - continue; - } - - auto *pCall = new CDiscordVoiceCall(); - pCall->szId = it["session_id"].as_mstring(); - pCall->channelId = channelId; - pCall->startTime = time(0); - arVoiceCalls.insert(pCall); - - char *szMessage = TranslateU("Incoming call"); - DBEVENTINFO dbei = {}; - dbei.szModule = m_szModuleName; - dbei.timestamp = pCall->startTime; - dbei.eventType = EVENT_INCOMING_CALL; - dbei.cbBlob = uint32_t(mir_strlen(szMessage) + 1); - dbei.pBlob = (uint8_t *)szMessage; - dbei.flags = DBEF_UTF; - db_event_add(pUser->hContact, &dbei); - } -} - -void CDiscordProto::OnCommandCallDeleted(const JSONNode &pRoot) -{ - SnowFlake channelId = ::getId(pRoot["channel_id"]); - auto *pUser = FindUserByChannel(channelId); - if (pUser == nullptr) { - debugLogA("Call from unknown channel %lld, skipping", channelId); - return; - } - - int elapsed = 0, currTime = time(0); - for (auto &call : arVoiceCalls.rev_iter()) - if (call->channelId == channelId) { - elapsed = currTime - call->startTime; - arVoiceCalls.removeItem(&call); - break; - } - - if (!elapsed) { - debugLogA("Call from channel %lld isn't registered, skipping", channelId); - return; - } - - CMStringA szMessage(FORMAT, TranslateU("Call ended, %d seconds long"), elapsed); - DBEVENTINFO dbei = {}; - dbei.szModule = m_szModuleName; - dbei.timestamp = currTime; - dbei.eventType = EVENT_CALL_FINISHED; - dbei.cbBlob = uint32_t(szMessage.GetLength() + 1); - dbei.pBlob = (uint8_t *)szMessage.c_str(); - dbei.flags = DBEF_UTF; - db_event_add(pUser->hContact, &dbei); -} - -void CDiscordProto::OnCommandCallUpdated(const JSONNode&) -{ -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Events & services - -INT_PTR __cdecl CDiscordProto::VoiceCaps(WPARAM, LPARAM) -{ - return VOICE_CAPS_VOICE | VOICE_CAPS_CALL_CONTACT; -} - -int __cdecl CDiscordProto::OnVoiceState(WPARAM wParam, LPARAM) -{ - auto *pVoice = (VOICE_CALL *)wParam; - if (mir_strcmp(pVoice->moduleName, m_szModuleName)) - return 0; - - CDiscordVoiceCall *pCall = nullptr; - for (auto &it : arVoiceCalls) - if (it->szId == pVoice->id) { - pCall = it; - break; - } - - if (pCall == nullptr) { - debugLogA("Unknown call: %s, exiting", pVoice->id); - return 0; - } - - debugLogA("Call %s state changed to %d", pVoice->id, pVoice->state); - return 0; -} +/*
+Copyright © 2016-22 Miranda NG team
+
+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, either version 2 of the License, or
+(at your option) any later version.
+
+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"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// call operations (voice & video)
+
+void CDiscordProto::OnCommandCallCreated(const JSONNode &pRoot)
+{
+ for (auto &it : pRoot["voice_states"]) {
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ auto *pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ debugLogA("Call from unknown channel %lld, skipping", channelId);
+ continue;
+ }
+
+ auto *pCall = new CDiscordVoiceCall();
+ pCall->szId = it["session_id"].as_mstring();
+ pCall->channelId = channelId;
+ pCall->startTime = time(0);
+ arVoiceCalls.insert(pCall);
+
+ char *szMessage = TranslateU("Incoming call");
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_szModuleName;
+ dbei.timestamp = pCall->startTime;
+ dbei.eventType = EVENT_INCOMING_CALL;
+ dbei.cbBlob = uint32_t(mir_strlen(szMessage) + 1);
+ dbei.pBlob = (uint8_t *)szMessage;
+ dbei.flags = DBEF_UTF;
+ db_event_add(pUser->hContact, &dbei);
+ }
+}
+
+void CDiscordProto::OnCommandCallDeleted(const JSONNode &pRoot)
+{
+ SnowFlake channelId = ::getId(pRoot["channel_id"]);
+ auto *pUser = FindUserByChannel(channelId);
+ if (pUser == nullptr) {
+ debugLogA("Call from unknown channel %lld, skipping", channelId);
+ return;
+ }
+
+ int elapsed = 0, currTime = time(0);
+ for (auto &call : arVoiceCalls.rev_iter())
+ if (call->channelId == channelId) {
+ elapsed = currTime - call->startTime;
+ arVoiceCalls.removeItem(&call);
+ break;
+ }
+
+ if (!elapsed) {
+ debugLogA("Call from channel %lld isn't registered, skipping", channelId);
+ return;
+ }
+
+ CMStringA szMessage(FORMAT, TranslateU("Call ended, %d seconds long"), elapsed);
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_szModuleName;
+ dbei.timestamp = currTime;
+ dbei.eventType = EVENT_CALL_FINISHED;
+ dbei.cbBlob = uint32_t(szMessage.GetLength() + 1);
+ dbei.pBlob = (uint8_t *)szMessage.c_str();
+ dbei.flags = DBEF_UTF;
+ db_event_add(pUser->hContact, &dbei);
+}
+
+void CDiscordProto::OnCommandCallUpdated(const JSONNode&)
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Events & services
+
+INT_PTR __cdecl CDiscordProto::VoiceCaps(WPARAM, LPARAM)
+{
+ return VOICE_CAPS_VOICE | VOICE_CAPS_CALL_CONTACT;
+}
+
+int __cdecl CDiscordProto::OnVoiceState(WPARAM wParam, LPARAM)
+{
+ auto *pVoice = (VOICE_CALL *)wParam;
+ if (mir_strcmp(pVoice->moduleName, m_szModuleName))
+ return 0;
+
+ CDiscordVoiceCall *pCall = nullptr;
+ for (auto &it : arVoiceCalls)
+ if (it->szId == pVoice->id) {
+ pCall = it;
+ break;
+ }
+
+ if (pCall == nullptr) {
+ debugLogA("Unknown call: %s, exiting", pVoice->id);
+ return 0;
+ }
+
+ debugLogA("Call %s state changed to %d", pVoice->id, pVoice->state);
+ return 0;
+}
diff --git a/protocols/Sametime/src/meanwhile/src/mw_error.h b/protocols/Sametime/src/meanwhile/src/mw_error.h index e53cc0c996..eec101d295 100644 --- a/protocols/Sametime/src/meanwhile/src/mw_error.h +++ b/protocols/Sametime/src/meanwhile/src/mw_error.h @@ -1,206 +1,206 @@ - -/* - Meanwhile - Unofficial Lotus Sametime Community Client Library - Copyright (C) 2004 Christopher (siege) O'Brien - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _MW_ERROR_H -#define _MW_ERROR_H - - -/** @file mw_error.h - - Common error code constants used by Meanwhile. - - Not all of these error codes (or even many, really) will ever - actually appear from Meanwhile. These are taken directly from the - houri draft, along with the minimal explanation for each. -*/ - - -#include <glib.h> - - -#ifdef __cplusplus -extern "C" { -#endif - - -/// Miranda NG development start -enum mwReturnCodeType { - mwReturnCodeInfo = 0x1000, - mwReturnCodeError = 0x2000 -}; - -struct mwReturnCodeDesc { - guint16 type; /**< @see mwReturnCodeType */ - char *codeString; /**< return code hex as string */ - char *name; /**< return code name */ - char *description; /**< return code description */ -}; - -struct mwReturnCodeDesc *mwGetReturnCodeDesc(guint32 code); -/// Miranda NG development end - -/** reference to a new string appropriate for the given error code.*/ -char* mwError(guint32 code); - - -/* 8.3 Constants */ -/* 8.3.1 Error Codes */ -/* 8.3.1.1 General error/success codes */ - -/** @enum ERR_GENERAL - general error codes */ -enum ERR_GENERAL { - ERR_SUCCESS = 0x00000000, - ERR_FAILURE = 0x80000000, - ERR_REQUEST_DELAY = 0x00000001, - ERR_REQUEST_INVALID = 0x80000001, - ERR_NOT_LOGGED_IN = 0x80000002, - ERR_NOT_AUTHORIZED = 0x80000003, - ERR_ABORT = 0x80000004, - ERR_NO_ELEMENT = 0x80000005, - ERR_NO_USER = 0x80000006, - ERR_BAD_DATA = 0x80000007, - ERR_NOT_IMPLEMENTED = 0x80000008, - ERR_UNKNOWN_ERROR = 0x80000009, /* what is this? */ - ERR_STARVING = 0x8000000a, - ERR_CHANNEL_NO_SUPPORT = 0x8000000b, - ERR_CHANNEL_EXISTS = 0x8000000c, - ERR_SERVICE_NO_SUPPORT = 0x8000000d, - ERR_PROTOCOL_NO_SUPPORT = 0x8000000e, - ERR_PROTOCOL_NO_SUPPORT2 = 0x8000000f, /* duplicate? */ - ERR_VERSION_NO_SUPPORT = 0x80000010, - ERR_USER_SKETCHY = 0x80000011, - ERR_ALREADY_INITIALIZED = 0x80000013, - ERR_NOT_OWNER = 0x80000014, - ERR_TOKEN_INVALID = 0x80000015, - ERR_TOKEN_EXPIRED = 0x80000016, - ERR_TOKEN_IP_MISMATCH = 0x80000017, - ERR_PORT_IN_USE = 0x80000018, - ERR_NETWORK_DEAD = 0x80000019, - ERR_NO_MASTER_CHANNEL = 0x8000001a, - ERR_ALREADY_SUBSCRIBED = 0x8000001b, - ERR_NOT_SUBSCRIBED = 0x8000001c, - ERR_ENCRYPT_NO_SUPPORT = 0x8000001d, - ERR_ENCRYPT_UNINITIALIZED = 0x8000001e, - ERR_ENCRYPT_UNACCEPTABLE = 0x8000001f, - ERR_ENCRYPT_INVALID = 0x80000020, - ERR_NO_COMMON_ENCRYPT = 0x80000021, - ERR_CHANNEL_DESTROYED = 0x80000022, - /// Miranda NG development start - //ERR_CHANNEL_REDIRECTED = 0x80000023 - ERR_CHANNEL_REDIRECTED = 0x00000023, +
+/*
+ Meanwhile - Unofficial Lotus Sametime Community Client Library
+ Copyright (C) 2004 Christopher (siege) O'Brien
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef _MW_ERROR_H
+#define _MW_ERROR_H
+
+
+/** @file mw_error.h
+
+ Common error code constants used by Meanwhile.
+
+ Not all of these error codes (or even many, really) will ever
+ actually appear from Meanwhile. These are taken directly from the
+ houri draft, along with the minimal explanation for each.
+*/
+
+
+#include <glib.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/// Miranda NG development start
+enum mwReturnCodeType {
+ mwReturnCodeInfo = 0x1000,
+ mwReturnCodeError = 0x2000
+};
+
+struct mwReturnCodeDesc {
+ guint16 type; /**< @see mwReturnCodeType */
+ char *codeString; /**< return code hex as string */
+ char *name; /**< return code name */
+ char *description; /**< return code description */
+};
+
+struct mwReturnCodeDesc *mwGetReturnCodeDesc(guint32 code);
+/// Miranda NG development end
+
+/** reference to a new string appropriate for the given error code.*/
+char* mwError(guint32 code);
+
+
+/* 8.3 Constants */
+/* 8.3.1 Error Codes */
+/* 8.3.1.1 General error/success codes */
+
+/** @enum ERR_GENERAL
+ general error codes */
+enum ERR_GENERAL {
+ ERR_SUCCESS = 0x00000000,
+ ERR_FAILURE = 0x80000000,
+ ERR_REQUEST_DELAY = 0x00000001,
+ ERR_REQUEST_INVALID = 0x80000001,
+ ERR_NOT_LOGGED_IN = 0x80000002,
+ ERR_NOT_AUTHORIZED = 0x80000003,
+ ERR_ABORT = 0x80000004,
+ ERR_NO_ELEMENT = 0x80000005,
+ ERR_NO_USER = 0x80000006,
+ ERR_BAD_DATA = 0x80000007,
+ ERR_NOT_IMPLEMENTED = 0x80000008,
+ ERR_UNKNOWN_ERROR = 0x80000009, /* what is this? */
+ ERR_STARVING = 0x8000000a,
+ ERR_CHANNEL_NO_SUPPORT = 0x8000000b,
+ ERR_CHANNEL_EXISTS = 0x8000000c,
+ ERR_SERVICE_NO_SUPPORT = 0x8000000d,
+ ERR_PROTOCOL_NO_SUPPORT = 0x8000000e,
+ ERR_PROTOCOL_NO_SUPPORT2 = 0x8000000f, /* duplicate? */
+ ERR_VERSION_NO_SUPPORT = 0x80000010,
+ ERR_USER_SKETCHY = 0x80000011,
+ ERR_ALREADY_INITIALIZED = 0x80000013,
+ ERR_NOT_OWNER = 0x80000014,
+ ERR_TOKEN_INVALID = 0x80000015,
+ ERR_TOKEN_EXPIRED = 0x80000016,
+ ERR_TOKEN_IP_MISMATCH = 0x80000017,
+ ERR_PORT_IN_USE = 0x80000018,
+ ERR_NETWORK_DEAD = 0x80000019,
+ ERR_NO_MASTER_CHANNEL = 0x8000001a,
+ ERR_ALREADY_SUBSCRIBED = 0x8000001b,
+ ERR_NOT_SUBSCRIBED = 0x8000001c,
+ ERR_ENCRYPT_NO_SUPPORT = 0x8000001d,
+ ERR_ENCRYPT_UNINITIALIZED = 0x8000001e,
+ ERR_ENCRYPT_UNACCEPTABLE = 0x8000001f,
+ ERR_ENCRYPT_INVALID = 0x80000020,
+ ERR_NO_COMMON_ENCRYPT = 0x80000021,
+ ERR_CHANNEL_DESTROYED = 0x80000022,
+ /// Miranda NG development start
+ //ERR_CHANNEL_REDIRECTED = 0x80000023
+ ERR_CHANNEL_REDIRECTED = 0x00000023,
ERR_INCORRECT_ENTRY = 0x80000239
- /// Miranda NG development end -}; - - -/* 8.3.1.2 Connection/disconnection errors */ - -#define VERSION_MISMATCH 0x80000200 -#define INSUF_BUFFER 0x80000201 -#define NOT_IN_USE 0x80000202 -#define INSUF_SOCKET 0x80000203 -#define HARDWARE_ERROR 0x80000204 -#define NETWORK_DOWN 0x80000205 -#define HOST_DOWN 0x80000206 -#define HOST_UNREACHABLE 0x80000207 -#define TCPIP_ERROR 0x80000208 -#define FAT_MESSAGE 0x80000209 -#define PROXY_ERROR 0x8000020A -#define SERVER_FULL 0x8000020B -#define SERVER_NORESPOND 0x8000020C -#define CANT_CONNECT 0x8000020D -#define USER_REMOVED 0x8000020E -#define PROTOCOL_ERROR 0x8000020F -#define USER_RESTRICTED 0x80000210 -#define INCORRECT_LOGIN 0x80000211 -#define ENCRYPT_MISMATCH 0x80000212 -#define USER_UNREGISTERED 0x80000213 -#define VERIFICATION_DOWN 0x80000214 -#define USER_TOO_IDLE 0x80000216 -#define GUEST_IN_USE 0x80000217 -#define USER_EXISTS 0x80000218 -#define USER_RE_LOGIN 0x80000219 -#define BAD_NAME 0x8000021A -#define REG_MODE_NS 0x8000021B -#define WRONG_USER_PRIV 0x8000021C -#define NEED_EMAIL 0x8000021D -#define DNS_ERROR 0x8000021E -#define DNS_FATAL_ERROR 0x8000021F -#define DNS_NOT_FOUND 0x80000220 -#define CONNECTION_BROKEN 0x80000221 -#define CONNECTION_ABORTED 0x80000222 -#define CONNECTION_REFUSED 0x80000223 -#define CONNECTION_RESET 0x80000224 -#define CONNECTION_TIMED 0x80000225 -#define CONNECTION_CLOSED 0x80000226 -#define MULTI_SERVER_LOGIN 0x80000227 -#define MULTI_SERVER_LOGIN2 0x80000228 -#define MULTI_LOGIN_COMP 0x80000229 -#define MUTLI_LOGIN_ALREADY 0x8000022A -#define SERVER_BROKEN 0x8000022B -#define SERVER_PATH_OLD 0x8000022C -#define APPLET_LOGOUT 0x8000022D - - -/* 8.3.1.3 Client error codes */ - -/** @enum ERR_CLIENT - Client error codes */ -enum ERR_CLIENT { - ERR_CLIENT_USER_GONE = 0x80002000, /* user isn't here */ - ERR_CLIENT_USER_DND = 0x80002001, /* user is DND */ - ERR_CLIENT_USER_ELSEWHERE = 0x80002002, /* already logged in elsewhere */ -}; - - -/* 8.3.1.4 IM error codes */ - -/** @enum ERR_IM - IM error codes */ -enum ERR_IM { - ERR_IM_COULDNT_REGISTER = 0x80002003, - ERR_IM_ALREADY_REGISTERED = 0x80002004, - - /** apparently, this is used to mean that the requested feature (per - the channel create addtl data) is not supported by the client on - the other end of the IM channel */ - ERR_IM_NOT_REGISTERED = 0x80002005, -}; - - -/// Miranda NG development start -/* 8.3.1.5 Resolve error codes */ - -/** @enum ERR_RESOLVE -Resolve error codes */ -enum ERR_RESOLVE { - ERR_RESOLVE_NOTCOMPLETED = 0x00010000, - ERR_RESOLVE_NAMENOTUNIQUE = 0x80020000, + /// Miranda NG development end
+};
+
+
+/* 8.3.1.2 Connection/disconnection errors */
+
+#define VERSION_MISMATCH 0x80000200
+#define INSUF_BUFFER 0x80000201
+#define NOT_IN_USE 0x80000202
+#define INSUF_SOCKET 0x80000203
+#define HARDWARE_ERROR 0x80000204
+#define NETWORK_DOWN 0x80000205
+#define HOST_DOWN 0x80000206
+#define HOST_UNREACHABLE 0x80000207
+#define TCPIP_ERROR 0x80000208
+#define FAT_MESSAGE 0x80000209
+#define PROXY_ERROR 0x8000020A
+#define SERVER_FULL 0x8000020B
+#define SERVER_NORESPOND 0x8000020C
+#define CANT_CONNECT 0x8000020D
+#define USER_REMOVED 0x8000020E
+#define PROTOCOL_ERROR 0x8000020F
+#define USER_RESTRICTED 0x80000210
+#define INCORRECT_LOGIN 0x80000211
+#define ENCRYPT_MISMATCH 0x80000212
+#define USER_UNREGISTERED 0x80000213
+#define VERIFICATION_DOWN 0x80000214
+#define USER_TOO_IDLE 0x80000216
+#define GUEST_IN_USE 0x80000217
+#define USER_EXISTS 0x80000218
+#define USER_RE_LOGIN 0x80000219
+#define BAD_NAME 0x8000021A
+#define REG_MODE_NS 0x8000021B
+#define WRONG_USER_PRIV 0x8000021C
+#define NEED_EMAIL 0x8000021D
+#define DNS_ERROR 0x8000021E
+#define DNS_FATAL_ERROR 0x8000021F
+#define DNS_NOT_FOUND 0x80000220
+#define CONNECTION_BROKEN 0x80000221
+#define CONNECTION_ABORTED 0x80000222
+#define CONNECTION_REFUSED 0x80000223
+#define CONNECTION_RESET 0x80000224
+#define CONNECTION_TIMED 0x80000225
+#define CONNECTION_CLOSED 0x80000226
+#define MULTI_SERVER_LOGIN 0x80000227
+#define MULTI_SERVER_LOGIN2 0x80000228
+#define MULTI_LOGIN_COMP 0x80000229
+#define MUTLI_LOGIN_ALREADY 0x8000022A
+#define SERVER_BROKEN 0x8000022B
+#define SERVER_PATH_OLD 0x8000022C
+#define APPLET_LOGOUT 0x8000022D
+
+
+/* 8.3.1.3 Client error codes */
+
+/** @enum ERR_CLIENT
+ Client error codes */
+enum ERR_CLIENT {
+ ERR_CLIENT_USER_GONE = 0x80002000, /* user isn't here */
+ ERR_CLIENT_USER_DND = 0x80002001, /* user is DND */
+ ERR_CLIENT_USER_ELSEWHERE = 0x80002002, /* already logged in elsewhere */
+};
+
+
+/* 8.3.1.4 IM error codes */
+
+/** @enum ERR_IM
+ IM error codes */
+enum ERR_IM {
+ ERR_IM_COULDNT_REGISTER = 0x80002003,
+ ERR_IM_ALREADY_REGISTERED = 0x80002004,
+
+ /** apparently, this is used to mean that the requested feature (per
+ the channel create addtl data) is not supported by the client on
+ the other end of the IM channel */
+ ERR_IM_NOT_REGISTERED = 0x80002005,
+};
+
+
+/// Miranda NG development start
+/* 8.3.1.5 Resolve error codes */
+
+/** @enum ERR_RESOLVE
+Resolve error codes */
+enum ERR_RESOLVE {
+ ERR_RESOLVE_NOTCOMPLETED = 0x00010000,
+ ERR_RESOLVE_NAMENOTUNIQUE = 0x80020000,
ERR_RESOLVE_NAMENOTRESOLVABLE = 0x80030000
-}; -/// Miranda NG development end - -#ifdef __cplusplus -} -#endif - - -#endif /* _MW_ERROR_H */ +};
+/// Miranda NG development end
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MW_ERROR_H */
diff --git a/protocols/Steam/src/api/enums.h b/protocols/Steam/src/api/enums.h index 087b99c5fa..2cf767e37f 100644 --- a/protocols/Steam/src/api/enums.h +++ b/protocols/Steam/src/api/enums.h @@ -1,88 +1,88 @@ -#ifndef _STEAM_ENUMS_H_ -#define _STEAM_ENUMS_H_ - -enum VisibilityState -{ - Private = 1, - FriendsOnly = 2, - FriendsOfFriends = 3, - UsersOnly = 4, - Public = 5, -}; - -enum PersonaState -{ - Offline = 0, - Online = 1, - Busy = 2, - Away = 3, - Snooze = 4, - LookingToTrade = 5, - LookingToPlay = 6, - Invisible = 7, -}; - -enum class PersonaStateFlag : int -{ - None = 0, - HasRichPresence = 1, - InJoinableGame = 2, - ClientTypeWeb = 256, - ClientTypeMobile = 512, - ClientTypeBigPicture = 1024, - ClientTypeVR = 2048, -}; - -inline PersonaStateFlag operator &(PersonaStateFlag lhs, PersonaStateFlag rhs) -{ - return static_cast<PersonaStateFlag> ( - static_cast<std::underlying_type<PersonaStateFlag>::type>(lhs) & - static_cast<std::underlying_type<PersonaStateFlag>::type>(rhs)); -} - -enum class PersonaStatusFlag : int -{ - Status = 1, - PlayerName = 2, - QueryPort = 4, - SourceID = 8, - Presence = 16, - Metadata = 32, - LastSeen = 64, - ClanInfo = 128, - GameExtraInfo = 256, - GameDataBlob = 512, - ClanTag = 1024, - Facebook = 2048, - Unknown = 4096, -}; - -inline PersonaStatusFlag operator &(PersonaStatusFlag lhs, PersonaStatusFlag rhs) -{ - return static_cast<PersonaStatusFlag> ( - static_cast<std::underlying_type<PersonaStatusFlag>::type>(lhs) & - static_cast<std::underlying_type<PersonaStatusFlag>::type>(rhs)); -} - -enum class PersonaRelationshipAction : int -{ - // friend removed from contact list - Remove = 0, - // friend added you to ignore list - Ignore = 1, - // friend requested auth - AuthRequest = 2, - // friend added you to contact list - AddToList = 3, - // friend got (or approved?) your auth request - AuthRequested = 4, -}; - -template<typename T> -bool contains_flag(T x, T y) { - return (static_cast<typename std::underlying_type<T>::type>(x) - & static_cast<typename std::underlying_type<T>::type>(y)) - == static_cast<typename std::underlying_type<T>::type>(y); -} - -#endif //_STEAM_ENUMS_H_ +#ifndef _STEAM_ENUMS_H_
+#define _STEAM_ENUMS_H_
+
+enum VisibilityState
+{
+ Private = 1,
+ FriendsOnly = 2,
+ FriendsOfFriends = 3,
+ UsersOnly = 4,
+ Public = 5,
+};
+
+enum PersonaState
+{
+ Offline = 0,
+ Online = 1,
+ Busy = 2,
+ Away = 3,
+ Snooze = 4,
+ LookingToTrade = 5,
+ LookingToPlay = 6,
+ Invisible = 7,
+};
+
+enum class PersonaStateFlag : int
+{
+ None = 0,
+ HasRichPresence = 1,
+ InJoinableGame = 2,
+ ClientTypeWeb = 256,
+ ClientTypeMobile = 512,
+ ClientTypeBigPicture = 1024,
+ ClientTypeVR = 2048,
+};
+
+inline PersonaStateFlag operator &(PersonaStateFlag lhs, PersonaStateFlag rhs)
+{
+ return static_cast<PersonaStateFlag> (
+ static_cast<std::underlying_type<PersonaStateFlag>::type>(lhs) &
+ static_cast<std::underlying_type<PersonaStateFlag>::type>(rhs));
+}
+
+enum class PersonaStatusFlag : int
+{
+ Status = 1,
+ PlayerName = 2,
+ QueryPort = 4,
+ SourceID = 8,
+ Presence = 16,
+ Metadata = 32,
+ LastSeen = 64,
+ ClanInfo = 128,
+ GameExtraInfo = 256,
+ GameDataBlob = 512,
+ ClanTag = 1024,
+ Facebook = 2048,
+ Unknown = 4096,
+};
+
+inline PersonaStatusFlag operator &(PersonaStatusFlag lhs, PersonaStatusFlag rhs)
+{
+ return static_cast<PersonaStatusFlag> (
+ static_cast<std::underlying_type<PersonaStatusFlag>::type>(lhs) &
+ static_cast<std::underlying_type<PersonaStatusFlag>::type>(rhs));
+}
+
+enum class PersonaRelationshipAction : int
+{
+ // friend removed from contact list
+ Remove = 0,
+ // friend added you to ignore list
+ Ignore = 1,
+ // friend requested auth
+ AuthRequest = 2,
+ // friend added you to contact list
+ AddToList = 3,
+ // friend got (or approved?) your auth request
+ AuthRequested = 4,
+};
+
+template<typename T>
+bool contains_flag(T x, T y) {
+ return (static_cast<typename std::underlying_type<T>::type>(x)
+ & static_cast<typename std::underlying_type<T>::type>(y))
+ == static_cast<typename std::underlying_type<T>::type>(y);
+}
+
+#endif //_STEAM_ENUMS_H_
diff --git a/protocols/Steam/src/steam_proto.cpp b/protocols/Steam/src/steam_proto.cpp index a6bac4aafb..f185171edd 100644 --- a/protocols/Steam/src/steam_proto.cpp +++ b/protocols/Steam/src/steam_proto.cpp @@ -1,354 +1,354 @@ -#include "stdafx.h" - -CSteamProto::CSteamProto(const char *protoName, const wchar_t *userName) : - PROTO<CSteamProto>(protoName, userName), - m_requestQueue(1), hAuthProcess(1), hMessageProcess(1) -{ - CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit); - - m_hRequestsQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL); - - // default group - m_defaultGroup = getWStringA("DefaultGroup"); - if (m_defaultGroup == nullptr) - m_defaultGroup = mir_wstrdup(L"Steam"); - - // icons - wchar_t filePath[MAX_PATH]; - GetModuleFileName(g_plugin.getInst(), filePath, MAX_PATH); - - wchar_t sectionName[100]; - mir_snwprintf(sectionName, L"%s/%s", LPGENW("Protocols"), _A2W(MODULE)); - - char settingName[100]; - mir_snprintf(settingName, "%s_%s", MODULE, "main"); - - SKINICONDESC sid = {}; - sid.flags = SIDF_ALL_UNICODE; - sid.defaultFile.w = filePath; - sid.pszName = settingName; - sid.section.w = sectionName; - sid.description.w = LPGENW("Protocol icon"); - sid.iDefaultIndex = -IDI_STEAM; - g_plugin.addIcon(&sid); - - mir_snprintf(settingName, "%s_%s", MODULE, "gaming"); - sid.description.w = LPGENW("Gaming icon"); - sid.iDefaultIndex = -IDI_GAMING; - g_plugin.addIcon(&sid); - - // temporary DB settings - db_set_resident(m_szModuleName, "XStatusId"); - db_set_resident(m_szModuleName, "XStatusName"); - db_set_resident(m_szModuleName, "XStatusMsg"); - db_set_resident(m_szModuleName, "IdleTS"); - db_set_resident(m_szModuleName, "GameID"); - db_set_resident(m_szModuleName, "ServerIP"); - db_set_resident(m_szModuleName, "ServerID"); - - SetAllContactStatuses(ID_STATUS_OFFLINE); - - // avatar API - CreateProtoService(PS_GETAVATARINFO, &CSteamProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps); - CreateProtoService(PS_GETMYAVATAR, &CSteamProto::GetMyAvatar); - - // custom status API - CreateProtoService(PS_GETCUSTOMSTATUSEX, &CSteamProto::OnGetXStatusEx); - CreateProtoService(PS_GETCUSTOMSTATUSICON, &CSteamProto::OnGetXStatusIcon); - CreateProtoService(PS_GETADVANCEDSTATUSICON, &CSteamProto::OnRequestAdvStatusIconIdx); - - // menus - CreateProtoService(PS_MENU_REQAUTH, &CSteamProto::AuthRequestCommand); - CreateProtoService(PS_MENU_REVOKEAUTH, &CSteamProto::AuthRevokeCommand); - - // custom db events API - CreateProtoService(STEAM_DB_GETEVENTTEXT_CHATSTATES, &CSteamProto::OnGetEventTextChatStates); - - // hooks - HookProtoEvent(ME_OPT_INITIALISE, &CSteamProto::OnOptionsInit); - - // netlib support - NETLIBUSER nlu = {}; - nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; - nlu.szDescriptiveName.w = m_tszUserName; - nlu.szSettingsModule = m_szModuleName; - m_hNetlibUser = Netlib_RegisterUser(&nlu); - - debugLogA(__FUNCTION__":Setting protocol / module name to '%s'", m_szModuleName); - - if (uint32_t iGlobalValue = getDword(DB_KEY_LASTMSGTS)) { - for (auto &cc : AccContacts()) - setDword(cc, DB_KEY_LASTMSGTS, iGlobalValue); - delSetting(DB_KEY_LASTMSGTS); - } -} - -CSteamProto::~CSteamProto() -{ - if (m_hRequestsQueueEvent) { - CloseHandle(m_hRequestsQueueEvent); - m_hRequestsQueueEvent = nullptr; - } -} - -MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr) -{ - MCONTACT hContact = AddContact(T2Utf(psr->id.w), psr->nick.w, true); - - if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) { - STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT *)psr; - UpdateContactDetails(hContact, *ssr->data); - } - - return hContact; -} - -MCONTACT CSteamProto::AddToListByEvent(int, int, MEVENT hDbEvent) -{ - DB::EventInfo dbei; - dbei.cbBlob = -1; - if (db_event_get(hDbEvent, &dbei)) - return 0; - if (mir_strcmp(dbei.szModule, m_szModuleName)) - return 0; - if (dbei.eventType != EVENTTYPE_AUTHREQUEST) - return 0; - - DB::AUTH_BLOB blob(dbei.pBlob); - return AddContact(blob.get_email(), Utf2T(blob.get_nick())); -} - -int CSteamProto::Authorize(MEVENT hDbEvent) -{ - if (IsOnline() && hDbEvent) { - MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - char *who = getStringA(hContact, "SteamID"); - - PushRequest( - new ApprovePendingRequest(token, sessionId, steamId, who), - &CSteamProto::OnPendingApproved, - who); - - return 0; - } - - return 1; -} - -int CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT *pre) -{ - // remember to not create this event again, unless authorization status changes again - setByte(hContact, "AuthAsked", 1); - return Proto_AuthRecv(m_szModuleName, pre); -} - -int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*) -{ - if (IsOnline() && hDbEvent) { - MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); - if (hContact == INVALID_CONTACT_ID) - return 1; - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - char *who = getStringA(hContact, "SteamID"); - - PushRequest( - new IgnorePendingRequest(token, sessionId, steamId, who), - &CSteamProto::OnPendingIgnoreded, - who); - - return 0; - } - - return 1; -} - -int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*) -{ - if (IsOnline() && hContact) { - UINT hAuth = InterlockedIncrement(&hAuthProcess); - - SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam)); - param->hContact = hContact; - param->hAuth = (HANDLE)hAuth; - - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - ptrA who(getStringA(hContact, "SteamID")); - - PushRequest( - new AddFriendRequest(token, sessionId, steamId, who), - &CSteamProto::OnFriendAdded, - param); - - return hAuth; - } - - return 1; -} - -INT_PTR CSteamProto::GetCaps(int type, MCONTACT) -{ - switch (type) { - case PFLAGNUM_1: - return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES | PF1_MODEMSGRECV; - case PFLAGNUM_2: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE; - case PFLAGNUM_4: - return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_SUPPORTIDLE | PF4_SUPPORTTYPING;// | PF4_IMSENDOFFLINE; - case PFLAGNUM_5: - return PF2_HEAVYDND | PF2_FREECHAT; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)TranslateT("SteamID"); - default: - return 0; - } -} - -HANDLE CSteamProto::SearchBasic(const wchar_t* id) -{ - if (!this->IsOnline()) - return nullptr; - - ptrA steamId(mir_u2a(id)); - PushRequest(new GetUserSummariesRequest(this, steamId), &CSteamProto::OnSearchResults, (HANDLE)STEAM_SEARCH_BYID); - - return (HANDLE)STEAM_SEARCH_BYID; -} - -HANDLE CSteamProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName) -{ - if (!IsOnline()) - return nullptr; - - // Combine all fields to single text - wchar_t keywordsT[200]; - mir_snwprintf(keywordsT, L"%s %s %s", nick, firstName, lastName); - - ptrA token(getStringA("TokenSecret")); - ptrA keywords(mir_utf8encodeW(rtrimw(keywordsT))); - - PushRequest( - new SearchRequest(token, keywords), - &CSteamProto::OnSearchByNameStarted, - (HANDLE)STEAM_SEARCH_BYNAME); - - return (HANDLE)STEAM_SEARCH_BYNAME; -} - -int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message) -{ - if (!IsOnline()) { - ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, nullptr, (LPARAM)TranslateT("You cannot send messages when you are offline.")); - return 0; - } - - return OnSendMessage(hContact, message); -} - -int CSteamProto::SetStatus(int new_status) -{ - // Routing statuses not supported by Steam - switch (new_status) { - case ID_STATUS_OFFLINE: - case ID_STATUS_AWAY: - case ID_STATUS_NA: - case ID_STATUS_INVISIBLE: - break; - - case ID_STATUS_DND: - case ID_STATUS_OCCUPIED: - new_status = ID_STATUS_NA; - break; - - default: - new_status = ID_STATUS_ONLINE; - break; - } - - { - mir_cslock lock(m_setStatusLock); - if (new_status == m_iDesiredStatus) - return 0; - } - - debugLogA(__FUNCTION__ ": changing status from %i to %i", m_iStatus, new_status); - - int old_status = m_iStatus; - m_iDesiredStatus = new_status; - - if (new_status == ID_STATUS_OFFLINE) { - // Reset relogin flag - isLoginAgain = false; - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - - if (!Miranda_IsTerminated()) - SetAllContactStatuses(ID_STATUS_OFFLINE); - - Logout(); - } - else if (m_hRequestQueueThread == nullptr && !IsStatusConnecting(m_iStatus)) { - m_iStatus = ID_STATUS_CONNECTING; - m_isTerminated = false; - ForkThread(&CSteamProto::RequestQueueThread); - - Login(); - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - } - else if (IsOnline()) { - m_iStatus = new_status; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); - } - return 0; -} - -void CSteamProto::GetAwayMsgThread(void *arg) -{ - // Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg() - Sleep(50); - - MCONTACT hContact = (UINT_PTR)arg; - CMStringW message(db_get_wsm(hContact, "CList", "StatusMsg")); - - // if contact has no status message, get xstatus message - if (message.IsEmpty()) { - ptrW xStatusName(getWStringA(hContact, "XStatusName")); - ptrW xStatusMsg(getWStringA(hContact, "XStatusMsg")); - - if (xStatusName) - message.AppendFormat(L"%s: %s", xStatusName.get(), xStatusMsg.get()); - else - message.Append(xStatusMsg); - } - - ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)message.c_str()); -} - -HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact) -{ - ForkThread(&CSteamProto::GetAwayMsgThread, (void*)hContact); - return (HANDLE)1; -} - -void CSteamProto::OnContactDeleted(MCONTACT hContact) -{ - // remove only authorized contacts - if (!getByte(hContact, "Auth", 0)) { - ptrA token(getStringA("TokenSecret")); - ptrA sessionId(getStringA("SessionID")); - ptrA steamId(getStringA("SteamID")); - char *who = getStringA(hContact, "SteamID"); - PushRequest(new RemoveFriendRequest(token, sessionId, steamId, who), &CSteamProto::OnFriendRemoved, (void*)who); - } -} +#include "stdafx.h"
+
+CSteamProto::CSteamProto(const char *protoName, const wchar_t *userName) :
+ PROTO<CSteamProto>(protoName, userName),
+ m_requestQueue(1), hAuthProcess(1), hMessageProcess(1)
+{
+ CreateProtoService(PS_CREATEACCMGRUI, &CSteamProto::OnAccountManagerInit);
+
+ m_hRequestsQueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ // default group
+ m_defaultGroup = getWStringA("DefaultGroup");
+ if (m_defaultGroup == nullptr)
+ m_defaultGroup = mir_wstrdup(L"Steam");
+
+ // icons
+ wchar_t filePath[MAX_PATH];
+ GetModuleFileName(g_plugin.getInst(), filePath, MAX_PATH);
+
+ wchar_t sectionName[100];
+ mir_snwprintf(sectionName, L"%s/%s", LPGENW("Protocols"), _A2W(MODULE));
+
+ char settingName[100];
+ mir_snprintf(settingName, "%s_%s", MODULE, "main");
+
+ SKINICONDESC sid = {};
+ sid.flags = SIDF_ALL_UNICODE;
+ sid.defaultFile.w = filePath;
+ sid.pszName = settingName;
+ sid.section.w = sectionName;
+ sid.description.w = LPGENW("Protocol icon");
+ sid.iDefaultIndex = -IDI_STEAM;
+ g_plugin.addIcon(&sid);
+
+ mir_snprintf(settingName, "%s_%s", MODULE, "gaming");
+ sid.description.w = LPGENW("Gaming icon");
+ sid.iDefaultIndex = -IDI_GAMING;
+ g_plugin.addIcon(&sid);
+
+ // temporary DB settings
+ db_set_resident(m_szModuleName, "XStatusId");
+ db_set_resident(m_szModuleName, "XStatusName");
+ db_set_resident(m_szModuleName, "XStatusMsg");
+ db_set_resident(m_szModuleName, "IdleTS");
+ db_set_resident(m_szModuleName, "GameID");
+ db_set_resident(m_szModuleName, "ServerIP");
+ db_set_resident(m_szModuleName, "ServerID");
+
+ SetAllContactStatuses(ID_STATUS_OFFLINE);
+
+ // avatar API
+ CreateProtoService(PS_GETAVATARINFO, &CSteamProto::GetAvatarInfo);
+ CreateProtoService(PS_GETAVATARCAPS, &CSteamProto::GetAvatarCaps);
+ CreateProtoService(PS_GETMYAVATAR, &CSteamProto::GetMyAvatar);
+
+ // custom status API
+ CreateProtoService(PS_GETCUSTOMSTATUSEX, &CSteamProto::OnGetXStatusEx);
+ CreateProtoService(PS_GETCUSTOMSTATUSICON, &CSteamProto::OnGetXStatusIcon);
+ CreateProtoService(PS_GETADVANCEDSTATUSICON, &CSteamProto::OnRequestAdvStatusIconIdx);
+
+ // menus
+ CreateProtoService(PS_MENU_REQAUTH, &CSteamProto::AuthRequestCommand);
+ CreateProtoService(PS_MENU_REVOKEAUTH, &CSteamProto::AuthRevokeCommand);
+
+ // custom db events API
+ CreateProtoService(STEAM_DB_GETEVENTTEXT_CHATSTATES, &CSteamProto::OnGetEventTextChatStates);
+
+ // hooks
+ HookProtoEvent(ME_OPT_INITIALISE, &CSteamProto::OnOptionsInit);
+
+ // netlib support
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szDescriptiveName.w = m_tszUserName;
+ nlu.szSettingsModule = m_szModuleName;
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ debugLogA(__FUNCTION__":Setting protocol / module name to '%s'", m_szModuleName);
+
+ if (uint32_t iGlobalValue = getDword(DB_KEY_LASTMSGTS)) {
+ for (auto &cc : AccContacts())
+ setDword(cc, DB_KEY_LASTMSGTS, iGlobalValue);
+ delSetting(DB_KEY_LASTMSGTS);
+ }
+}
+
+CSteamProto::~CSteamProto()
+{
+ if (m_hRequestsQueueEvent) {
+ CloseHandle(m_hRequestsQueueEvent);
+ m_hRequestsQueueEvent = nullptr;
+ }
+}
+
+MCONTACT CSteamProto::AddToList(int, PROTOSEARCHRESULT *psr)
+{
+ MCONTACT hContact = AddContact(T2Utf(psr->id.w), psr->nick.w, true);
+
+ if (psr->cbSize == sizeof(STEAM_SEARCH_RESULT)) {
+ STEAM_SEARCH_RESULT *ssr = (STEAM_SEARCH_RESULT *)psr;
+ UpdateContactDetails(hContact, *ssr->data);
+ }
+
+ return hContact;
+}
+
+MCONTACT CSteamProto::AddToListByEvent(int, int, MEVENT hDbEvent)
+{
+ DB::EventInfo dbei;
+ dbei.cbBlob = -1;
+ if (db_event_get(hDbEvent, &dbei))
+ return 0;
+ if (mir_strcmp(dbei.szModule, m_szModuleName))
+ return 0;
+ if (dbei.eventType != EVENTTYPE_AUTHREQUEST)
+ return 0;
+
+ DB::AUTH_BLOB blob(dbei.pBlob);
+ return AddContact(blob.get_email(), Utf2T(blob.get_nick()));
+}
+
+int CSteamProto::Authorize(MEVENT hDbEvent)
+{
+ if (IsOnline() && hDbEvent) {
+ MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
+ if (hContact == INVALID_CONTACT_ID)
+ return 1;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new ApprovePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingApproved,
+ who);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int CSteamProto::AuthRecv(MCONTACT hContact, PROTORECVEVENT *pre)
+{
+ // remember to not create this event again, unless authorization status changes again
+ setByte(hContact, "AuthAsked", 1);
+ return Proto_AuthRecv(m_szModuleName, pre);
+}
+
+int CSteamProto::AuthDeny(MEVENT hDbEvent, const wchar_t*)
+{
+ if (IsOnline() && hDbEvent) {
+ MCONTACT hContact = GetContactFromAuthEvent(hDbEvent);
+ if (hContact == INVALID_CONTACT_ID)
+ return 1;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+
+ PushRequest(
+ new IgnorePendingRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnPendingIgnoreded,
+ who);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+int CSteamProto::AuthRequest(MCONTACT hContact, const wchar_t*)
+{
+ if (IsOnline() && hContact) {
+ UINT hAuth = InterlockedIncrement(&hAuthProcess);
+
+ SendAuthParam *param = (SendAuthParam*)mir_calloc(sizeof(SendAuthParam));
+ param->hContact = hContact;
+ param->hAuth = (HANDLE)hAuth;
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ ptrA who(getStringA(hContact, "SteamID"));
+
+ PushRequest(
+ new AddFriendRequest(token, sessionId, steamId, who),
+ &CSteamProto::OnFriendAdded,
+ param);
+
+ return hAuth;
+ }
+
+ return 1;
+}
+
+INT_PTR CSteamProto::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_BASICSEARCH | PF1_SEARCHBYNAME | PF1_AUTHREQ | PF1_SERVERCLIST | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT | PF2_INVISIBLE;
+ case PFLAGNUM_4:
+ return PF4_AVATARS | PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH | PF4_SUPPORTIDLE | PF4_SUPPORTTYPING;// | PF4_IMSENDOFFLINE;
+ case PFLAGNUM_5:
+ return PF2_HEAVYDND | PF2_FREECHAT;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)TranslateT("SteamID");
+ default:
+ return 0;
+ }
+}
+
+HANDLE CSteamProto::SearchBasic(const wchar_t* id)
+{
+ if (!this->IsOnline())
+ return nullptr;
+
+ ptrA steamId(mir_u2a(id));
+ PushRequest(new GetUserSummariesRequest(this, steamId), &CSteamProto::OnSearchResults, (HANDLE)STEAM_SEARCH_BYID);
+
+ return (HANDLE)STEAM_SEARCH_BYID;
+}
+
+HANDLE CSteamProto::SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName)
+{
+ if (!IsOnline())
+ return nullptr;
+
+ // Combine all fields to single text
+ wchar_t keywordsT[200];
+ mir_snwprintf(keywordsT, L"%s %s %s", nick, firstName, lastName);
+
+ ptrA token(getStringA("TokenSecret"));
+ ptrA keywords(mir_utf8encodeW(rtrimw(keywordsT)));
+
+ PushRequest(
+ new SearchRequest(token, keywords),
+ &CSteamProto::OnSearchByNameStarted,
+ (HANDLE)STEAM_SEARCH_BYNAME);
+
+ return (HANDLE)STEAM_SEARCH_BYNAME;
+}
+
+int CSteamProto::SendMsg(MCONTACT hContact, int, const char *message)
+{
+ if (!IsOnline()) {
+ ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, nullptr, (LPARAM)TranslateT("You cannot send messages when you are offline."));
+ return 0;
+ }
+
+ return OnSendMessage(hContact, message);
+}
+
+int CSteamProto::SetStatus(int new_status)
+{
+ // Routing statuses not supported by Steam
+ switch (new_status) {
+ case ID_STATUS_OFFLINE:
+ case ID_STATUS_AWAY:
+ case ID_STATUS_NA:
+ case ID_STATUS_INVISIBLE:
+ break;
+
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ new_status = ID_STATUS_NA;
+ break;
+
+ default:
+ new_status = ID_STATUS_ONLINE;
+ break;
+ }
+
+ {
+ mir_cslock lock(m_setStatusLock);
+ if (new_status == m_iDesiredStatus)
+ return 0;
+ }
+
+ debugLogA(__FUNCTION__ ": changing status from %i to %i", m_iStatus, new_status);
+
+ int old_status = m_iStatus;
+ m_iDesiredStatus = new_status;
+
+ if (new_status == ID_STATUS_OFFLINE) {
+ // Reset relogin flag
+ isLoginAgain = false;
+
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+
+ if (!Miranda_IsTerminated())
+ SetAllContactStatuses(ID_STATUS_OFFLINE);
+
+ Logout();
+ }
+ else if (m_hRequestQueueThread == nullptr && !IsStatusConnecting(m_iStatus)) {
+ m_iStatus = ID_STATUS_CONNECTING;
+ m_isTerminated = false;
+ ForkThread(&CSteamProto::RequestQueueThread);
+
+ Login();
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ }
+ else if (IsOnline()) {
+ m_iStatus = new_status;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus);
+ }
+ return 0;
+}
+
+void CSteamProto::GetAwayMsgThread(void *arg)
+{
+ // Maybe not needed, but better to be sure that this won't happen faster than core handling return value of GetAwayMsg()
+ Sleep(50);
+
+ MCONTACT hContact = (UINT_PTR)arg;
+ CMStringW message(db_get_wsm(hContact, "CList", "StatusMsg"));
+
+ // if contact has no status message, get xstatus message
+ if (message.IsEmpty()) {
+ ptrW xStatusName(getWStringA(hContact, "XStatusName"));
+ ptrW xStatusMsg(getWStringA(hContact, "XStatusMsg"));
+
+ if (xStatusName)
+ message.AppendFormat(L"%s: %s", xStatusName.get(), xStatusMsg.get());
+ else
+ message.Append(xStatusMsg);
+ }
+
+ ProtoBroadcastAck(hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)1, (LPARAM)message.c_str());
+}
+
+HANDLE CSteamProto::GetAwayMsg(MCONTACT hContact)
+{
+ ForkThread(&CSteamProto::GetAwayMsgThread, (void*)hContact);
+ return (HANDLE)1;
+}
+
+void CSteamProto::OnContactDeleted(MCONTACT hContact)
+{
+ // remove only authorized contacts
+ if (!getByte(hContact, "Auth", 0)) {
+ ptrA token(getStringA("TokenSecret"));
+ ptrA sessionId(getStringA("SessionID"));
+ ptrA steamId(getStringA("SteamID"));
+ char *who = getStringA(hContact, "SteamID");
+ PushRequest(new RemoveFriendRequest(token, sessionId, steamId, who), &CSteamProto::OnFriendRemoved, (void*)who);
+ }
+}
diff --git a/protocols/Telegram/.gitignore b/protocols/Telegram/.gitignore index c3af857904..cc2225d405 100644 --- a/protocols/Telegram/.gitignore +++ b/protocols/Telegram/.gitignore @@ -1 +1 @@ -lib/ +lib/
diff --git a/protocols/Telegram/Telegram.vcxproj b/protocols/Telegram/Telegram.vcxproj index 9c1812a737..16b8bbd8a1 100644 --- a/protocols/Telegram/Telegram.vcxproj +++ b/protocols/Telegram/Telegram.vcxproj @@ -1,68 +1,68 @@ -<?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"> - <ProjectGuid>{AE708252-0DF8-42BA-9EF9-9ACC038EEDA7}</ProjectGuid> - <ProjectName>Telegram</ProjectName> - </PropertyGroup> - <ImportGroup Label="PropertySheets"> - <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> - </ImportGroup> - <ItemGroup> - <ClCompile Include="src\auth.cpp" /> - <ClCompile Include="src\avatars.cpp" /> - <ClCompile Include="src\main.cpp" /> - <ClCompile Include="src\mt_proto.cpp" /> - <ClCompile Include="src\options.cpp" /> - <ClCompile Include="src\server.cpp" /> - <ClCompile Include="src\stdafx.cxx"> - <PrecompiledHeader>Create</PrecompiledHeader> - </ClCompile> - <ClCompile Include="src\utils.cpp" /> - </ItemGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\tdlib\td;.\tdlib\td\td\generate\auto;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> - <Link> - <AdditionalLibraryDirectories Condition="'$(Platform)'=='Win32'">.\tdlib\lib\$(Configuration)32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalLibraryDirectories Condition="'$(Platform)'=='x64'">.\tdlib\lib\$(Configuration)64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> - <AdditionalDependencies>libcrypto.lib;libssl.lib;crypt32.lib;psapi.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies> - </Link> - </ItemDefinitionGroup> - <ItemGroup> - <ClInclude Include="src\mt_proto.h" /> - <ClInclude Include="src\resource.h" /> - <ClInclude Include="src\stdafx.h" /> - <ClInclude Include="src\version.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\..\libs\sqlite3\sqlite3.vcxproj"> - <Project>{0c02e395-e73f-47e3-8b95-b7924c0c7a6a}</Project> - </ProjectReference> - <ProjectReference Include="..\..\libs\zlib\zlib.vcxproj"> - <Project>{e2a369cd-eda3-414f-8ad0-e732cd7ee68c}</Project> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\resource.rc" /> - <ResourceCompile Include="res\version.rc" /> - </ItemGroup> +<?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">
+ <ProjectGuid>{AE708252-0DF8-42BA-9EF9-9ACC038EEDA7}</ProjectGuid>
+ <ProjectName>Telegram</ProjectName>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClCompile Include="src\auth.cpp" />
+ <ClCompile Include="src\avatars.cpp" />
+ <ClCompile Include="src\main.cpp" />
+ <ClCompile Include="src\mt_proto.cpp" />
+ <ClCompile Include="src\options.cpp" />
+ <ClCompile Include="src\server.cpp" />
+ <ClCompile Include="src\stdafx.cxx">
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp" />
+ </ItemGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\tdlib\td;.\tdlib\td\td\generate\auto;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <AdditionalLibraryDirectories Condition="'$(Platform)'=='Win32'">.\tdlib\lib\$(Configuration)32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories Condition="'$(Platform)'=='x64'">.\tdlib\lib\$(Configuration)64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>libcrypto.lib;libssl.lib;crypt32.lib;psapi.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="src\mt_proto.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\stdafx.h" />
+ <ClInclude Include="src\version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\libs\sqlite3\sqlite3.vcxproj">
+ <Project>{0c02e395-e73f-47e3-8b95-b7924c0c7a6a}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\..\libs\zlib\zlib.vcxproj">
+ <Project>{e2a369cd-eda3-414f-8ad0-e732cd7ee68c}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\resource.rc" />
+ <ResourceCompile Include="res\version.rc" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/Telegram.vcxproj.filters b/protocols/Telegram/Telegram.vcxproj.filters index e6d8a2433a..528f29127c 100644 --- a/protocols/Telegram/Telegram.vcxproj.filters +++ b/protocols/Telegram/Telegram.vcxproj.filters @@ -1,60 +1,60 @@ -<?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" /> - <ItemGroup> - <ClCompile Include="src\mt_proto.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\stdafx.cxx"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\server.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\options.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\utils.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\auth.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\avatars.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClCompile Include="src\stdafx.cxx"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\main.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\mt_proto.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="src\mt_proto.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\stdafx.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\version.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\version.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - <ResourceCompile Include="res\resource.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> +<?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" />
+ <ItemGroup>
+ <ClCompile Include="src\mt_proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\stdafx.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\server.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\auth.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\avatars.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="src\stdafx.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\mt_proto.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\mt_proto.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="res\resource.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/proto_telegram/CMakeLists.txt b/protocols/Telegram/proto_telegram/CMakeLists.txt index 223ee6af39..122641d52b 100644 --- a/protocols/Telegram/proto_telegram/CMakeLists.txt +++ b/protocols/Telegram/proto_telegram/CMakeLists.txt @@ -1,2 +1,2 @@ -set(TARGET Proto_Telegram) +set(TARGET Proto_Telegram)
include(${CMAKE_SOURCE_DIR}/cmake/icons.cmake)
\ No newline at end of file diff --git a/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj b/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj index 3eb5b57a48..715dbd2330 100644 --- a/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj +++ b/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj @@ -1,34 +1,34 @@ -<?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_Telegram</ProjectName> - <ProjectGuid>{129A4E61-45E8-E476-BD50-5E03BA80E9AD}</ProjectGuid> - </PropertyGroup> - <ImportGroup Label="PropertySheets"> - <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" /> - </ImportGroup> - <ItemGroup> - <ClInclude Include="src\resource.h" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Proto_Telegram.rc" /> - </ItemGroup> +<?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_Telegram</ProjectName>
+ <ProjectGuid>{129A4E61-45E8-E476-BD50-5E03BA80E9AD}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClInclude Include="src\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Telegram.rc" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj.filters b/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj.filters index 19bac99d33..7ae0743b90 100644 --- a/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj.filters +++ b/protocols/Telegram/proto_telegram/Proto_Telegram.vcxproj.filters @@ -1,14 +1,14 @@ -<?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" /> - <ItemGroup> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Proto_Telegram.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> +<?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" />
+ <ItemGroup>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Proto_Telegram.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/proto_telegram/res/Proto_Telegram.rc b/protocols/Telegram/proto_telegram/res/Proto_Telegram.rc index c72b18eb8c..201a96305c 100644 --- a/protocols/Telegram/proto_telegram/res/Proto_Telegram.rc +++ b/protocols/Telegram/proto_telegram/res/Proto_Telegram.rc @@ -1,71 +1,71 @@ -// 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" - -#endif // Russian (Russia) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// 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"
+
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Telegram/proto_telegram/src/resource.h b/protocols/Telegram/proto_telegram/src/resource.h index 12364e6a49..192c1b9f19 100644 --- a/protocols/Telegram/proto_telegram/src/resource.h +++ b/protocols/Telegram/proto_telegram/src/resource.h @@ -1,19 +1,19 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Proto_Telegram.rc -// -#define IDI_ICON1 105 -#define IDI_ICON2 104 -#define IDI_ICON3 128 -#define IDI_ICON4 159 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 106 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_Telegram.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+#define IDI_ICON3 128
+#define IDI_ICON4 159
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Telegram/res/resource.rc b/protocols/Telegram/res/resource.rc index 0aacaa94c4..8e8936badf 100644 --- a/protocols/Telegram/res/resource.rc +++ b/protocols/Telegram/res/resource.rc @@ -1,154 +1,154 @@ -// Microsoft Visual C++ generated resource script. -// -#include "..\src\resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// Russian (Russia) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) -LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT -#pragma code_page(1251) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "..\\src\\resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -#endif // Russian (Russia) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (Neutral) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL -#pragma code_page(1252) - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ACCMGRUI DIALOGEX 0, 0, 188, 144 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 400, 0, 0x0 -BEGIN - LTEXT "Phone number:",IDC_STATIC,0,6,89,10 - EDITTEXT IDC_PHONE,96,4,86,12,ES_AUTOHSCROLL - LTEXT "Default group:",IDC_STATIC,0,23,89,10 - EDITTEXT IDC_DEFGROUP,96,21,86,12,ES_AUTOHSCROLL - LTEXT "Device name:",IDC_STATIC,0,39,89,10 - EDITTEXT IDC_DEVICE_NAME,96,38,86,12,ES_AUTOHSCROLL - CONTROL "Do not open chat windows on creation",IDC_HIDECHATS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,57,182,10 -END - -IDD_OPTIONS DIALOGEX 0, 0, 305, 188 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - LTEXT "Phone number:",IDC_STATIC,5,6,79,10 - EDITTEXT IDC_PHONE,87,5,211,12,ES_AUTOHSCROLL - LTEXT "Default group:",IDC_STATIC,5,24,79,10 - EDITTEXT IDC_DEFGROUP,87,23,211,12,ES_AUTOHSCROLL - LTEXT "Device name:",IDC_STATIC,5,43,79,10 - EDITTEXT IDC_DEVICE_NAME,87,41,211,12,ES_AUTOHSCROLL - CONTROL "Do not open chat windows on creation",IDC_HIDECHATS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,64,294,10 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_TELEGRAM ICON "telegram.ico" - -IDI_PREMIUM ICON "premium.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ACCMGRUI, DIALOG - BEGIN - END - - IDD_OPTIONS, DIALOG - BEGIN - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_ACCMGRUI AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -IDD_OPTIONS AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // English (Neutral) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (Neutral) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ACCMGRUI DIALOGEX 0, 0, 188, 144
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ LTEXT "Phone number:",IDC_STATIC,0,6,89,10
+ EDITTEXT IDC_PHONE,96,4,86,12,ES_AUTOHSCROLL
+ LTEXT "Default group:",IDC_STATIC,0,23,89,10
+ EDITTEXT IDC_DEFGROUP,96,21,86,12,ES_AUTOHSCROLL
+ LTEXT "Device name:",IDC_STATIC,0,39,89,10
+ EDITTEXT IDC_DEVICE_NAME,96,38,86,12,ES_AUTOHSCROLL
+ CONTROL "Do not open chat windows on creation",IDC_HIDECHATS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,57,182,10
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 305, 188
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Phone number:",IDC_STATIC,5,6,79,10
+ EDITTEXT IDC_PHONE,87,5,211,12,ES_AUTOHSCROLL
+ LTEXT "Default group:",IDC_STATIC,5,24,79,10
+ EDITTEXT IDC_DEFGROUP,87,23,211,12,ES_AUTOHSCROLL
+ LTEXT "Device name:",IDC_STATIC,5,43,79,10
+ EDITTEXT IDC_DEVICE_NAME,87,41,211,12,ES_AUTOHSCROLL
+ CONTROL "Do not open chat windows on creation",IDC_HIDECHATS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,64,294,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_TELEGRAM ICON "telegram.ico"
+
+IDI_PREMIUM ICON "premium.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_ACCMGRUI, DIALOG
+ BEGIN
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_ACCMGRUI AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+IDD_OPTIONS AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+#endif // English (Neutral) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/Telegram/res/telegram.ico b/protocols/Telegram/res/telegram.ico Binary files differindex dd8dbdb7ad..45b58cead4 100644 --- a/protocols/Telegram/res/telegram.ico +++ b/protocols/Telegram/res/telegram.ico diff --git a/protocols/Telegram/src/auth.cpp b/protocols/Telegram/src/auth.cpp index 3778ff1039..043628ab19 100644 --- a/protocols/Telegram/src/auth.cpp +++ b/protocols/Telegram/src/auth.cpp @@ -1,126 +1,126 @@ -/* -Copyright (C) 2012-23 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" - -#include "../../../../miranda-private-keys/Telegram/api.h" - -/////////////////////////////////////////////////////////////////////////////// - -INT_PTR CALLBACK CMTProto::EnterPhoneCode(void *param) -{ - auto *ppro = (CMTProto *)param; - - ENTER_STRING es = {}; - es.szModuleName = ppro->m_szModuleName; - es.caption = TranslateT("Enter secret code sent to your phone"); - if (EnterString(&es)) { - ppro->SendQuery(new TD::checkAuthenticationCode(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); - mir_free(es.ptszResult); - } - else ppro->LogOut(); - return 0; -} - -INT_PTR CALLBACK CMTProto::EnterPassword(void *param) -{ - auto *ppro = (CMTProto *)param; - CMStringW wszTitle(TranslateT("Enter password")); - - auto *pAuth = (TD::authorizationStateWaitPassword *)ppro->pAuthState.get(); - if (!pAuth->password_hint_.empty()) - wszTitle.AppendFormat(TranslateT(" (hint: %s)"), Utf2T(pAuth->password_hint_.c_str()).get()); - - ENTER_STRING es = {}; - es.szModuleName = ppro->m_szModuleName; - es.caption = wszTitle; - es.type = ESF_PASSWORD; - if (EnterString(&es)) { - ppro->SendQuery(new TD::checkAuthenticationPassword(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth); - mir_free(es.ptszResult); - } - else ppro->LogOut(); - return 0; -} - -void CMTProto::ProcessAuth(TD::updateAuthorizationState *pObj) -{ - pAuthState = std::move(pObj->authorization_state_); - switch (pAuthState->get_id()) { - case TD::authorizationStateWaitTdlibParameters::ID: - { - MFileVersion v; - char text[100]; - Miranda_GetFileVersion(&v); - mir_snprintf(text, "%d.%d.%d.%d", v[0], v[1], v[2], v[3]); - - CMStringW wszPath(GetProtoFolder()); - - auto *request = new TD::setTdlibParameters(); - request->database_directory_ = T2Utf(wszPath).get(); - request->use_message_database_ = false; - request->use_secret_chats_ = true; - request->api_id_ = MIRANDA_API_ID; - request->api_hash_ = MIRANDA_API_HASH; - request->system_language_code_ = "en"; - request->device_model_ = T2Utf(m_wszDeviceName).get(); - request->application_version_ = text; - request->enable_storage_optimizer_ = true; - SendQuery(request, &CMTProto::OnUpdateAuth); - } - break; - - case TD::authorizationStateWaitPhoneNumber::ID: - SendQuery(new TD::setAuthenticationPhoneNumber(_T2A(m_szOwnPhone).get(), nullptr), &CMTProto::OnUpdateAuth); - break; - - case TD::authorizationStateWaitCode::ID: - CallFunctionSync(EnterPhoneCode, this); - break; - - case TD::authorizationStateWaitPassword::ID: - CallFunctionSync(EnterPassword, this); - break; - - case TD::authorizationStateReady::ID: - OnLoggedIn(); - break; - - case TD::authorizationStateClosed::ID: - debugLogA("Connection terminated, exiting"); - LogOut(); - break; - } -} - -void CMTProto::OnUpdateAuth(td::ClientManager::Response &response) -{ - if (response.object->get_id() == TD::error::ID) { - auto *pError = (TD::error *)response.object.get(); - debugLogA("error happened: %s", to_string(*pError).c_str()); - - if (pError->message_ == "PHONE_CODE_EXPIRED") - Popup(0, TranslateT("Phone code expired"), TranslateT("Error")); - else if (pError->message_ == "INVALID_PHONE_CODE") - Popup(0, TranslateT("Invalid phone code"), TranslateT("Error")); - else if (pError->message_ == "PASSWORD_HASH_INVALID") - Popup(0, TranslateT("Invalid password"), TranslateT("Error")); - - pAuthState = std::move(nullptr); - LogOut(); - } -} +/*
+Copyright (C) 2012-23 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"
+
+#include "../../../../miranda-private-keys/Telegram/api.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CALLBACK CMTProto::EnterPhoneCode(void *param)
+{
+ auto *ppro = (CMTProto *)param;
+
+ ENTER_STRING es = {};
+ es.szModuleName = ppro->m_szModuleName;
+ es.caption = TranslateT("Enter secret code sent to your phone");
+ if (EnterString(&es)) {
+ ppro->SendQuery(new TD::checkAuthenticationCode(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth);
+ mir_free(es.ptszResult);
+ }
+ else ppro->LogOut();
+ return 0;
+}
+
+INT_PTR CALLBACK CMTProto::EnterPassword(void *param)
+{
+ auto *ppro = (CMTProto *)param;
+ CMStringW wszTitle(TranslateT("Enter password"));
+
+ auto *pAuth = (TD::authorizationStateWaitPassword *)ppro->pAuthState.get();
+ if (!pAuth->password_hint_.empty())
+ wszTitle.AppendFormat(TranslateT(" (hint: %s)"), Utf2T(pAuth->password_hint_.c_str()).get());
+
+ ENTER_STRING es = {};
+ es.szModuleName = ppro->m_szModuleName;
+ es.caption = wszTitle;
+ es.type = ESF_PASSWORD;
+ if (EnterString(&es)) {
+ ppro->SendQuery(new TD::checkAuthenticationPassword(_T2A(es.ptszResult).get()), &CMTProto::OnUpdateAuth);
+ mir_free(es.ptszResult);
+ }
+ else ppro->LogOut();
+ return 0;
+}
+
+void CMTProto::ProcessAuth(TD::updateAuthorizationState *pObj)
+{
+ pAuthState = std::move(pObj->authorization_state_);
+ switch (pAuthState->get_id()) {
+ case TD::authorizationStateWaitTdlibParameters::ID:
+ {
+ MFileVersion v;
+ char text[100];
+ Miranda_GetFileVersion(&v);
+ mir_snprintf(text, "%d.%d.%d.%d", v[0], v[1], v[2], v[3]);
+
+ CMStringW wszPath(GetProtoFolder());
+
+ auto *request = new TD::setTdlibParameters();
+ request->database_directory_ = T2Utf(wszPath).get();
+ request->use_message_database_ = false;
+ request->use_secret_chats_ = true;
+ request->api_id_ = MIRANDA_API_ID;
+ request->api_hash_ = MIRANDA_API_HASH;
+ request->system_language_code_ = "en";
+ request->device_model_ = T2Utf(m_wszDeviceName).get();
+ request->application_version_ = text;
+ request->enable_storage_optimizer_ = true;
+ SendQuery(request, &CMTProto::OnUpdateAuth);
+ }
+ break;
+
+ case TD::authorizationStateWaitPhoneNumber::ID:
+ SendQuery(new TD::setAuthenticationPhoneNumber(_T2A(m_szOwnPhone).get(), nullptr), &CMTProto::OnUpdateAuth);
+ break;
+
+ case TD::authorizationStateWaitCode::ID:
+ CallFunctionSync(EnterPhoneCode, this);
+ break;
+
+ case TD::authorizationStateWaitPassword::ID:
+ CallFunctionSync(EnterPassword, this);
+ break;
+
+ case TD::authorizationStateReady::ID:
+ OnLoggedIn();
+ break;
+
+ case TD::authorizationStateClosed::ID:
+ debugLogA("Connection terminated, exiting");
+ LogOut();
+ break;
+ }
+}
+
+void CMTProto::OnUpdateAuth(td::ClientManager::Response &response)
+{
+ if (response.object->get_id() == TD::error::ID) {
+ auto *pError = (TD::error *)response.object.get();
+ debugLogA("error happened: %s", to_string(*pError).c_str());
+
+ if (pError->message_ == "PHONE_CODE_EXPIRED")
+ Popup(0, TranslateT("Phone code expired"), TranslateT("Error"));
+ else if (pError->message_ == "INVALID_PHONE_CODE")
+ Popup(0, TranslateT("Invalid phone code"), TranslateT("Error"));
+ else if (pError->message_ == "PASSWORD_HASH_INVALID")
+ Popup(0, TranslateT("Invalid password"), TranslateT("Error"));
+
+ pAuthState = std::move(nullptr);
+ LogOut();
+ }
+}
diff --git a/protocols/Telegram/src/avatars.cpp b/protocols/Telegram/src/avatars.cpp index b21ddf81d0..bd24079f5f 100644 --- a/protocols/Telegram/src/avatars.cpp +++ b/protocols/Telegram/src/avatars.cpp @@ -1,95 +1,95 @@ -/* -Copyright (C) 2012-23 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" - -INT_PTR CMTProto::SvcGetAvatarCaps(WPARAM wParam, LPARAM lParam) -{ - switch (wParam) { - case AF_MAXSIZE: - ((POINT *)lParam)->x = 160; - ((POINT *)lParam)->y = 160; - break; - - case AF_MAXFILESIZE: - return 32000; - - case AF_PROPORTION: - return PIP_SQUARE; - - case AF_FORMATSUPPORTED: - case AF_ENABLED: - case AF_DONTNEEDDELAYS: - case AF_FETCHIFPROTONOTVISIBLE: - case AF_FETCHIFCONTACTOFFLINE: - return 1; - } - return 0; -} - -INT_PTR CMTProto::SvcGetAvatarInfo(WPARAM, LPARAM lParam) -{ - auto *pai = (PROTO_AVATAR_INFORMATION *)lParam; - - ptrW wszPath(getWStringA(pai->hContact, DBKEY_AVATAR_PATH)); - if (wszPath == nullptr) - return GAIR_NOAVATAR; - - pai->format = getByte(pai->hContact, DBKEY_AVATAR_TYPE, PA_FORMAT_JPEG); - wcsncpy_s(pai->filename, wszPath, _TRUNCATE); - - if (::_waccess(pai->filename, 0) == 0) - return GAIR_SUCCESS; - - debugLogA("No avatar"); - return GAIR_NOAVATAR; -} - -INT_PTR CMTProto::SvcGetMyAvatar(WPARAM, LPARAM) -{ - return 1; -} - -INT_PTR CMTProto::SvcSetMyAvatar(WPARAM, LPARAM) -{ - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CMTProto::ProcessFile(TD::updateFile *pObj) -{ - if (auto *pFile = pObj->file_.get()) { - if (!pFile->local_->is_downloading_completed_) - return; - - for (auto &it : m_arUsers) { - if (it->szAvatarHash == pFile->remote_->unique_id_.c_str()) { - PROTO_AVATAR_INFORMATION pai; - wcsncpy_s(pai.filename, Utf2T(pFile->local_->path_.c_str()), _TRUNCATE); - pai.hContact = it->hContact; - pai.format = ProtoGetAvatarFileFormat(pai.filename); - - setByte(pai.hContact, DBKEY_AVATAR_TYPE, pai.format); - setWString(pai.hContact, DBKEY_AVATAR_PATH, pai.filename); - - ProtoBroadcastAck(it->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &pai); - break; - } - } - } -} +/*
+Copyright (C) 2012-23 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"
+
+INT_PTR CMTProto::SvcGetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ case AF_MAXSIZE:
+ ((POINT *)lParam)->x = 160;
+ ((POINT *)lParam)->y = 160;
+ break;
+
+ case AF_MAXFILESIZE:
+ return 32000;
+
+ case AF_PROPORTION:
+ return PIP_SQUARE;
+
+ case AF_FORMATSUPPORTED:
+ case AF_ENABLED:
+ case AF_DONTNEEDDELAYS:
+ case AF_FETCHIFPROTONOTVISIBLE:
+ case AF_FETCHIFCONTACTOFFLINE:
+ return 1;
+ }
+ return 0;
+}
+
+INT_PTR CMTProto::SvcGetAvatarInfo(WPARAM, LPARAM lParam)
+{
+ auto *pai = (PROTO_AVATAR_INFORMATION *)lParam;
+
+ ptrW wszPath(getWStringA(pai->hContact, DBKEY_AVATAR_PATH));
+ if (wszPath == nullptr)
+ return GAIR_NOAVATAR;
+
+ pai->format = getByte(pai->hContact, DBKEY_AVATAR_TYPE, PA_FORMAT_JPEG);
+ wcsncpy_s(pai->filename, wszPath, _TRUNCATE);
+
+ if (::_waccess(pai->filename, 0) == 0)
+ return GAIR_SUCCESS;
+
+ debugLogA("No avatar");
+ return GAIR_NOAVATAR;
+}
+
+INT_PTR CMTProto::SvcGetMyAvatar(WPARAM, LPARAM)
+{
+ return 1;
+}
+
+INT_PTR CMTProto::SvcSetMyAvatar(WPARAM, LPARAM)
+{
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CMTProto::ProcessFile(TD::updateFile *pObj)
+{
+ if (auto *pFile = pObj->file_.get()) {
+ if (!pFile->local_->is_downloading_completed_)
+ return;
+
+ for (auto &it : m_arUsers) {
+ if (it->szAvatarHash == pFile->remote_->unique_id_.c_str()) {
+ PROTO_AVATAR_INFORMATION pai;
+ wcsncpy_s(pai.filename, Utf2T(pFile->local_->path_.c_str()), _TRUNCATE);
+ pai.hContact = it->hContact;
+ pai.format = ProtoGetAvatarFileFormat(pai.filename);
+
+ setByte(pai.hContact, DBKEY_AVATAR_TYPE, pai.format);
+ setWString(pai.hContact, DBKEY_AVATAR_PATH, pai.filename);
+
+ ProtoBroadcastAck(it->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &pai);
+ break;
+ }
+ }
+ }
+}
diff --git a/protocols/Telegram/src/main.cpp b/protocols/Telegram/src/main.cpp index 6af8517ab7..c00b87536d 100644 --- a/protocols/Telegram/src/main.cpp +++ b/protocols/Telegram/src/main.cpp @@ -1,52 +1,52 @@ -#include "stdafx.h" - -int hLangpack; -CMPlugin g_plugin; - -#pragma comment(lib, "tdactor.lib") -#pragma comment(lib, "tdcore.lib") -#pragma comment(lib, "tddb.lib") -#pragma comment(lib, "tdlib.lib") -#pragma comment(lib, "tdnet.lib") -#pragma comment(lib, "tdutils.lib") - -///////////////////////////////////////////////////////////////////////////////////////// - -PLUGININFOEX pluginInfo = -{ - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {AE708252-0DF8-42BA-9EF9-9ACC038EEDA7} - {0xae708252, 0xdf8, 0x42ba, {0x9e, 0xf9, 0x9a, 0xcc, 0x3, 0x8e, 0xed, 0xa7}} -}; - -CMPlugin::CMPlugin() : - ACCPROTOPLUGIN<CMTProto>("Telegram", pluginInfo) -{ - SetUniqueId(DBKEY_ID); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST }; - -///////////////////////////////////////////////////////////////////////////////////////// - -static IconItem iconList[] = -{ - { LPGEN("Premium user"), "premuim", IDI_PREMIUM }, -}; - -int CMPlugin::Load() -{ - registerIcon("Protocols/Telegram", iconList, "tg"); - - m_hIcon = ExtraIcon_RegisterIcolib("tg_premium", "Telegram Premium User", getIconHandle(IDI_PREMIUM)); - return 0; -} +#include "stdafx.h"
+
+int hLangpack;
+CMPlugin g_plugin;
+
+#pragma comment(lib, "tdactor.lib")
+#pragma comment(lib, "tdcore.lib")
+#pragma comment(lib, "tddb.lib")
+#pragma comment(lib, "tdlib.lib")
+#pragma comment(lib, "tdnet.lib")
+#pragma comment(lib, "tdutils.lib")
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfo =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {AE708252-0DF8-42BA-9EF9-9ACC038EEDA7}
+ {0xae708252, 0xdf8, 0x42ba, {0x9e, 0xf9, 0x9a, 0xcc, 0x3, 0x8e, 0xed, 0xa7}}
+};
+
+CMPlugin::CMPlugin() :
+ ACCPROTOPLUGIN<CMTProto>("Telegram", pluginInfo)
+{
+ SetUniqueId(DBKEY_ID);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static IconItem iconList[] =
+{
+ { LPGEN("Premium user"), "premuim", IDI_PREMIUM },
+};
+
+int CMPlugin::Load()
+{
+ registerIcon("Protocols/Telegram", iconList, "tg");
+
+ m_hIcon = ExtraIcon_RegisterIcolib("tg_premium", "Telegram Premium User", getIconHandle(IDI_PREMIUM));
+ return 0;
+}
diff --git a/protocols/Telegram/src/mt_proto.cpp b/protocols/Telegram/src/mt_proto.cpp index a58c3ded1d..2728aa94fb 100644 --- a/protocols/Telegram/src/mt_proto.cpp +++ b/protocols/Telegram/src/mt_proto.cpp @@ -1,198 +1,198 @@ -#include "stdafx.h" - -static int CompareRequests(const TG_REQUEST_BASE *p1, const TG_REQUEST_BASE *p2) -{ - if (p1->requestId == p2->requestId) - return 0; - - return (p1->requestId < p2->requestId) ? -1 : 1; -} - -static int CompareUsers(const TG_USER *p1, const TG_USER *p2) -{ - if (p1->id == p2->id) - return 0; - - return (p1->id < p2->id) ? -1 : 1; -} - -CMTProto::CMTProto(const char* protoName, const wchar_t* userName) : - PROTO<CMTProto>(protoName, userName), - m_impl(*this), - m_arUsers(10, CompareUsers), - m_arRequests(10, CompareRequests), - m_szOwnPhone(this, "Phone"), - m_wszDeviceName(this, "DeviceName", L"Miranda"), - m_wszDefaultGroup(this, "DefaultGroup", L"Telegram"), - m_bUsePopups(this, "UsePopups", true), - m_bHideGroupchats(this, "HideChats", true) -{ - m_iOwnId = _atoi64(getMStringA(DBKEY_ID)); - - CreateProtoService(PS_CREATEACCMGRUI, &CMTProto::SvcCreateAccMgrUI); - CreateProtoService(PS_GETAVATARCAPS, &CMTProto::SvcGetAvatarCaps); - CreateProtoService(PS_GETAVATARINFO, &CMTProto::SvcGetAvatarInfo); - CreateProtoService(PS_GETMYAVATAR, &CMTProto::SvcGetMyAvatar); - CreateProtoService(PS_SETMYAVATAR, &CMTProto::SvcSetMyAvatar); - - HookProtoEvent(ME_OPT_INITIALISE, &CMTProto::OnOptionsInit); - HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CMTProto::OnDbMarkedRead); - - // default contacts group - if (m_wszDefaultGroup == NULL) - m_wszDefaultGroup = mir_wstrdup(L"WhatsApp"); - m_iBaseGroup = Clist_GroupCreate(0, m_wszDefaultGroup); - - // Create standard network connection - NETLIBUSER nlu = {}; - nlu.flags = NUF_UNICODE; - nlu.szSettingsModule = m_szModuleName; - nlu.szDescriptiveName.w = m_tszUserName; - m_hNetlibUser = Netlib_RegisterUser(&nlu); - - // groupchat initialization - GCREGISTER gcr = {}; - gcr.dwFlags = GC_TYPNOTIF | GC_DATABASE; - gcr.ptszDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - Chat_Register(&gcr); - - // HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::GcEventHook); - // HookProtoEvent(ME_GC_BUILDMENU, &WhatsAppProto::GcMenuHook); -} - -CMTProto::~CMTProto() -{ -} - -void CMTProto::OnModulesLoaded() -{ - CMStringA szId(getMStringA(DBKEY_ID)); - if (!szId.IsEmpty()) - m_arUsers.insert(new TG_USER(_atoi64(szId.c_str()), 0)); - - for (auto &cc : AccContacts()) { - bool isGroupChat = isChatRoom(cc); - szId = getMStringA(cc, isGroupChat ? "ChatRoomID" : DBKEY_ID); - if (!szId.IsEmpty()) { - auto *pUser = new TG_USER(_atoi64(szId.c_str()), cc, isGroupChat); - pUser->szAvatarHash = getMStringA(cc, DBKEY_AVATAR_HASH); - m_arUsers.insert(pUser); - } - } -} - -void CMTProto::OnShutdown() -{ - m_bTerminated = true; -} - -void CMTProto::OnErase() -{ - m_bUnregister = true; - ServerThread(0); - - DeleteDirectoryTreeW(GetProtoFolder(), false); -} - -int CMTProto::OnDbMarkedRead(WPARAM hContact, LPARAM hDbEvent) -{ - if (!hContact) - return 0; - - // filter out only events of my protocol - const char *szProto = Proto_GetBaseAccountName(hContact); - if (mir_strcmp(szProto, m_szModuleName)) - return 0; - - ptrA userId(getStringA(hContact, DBKEY_ID)); - if (userId) { - DBEVENTINFO dbei = {}; - db_event_get(hDbEvent, &dbei); - if (dbei.szId) { - mir_cslock lck(m_csMarkRead); - if (m_markContact) { - if (m_markContact != hContact) - SendMarkRead(); - - m_impl.m_markRead.Stop(); - } - - m_markContact = hContact; - m_markIds.push_back(_atoi64(dbei.szId)); - m_impl.m_markRead.Start(500); - } - } - - return 0; -} - -INT_PTR CMTProto::GetCaps(int type, MCONTACT) -{ - switch (type) { - case PFLAGNUM_1: - return PF1_IM | PF1_FILE | PF1_CHAT | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSGRECV; - case PFLAGNUM_2: - return PF2_ONLINE; - case PFLAGNUM_3: - return 0; - case PFLAGNUM_4: - return PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_OFFLINEFILES | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID; - case PFLAGNUM_5: - return 0; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)L"Phone"; - } - return 0; -} - -int CMTProto::SendMsg(MCONTACT hContact, int, const char *pszMessage) -{ - ptrA szId(getStringA(hContact, DBKEY_ID)); - if (szId == nullptr) - return 0; - - return SendTextMessage(_atoi64(szId), pszMessage); -} - -int CMTProto::SetStatus(int iNewStatus) -{ - if (m_iDesiredStatus == iNewStatus) - return 0; - - int oldStatus = m_iStatus; - - // Routing statuses not supported by Telegram - switch (iNewStatus) { - case ID_STATUS_OFFLINE: - m_iDesiredStatus = iNewStatus; - break; - - case ID_STATUS_ONLINE: - case ID_STATUS_FREECHAT: - default: - m_iDesiredStatus = ID_STATUS_ONLINE; - break; - } - - if (m_iDesiredStatus == ID_STATUS_OFFLINE) { - if (isRunning()) - SendQuery(new TD::close()); - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - } - else if (!isRunning() && !IsStatusConnecting(m_iStatus)) { - m_iStatus = ID_STATUS_CONNECTING; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - - ForkThread(&CMTProto::ServerThread); - } - else if (isRunning()) { - m_iStatus = m_iDesiredStatus; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - } - else ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - - return 0; -} +#include "stdafx.h"
+
+static int CompareRequests(const TG_REQUEST_BASE *p1, const TG_REQUEST_BASE *p2)
+{
+ if (p1->requestId == p2->requestId)
+ return 0;
+
+ return (p1->requestId < p2->requestId) ? -1 : 1;
+}
+
+static int CompareUsers(const TG_USER *p1, const TG_USER *p2)
+{
+ if (p1->id == p2->id)
+ return 0;
+
+ return (p1->id < p2->id) ? -1 : 1;
+}
+
+CMTProto::CMTProto(const char* protoName, const wchar_t* userName) :
+ PROTO<CMTProto>(protoName, userName),
+ m_impl(*this),
+ m_arUsers(10, CompareUsers),
+ m_arRequests(10, CompareRequests),
+ m_szOwnPhone(this, "Phone"),
+ m_wszDeviceName(this, "DeviceName", L"Miranda"),
+ m_wszDefaultGroup(this, "DefaultGroup", L"Telegram"),
+ m_bUsePopups(this, "UsePopups", true),
+ m_bHideGroupchats(this, "HideChats", true)
+{
+ m_iOwnId = _atoi64(getMStringA(DBKEY_ID));
+
+ CreateProtoService(PS_CREATEACCMGRUI, &CMTProto::SvcCreateAccMgrUI);
+ CreateProtoService(PS_GETAVATARCAPS, &CMTProto::SvcGetAvatarCaps);
+ CreateProtoService(PS_GETAVATARINFO, &CMTProto::SvcGetAvatarInfo);
+ CreateProtoService(PS_GETMYAVATAR, &CMTProto::SvcGetMyAvatar);
+ CreateProtoService(PS_SETMYAVATAR, &CMTProto::SvcSetMyAvatar);
+
+ HookProtoEvent(ME_OPT_INITIALISE, &CMTProto::OnOptionsInit);
+ HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CMTProto::OnDbMarkedRead);
+
+ // default contacts group
+ if (m_wszDefaultGroup == NULL)
+ m_wszDefaultGroup = mir_wstrdup(L"WhatsApp");
+ m_iBaseGroup = Clist_GroupCreate(0, m_wszDefaultGroup);
+
+ // Create standard network connection
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_UNICODE;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.szDescriptiveName.w = m_tszUserName;
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ // groupchat initialization
+ GCREGISTER gcr = {};
+ gcr.dwFlags = GC_TYPNOTIF | GC_DATABASE;
+ gcr.ptszDispName = m_tszUserName;
+ gcr.pszModule = m_szModuleName;
+ Chat_Register(&gcr);
+
+ // HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::GcEventHook);
+ // HookProtoEvent(ME_GC_BUILDMENU, &WhatsAppProto::GcMenuHook);
+}
+
+CMTProto::~CMTProto()
+{
+}
+
+void CMTProto::OnModulesLoaded()
+{
+ CMStringA szId(getMStringA(DBKEY_ID));
+ if (!szId.IsEmpty())
+ m_arUsers.insert(new TG_USER(_atoi64(szId.c_str()), 0));
+
+ for (auto &cc : AccContacts()) {
+ bool isGroupChat = isChatRoom(cc);
+ szId = getMStringA(cc, isGroupChat ? "ChatRoomID" : DBKEY_ID);
+ if (!szId.IsEmpty()) {
+ auto *pUser = new TG_USER(_atoi64(szId.c_str()), cc, isGroupChat);
+ pUser->szAvatarHash = getMStringA(cc, DBKEY_AVATAR_HASH);
+ m_arUsers.insert(pUser);
+ }
+ }
+}
+
+void CMTProto::OnShutdown()
+{
+ m_bTerminated = true;
+}
+
+void CMTProto::OnErase()
+{
+ m_bUnregister = true;
+ ServerThread(0);
+
+ DeleteDirectoryTreeW(GetProtoFolder(), false);
+}
+
+int CMTProto::OnDbMarkedRead(WPARAM hContact, LPARAM hDbEvent)
+{
+ if (!hContact)
+ return 0;
+
+ // filter out only events of my protocol
+ const char *szProto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(szProto, m_szModuleName))
+ return 0;
+
+ ptrA userId(getStringA(hContact, DBKEY_ID));
+ if (userId) {
+ DBEVENTINFO dbei = {};
+ db_event_get(hDbEvent, &dbei);
+ if (dbei.szId) {
+ mir_cslock lck(m_csMarkRead);
+ if (m_markContact) {
+ if (m_markContact != hContact)
+ SendMarkRead();
+
+ m_impl.m_markRead.Stop();
+ }
+
+ m_markContact = hContact;
+ m_markIds.push_back(_atoi64(dbei.szId));
+ m_impl.m_markRead.Start(500);
+ }
+ }
+
+ return 0;
+}
+
+INT_PTR CMTProto::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_FILE | PF1_CHAT | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
+ case PFLAGNUM_2:
+ return PF2_ONLINE;
+ case PFLAGNUM_3:
+ return 0;
+ case PFLAGNUM_4:
+ return PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_OFFLINEFILES | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID;
+ case PFLAGNUM_5:
+ return 0;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)L"Phone";
+ }
+ return 0;
+}
+
+int CMTProto::SendMsg(MCONTACT hContact, int, const char *pszMessage)
+{
+ ptrA szId(getStringA(hContact, DBKEY_ID));
+ if (szId == nullptr)
+ return 0;
+
+ return SendTextMessage(_atoi64(szId), pszMessage);
+}
+
+int CMTProto::SetStatus(int iNewStatus)
+{
+ if (m_iDesiredStatus == iNewStatus)
+ return 0;
+
+ int oldStatus = m_iStatus;
+
+ // Routing statuses not supported by Telegram
+ switch (iNewStatus) {
+ case ID_STATUS_OFFLINE:
+ m_iDesiredStatus = iNewStatus;
+ break;
+
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_FREECHAT:
+ default:
+ m_iDesiredStatus = ID_STATUS_ONLINE;
+ break;
+ }
+
+ if (m_iDesiredStatus == ID_STATUS_OFFLINE) {
+ if (isRunning())
+ SendQuery(new TD::close());
+
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ else if (!isRunning() && !IsStatusConnecting(m_iStatus)) {
+ m_iStatus = ID_STATUS_CONNECTING;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+
+ ForkThread(&CMTProto::ServerThread);
+ }
+ else if (isRunning()) {
+ m_iStatus = m_iDesiredStatus;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ else ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+
+ return 0;
+}
diff --git a/protocols/Telegram/src/mt_proto.h b/protocols/Telegram/src/mt_proto.h index 8bc5cc3c66..bf5c9e667b 100644 --- a/protocols/Telegram/src/mt_proto.h +++ b/protocols/Telegram/src/mt_proto.h @@ -1,209 +1,209 @@ -#pragma once - -#define DBKEY_ID "id" - -#define DBKEY_AVATAR_HASH "AvatarHash" -#define DBKEY_AVATAR_PATH "AvatarPath" -#define DBKEY_AVATAR_TYPE "AvatarType" - -class CMTProto; -typedef void (CMTProto:: *TG_QUERY_HANDLER)(td::ClientManager::Response &response); -typedef void (CMTProto:: *TG_QUERY_HANDLER_FULL)(td::ClientManager::Response &response, void *pUserInfo); - -struct TG_REQUEST_BASE -{ - TG_REQUEST_BASE(td::ClientManager::RequestId _1) : - requestId(_1) - {} - - virtual ~TG_REQUEST_BASE() - {} - - td::ClientManager::RequestId requestId; - - virtual void Execute(CMTProto *ppro, td::ClientManager::Response &response) = 0; -}; - -struct TG_REQUEST : public TG_REQUEST_BASE -{ - TG_REQUEST(td::ClientManager::RequestId _1, TG_QUERY_HANDLER _2) : - TG_REQUEST_BASE(_1), - pHandler(_2) - {} - - TG_QUERY_HANDLER pHandler; - - void Execute(CMTProto *ppro, td::ClientManager::Response &response) override - { - (ppro->*pHandler)(response); - } -}; - -struct TG_REQUEST_FULL : public TG_REQUEST_BASE -{ - TG_REQUEST_FULL(td::ClientManager::RequestId _1, TG_QUERY_HANDLER_FULL _2, void *_3) : - TG_REQUEST_BASE(_1), - pHandler(_2), - pUserInfo(_3) - {} - - TG_QUERY_HANDLER_FULL pHandler; - void *pUserInfo; - - void Execute(CMTProto *ppro, td::ClientManager::Response &response) override - { - (ppro->*pHandler)(response, pUserInfo); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct TG_USER -{ - TG_USER(uint64_t _1, MCONTACT _2, bool _3 = false) : - id(_1), - hContact(_2), - isGroupChat(_3) - {} - - uint64_t id; - MCONTACT hContact; - bool isGroupChat; - CMStringA szAvatarHash; - time_t m_timer1 = 0, m_timer2 = 0; -}; - -class CMTProto : public PROTO<CMTProto> -{ - class CProtoImpl - { - friend class CMTProto; - CMTProto &m_proto; - - CTimer m_keepAlive, m_markRead; - void OnKeepAlive(CTimer *) - { m_proto.SendKeepAlive(); - } - - void OnMarkRead(CTimer *) - { m_proto.SendMarkRead(); - } - - CProtoImpl(CMTProto &pro) : - m_proto(pro), - m_markRead(Miranda_GetSystemWindow(), UINT_PTR(this)), - m_keepAlive(Miranda_GetSystemWindow(), UINT_PTR(this)+1) - { - m_markRead.OnEvent = Callback(this, &CProtoImpl::OnMarkRead); - m_keepAlive.OnEvent = Callback(this, &CProtoImpl::OnKeepAlive); - } - } m_impl; - - bool __forceinline isRunning() const - { return m_pClientMmanager != nullptr; - } - - std::unique_ptr<td::ClientManager> m_pClientMmanager; - TD::object_ptr<TD::AuthorizationState> pAuthState; - - mir_cs m_csMarkRead; - MCONTACT m_markContact = 0; - TD::array<TD::int53> m_markIds; - - bool m_bAuthorized, m_bTerminated, m_bUnregister = false; - int32_t m_iClientId, m_iMsgId; - uint64_t m_iQueryId; - - OBJLIST<TG_REQUEST_BASE> m_arRequests; - - static INT_PTR CALLBACK EnterPhoneCode(void *param); - static INT_PTR CALLBACK EnterPassword(void *param); - - CMStringW GetProtoFolder() const - { return CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName); - } - - void OnEndSession(td::ClientManager::Response &response); - void OnSendMessage(td::ClientManager::Response &response, void *pUserInfo); - void OnUpdateAuth(td::ClientManager::Response &response); - - void LogOut(void); - void OnLoggedIn(void); - void ProcessResponse(td::ClientManager::Response); - - void SendKeepAlive(void); - void SendMarkRead(void); - void SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER pHandler = nullptr); - void SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER_FULL pHandler, void *pUserInfo); - int SendTextMessage(uint64_t chatId, const char *pszMessage); - - void ProcessAuth(TD::updateAuthorizationState *pObj); - void ProcessChat(TD::updateNewChat *pObj); - void ProcessChatPosition(TD::updateChatPosition *pObj); - void ProcessFile(TD::updateFile *pObj); - void ProcessGroups(TD::updateChatFilters *pObj); - void ProcessMarkRead(TD::updateChatReadInbox *pObj); - void ProcessMessage(TD::updateNewMessage *pObj); - void ProcessStatus(TD::updateUserStatus *pObj); - void ProcessUser(TD::updateUser *pObj); - - void UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str); - - // Users - int64_t m_iOwnId; - MGROUP m_iBaseGroup; - OBJLIST<TG_USER> m_arUsers; - - TG_USER* FindUser(uint64_t id); - TG_USER* AddUser(uint64_t id, bool bIsChat); - - // Popups - HANDLE m_hPopupClass; - - void InitPopups(void); - void Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle); - -public: - ////////////////////////////////////////////////////////////////////////////////////// - // Ctors - - CMTProto(const char *protoName, const wchar_t *userName); - ~CMTProto(); - - ////////////////////////////////////////////////////////////////////////////////////// - // Virtual functions - - INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; - - int SendMsg(MCONTACT hContact, int flags, const char *pszMessage) override; - int SetStatus(int iNewStatus) override; - - void OnModulesLoaded() override; - void OnShutdown() override; - void OnErase() override; - - // Services ////////////////////////////////////////////////////////////////////////// - - INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); - INT_PTR __cdecl SvcGetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl SvcGetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl SvcGetMyAvatar(WPARAM, LPARAM); - INT_PTR __cdecl SvcSetMyAvatar(WPARAM, LPARAM); - - // Events //////////////////////////////////////////////////////////////////////////// - - int __cdecl OnOptionsInit(WPARAM, LPARAM); - int __cdecl OnDbMarkedRead(WPARAM, LPARAM); - - // Options /////////////////////////////////////////////////////////////////////////// - - CMOption<wchar_t*> m_szOwnPhone; // our own phone number - CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts - CMOption<wchar_t*> m_wszDeviceName; // how do you see this session in Device List - CMOption<bool> m_bHideGroupchats; // do not open chat windows on creation - CMOption<bool> m_bUsePopups; - - // Processing Threads //////////////////////////////////////////////////////////////// - - void __cdecl ServerThread(void *); -}; +#pragma once
+
+#define DBKEY_ID "id"
+
+#define DBKEY_AVATAR_HASH "AvatarHash"
+#define DBKEY_AVATAR_PATH "AvatarPath"
+#define DBKEY_AVATAR_TYPE "AvatarType"
+
+class CMTProto;
+typedef void (CMTProto:: *TG_QUERY_HANDLER)(td::ClientManager::Response &response);
+typedef void (CMTProto:: *TG_QUERY_HANDLER_FULL)(td::ClientManager::Response &response, void *pUserInfo);
+
+struct TG_REQUEST_BASE
+{
+ TG_REQUEST_BASE(td::ClientManager::RequestId _1) :
+ requestId(_1)
+ {}
+
+ virtual ~TG_REQUEST_BASE()
+ {}
+
+ td::ClientManager::RequestId requestId;
+
+ virtual void Execute(CMTProto *ppro, td::ClientManager::Response &response) = 0;
+};
+
+struct TG_REQUEST : public TG_REQUEST_BASE
+{
+ TG_REQUEST(td::ClientManager::RequestId _1, TG_QUERY_HANDLER _2) :
+ TG_REQUEST_BASE(_1),
+ pHandler(_2)
+ {}
+
+ TG_QUERY_HANDLER pHandler;
+
+ void Execute(CMTProto *ppro, td::ClientManager::Response &response) override
+ {
+ (ppro->*pHandler)(response);
+ }
+};
+
+struct TG_REQUEST_FULL : public TG_REQUEST_BASE
+{
+ TG_REQUEST_FULL(td::ClientManager::RequestId _1, TG_QUERY_HANDLER_FULL _2, void *_3) :
+ TG_REQUEST_BASE(_1),
+ pHandler(_2),
+ pUserInfo(_3)
+ {}
+
+ TG_QUERY_HANDLER_FULL pHandler;
+ void *pUserInfo;
+
+ void Execute(CMTProto *ppro, td::ClientManager::Response &response) override
+ {
+ (ppro->*pHandler)(response, pUserInfo);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct TG_USER
+{
+ TG_USER(uint64_t _1, MCONTACT _2, bool _3 = false) :
+ id(_1),
+ hContact(_2),
+ isGroupChat(_3)
+ {}
+
+ uint64_t id;
+ MCONTACT hContact;
+ bool isGroupChat;
+ CMStringA szAvatarHash;
+ time_t m_timer1 = 0, m_timer2 = 0;
+};
+
+class CMTProto : public PROTO<CMTProto>
+{
+ class CProtoImpl
+ {
+ friend class CMTProto;
+ CMTProto &m_proto;
+
+ CTimer m_keepAlive, m_markRead;
+ void OnKeepAlive(CTimer *)
+ { m_proto.SendKeepAlive();
+ }
+
+ void OnMarkRead(CTimer *)
+ { m_proto.SendMarkRead();
+ }
+
+ CProtoImpl(CMTProto &pro) :
+ m_proto(pro),
+ m_markRead(Miranda_GetSystemWindow(), UINT_PTR(this)),
+ m_keepAlive(Miranda_GetSystemWindow(), UINT_PTR(this)+1)
+ {
+ m_markRead.OnEvent = Callback(this, &CProtoImpl::OnMarkRead);
+ m_keepAlive.OnEvent = Callback(this, &CProtoImpl::OnKeepAlive);
+ }
+ } m_impl;
+
+ bool __forceinline isRunning() const
+ { return m_pClientMmanager != nullptr;
+ }
+
+ std::unique_ptr<td::ClientManager> m_pClientMmanager;
+ TD::object_ptr<TD::AuthorizationState> pAuthState;
+
+ mir_cs m_csMarkRead;
+ MCONTACT m_markContact = 0;
+ TD::array<TD::int53> m_markIds;
+
+ bool m_bAuthorized, m_bTerminated, m_bUnregister = false;
+ int32_t m_iClientId, m_iMsgId;
+ uint64_t m_iQueryId;
+
+ OBJLIST<TG_REQUEST_BASE> m_arRequests;
+
+ static INT_PTR CALLBACK EnterPhoneCode(void *param);
+ static INT_PTR CALLBACK EnterPassword(void *param);
+
+ CMStringW GetProtoFolder() const
+ { return CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName);
+ }
+
+ void OnEndSession(td::ClientManager::Response &response);
+ void OnSendMessage(td::ClientManager::Response &response, void *pUserInfo);
+ void OnUpdateAuth(td::ClientManager::Response &response);
+
+ void LogOut(void);
+ void OnLoggedIn(void);
+ void ProcessResponse(td::ClientManager::Response);
+
+ void SendKeepAlive(void);
+ void SendMarkRead(void);
+ void SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER pHandler = nullptr);
+ void SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER_FULL pHandler, void *pUserInfo);
+ int SendTextMessage(uint64_t chatId, const char *pszMessage);
+
+ void ProcessAuth(TD::updateAuthorizationState *pObj);
+ void ProcessChat(TD::updateNewChat *pObj);
+ void ProcessChatPosition(TD::updateChatPosition *pObj);
+ void ProcessFile(TD::updateFile *pObj);
+ void ProcessGroups(TD::updateChatFilters *pObj);
+ void ProcessMarkRead(TD::updateChatReadInbox *pObj);
+ void ProcessMessage(TD::updateNewMessage *pObj);
+ void ProcessStatus(TD::updateUserStatus *pObj);
+ void ProcessUser(TD::updateUser *pObj);
+
+ void UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str);
+
+ // Users
+ int64_t m_iOwnId;
+ MGROUP m_iBaseGroup;
+ OBJLIST<TG_USER> m_arUsers;
+
+ TG_USER* FindUser(uint64_t id);
+ TG_USER* AddUser(uint64_t id, bool bIsChat);
+
+ // Popups
+ HANDLE m_hPopupClass;
+
+ void InitPopups(void);
+ void Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle);
+
+public:
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Ctors
+
+ CMTProto(const char *protoName, const wchar_t *userName);
+ ~CMTProto();
+
+ //////////////////////////////////////////////////////////////////////////////////////
+ // Virtual functions
+
+ INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
+
+ int SendMsg(MCONTACT hContact, int flags, const char *pszMessage) override;
+ int SetStatus(int iNewStatus) override;
+
+ void OnModulesLoaded() override;
+ void OnShutdown() override;
+ void OnErase() override;
+
+ // Services //////////////////////////////////////////////////////////////////////////
+
+ INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetAvatarCaps(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetAvatarInfo(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcGetMyAvatar(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcSetMyAvatar(WPARAM, LPARAM);
+
+ // Events ////////////////////////////////////////////////////////////////////////////
+
+ int __cdecl OnOptionsInit(WPARAM, LPARAM);
+ int __cdecl OnDbMarkedRead(WPARAM, LPARAM);
+
+ // Options ///////////////////////////////////////////////////////////////////////////
+
+ CMOption<wchar_t*> m_szOwnPhone; // our own phone number
+ CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts
+ CMOption<wchar_t*> m_wszDeviceName; // how do you see this session in Device List
+ CMOption<bool> m_bHideGroupchats; // do not open chat windows on creation
+ CMOption<bool> m_bUsePopups;
+
+ // Processing Threads ////////////////////////////////////////////////////////////////
+
+ void __cdecl ServerThread(void *);
+};
diff --git a/protocols/Telegram/src/options.cpp b/protocols/Telegram/src/options.cpp index 9159d7304e..f3c5cbfb37 100644 --- a/protocols/Telegram/src/options.cpp +++ b/protocols/Telegram/src/options.cpp @@ -1,82 +1,82 @@ -/* -Copyright (C) 2012-23 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" - -///////////////////////////////////////////////////////////////////////////////////////// - -class COptionsDlg : public CProtoDlgBase<CMTProto> -{ - CCtrlCheck chkHideChats, chkUsePopups; - CCtrlEdit edtGroup, edtPhone, edtDeviceName; - ptrW m_wszOldGroup; - -public: - COptionsDlg(CMTProto *ppro, int iDlgID, bool bFullDlg) : - CProtoDlgBase<CMTProto>(ppro, iDlgID), - chkUsePopups(this, IDC_POPUPS), - chkHideChats(this, IDC_HIDECHATS), - edtPhone(this, IDC_PHONE), - edtGroup(this, IDC_DEFGROUP), - edtDeviceName(this, IDC_DEVICE_NAME), - m_wszOldGroup(mir_wstrdup(ppro->m_wszDefaultGroup)) - { - CreateLink(edtPhone, ppro->m_szOwnPhone); - CreateLink(edtGroup, ppro->m_wszDefaultGroup); - CreateLink(edtDeviceName, ppro->m_wszDeviceName); - CreateLink(chkHideChats, ppro->m_bHideGroupchats); - - if (bFullDlg) - CreateLink(chkUsePopups, ppro->m_bUsePopups); - } - - bool OnApply() override - { - if (!mir_wstrlen(m_proto->m_szOwnPhone)) { - SetFocus(edtPhone.GetHwnd()); - return false; - } - - if (mir_wstrcmp(m_proto->m_wszDefaultGroup, m_wszOldGroup)) - Clist_GroupCreate(0, m_proto->m_wszDefaultGroup); - return true; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CMTProto::SvcCreateAccMgrUI(WPARAM, LPARAM hwndParent) -{ - auto *pDlg = new COptionsDlg(this, IDD_ACCMGRUI, false); - pDlg->SetParent((HWND)hwndParent); - pDlg->Create(); - return (INT_PTR)pDlg->GetHwnd(); -} - -int CMTProto::OnOptionsInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.szTitle.w = m_tszUserName; - odp.flags = ODPF_UNICODE; - odp.szGroup.w = LPGENW("Network"); - - odp.position = 1; - odp.szTab.w = LPGENW("Account"); - odp.pDialog = new COptionsDlg(this, IDD_OPTIONS, true); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/*
+Copyright (C) 2012-23 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"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class COptionsDlg : public CProtoDlgBase<CMTProto>
+{
+ CCtrlCheck chkHideChats, chkUsePopups;
+ CCtrlEdit edtGroup, edtPhone, edtDeviceName;
+ ptrW m_wszOldGroup;
+
+public:
+ COptionsDlg(CMTProto *ppro, int iDlgID, bool bFullDlg) :
+ CProtoDlgBase<CMTProto>(ppro, iDlgID),
+ chkUsePopups(this, IDC_POPUPS),
+ chkHideChats(this, IDC_HIDECHATS),
+ edtPhone(this, IDC_PHONE),
+ edtGroup(this, IDC_DEFGROUP),
+ edtDeviceName(this, IDC_DEVICE_NAME),
+ m_wszOldGroup(mir_wstrdup(ppro->m_wszDefaultGroup))
+ {
+ CreateLink(edtPhone, ppro->m_szOwnPhone);
+ CreateLink(edtGroup, ppro->m_wszDefaultGroup);
+ CreateLink(edtDeviceName, ppro->m_wszDeviceName);
+ CreateLink(chkHideChats, ppro->m_bHideGroupchats);
+
+ if (bFullDlg)
+ CreateLink(chkUsePopups, ppro->m_bUsePopups);
+ }
+
+ bool OnApply() override
+ {
+ if (!mir_wstrlen(m_proto->m_szOwnPhone)) {
+ SetFocus(edtPhone.GetHwnd());
+ return false;
+ }
+
+ if (mir_wstrcmp(m_proto->m_wszDefaultGroup, m_wszOldGroup))
+ Clist_GroupCreate(0, m_proto->m_wszDefaultGroup);
+ return true;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CMTProto::SvcCreateAccMgrUI(WPARAM, LPARAM hwndParent)
+{
+ auto *pDlg = new COptionsDlg(this, IDD_ACCMGRUI, false);
+ pDlg->SetParent((HWND)hwndParent);
+ pDlg->Create();
+ return (INT_PTR)pDlg->GetHwnd();
+}
+
+int CMTProto::OnOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szTitle.w = m_tszUserName;
+ odp.flags = ODPF_UNICODE;
+ odp.szGroup.w = LPGENW("Network");
+
+ odp.position = 1;
+ odp.szTab.w = LPGENW("Account");
+ odp.pDialog = new COptionsDlg(this, IDD_OPTIONS, true);
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/Telegram/src/resource.h b/protocols/Telegram/src/resource.h index 87a094b2bc..9ea3641d02 100644 --- a/protocols/Telegram/src/resource.h +++ b/protocols/Telegram/src/resource.h @@ -1,25 +1,25 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by W:\miranda-ng\protocols\Telegram\res\resource.rc -// -#define IDI_TELEGRAM 100 -#define IDD_ACCMGRUI 101 -#define IDD_OPTIONS 102 -#define IDI_PREMIUM 103 -#define IDC_PHONE 1001 -#define IDC_DEFGROUP 1002 -#define IDC_HIDECHATS 1003 -#define IDC_POPUPS 1004 -#define IDC_DEFGROUP2 1004 -#define IDC_DEVICE_NAME 1005 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 106 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1006 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by W:\miranda-ng\protocols\Telegram\res\resource.rc
+//
+#define IDI_TELEGRAM 100
+#define IDD_ACCMGRUI 101
+#define IDD_OPTIONS 102
+#define IDI_PREMIUM 103
+#define IDC_PHONE 1001
+#define IDC_DEFGROUP 1002
+#define IDC_HIDECHATS 1003
+#define IDC_POPUPS 1004
+#define IDC_DEFGROUP2 1004
+#define IDC_DEVICE_NAME 1005
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1006
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/Telegram/src/server.cpp b/protocols/Telegram/src/server.cpp index 24ad055fff..5828478802 100644 --- a/protocols/Telegram/src/server.cpp +++ b/protocols/Telegram/src/server.cpp @@ -1,419 +1,419 @@ -/* -Copyright (C) 2012-23 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 CMTProto::OnEndSession(td::ClientManager::Response&) -{ - m_bTerminated = true; -} - -void __cdecl CMTProto::ServerThread(void *) -{ - m_bTerminated = m_bAuthorized = false; - - m_pClientMmanager = std::make_unique<td::ClientManager>(); - m_iClientId = m_pClientMmanager->create_client_id(); - - SendQuery(new TD::getOption("version")); - - while (!m_bTerminated) { - ProcessResponse(m_pClientMmanager->receive(1)); - } - - m_pClientMmanager = std::move(nullptr); -} - -void CMTProto::LogOut() -{ - if (m_bTerminated) - return; - - debugLogA("CMTProto::OnLoggedOut"); - m_bTerminated = true; - m_bAuthorized = false; - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - - setAllContactStatuses(ID_STATUS_OFFLINE, false); -} - -void CMTProto::OnLoggedIn() -{ - m_bAuthorized = true; - - debugLogA("CMTProto::OnLoggedIn"); - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); - m_iStatus = m_iDesiredStatus; - - if (m_bUnregister) { - SendQuery(new TD::terminateSession()); - SendQuery(new TD::logOut(), &CMTProto::OnEndSession); - } - else SendQuery(new TD::getChats(td::tl::unique_ptr<TD::chatListMain>(), 1000)); -} - -/////////////////////////////////////////////////////////////////////////////// - -void CMTProto::SendKeepAlive() -{ - time_t now = time(0); - - for (auto &it : m_arUsers) { - if (it->m_timer1 && now - it->m_timer1 > 600) { - it->m_timer1 = 0; - it->m_timer2 = now; - setWord(it->hContact, "Status", ID_STATUS_AWAY); - } - else if (it->m_timer2 && now - it->m_timer2 > 600) { - it->m_timer2 = 0; - setWord(it->hContact, "Status", ID_STATUS_OFFLINE); - } - } -} - -void CMTProto::SendMarkRead() -{ - m_impl.m_markRead.Stop(); - - mir_cslock lck(m_csMarkRead); - uint64_t userId = _atoi64(getMStringA(m_markContact, DBKEY_ID)); - SendQuery(new TD::viewMessages(userId, 0, std::move(m_markIds), true)); - m_markContact = 0; -} - -/////////////////////////////////////////////////////////////////////////////// - -void CMTProto::ProcessResponse(td::ClientManager::Response response) -{ - if (!response.object) - return; - - debugLogA("ProcessResponse: id=%d (%s)", int(response.request_id), to_string(response.object).c_str()); - - if (response.request_id) { - TG_REQUEST tmp(response.request_id, 0); - auto *p = m_arRequests.find(&tmp); - if (p) { - p->Execute(this, response); - m_arRequests.remove(p); - } - return; - } - - switch (response.object->get_id()) { - case TD::updateAuthorizationState::ID: - ProcessAuth((TD::updateAuthorizationState *)response.object.get()); - break; - - case TD::updateChatFilters::ID: - ProcessGroups((TD::updateChatFilters *)response.object.get()); - break; - - case TD::updateChatPosition::ID: - ProcessChatPosition((TD::updateChatPosition *)response.object.get()); - break; - - case TD::updateChatReadInbox::ID: - ProcessMarkRead((TD::updateChatReadInbox *)response.object.get()); - break; - - case TD::updateFile::ID: - ProcessFile((TD::updateFile*)response.object.get()); - break; - - case TD::updateNewChat::ID: - ProcessChat((TD::updateNewChat *)response.object.get()); - break; - - case TD::updateNewMessage::ID: - ProcessMessage((TD::updateNewMessage *)response.object.get()); - break; - - case TD::updateUserStatus::ID: - ProcessStatus((TD::updateUserStatus *)response.object.get()); - break; - - case TD::updateUser::ID: - ProcessUser((TD::updateUser *)response.object.get()); - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CMTProto::OnSendMessage(td::ClientManager::Response &response, void *pUserInfo) -{ - if (!response.object) - return; - - if (response.object->get_id() != TD::message::ID) { - debugLogA("Gotten class ID %d instead of %d, exiting", response.object->get_id(), TD::message::ID); - return; - } - - auto *pMessage = ((TD::message *)response.object.get()); - auto *pUser = FindUser(pMessage->chat_id_); - if (pUser) { - char szMsgId[100]; - _i64toa(pMessage->id_, szMsgId, 10); - ProtoBroadcastAck(pUser->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, pUserInfo, (LPARAM)szMsgId); - } -} - -int CMTProto::SendTextMessage(uint64_t chatId, const char *pszMessage) -{ - int ret = m_iMsgId++; - - auto pContent = TD::make_object<TD::inputMessageText>(); - pContent->text_ = TD::make_object<TD::formattedText>(); - pContent->text_->text_ = std::move(pszMessage); - - auto *pMessage = new TD::sendMessage(); - pMessage->chat_id_ = chatId; - pMessage->input_message_content_ = std::move(pContent); - SendQuery(pMessage, &CMTProto::OnSendMessage, (void*)ret); - - return ret; -} - -void CMTProto::SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER pHandler) -{ - int queryId = ++m_iQueryId; - - auto szDescr = to_string(*pFunc); - debugLogA("Sending query %d:\n%s", queryId, szDescr.c_str()); - - m_pClientMmanager->send(m_iClientId, queryId, TD::object_ptr<TD::Function>(pFunc)); - - if (pHandler) - m_arRequests.insert(new TG_REQUEST(queryId, pHandler)); -} - -void CMTProto::SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER_FULL pHandler, void *pUserInfo) -{ - int queryId = ++m_iQueryId; - - auto szDescr = to_string(*pFunc); - debugLogA("Sending full query %d:\n%s", queryId, szDescr.c_str()); - - m_pClientMmanager->send(m_iClientId, queryId, TD::object_ptr<TD::Function>(pFunc)); - - if (pHandler) - m_arRequests.insert(new TG_REQUEST_FULL(queryId, pHandler, pUserInfo)); -} - -/////////////////////////////////////////////////////////////////////////////// - -void CMTProto::ProcessChat(TD::updateNewChat *pObj) -{ - auto &pChat = pObj->chat_; - if (pChat->type_->get_id() != TD::chatTypePrivate::ID) { - debugLogA("Only private chats are currently supported"); - return; - } - - if (auto *pUser = FindUser(pChat->id_)) - if (!pChat->title_.empty()) - setUString(pUser->hContact, "Nick", pChat->title_.c_str()); -} - -void CMTProto::ProcessChatPosition(TD::updateChatPosition *pObj) -{ - if (pObj->position_->get_id() != TD::chatPosition::ID) { - debugLogA("Unsupport position"); - return; - } - - auto *pUser = FindUser(pObj->chat_id_); - if (pUser == nullptr) { - debugLogA("Unknown chat, skipping"); - return; - } - - auto *pPos = (TD::chatPosition *)pObj->position_.get(); - if (pPos->list_) { - auto *pList = (TD::chatListFilter*)pPos->list_.get(); - - CMStringA szSetting(FORMAT, "ChatFilter%d", pList->chat_filter_id_); - CMStringW wszGroup(getMStringW(szSetting)); - if (!wszGroup.IsEmpty()) { - ptrW pwszExistingGroup(Clist_GetGroup(pUser->hContact)); - if (!pwszExistingGroup || !mir_wstrcmp(pwszExistingGroup, m_wszDefaultGroup)) { - CMStringW wszNewGroup(FORMAT, L"%s\\%s", (wchar_t *)m_wszDefaultGroup, wszGroup.c_str()); - Clist_SetGroup(pUser->hContact, wszNewGroup); - } - } - } -} - -void CMTProto::ProcessGroups(TD::updateChatFilters *pObj) -{ - for (auto &grp : pObj->chat_filters_) { - if (grp->icon_name_ != "Custom") - continue; - - CMStringA szSetting(FORMAT, "ChatFilter%d", grp->id_); - CMStringW wszOldValue(getMStringW(szSetting)); - Utf2T wszNewValue(grp->title_.c_str()); - if (wszOldValue.IsEmpty()) { - Clist_GroupCreate(m_iBaseGroup, wszNewValue); - setWString(szSetting, wszNewValue); - } - else if (wszOldValue != wszNewValue) { - CMStringW wszFullGroup(FORMAT, L"%s\\%s", (wchar_t*)m_wszDefaultGroup, wszNewValue); - MGROUP oldGroup = Clist_GroupExists(wszFullGroup); - if (!oldGroup) - Clist_GroupCreate(m_iBaseGroup, wszFullGroup); - else - Clist_GroupRename(oldGroup, wszFullGroup); - setWString(szSetting, wszNewValue); - } - } -} - -void CMTProto::ProcessMarkRead(TD::updateChatReadInbox *pObj) -{ - auto *pUser = FindUser(pObj->chat_id_); - if (pUser == nullptr) { - debugLogA("message from unknown chat/user, ignored"); - return; - } - - char szId[100]; - _i64toa(pObj->last_read_inbox_message_id_, szId, 10); - MEVENT hLastRead = db_event_getById(m_szModuleName, szId); - if (hLastRead == 0) { - debugLogA("unknown event, ignored"); - return; - } - - bool bExit = false; - for (MEVENT hEvent = db_event_firstUnread(pUser->hContact); hEvent; hEvent = db_event_next(pUser->hContact, hEvent)) { - if (bExit) - break; - - bExit = (hEvent == hLastRead); - - DBEVENTINFO dbei = {}; - if (db_event_get(hEvent, &dbei)) - continue; - - if (!dbei.markedRead()) - db_event_markRead(pUser->hContact, hEvent); - } -} - -void CMTProto::ProcessMessage(TD::updateNewMessage *pObj) -{ - auto &pMessage = pObj->message_; - - auto *pUser = FindUser(pMessage->chat_id_); - if (pUser == nullptr) { - debugLogA("message from unknown chat/user, ignored"); - return; - } - - if (pUser->isGroupChat) { - debugLogA("message from group chat, ignored"); - return; - } - - CMStringA szText(getMessageText(pMessage->content_.get())); - if (szText.IsEmpty()) { - debugLogA("this message was not processed, ignored"); - return; - } - - char szId[100]; - _i64toa(pMessage->id_, szId, 10); - - PROTORECVEVENT pre = {}; - pre.szMessage = szText.GetBuffer(); - pre.szMsgId = szId; - pre.timestamp = pMessage->date_; - if (pMessage->sender_id_->get_id() == TD::messageSenderUser::ID) - if (((TD::messageSenderUser *)pMessage->sender_id_.get())->user_id_ == m_iOwnId) - pre.flags |= PREF_SENT; - ProtoChainRecvMsg(pUser->hContact, &pre); -} - -void CMTProto::ProcessStatus(TD::updateUserStatus *pObj) -{ - if (auto *pUser = FindUser(pObj->user_id_)) { - if (pObj->status_->get_id() == TD::userStatusOnline::ID) - setWord(pUser->hContact, "Status", ID_STATUS_ONLINE); - else if (pObj->status_->get_id() == TD::userStatusOffline::ID) { - setWord(pUser->hContact, "Status", ID_STATUS_AWAY); - pUser->m_timer1 = time(0); - } - else debugLogA("!!!!! Unknown status packet, report it to the developers"); - } -} - -void CMTProto::ProcessUser(TD::updateUser *pObj) -{ - auto *pUser = pObj->user_.get(); - - if (pUser->phone_number_ == _T2A(m_szOwnPhone).get()) { - m_iOwnId = pUser->id_; - - if (!FindUser(pUser->id_)) - m_arUsers.insert(new TG_USER(pUser->id_, 0)); - } - - if (!pUser->is_contact_) { - debugLogA("User doesn't belong to your contacts, skipping"); - return; - } - - auto *pu = AddUser(pUser->id_, false); - UpdateString(pu->hContact, "FirstName", pUser->first_name_); - UpdateString(pu->hContact, "LastName", pUser->last_name_); - UpdateString(pu->hContact, "Phone", pUser->phone_number_); - if (pUser->usernames_) - UpdateString(pu->hContact, "Nick", pUser->usernames_->editable_username_); - - if (pUser->is_premium_) - ExtraIcon_SetIconByName(g_plugin.m_hIcon, pu->hContact, "tg_premium"); - else - ExtraIcon_SetIconByName(g_plugin.m_hIcon, pu->hContact, nullptr); - - if (auto *pPhoto = pUser->profile_photo_.get()) { - if (auto *pSmall = pPhoto->small_.get()) { - auto remoteId = pSmall->remote_->unique_id_; - auto storedId = getMStringA(pu->hContact, DBKEY_AVATAR_HASH); - if (remoteId != storedId.c_str()) { - if (!remoteId.empty()) { - pu->szAvatarHash = remoteId.c_str(); - setString(pu->hContact, DBKEY_AVATAR_HASH, remoteId.c_str()); - SendQuery(new TD::downloadFile(pSmall->id_, 5, 0, 0, false)); - } - else delSetting(pu->hContact, DBKEY_AVATAR_HASH); - } - } - } - - if (pUser->status_) { - if (pUser->status_->get_id() == TD::userStatusOffline::ID) { - auto *pOffline = (TD::userStatusOffline *)pUser->status_.get(); - setDword(pu->hContact, "LastSeen", pOffline->was_online_); - } - } -} +/*
+Copyright (C) 2012-23 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 CMTProto::OnEndSession(td::ClientManager::Response&)
+{
+ m_bTerminated = true;
+}
+
+void __cdecl CMTProto::ServerThread(void *)
+{
+ m_bTerminated = m_bAuthorized = false;
+
+ m_pClientMmanager = std::make_unique<td::ClientManager>();
+ m_iClientId = m_pClientMmanager->create_client_id();
+
+ SendQuery(new TD::getOption("version"));
+
+ while (!m_bTerminated) {
+ ProcessResponse(m_pClientMmanager->receive(1));
+ }
+
+ m_pClientMmanager = std::move(nullptr);
+}
+
+void CMTProto::LogOut()
+{
+ if (m_bTerminated)
+ return;
+
+ debugLogA("CMTProto::OnLoggedOut");
+ m_bTerminated = true;
+ m_bAuthorized = false;
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE);
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+
+ setAllContactStatuses(ID_STATUS_OFFLINE, false);
+}
+
+void CMTProto::OnLoggedIn()
+{
+ m_bAuthorized = true;
+
+ debugLogA("CMTProto::OnLoggedIn");
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus);
+ m_iStatus = m_iDesiredStatus;
+
+ if (m_bUnregister) {
+ SendQuery(new TD::terminateSession());
+ SendQuery(new TD::logOut(), &CMTProto::OnEndSession);
+ }
+ else SendQuery(new TD::getChats(td::tl::unique_ptr<TD::chatListMain>(), 1000));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CMTProto::SendKeepAlive()
+{
+ time_t now = time(0);
+
+ for (auto &it : m_arUsers) {
+ if (it->m_timer1 && now - it->m_timer1 > 600) {
+ it->m_timer1 = 0;
+ it->m_timer2 = now;
+ setWord(it->hContact, "Status", ID_STATUS_AWAY);
+ }
+ else if (it->m_timer2 && now - it->m_timer2 > 600) {
+ it->m_timer2 = 0;
+ setWord(it->hContact, "Status", ID_STATUS_OFFLINE);
+ }
+ }
+}
+
+void CMTProto::SendMarkRead()
+{
+ m_impl.m_markRead.Stop();
+
+ mir_cslock lck(m_csMarkRead);
+ uint64_t userId = _atoi64(getMStringA(m_markContact, DBKEY_ID));
+ SendQuery(new TD::viewMessages(userId, 0, std::move(m_markIds), true));
+ m_markContact = 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CMTProto::ProcessResponse(td::ClientManager::Response response)
+{
+ if (!response.object)
+ return;
+
+ debugLogA("ProcessResponse: id=%d (%s)", int(response.request_id), to_string(response.object).c_str());
+
+ if (response.request_id) {
+ TG_REQUEST tmp(response.request_id, 0);
+ auto *p = m_arRequests.find(&tmp);
+ if (p) {
+ p->Execute(this, response);
+ m_arRequests.remove(p);
+ }
+ return;
+ }
+
+ switch (response.object->get_id()) {
+ case TD::updateAuthorizationState::ID:
+ ProcessAuth((TD::updateAuthorizationState *)response.object.get());
+ break;
+
+ case TD::updateChatFilters::ID:
+ ProcessGroups((TD::updateChatFilters *)response.object.get());
+ break;
+
+ case TD::updateChatPosition::ID:
+ ProcessChatPosition((TD::updateChatPosition *)response.object.get());
+ break;
+
+ case TD::updateChatReadInbox::ID:
+ ProcessMarkRead((TD::updateChatReadInbox *)response.object.get());
+ break;
+
+ case TD::updateFile::ID:
+ ProcessFile((TD::updateFile*)response.object.get());
+ break;
+
+ case TD::updateNewChat::ID:
+ ProcessChat((TD::updateNewChat *)response.object.get());
+ break;
+
+ case TD::updateNewMessage::ID:
+ ProcessMessage((TD::updateNewMessage *)response.object.get());
+ break;
+
+ case TD::updateUserStatus::ID:
+ ProcessStatus((TD::updateUserStatus *)response.object.get());
+ break;
+
+ case TD::updateUser::ID:
+ ProcessUser((TD::updateUser *)response.object.get());
+ break;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CMTProto::OnSendMessage(td::ClientManager::Response &response, void *pUserInfo)
+{
+ if (!response.object)
+ return;
+
+ if (response.object->get_id() != TD::message::ID) {
+ debugLogA("Gotten class ID %d instead of %d, exiting", response.object->get_id(), TD::message::ID);
+ return;
+ }
+
+ auto *pMessage = ((TD::message *)response.object.get());
+ auto *pUser = FindUser(pMessage->chat_id_);
+ if (pUser) {
+ char szMsgId[100];
+ _i64toa(pMessage->id_, szMsgId, 10);
+ ProtoBroadcastAck(pUser->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, pUserInfo, (LPARAM)szMsgId);
+ }
+}
+
+int CMTProto::SendTextMessage(uint64_t chatId, const char *pszMessage)
+{
+ int ret = m_iMsgId++;
+
+ auto pContent = TD::make_object<TD::inputMessageText>();
+ pContent->text_ = TD::make_object<TD::formattedText>();
+ pContent->text_->text_ = std::move(pszMessage);
+
+ auto *pMessage = new TD::sendMessage();
+ pMessage->chat_id_ = chatId;
+ pMessage->input_message_content_ = std::move(pContent);
+ SendQuery(pMessage, &CMTProto::OnSendMessage, (void*)ret);
+
+ return ret;
+}
+
+void CMTProto::SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER pHandler)
+{
+ int queryId = ++m_iQueryId;
+
+ auto szDescr = to_string(*pFunc);
+ debugLogA("Sending query %d:\n%s", queryId, szDescr.c_str());
+
+ m_pClientMmanager->send(m_iClientId, queryId, TD::object_ptr<TD::Function>(pFunc));
+
+ if (pHandler)
+ m_arRequests.insert(new TG_REQUEST(queryId, pHandler));
+}
+
+void CMTProto::SendQuery(TD::Function *pFunc, TG_QUERY_HANDLER_FULL pHandler, void *pUserInfo)
+{
+ int queryId = ++m_iQueryId;
+
+ auto szDescr = to_string(*pFunc);
+ debugLogA("Sending full query %d:\n%s", queryId, szDescr.c_str());
+
+ m_pClientMmanager->send(m_iClientId, queryId, TD::object_ptr<TD::Function>(pFunc));
+
+ if (pHandler)
+ m_arRequests.insert(new TG_REQUEST_FULL(queryId, pHandler, pUserInfo));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CMTProto::ProcessChat(TD::updateNewChat *pObj)
+{
+ auto &pChat = pObj->chat_;
+ if (pChat->type_->get_id() != TD::chatTypePrivate::ID) {
+ debugLogA("Only private chats are currently supported");
+ return;
+ }
+
+ if (auto *pUser = FindUser(pChat->id_))
+ if (!pChat->title_.empty())
+ setUString(pUser->hContact, "Nick", pChat->title_.c_str());
+}
+
+void CMTProto::ProcessChatPosition(TD::updateChatPosition *pObj)
+{
+ if (pObj->position_->get_id() != TD::chatPosition::ID) {
+ debugLogA("Unsupport position");
+ return;
+ }
+
+ auto *pUser = FindUser(pObj->chat_id_);
+ if (pUser == nullptr) {
+ debugLogA("Unknown chat, skipping");
+ return;
+ }
+
+ auto *pPos = (TD::chatPosition *)pObj->position_.get();
+ if (pPos->list_) {
+ auto *pList = (TD::chatListFilter*)pPos->list_.get();
+
+ CMStringA szSetting(FORMAT, "ChatFilter%d", pList->chat_filter_id_);
+ CMStringW wszGroup(getMStringW(szSetting));
+ if (!wszGroup.IsEmpty()) {
+ ptrW pwszExistingGroup(Clist_GetGroup(pUser->hContact));
+ if (!pwszExistingGroup || !mir_wstrcmp(pwszExistingGroup, m_wszDefaultGroup)) {
+ CMStringW wszNewGroup(FORMAT, L"%s\\%s", (wchar_t *)m_wszDefaultGroup, wszGroup.c_str());
+ Clist_SetGroup(pUser->hContact, wszNewGroup);
+ }
+ }
+ }
+}
+
+void CMTProto::ProcessGroups(TD::updateChatFilters *pObj)
+{
+ for (auto &grp : pObj->chat_filters_) {
+ if (grp->icon_name_ != "Custom")
+ continue;
+
+ CMStringA szSetting(FORMAT, "ChatFilter%d", grp->id_);
+ CMStringW wszOldValue(getMStringW(szSetting));
+ Utf2T wszNewValue(grp->title_.c_str());
+ if (wszOldValue.IsEmpty()) {
+ Clist_GroupCreate(m_iBaseGroup, wszNewValue);
+ setWString(szSetting, wszNewValue);
+ }
+ else if (wszOldValue != wszNewValue) {
+ CMStringW wszFullGroup(FORMAT, L"%s\\%s", (wchar_t*)m_wszDefaultGroup, wszNewValue);
+ MGROUP oldGroup = Clist_GroupExists(wszFullGroup);
+ if (!oldGroup)
+ Clist_GroupCreate(m_iBaseGroup, wszFullGroup);
+ else
+ Clist_GroupRename(oldGroup, wszFullGroup);
+ setWString(szSetting, wszNewValue);
+ }
+ }
+}
+
+void CMTProto::ProcessMarkRead(TD::updateChatReadInbox *pObj)
+{
+ auto *pUser = FindUser(pObj->chat_id_);
+ if (pUser == nullptr) {
+ debugLogA("message from unknown chat/user, ignored");
+ return;
+ }
+
+ char szId[100];
+ _i64toa(pObj->last_read_inbox_message_id_, szId, 10);
+ MEVENT hLastRead = db_event_getById(m_szModuleName, szId);
+ if (hLastRead == 0) {
+ debugLogA("unknown event, ignored");
+ return;
+ }
+
+ bool bExit = false;
+ for (MEVENT hEvent = db_event_firstUnread(pUser->hContact); hEvent; hEvent = db_event_next(pUser->hContact, hEvent)) {
+ if (bExit)
+ break;
+
+ bExit = (hEvent == hLastRead);
+
+ DBEVENTINFO dbei = {};
+ if (db_event_get(hEvent, &dbei))
+ continue;
+
+ if (!dbei.markedRead())
+ db_event_markRead(pUser->hContact, hEvent);
+ }
+}
+
+void CMTProto::ProcessMessage(TD::updateNewMessage *pObj)
+{
+ auto &pMessage = pObj->message_;
+
+ auto *pUser = FindUser(pMessage->chat_id_);
+ if (pUser == nullptr) {
+ debugLogA("message from unknown chat/user, ignored");
+ return;
+ }
+
+ if (pUser->isGroupChat) {
+ debugLogA("message from group chat, ignored");
+ return;
+ }
+
+ CMStringA szText(getMessageText(pMessage->content_.get()));
+ if (szText.IsEmpty()) {
+ debugLogA("this message was not processed, ignored");
+ return;
+ }
+
+ char szId[100];
+ _i64toa(pMessage->id_, szId, 10);
+
+ PROTORECVEVENT pre = {};
+ pre.szMessage = szText.GetBuffer();
+ pre.szMsgId = szId;
+ pre.timestamp = pMessage->date_;
+ if (pMessage->sender_id_->get_id() == TD::messageSenderUser::ID)
+ if (((TD::messageSenderUser *)pMessage->sender_id_.get())->user_id_ == m_iOwnId)
+ pre.flags |= PREF_SENT;
+ ProtoChainRecvMsg(pUser->hContact, &pre);
+}
+
+void CMTProto::ProcessStatus(TD::updateUserStatus *pObj)
+{
+ if (auto *pUser = FindUser(pObj->user_id_)) {
+ if (pObj->status_->get_id() == TD::userStatusOnline::ID)
+ setWord(pUser->hContact, "Status", ID_STATUS_ONLINE);
+ else if (pObj->status_->get_id() == TD::userStatusOffline::ID) {
+ setWord(pUser->hContact, "Status", ID_STATUS_AWAY);
+ pUser->m_timer1 = time(0);
+ }
+ else debugLogA("!!!!! Unknown status packet, report it to the developers");
+ }
+}
+
+void CMTProto::ProcessUser(TD::updateUser *pObj)
+{
+ auto *pUser = pObj->user_.get();
+
+ if (pUser->phone_number_ == _T2A(m_szOwnPhone).get()) {
+ m_iOwnId = pUser->id_;
+
+ if (!FindUser(pUser->id_))
+ m_arUsers.insert(new TG_USER(pUser->id_, 0));
+ }
+
+ if (!pUser->is_contact_) {
+ debugLogA("User doesn't belong to your contacts, skipping");
+ return;
+ }
+
+ auto *pu = AddUser(pUser->id_, false);
+ UpdateString(pu->hContact, "FirstName", pUser->first_name_);
+ UpdateString(pu->hContact, "LastName", pUser->last_name_);
+ UpdateString(pu->hContact, "Phone", pUser->phone_number_);
+ if (pUser->usernames_)
+ UpdateString(pu->hContact, "Nick", pUser->usernames_->editable_username_);
+
+ if (pUser->is_premium_)
+ ExtraIcon_SetIconByName(g_plugin.m_hIcon, pu->hContact, "tg_premium");
+ else
+ ExtraIcon_SetIconByName(g_plugin.m_hIcon, pu->hContact, nullptr);
+
+ if (auto *pPhoto = pUser->profile_photo_.get()) {
+ if (auto *pSmall = pPhoto->small_.get()) {
+ auto remoteId = pSmall->remote_->unique_id_;
+ auto storedId = getMStringA(pu->hContact, DBKEY_AVATAR_HASH);
+ if (remoteId != storedId.c_str()) {
+ if (!remoteId.empty()) {
+ pu->szAvatarHash = remoteId.c_str();
+ setString(pu->hContact, DBKEY_AVATAR_HASH, remoteId.c_str());
+ SendQuery(new TD::downloadFile(pSmall->id_, 5, 0, 0, false));
+ }
+ else delSetting(pu->hContact, DBKEY_AVATAR_HASH);
+ }
+ }
+ }
+
+ if (pUser->status_) {
+ if (pUser->status_->get_id() == TD::userStatusOffline::ID) {
+ auto *pOffline = (TD::userStatusOffline *)pUser->status_.get();
+ setDword(pu->hContact, "LastSeen", pOffline->was_online_);
+ }
+ }
+}
diff --git a/protocols/Telegram/src/stdafx.cxx b/protocols/Telegram/src/stdafx.cxx index b08670e67f..8c570f6949 100644 --- a/protocols/Telegram/src/stdafx.cxx +++ b/protocols/Telegram/src/stdafx.cxx @@ -1,18 +1,18 @@ -/* -Copyright (C) 2012-23 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" +/*
+Copyright (C) 2012-23 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"
diff --git a/protocols/Telegram/src/stdafx.h b/protocols/Telegram/src/stdafx.h index cae3629bf9..8e56956840 100644 --- a/protocols/Telegram/src/stdafx.h +++ b/protocols/Telegram/src/stdafx.h @@ -1,48 +1,48 @@ -#ifndef _COMMON_H_ -#define _COMMON_H_ - -#include <time.h> -#include <windows.h> - -#include <map> -#include <memory> - -#include <newpluginapi.h> - -#include <m_protoint.h> -#include <m_protosvc.h> - -#include <m_avatars.h> -#include <m_clist.h> -#include <m_chat.h> -#include <m_contacts.h> -#include <m_database.h> -#include <m_extraicons.h> -#include <m_icolib.h> -#include <m_langpack.h> -#include <m_netlib.h> -#include <m_options.h> -#include <m_popup.h> - -#include "td/telegram/Client.h" -#include "td/telegram/td_api.h" -#include "td/telegram/td_api.hpp" -namespace TD = td::td_api; - -#define MODULE "Telegram" - -#include "version.h" -#include "resource.h" -#include "mt_proto.h" -#include "utils.h" - -struct CMPlugin : public ACCPROTOPLUGIN<CMTProto> -{ - CMPlugin(); - - HANDLE m_hIcon; - - int Load() override; -}; - +#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include <time.h>
+#include <windows.h>
+
+#include <map>
+#include <memory>
+
+#include <newpluginapi.h>
+
+#include <m_protoint.h>
+#include <m_protosvc.h>
+
+#include <m_avatars.h>
+#include <m_clist.h>
+#include <m_chat.h>
+#include <m_contacts.h>
+#include <m_database.h>
+#include <m_extraicons.h>
+#include <m_icolib.h>
+#include <m_langpack.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+
+#include "td/telegram/Client.h"
+#include "td/telegram/td_api.h"
+#include "td/telegram/td_api.hpp"
+namespace TD = td::td_api;
+
+#define MODULE "Telegram"
+
+#include "version.h"
+#include "resource.h"
+#include "mt_proto.h"
+#include "utils.h"
+
+struct CMPlugin : public ACCPROTOPLUGIN<CMTProto>
+{
+ CMPlugin();
+
+ HANDLE m_hIcon;
+
+ int Load() override;
+};
+
#endif //_COMMON_H_
\ No newline at end of file diff --git a/protocols/Telegram/src/utils.cpp b/protocols/Telegram/src/utils.cpp index 6113870bd3..df4a0d9118 100644 --- a/protocols/Telegram/src/utils.cpp +++ b/protocols/Telegram/src/utils.cpp @@ -1,126 +1,126 @@ -/* -Copyright (C) 2012-23 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 CMTProto::UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str) -{ - if (str.empty()) - delSetting(hContact, pszSetting); - else - setUString(hContact, pszSetting, str.c_str()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Users - -TG_USER* CMTProto::FindUser(uint64_t id) -{ - if (auto *pCache = m_arUsers.find((TG_USER *)&id)) - return pCache; - - return nullptr; -} - -TG_USER* CMTProto::AddUser(uint64_t id, bool bIsChat) -{ - auto *pUser = FindUser(id); - if (pUser != nullptr) - return pUser; - - MCONTACT hContact = db_add_contact(); - Proto_AddToContact(hContact, m_szModuleName); - - char szId[100]; - _i64toa(id, szId, 10); - - if (bIsChat) { - Clist_SetGroup(hContact, TranslateT("Chat rooms")); - setByte(hContact, "ChatRoom", 1); - setString(hContact, "ChatRoomID", szId); - } - else { - setString(hContact, DBKEY_ID, szId); - if (mir_wstrlen(m_wszDefaultGroup)) - Clist_SetGroup(hContact, m_wszDefaultGroup); - } - - pUser = new TG_USER(id, hContact, bIsChat); - m_arUsers.insert(pUser); - return pUser; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Popups - -void CMTProto::InitPopups(void) -{ - g_plugin.addPopupOption(CMStringW(FORMAT, TranslateT("%s error notifications"), m_tszUserName), m_bUsePopups); - - char name[256]; - mir_snprintf(name, "%s_%s", m_szModuleName, "Error"); - - wchar_t desc[256]; - mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Errors")); - - POPUPCLASS ppc = {}; - ppc.flags = PCF_UNICODE; - ppc.pszName = name; - ppc.pszDescription.w = desc; - ppc.hIcon = IcoLib_GetIconByHandle(m_hProtoIcon); - ppc.colorBack = RGB(191, 0, 0); //Red - ppc.colorText = RGB(255, 245, 225); //Yellow - ppc.iSeconds = 60; - m_hPopupClass = Popup_RegisterClass(&ppc); - - IcoLib_ReleaseIcon(ppc.hIcon); -} - -void CMTProto::Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle) -{ - if (!m_bUsePopups) - return; - - char name[256]; - mir_snprintf(name, "%s_%s", m_szModuleName, "Error"); - - CMStringW wszTitle(szTitle); - if (hContact == 0) { - wszTitle.Insert(0, L": "); - wszTitle.Insert(0, m_tszUserName); - } - - POPUPDATACLASS ppd = {}; - ppd.szTitle.w = wszTitle; - ppd.szText.w = szMsg; - ppd.pszClassName = name; - ppd.hContact = hContact; - Popup_AddClass(&ppd); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CMStringA getMessageText(TD::MessageContent *pBody) -{ - if (pBody->get_id() == TD::messageText::ID) { - auto pText = ((TD::messageText *)pBody)->text_.get(); - if (pText->get_id() == TD::formattedText::ID) - return CMStringA(((TD::formattedText *)pText)->text_.c_str()); - } - - return CMStringA(); -} +/*
+Copyright (C) 2012-23 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 CMTProto::UpdateString(MCONTACT hContact, const char *pszSetting, const std::string &str)
+{
+ if (str.empty())
+ delSetting(hContact, pszSetting);
+ else
+ setUString(hContact, pszSetting, str.c_str());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Users
+
+TG_USER* CMTProto::FindUser(uint64_t id)
+{
+ if (auto *pCache = m_arUsers.find((TG_USER *)&id))
+ return pCache;
+
+ return nullptr;
+}
+
+TG_USER* CMTProto::AddUser(uint64_t id, bool bIsChat)
+{
+ auto *pUser = FindUser(id);
+ if (pUser != nullptr)
+ return pUser;
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+
+ char szId[100];
+ _i64toa(id, szId, 10);
+
+ if (bIsChat) {
+ Clist_SetGroup(hContact, TranslateT("Chat rooms"));
+ setByte(hContact, "ChatRoom", 1);
+ setString(hContact, "ChatRoomID", szId);
+ }
+ else {
+ setString(hContact, DBKEY_ID, szId);
+ if (mir_wstrlen(m_wszDefaultGroup))
+ Clist_SetGroup(hContact, m_wszDefaultGroup);
+ }
+
+ pUser = new TG_USER(id, hContact, bIsChat);
+ m_arUsers.insert(pUser);
+ return pUser;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popups
+
+void CMTProto::InitPopups(void)
+{
+ g_plugin.addPopupOption(CMStringW(FORMAT, TranslateT("%s error notifications"), m_tszUserName), m_bUsePopups);
+
+ char name[256];
+ mir_snprintf(name, "%s_%s", m_szModuleName, "Error");
+
+ wchar_t desc[256];
+ mir_snwprintf(desc, L"%s/%s", m_tszUserName, TranslateT("Errors"));
+
+ POPUPCLASS ppc = {};
+ ppc.flags = PCF_UNICODE;
+ ppc.pszName = name;
+ ppc.pszDescription.w = desc;
+ ppc.hIcon = IcoLib_GetIconByHandle(m_hProtoIcon);
+ ppc.colorBack = RGB(191, 0, 0); //Red
+ ppc.colorText = RGB(255, 245, 225); //Yellow
+ ppc.iSeconds = 60;
+ m_hPopupClass = Popup_RegisterClass(&ppc);
+
+ IcoLib_ReleaseIcon(ppc.hIcon);
+}
+
+void CMTProto::Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle)
+{
+ if (!m_bUsePopups)
+ return;
+
+ char name[256];
+ mir_snprintf(name, "%s_%s", m_szModuleName, "Error");
+
+ CMStringW wszTitle(szTitle);
+ if (hContact == 0) {
+ wszTitle.Insert(0, L": ");
+ wszTitle.Insert(0, m_tszUserName);
+ }
+
+ POPUPDATACLASS ppd = {};
+ ppd.szTitle.w = wszTitle;
+ ppd.szText.w = szMsg;
+ ppd.pszClassName = name;
+ ppd.hContact = hContact;
+ Popup_AddClass(&ppd);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CMStringA getMessageText(TD::MessageContent *pBody)
+{
+ if (pBody->get_id() == TD::messageText::ID) {
+ auto pText = ((TD::messageText *)pBody)->text_.get();
+ if (pText->get_id() == TD::formattedText::ID)
+ return CMStringA(((TD::formattedText *)pText)->text_.c_str());
+ }
+
+ return CMStringA();
+}
diff --git a/protocols/Telegram/src/utils.h b/protocols/Telegram/src/utils.h index 2526393a5f..a0811da20e 100644 --- a/protocols/Telegram/src/utils.h +++ b/protocols/Telegram/src/utils.h @@ -1,3 +1,3 @@ -#pragma once - -CMStringA getMessageText(TD::MessageContent *pBody); +#pragma once
+
+CMStringA getMessageText(TD::MessageContent *pBody);
diff --git a/protocols/Telegram/tdlib/tdactor.vcxproj b/protocols/Telegram/tdlib/tdactor.vcxproj index b8023c00e1..dfce57bbe9 100644 --- a/protocols/Telegram/tdlib/tdactor.vcxproj +++ b/protocols/Telegram/tdlib/tdactor.vcxproj @@ -1,75 +1,75 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{85F63934-02FE-332A-8703-059040B65512}</ProjectGuid> - <ProjectName>tdactor</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\td\tdactor;.\td\tdutils;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\tdactor\td\actor\ConcurrentScheduler.cpp" /> - <ClCompile Include="td\tdactor\td\actor\impl\Scheduler.cpp" /> - <ClCompile Include="td\tdactor\td\actor\MultiPromise.cpp" /> - <ClCompile Include="td\tdactor\td\actor\MultiTimeout.cpp" /> - <ClInclude Include="td\tdactor\td\actor\ConcurrentScheduler.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Actor-decl.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Actor.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\ActorId-decl.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\ActorId.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo-decl.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\EventFull-decl.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\EventFull.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Event.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Scheduler-decl.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Scheduler.h" /> - <ClInclude Include="td\tdactor\td\actor\MultiPromise.h" /> - <ClInclude Include="td\tdactor\td\actor\MultiTimeout.h" /> - <ClInclude Include="td\tdactor\td\actor\PromiseFuture.h" /> - <ClInclude Include="td\tdactor\td\actor\SchedulerLocalStorage.h" /> - <ClInclude Include="td\tdactor\td\actor\SignalSlot.h" /> - <ClInclude Include="td\tdactor\td\actor\SleepActor.h" /> - <ClInclude Include="td\tdactor\td\actor\Timeout.h" /> - <ClInclude Include="td\tdactor\td\actor\actor.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="tdutils.vcxproj"> - <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project> - <Name>tdutils</Name> - </ProjectReference> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{85F63934-02FE-332A-8703-059040B65512}</ProjectGuid>
+ <ProjectName>tdactor</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\td\tdactor;.\td\tdutils;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\tdactor\td\actor\ConcurrentScheduler.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\impl\Scheduler.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\MultiPromise.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\MultiTimeout.cpp" />
+ <ClInclude Include="td\tdactor\td\actor\ConcurrentScheduler.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Actor-decl.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Actor.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorId-decl.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorId.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo-decl.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\EventFull-decl.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\EventFull.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Event.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Scheduler-decl.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Scheduler.h" />
+ <ClInclude Include="td\tdactor\td\actor\MultiPromise.h" />
+ <ClInclude Include="td\tdactor\td\actor\MultiTimeout.h" />
+ <ClInclude Include="td\tdactor\td\actor\PromiseFuture.h" />
+ <ClInclude Include="td\tdactor\td\actor\SchedulerLocalStorage.h" />
+ <ClInclude Include="td\tdactor\td\actor\SignalSlot.h" />
+ <ClInclude Include="td\tdactor\td\actor\SleepActor.h" />
+ <ClInclude Include="td\tdactor\td\actor\Timeout.h" />
+ <ClInclude Include="td\tdactor\td\actor\actor.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="tdutils.vcxproj">
+ <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project>
+ <Name>tdutils</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdactor.vcxproj.filters b/protocols/Telegram/tdlib/tdactor.vcxproj.filters index 341d789cce..5535137d6d 100644 --- a/protocols/Telegram/tdlib/tdactor.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdactor.vcxproj.filters @@ -1,60 +1,60 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\tdactor\td\actor\MultiPromise.cpp" /> - <ClCompile Include="td\tdactor\td\actor\ConcurrentScheduler.cpp" /> - <ClCompile Include="td\tdactor\td\actor\MultiTimeout.cpp" /> - <ClCompile Include="td\tdactor\td\actor\impl\Scheduler.cpp"> - <Filter>Impl</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\tdactor\td\actor\MultiPromise.h" /> - <ClInclude Include="td\tdactor\td\actor\PromiseFuture.h" /> - <ClInclude Include="td\tdactor\td\actor\SchedulerLocalStorage.h" /> - <ClInclude Include="td\tdactor\td\actor\SignalSlot.h" /> - <ClInclude Include="td\tdactor\td\actor\SleepActor.h" /> - <ClInclude Include="td\tdactor\td\actor\Timeout.h" /> - <ClInclude Include="td\tdactor\td\actor\actor.h" /> - <ClInclude Include="td\tdactor\td\actor\ConcurrentScheduler.h" /> - <ClInclude Include="td\tdactor\td\actor\MultiTimeout.h" /> - <ClInclude Include="td\tdactor\td\actor\impl\Actor.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\Actor-decl.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\ActorId.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\ActorId-decl.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo-decl.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\EventFull.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\EventFull-decl.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\Scheduler-decl.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\Scheduler.h"> - <Filter>Impl</Filter> - </ClInclude> - <ClInclude Include="td\tdactor\td\actor\impl\Event.h"> - <Filter>Impl</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <Filter Include="Impl"> - <UniqueIdentifier>{781720b8-b4b7-4498-9e33-b123d317aea3}</UniqueIdentifier> - </Filter> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\tdactor\td\actor\MultiPromise.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\ConcurrentScheduler.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\MultiTimeout.cpp" />
+ <ClCompile Include="td\tdactor\td\actor\impl\Scheduler.cpp">
+ <Filter>Impl</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\tdactor\td\actor\MultiPromise.h" />
+ <ClInclude Include="td\tdactor\td\actor\PromiseFuture.h" />
+ <ClInclude Include="td\tdactor\td\actor\SchedulerLocalStorage.h" />
+ <ClInclude Include="td\tdactor\td\actor\SignalSlot.h" />
+ <ClInclude Include="td\tdactor\td\actor\SleepActor.h" />
+ <ClInclude Include="td\tdactor\td\actor\Timeout.h" />
+ <ClInclude Include="td\tdactor\td\actor\actor.h" />
+ <ClInclude Include="td\tdactor\td\actor\ConcurrentScheduler.h" />
+ <ClInclude Include="td\tdactor\td\actor\MultiTimeout.h" />
+ <ClInclude Include="td\tdactor\td\actor\impl\Actor.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\Actor-decl.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorId.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorId-decl.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\ActorInfo-decl.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\EventFull.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\EventFull-decl.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\Scheduler-decl.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\Scheduler.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ <ClInclude Include="td\tdactor\td\actor\impl\Event.h">
+ <Filter>Impl</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Impl">
+ <UniqueIdentifier>{781720b8-b4b7-4498-9e33-b123d317aea3}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdcore.vcxproj b/protocols/Telegram/tdlib/tdcore.vcxproj index 1c9cb96322..238d8a5bee 100644 --- a/protocols/Telegram/tdlib/tdcore.vcxproj +++ b/protocols/Telegram/tdlib/tdcore.vcxproj @@ -1,299 +1,299 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{FC88FB5A-AAED-3F3E-9959-236444D8F644}</ProjectGuid> - <ProjectName>tdcore</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\td;.\td\td\generate\auto;..\..\..\include;.\td\tdactor;.\td\tdutils;.\td\tdnet;.\td\tddb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\td\mtproto\AuthData.cpp" /> - <ClCompile Include="td\td\mtproto\Handshake.cpp" /> - <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" /> - <ClCompile Include="td\td\mtproto\HttpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" /> - <ClCompile Include="td\td\mtproto\RawConnection.cpp" /> - <ClCompile Include="td\td\mtproto\SessionConnection.cpp" /> - <ClCompile Include="td\td\mtproto\TcpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\Transport.cpp" /> - <ClCompile Include="td\td\mtproto\utils.cpp" /> - <ClCompile Include="td\td\telegram\AnimationsManager.cpp" /> - <ClCompile Include="td\td\telegram\AudiosManager.cpp" /> - <ClCompile Include="td\td\telegram\AuthManager.cpp" /> - <ClCompile Include="td\td\telegram\CallActor.cpp" /> - <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" /> - <ClCompile Include="td\td\telegram\CallManager.cpp" /> - <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\ClientActor.cpp" /> - <ClCompile Include="td\td\telegram\ConfigManager.cpp" /> - <ClCompile Include="td\td\telegram\Contact.cpp" /> - <ClCompile Include="td\td\telegram\ContactsManager.cpp" /> - <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" /> - <ClCompile Include="td\td\telegram\DhCache.cpp" /> - <ClCompile Include="td\td\telegram\DialogDb.cpp" /> - <ClCompile Include="td\td\telegram\DialogId.cpp" /> - <ClCompile Include="td\td\telegram\DialogParticipant.cpp" /> - <ClCompile Include="td\td\telegram\DocumentsManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDb.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStats.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\PartsManager.cpp" /> - <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" /> - <ClCompile Include="td\td\telegram\Game.cpp" /> - <ClCompile Include="td\td\telegram\Global.cpp" /> - <ClCompile Include="td\td\telegram\HashtagHints.cpp" /> - <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\Location.cpp" /> - <ClCompile Include="td\td\telegram\MessageEntity.cpp" /> - <ClCompile Include="td\td\telegram\MessagesManager.cpp" /> - <ClCompile Include="td\td\telegram\misc.cpp" /> - <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" /> - <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" /> - <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" /> - <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" /> - <ClCompile Include="td\td\telegram\net\NetActor.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQuery.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" /> - <ClCompile Include="td\td\telegram\net\Session.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" /> - <ClCompile Include="td\td\telegram\Payments.cpp" /> - <ClCompile Include="td\td\telegram\PasswordManager.cpp" /> - <ClCompile Include="td\td\telegram\PrivacyManager.cpp" /> - <ClCompile Include="td\td\telegram\Photo.cpp" /> - <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatActor.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatDb.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" /> - <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\StateManager.cpp" /> - <ClCompile Include="td\td\telegram\StickersManager.cpp" /> - <ClCompile Include="td\td\telegram\StorageManager.cpp" /> - <ClCompile Include="td\td\telegram\Td.cpp" /> - <ClCompile Include="td\td\telegram\TdDb.cpp" /> - <ClCompile Include="td\td\telegram\TopDialogManager.cpp" /> - <ClCompile Include="td\td\telegram\UpdatesManager.cpp" /> - <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\VideosManager.cpp" /> - <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\WebPagesManager.cpp" /> - <ClInclude Include="td\td\mtproto\AuthData.h" /> - <ClInclude Include="td\td\mtproto\AuthKey.h" /> - <ClInclude Include="td\td\mtproto\CryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\Handshake.h" /> - <ClInclude Include="td\td\mtproto\HandshakeActor.h" /> - <ClInclude Include="td\td\mtproto\HandshakeConnection.h" /> - <ClInclude Include="td\td\mtproto\HttpTransport.h" /> - <ClInclude Include="td\td\mtproto\IStreamTransport.h" /> - <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\PacketStorer.h" /> - <ClInclude Include="td\td\mtproto\PingConnection.h" /> - <ClInclude Include="td\td\mtproto\RawConnection.h" /> - <ClInclude Include="td\td\mtproto\SessionConnection.h" /> - <ClInclude Include="td\td\mtproto\TcpTransport.h" /> - <ClInclude Include="td\td\mtproto\Transport.h" /> - <ClInclude Include="td\td\mtproto\utils.h" /> - <ClInclude Include="td\td\telegram\AccessRights.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.h" /> - <ClInclude Include="td\td\telegram\AudiosManager.h" /> - <ClInclude Include="td\td\telegram\AuthManager.h" /> - <ClInclude Include="td\td\telegram\CallActor.h" /> - <ClInclude Include="td\td\telegram\CallDiscardReason.h" /> - <ClInclude Include="td\td\telegram\CallId.h" /> - <ClInclude Include="td\td\telegram\CallManager.h" /> - <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" /> - <ClInclude Include="td\td\telegram\ChannelId.h" /> - <ClInclude Include="td\td\telegram\ChatId.h" /> - <ClInclude Include="td\td\telegram\ClientActor.h" /> - <ClInclude Include="td\td\telegram\ConfigManager.h" /> - <ClInclude Include="td\td\telegram\Contact.h" /> - <ClInclude Include="td\td\telegram\ContactsManager.h" /> - <ClInclude Include="td\td\telegram\DelayDispatcher.h" /> - <ClInclude Include="td\td\telegram\DeviceTokenManager.h" /> - <ClInclude Include="td\td\telegram\DhCache.h" /> - <ClInclude Include="td\td\telegram\DhConfig.h" /> - <ClInclude Include="td\td\telegram\DialogDb.h" /> - <ClInclude Include="td\td\telegram\DialogId.h" /> - <ClInclude Include="td\td\telegram\DialogParticipant.h" /> - <ClInclude Include="td\td\telegram\DocumentsManager.h" /> - <ClInclude Include="td\td\telegram\files\FileDb.h" /> - <ClInclude Include="td\td\telegram\files\FileDownloader.h" /> - <ClInclude Include="td\td\telegram\files\FileFromBytes.h" /> - <ClInclude Include="td\td\telegram\files\FileGcParameters.h" /> - <ClInclude Include="td\td\telegram\files\FileGcWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" /> - <ClInclude Include="td\td\telegram\files\FileHashUploader.h" /> - <ClInclude Include="td\td\telegram\files\FileId.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" /> - <ClInclude Include="td\td\telegram\files\FileLoader.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" /> - <ClInclude Include="td\td\telegram\files\FileLoadManager.h" /> - <ClInclude Include="td\td\telegram\files\FileLocation.h" /> - <ClInclude Include="td\td\telegram\files\FileManager.h" /> - <ClInclude Include="td\td\telegram\files\FileStats.h" /> - <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileUploader.h" /> - <ClInclude Include="td\td\telegram\files\PartsManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceState.h" /> - <ClInclude Include="td\td\telegram\Game.h" /> - <ClInclude Include="td\td\telegram\Global.h" /> - <ClInclude Include="td\td\telegram\HashtagHints.h" /> - <ClInclude Include="td\td\telegram\InlineQueriesManager.h" /> - <ClInclude Include="td\td\telegram\Location.h" /> - <ClInclude Include="td\td\telegram\logevent\LogEvent.h" /> - <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" /> - <ClInclude Include="td\td\telegram\MessageEntity.h" /> - <ClInclude Include="td\td\telegram\MessageId.h" /> - <ClInclude Include="td\td\telegram\MessagesManager.h" /> - <ClInclude Include="td\td\telegram\misc.h" /> - <ClInclude Include="td\td\telegram\net\AuthDataShared.h" /> - <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" /> - <ClInclude Include="td\td\telegram\net\DcAuthManager.h" /> - <ClInclude Include="td\td\telegram\net\DcId.h" /> - <ClInclude Include="td\td\telegram\net\DcOptions.h" /> - <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" /> - <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" /> - <ClInclude Include="td\td\telegram\net\NetActor.h" /> - <ClInclude Include="td\td\telegram\net\NetQuery.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" /> - <ClInclude Include="td\td\telegram\net\NetStatsManager.h" /> - <ClInclude Include="td\td\telegram\net\NetType.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\net\Session.h" /> - <ClInclude Include="td\td\telegram\net\SessionProxy.h" /> - <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" /> - <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\PasswordManager.h" /> - <ClInclude Include="td\td\telegram\Payments.h" /> - <ClInclude Include="td\td\telegram\Photo.h" /> - <ClInclude Include="td\td\telegram\PrivacyManager.h" /> - <ClInclude Include="td\td\telegram\PtsManager.h" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.h" /> - <ClInclude Include="td\td\telegram\SecretChatActor.h" /> - <ClInclude Include="td\td\telegram\SecretChatId.h" /> - <ClInclude Include="td\td\telegram\SecretChatDb.h" /> - <ClInclude Include="td\td\telegram\SecretChatsManager.h" /> - <ClInclude Include="td\td\telegram\SecretInputMedia.h" /> - <ClInclude Include="td\td\telegram\SequenceDispatcher.h" /> - <ClInclude Include="td\td\telegram\StateManager.h" /> - <ClInclude Include="td\td\telegram\StickersManager.h" /> - <ClInclude Include="td\td\telegram\StorageManager.h" /> - <ClInclude Include="td\td\telegram\Td.h" /> - <ClInclude Include="td\td\telegram\TdCallback.h" /> - <ClInclude Include="td\td\telegram\TdDb.h" /> - <ClInclude Include="td\td\telegram\TdParameters.h" /> - <ClInclude Include="td\td\telegram\TopDialogManager.h" /> - <ClInclude Include="td\td\telegram\UniqueId.h" /> - <ClInclude Include="td\td\telegram\UpdatesManager.h" /> - <ClInclude Include="td\td\telegram\UserId.h" /> - <ClInclude Include="td\td\telegram\Version.h" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.h" /> - <ClInclude Include="td\td\telegram\VideosManager.h" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.h" /> - <ClInclude Include="td\td\telegram\WebPageId.h" /> - <ClInclude Include="td\td\telegram\WebPagesManager.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.hpp" /> - <ClInclude Include="td\td\telegram\AudiosManager.hpp" /> - <ClInclude Include="td\td\telegram\AuthManager.hpp" /> - <ClInclude Include="td\td\telegram\DocumentsManager.hpp" /> - <ClInclude Include="td\td\telegram\files\FileId.hpp" /> - <ClInclude Include="td\td\telegram\files\FileManager.hpp" /> - <ClInclude Include="td\td\telegram\Game.hpp" /> - <ClInclude Include="td\td\telegram\Photo.hpp" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" /> - <ClInclude Include="td\td\telegram\StickersManager.hpp" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" /> - <ClInclude Include="td\td\telegram\VideosManager.hpp" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" /> - <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" /> - <ClInclude Include="td\td\tl\TlObject.h" /> - <ClInclude Include="td\td\tl\tl_object_parse.h" /> - <ClInclude Include="td\td\tl\tl_object_store.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="tdactor.vcxproj"> - <Project>{85F63934-02FE-332A-8703-059040B65512}</Project> - <Name>tdactor</Name> - </ProjectReference> - <ProjectReference Include="tddb.vcxproj"> - <Project>{F525EE11-8820-3D8A-87A5-465D50A98A64}</Project> - <Name>tddb</Name> - </ProjectReference> - <ProjectReference Include="tdnet.vcxproj"> - <Project>{2246C3CF-7888-3102-984A-80214ADF418C}</Project> - <Name>tdnet</Name> - </ProjectReference> - <ProjectReference Include="tdutils.vcxproj"> - <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project> - <Name>tdutils</Name> - </ProjectReference> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{FC88FB5A-AAED-3F3E-9959-236444D8F644}</ProjectGuid>
+ <ProjectName>tdcore</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\td;.\td\td\generate\auto;..\..\..\include;.\td\tdactor;.\td\tdutils;.\td\tdnet;.\td\tddb;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\td\mtproto\AuthData.cpp" />
+ <ClCompile Include="td\td\mtproto\Handshake.cpp" />
+ <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" />
+ <ClCompile Include="td\td\mtproto\HttpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\RawConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\SessionConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\TcpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\Transport.cpp" />
+ <ClCompile Include="td\td\mtproto\utils.cpp" />
+ <ClCompile Include="td\td\telegram\AnimationsManager.cpp" />
+ <ClCompile Include="td\td\telegram\AudiosManager.cpp" />
+ <ClCompile Include="td\td\telegram\AuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\CallActor.cpp" />
+ <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" />
+ <ClCompile Include="td\td\telegram\CallManager.cpp" />
+ <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\ClientActor.cpp" />
+ <ClCompile Include="td\td\telegram\ConfigManager.cpp" />
+ <ClCompile Include="td\td\telegram\Contact.cpp" />
+ <ClCompile Include="td\td\telegram\ContactsManager.cpp" />
+ <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" />
+ <ClCompile Include="td\td\telegram\DhCache.cpp" />
+ <ClCompile Include="td\td\telegram\DialogDb.cpp" />
+ <ClCompile Include="td\td\telegram\DialogId.cpp" />
+ <ClCompile Include="td\td\telegram\DialogParticipant.cpp" />
+ <ClCompile Include="td\td\telegram\DocumentsManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDb.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStats.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\PartsManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" />
+ <ClCompile Include="td\td\telegram\Game.cpp" />
+ <ClCompile Include="td\td\telegram\Global.cpp" />
+ <ClCompile Include="td\td\telegram\HashtagHints.cpp" />
+ <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\Location.cpp" />
+ <ClCompile Include="td\td\telegram\MessageEntity.cpp" />
+ <ClCompile Include="td\td\telegram\MessagesManager.cpp" />
+ <ClCompile Include="td\td\telegram\misc.cpp" />
+ <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" />
+ <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetActor.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQuery.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" />
+ <ClCompile Include="td\td\telegram\net\Session.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" />
+ <ClCompile Include="td\td\telegram\Payments.cpp" />
+ <ClCompile Include="td\td\telegram\PasswordManager.cpp" />
+ <ClCompile Include="td\td\telegram\PrivacyManager.cpp" />
+ <ClCompile Include="td\td\telegram\Photo.cpp" />
+ <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatActor.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatDb.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\StateManager.cpp" />
+ <ClCompile Include="td\td\telegram\StickersManager.cpp" />
+ <ClCompile Include="td\td\telegram\StorageManager.cpp" />
+ <ClCompile Include="td\td\telegram\Td.cpp" />
+ <ClCompile Include="td\td\telegram\TdDb.cpp" />
+ <ClCompile Include="td\td\telegram\TopDialogManager.cpp" />
+ <ClCompile Include="td\td\telegram\UpdatesManager.cpp" />
+ <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\VideosManager.cpp" />
+ <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\WebPagesManager.cpp" />
+ <ClInclude Include="td\td\mtproto\AuthData.h" />
+ <ClInclude Include="td\td\mtproto\AuthKey.h" />
+ <ClInclude Include="td\td\mtproto\CryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\Handshake.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeActor.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeConnection.h" />
+ <ClInclude Include="td\td\mtproto\HttpTransport.h" />
+ <ClInclude Include="td\td\mtproto\IStreamTransport.h" />
+ <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\PacketStorer.h" />
+ <ClInclude Include="td\td\mtproto\PingConnection.h" />
+ <ClInclude Include="td\td\mtproto\RawConnection.h" />
+ <ClInclude Include="td\td\mtproto\SessionConnection.h" />
+ <ClInclude Include="td\td\mtproto\TcpTransport.h" />
+ <ClInclude Include="td\td\mtproto\Transport.h" />
+ <ClInclude Include="td\td\mtproto\utils.h" />
+ <ClInclude Include="td\td\telegram\AccessRights.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.h" />
+ <ClInclude Include="td\td\telegram\AudiosManager.h" />
+ <ClInclude Include="td\td\telegram\AuthManager.h" />
+ <ClInclude Include="td\td\telegram\CallActor.h" />
+ <ClInclude Include="td\td\telegram\CallDiscardReason.h" />
+ <ClInclude Include="td\td\telegram\CallId.h" />
+ <ClInclude Include="td\td\telegram\CallManager.h" />
+ <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\ChannelId.h" />
+ <ClInclude Include="td\td\telegram\ChatId.h" />
+ <ClInclude Include="td\td\telegram\ClientActor.h" />
+ <ClInclude Include="td\td\telegram\ConfigManager.h" />
+ <ClInclude Include="td\td\telegram\Contact.h" />
+ <ClInclude Include="td\td\telegram\ContactsManager.h" />
+ <ClInclude Include="td\td\telegram\DelayDispatcher.h" />
+ <ClInclude Include="td\td\telegram\DeviceTokenManager.h" />
+ <ClInclude Include="td\td\telegram\DhCache.h" />
+ <ClInclude Include="td\td\telegram\DhConfig.h" />
+ <ClInclude Include="td\td\telegram\DialogDb.h" />
+ <ClInclude Include="td\td\telegram\DialogId.h" />
+ <ClInclude Include="td\td\telegram\DialogParticipant.h" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileDb.h" />
+ <ClInclude Include="td\td\telegram\files\FileDownloader.h" />
+ <ClInclude Include="td\td\telegram\files\FileFromBytes.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcParameters.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileHashUploader.h" />
+ <ClInclude Include="td\td\telegram\files\FileId.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoader.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoadManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileLocation.h" />
+ <ClInclude Include="td\td\telegram\files\FileManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileStats.h" />
+ <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileUploader.h" />
+ <ClInclude Include="td\td\telegram\files\PartsManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceState.h" />
+ <ClInclude Include="td\td\telegram\Game.h" />
+ <ClInclude Include="td\td\telegram\Global.h" />
+ <ClInclude Include="td\td\telegram\HashtagHints.h" />
+ <ClInclude Include="td\td\telegram\InlineQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\Location.h" />
+ <ClInclude Include="td\td\telegram\logevent\LogEvent.h" />
+ <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" />
+ <ClInclude Include="td\td\telegram\MessageEntity.h" />
+ <ClInclude Include="td\td\telegram\MessageId.h" />
+ <ClInclude Include="td\td\telegram\MessagesManager.h" />
+ <ClInclude Include="td\td\telegram\misc.h" />
+ <ClInclude Include="td\td\telegram\net\AuthDataShared.h" />
+ <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" />
+ <ClInclude Include="td\td\telegram\net\DcAuthManager.h" />
+ <ClInclude Include="td\td\telegram\net\DcId.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptions.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" />
+ <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" />
+ <ClInclude Include="td\td\telegram\net\NetActor.h" />
+ <ClInclude Include="td\td\telegram\net\NetQuery.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" />
+ <ClInclude Include="td\td\telegram\net\NetStatsManager.h" />
+ <ClInclude Include="td\td\telegram\net\NetType.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\net\Session.h" />
+ <ClInclude Include="td\td\telegram\net\SessionProxy.h" />
+ <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" />
+ <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\PasswordManager.h" />
+ <ClInclude Include="td\td\telegram\Payments.h" />
+ <ClInclude Include="td\td\telegram\Photo.h" />
+ <ClInclude Include="td\td\telegram\PrivacyManager.h" />
+ <ClInclude Include="td\td\telegram\PtsManager.h" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.h" />
+ <ClInclude Include="td\td\telegram\SecretChatActor.h" />
+ <ClInclude Include="td\td\telegram\SecretChatId.h" />
+ <ClInclude Include="td\td\telegram\SecretChatDb.h" />
+ <ClInclude Include="td\td\telegram\SecretChatsManager.h" />
+ <ClInclude Include="td\td\telegram\SecretInputMedia.h" />
+ <ClInclude Include="td\td\telegram\SequenceDispatcher.h" />
+ <ClInclude Include="td\td\telegram\StateManager.h" />
+ <ClInclude Include="td\td\telegram\StickersManager.h" />
+ <ClInclude Include="td\td\telegram\StorageManager.h" />
+ <ClInclude Include="td\td\telegram\Td.h" />
+ <ClInclude Include="td\td\telegram\TdCallback.h" />
+ <ClInclude Include="td\td\telegram\TdDb.h" />
+ <ClInclude Include="td\td\telegram\TdParameters.h" />
+ <ClInclude Include="td\td\telegram\TopDialogManager.h" />
+ <ClInclude Include="td\td\telegram\UniqueId.h" />
+ <ClInclude Include="td\td\telegram\UpdatesManager.h" />
+ <ClInclude Include="td\td\telegram\UserId.h" />
+ <ClInclude Include="td\td\telegram\Version.h" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.h" />
+ <ClInclude Include="td\td\telegram\VideosManager.h" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.h" />
+ <ClInclude Include="td\td\telegram\WebPageId.h" />
+ <ClInclude Include="td\td\telegram\WebPagesManager.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.hpp" />
+ <ClInclude Include="td\td\telegram\AudiosManager.hpp" />
+ <ClInclude Include="td\td\telegram\AuthManager.hpp" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileId.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileManager.hpp" />
+ <ClInclude Include="td\td\telegram\Game.hpp" />
+ <ClInclude Include="td\td\telegram\Photo.hpp" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" />
+ <ClInclude Include="td\td\telegram\StickersManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideosManager.hpp" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" />
+ <ClInclude Include="td\td\tl\TlObject.h" />
+ <ClInclude Include="td\td\tl\tl_object_parse.h" />
+ <ClInclude Include="td\td\tl\tl_object_store.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="tdactor.vcxproj">
+ <Project>{85F63934-02FE-332A-8703-059040B65512}</Project>
+ <Name>tdactor</Name>
+ </ProjectReference>
+ <ProjectReference Include="tddb.vcxproj">
+ <Project>{F525EE11-8820-3D8A-87A5-465D50A98A64}</Project>
+ <Name>tddb</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdnet.vcxproj">
+ <Project>{2246C3CF-7888-3102-984A-80214ADF418C}</Project>
+ <Name>tdnet</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdutils.vcxproj">
+ <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project>
+ <Name>tdutils</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdcore.vcxproj.filters b/protocols/Telegram/tdlib/tdcore.vcxproj.filters index 4a41579e0d..155ff0b5ff 100644 --- a/protocols/Telegram/tdlib/tdcore.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdcore.vcxproj.filters @@ -1,251 +1,251 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\td\mtproto\AuthData.cpp" /> - <ClCompile Include="td\td\mtproto\Handshake.cpp" /> - <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" /> - <ClCompile Include="td\td\mtproto\HttpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" /> - <ClCompile Include="td\td\mtproto\RawConnection.cpp" /> - <ClCompile Include="td\td\mtproto\SessionConnection.cpp" /> - <ClCompile Include="td\td\mtproto\TcpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\Transport.cpp" /> - <ClCompile Include="td\td\mtproto\utils.cpp" /> - <ClCompile Include="td\td\telegram\AnimationsManager.cpp" /> - <ClCompile Include="td\td\telegram\AudiosManager.cpp" /> - <ClCompile Include="td\td\telegram\AuthManager.cpp" /> - <ClCompile Include="td\td\telegram\CallActor.cpp" /> - <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" /> - <ClCompile Include="td\td\telegram\CallManager.cpp" /> - <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\ClientActor.cpp" /> - <ClCompile Include="td\td\telegram\ConfigManager.cpp" /> - <ClCompile Include="td\td\telegram\Contact.cpp" /> - <ClCompile Include="td\td\telegram\ContactsManager.cpp" /> - <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" /> - <ClCompile Include="td\td\telegram\DhCache.cpp" /> - <ClCompile Include="td\td\telegram\DialogDb.cpp" /> - <ClCompile Include="td\td\telegram\DialogId.cpp" /> - <ClCompile Include="td\td\telegram\DialogParticipant.cpp" /> - <ClCompile Include="td\td\telegram\DocumentsManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDb.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStats.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\PartsManager.cpp" /> - <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" /> - <ClCompile Include="td\td\telegram\Game.cpp" /> - <ClCompile Include="td\td\telegram\Global.cpp" /> - <ClCompile Include="td\td\telegram\HashtagHints.cpp" /> - <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\Location.cpp" /> - <ClCompile Include="td\td\telegram\MessageEntity.cpp" /> - <ClCompile Include="td\td\telegram\MessagesManager.cpp" /> - <ClCompile Include="td\td\telegram\misc.cpp" /> - <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" /> - <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" /> - <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" /> - <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" /> - <ClCompile Include="td\td\telegram\net\NetActor.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQuery.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" /> - <ClCompile Include="td\td\telegram\net\Session.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" /> - <ClCompile Include="td\td\telegram\Payments.cpp" /> - <ClCompile Include="td\td\telegram\PasswordManager.cpp" /> - <ClCompile Include="td\td\telegram\PrivacyManager.cpp" /> - <ClCompile Include="td\td\telegram\Photo.cpp" /> - <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatActor.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatDb.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" /> - <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\StateManager.cpp" /> - <ClCompile Include="td\td\telegram\StickersManager.cpp" /> - <ClCompile Include="td\td\telegram\StorageManager.cpp" /> - <ClCompile Include="td\td\telegram\Td.cpp" /> - <ClCompile Include="td\td\telegram\TdDb.cpp" /> - <ClCompile Include="td\td\telegram\TopDialogManager.cpp" /> - <ClCompile Include="td\td\telegram\UpdatesManager.cpp" /> - <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\VideosManager.cpp" /> - <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\WebPagesManager.cpp" /> - <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\td\mtproto\AuthData.h" /> - <ClInclude Include="td\td\mtproto\AuthKey.h" /> - <ClInclude Include="td\td\mtproto\CryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\Handshake.h" /> - <ClInclude Include="td\td\mtproto\HandshakeActor.h" /> - <ClInclude Include="td\td\mtproto\HandshakeConnection.h" /> - <ClInclude Include="td\td\mtproto\HttpTransport.h" /> - <ClInclude Include="td\td\mtproto\IStreamTransport.h" /> - <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\PacketStorer.h" /> - <ClInclude Include="td\td\mtproto\PingConnection.h" /> - <ClInclude Include="td\td\mtproto\RawConnection.h" /> - <ClInclude Include="td\td\mtproto\SessionConnection.h" /> - <ClInclude Include="td\td\mtproto\TcpTransport.h" /> - <ClInclude Include="td\td\mtproto\Transport.h" /> - <ClInclude Include="td\td\mtproto\utils.h" /> - <ClInclude Include="td\td\telegram\AccessRights.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.h" /> - <ClInclude Include="td\td\telegram\AudiosManager.h" /> - <ClInclude Include="td\td\telegram\AuthManager.h" /> - <ClInclude Include="td\td\telegram\CallActor.h" /> - <ClInclude Include="td\td\telegram\CallDiscardReason.h" /> - <ClInclude Include="td\td\telegram\CallId.h" /> - <ClInclude Include="td\td\telegram\CallManager.h" /> - <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" /> - <ClInclude Include="td\td\telegram\ChannelId.h" /> - <ClInclude Include="td\td\telegram\ChatId.h" /> - <ClInclude Include="td\td\telegram\ClientActor.h" /> - <ClInclude Include="td\td\telegram\ConfigManager.h" /> - <ClInclude Include="td\td\telegram\Contact.h" /> - <ClInclude Include="td\td\telegram\ContactsManager.h" /> - <ClInclude Include="td\td\telegram\DelayDispatcher.h" /> - <ClInclude Include="td\td\telegram\DeviceTokenManager.h" /> - <ClInclude Include="td\td\telegram\DhCache.h" /> - <ClInclude Include="td\td\telegram\DhConfig.h" /> - <ClInclude Include="td\td\telegram\DialogDb.h" /> - <ClInclude Include="td\td\telegram\DialogId.h" /> - <ClInclude Include="td\td\telegram\DialogParticipant.h" /> - <ClInclude Include="td\td\telegram\DocumentsManager.h" /> - <ClInclude Include="td\td\telegram\files\FileDb.h" /> - <ClInclude Include="td\td\telegram\files\FileDownloader.h" /> - <ClInclude Include="td\td\telegram\files\FileFromBytes.h" /> - <ClInclude Include="td\td\telegram\files\FileGcParameters.h" /> - <ClInclude Include="td\td\telegram\files\FileGcWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" /> - <ClInclude Include="td\td\telegram\files\FileHashUploader.h" /> - <ClInclude Include="td\td\telegram\files\FileId.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" /> - <ClInclude Include="td\td\telegram\files\FileLoader.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" /> - <ClInclude Include="td\td\telegram\files\FileLoadManager.h" /> - <ClInclude Include="td\td\telegram\files\FileLocation.h" /> - <ClInclude Include="td\td\telegram\files\FileManager.h" /> - <ClInclude Include="td\td\telegram\files\FileStats.h" /> - <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileUploader.h" /> - <ClInclude Include="td\td\telegram\files\PartsManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceState.h" /> - <ClInclude Include="td\td\telegram\Game.h" /> - <ClInclude Include="td\td\telegram\Global.h" /> - <ClInclude Include="td\td\telegram\HashtagHints.h" /> - <ClInclude Include="td\td\telegram\InlineQueriesManager.h" /> - <ClInclude Include="td\td\telegram\Location.h" /> - <ClInclude Include="td\td\telegram\logevent\LogEvent.h" /> - <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" /> - <ClInclude Include="td\td\telegram\MessageEntity.h" /> - <ClInclude Include="td\td\telegram\MessageId.h" /> - <ClInclude Include="td\td\telegram\MessagesManager.h" /> - <ClInclude Include="td\td\telegram\misc.h" /> - <ClInclude Include="td\td\telegram\net\AuthDataShared.h" /> - <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" /> - <ClInclude Include="td\td\telegram\net\DcAuthManager.h" /> - <ClInclude Include="td\td\telegram\net\DcId.h" /> - <ClInclude Include="td\td\telegram\net\DcOptions.h" /> - <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" /> - <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" /> - <ClInclude Include="td\td\telegram\net\NetActor.h" /> - <ClInclude Include="td\td\telegram\net\NetQuery.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" /> - <ClInclude Include="td\td\telegram\net\NetStatsManager.h" /> - <ClInclude Include="td\td\telegram\net\NetType.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\net\Session.h" /> - <ClInclude Include="td\td\telegram\net\SessionProxy.h" /> - <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" /> - <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\PasswordManager.h" /> - <ClInclude Include="td\td\telegram\Payments.h" /> - <ClInclude Include="td\td\telegram\Photo.h" /> - <ClInclude Include="td\td\telegram\PrivacyManager.h" /> - <ClInclude Include="td\td\telegram\PtsManager.h" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.h" /> - <ClInclude Include="td\td\telegram\SecretChatActor.h" /> - <ClInclude Include="td\td\telegram\SecretChatId.h" /> - <ClInclude Include="td\td\telegram\SecretChatDb.h" /> - <ClInclude Include="td\td\telegram\SecretChatsManager.h" /> - <ClInclude Include="td\td\telegram\SecretInputMedia.h" /> - <ClInclude Include="td\td\telegram\SequenceDispatcher.h" /> - <ClInclude Include="td\td\telegram\StateManager.h" /> - <ClInclude Include="td\td\telegram\StickersManager.h" /> - <ClInclude Include="td\td\telegram\StorageManager.h" /> - <ClInclude Include="td\td\telegram\Td.h" /> - <ClInclude Include="td\td\telegram\TdCallback.h" /> - <ClInclude Include="td\td\telegram\TdDb.h" /> - <ClInclude Include="td\td\telegram\TdParameters.h" /> - <ClInclude Include="td\td\telegram\TopDialogManager.h" /> - <ClInclude Include="td\td\telegram\UniqueId.h" /> - <ClInclude Include="td\td\telegram\UpdatesManager.h" /> - <ClInclude Include="td\td\telegram\UserId.h" /> - <ClInclude Include="td\td\telegram\Version.h" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.h" /> - <ClInclude Include="td\td\telegram\VideosManager.h" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.h" /> - <ClInclude Include="td\td\telegram\WebPageId.h" /> - <ClInclude Include="td\td\telegram\WebPagesManager.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.hpp" /> - <ClInclude Include="td\td\telegram\AudiosManager.hpp" /> - <ClInclude Include="td\td\telegram\AuthManager.hpp" /> - <ClInclude Include="td\td\telegram\DocumentsManager.hpp" /> - <ClInclude Include="td\td\telegram\files\FileId.hpp" /> - <ClInclude Include="td\td\telegram\files\FileManager.hpp" /> - <ClInclude Include="td\td\telegram\Game.hpp" /> - <ClInclude Include="td\td\telegram\Photo.hpp" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" /> - <ClInclude Include="td\td\telegram\StickersManager.hpp" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" /> - <ClInclude Include="td\td\telegram\VideosManager.hpp" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" /> - <ClInclude Include="td\td\tl\TlObject.h" /> - <ClInclude Include="td\td\tl\tl_object_parse.h" /> - <ClInclude Include="td\td\tl\tl_object_store.h" /> - </ItemGroup> - <ItemGroup> - <Filter Include="Header Files"> - <UniqueIdentifier>{0FD26E20-5E51-396B-B4E5-98068F96B37E}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files"> - <UniqueIdentifier>{CC4593AA-1CC3-37C8-BDF9-C5986B1808BD}</UniqueIdentifier> - </Filter> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\td\mtproto\AuthData.cpp" />
+ <ClCompile Include="td\td\mtproto\Handshake.cpp" />
+ <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" />
+ <ClCompile Include="td\td\mtproto\HttpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\RawConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\SessionConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\TcpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\Transport.cpp" />
+ <ClCompile Include="td\td\mtproto\utils.cpp" />
+ <ClCompile Include="td\td\telegram\AnimationsManager.cpp" />
+ <ClCompile Include="td\td\telegram\AudiosManager.cpp" />
+ <ClCompile Include="td\td\telegram\AuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\CallActor.cpp" />
+ <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" />
+ <ClCompile Include="td\td\telegram\CallManager.cpp" />
+ <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\ClientActor.cpp" />
+ <ClCompile Include="td\td\telegram\ConfigManager.cpp" />
+ <ClCompile Include="td\td\telegram\Contact.cpp" />
+ <ClCompile Include="td\td\telegram\ContactsManager.cpp" />
+ <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" />
+ <ClCompile Include="td\td\telegram\DhCache.cpp" />
+ <ClCompile Include="td\td\telegram\DialogDb.cpp" />
+ <ClCompile Include="td\td\telegram\DialogId.cpp" />
+ <ClCompile Include="td\td\telegram\DialogParticipant.cpp" />
+ <ClCompile Include="td\td\telegram\DocumentsManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDb.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStats.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\PartsManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" />
+ <ClCompile Include="td\td\telegram\Game.cpp" />
+ <ClCompile Include="td\td\telegram\Global.cpp" />
+ <ClCompile Include="td\td\telegram\HashtagHints.cpp" />
+ <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\Location.cpp" />
+ <ClCompile Include="td\td\telegram\MessageEntity.cpp" />
+ <ClCompile Include="td\td\telegram\MessagesManager.cpp" />
+ <ClCompile Include="td\td\telegram\misc.cpp" />
+ <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" />
+ <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetActor.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQuery.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" />
+ <ClCompile Include="td\td\telegram\net\Session.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" />
+ <ClCompile Include="td\td\telegram\Payments.cpp" />
+ <ClCompile Include="td\td\telegram\PasswordManager.cpp" />
+ <ClCompile Include="td\td\telegram\PrivacyManager.cpp" />
+ <ClCompile Include="td\td\telegram\Photo.cpp" />
+ <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatActor.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatDb.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\StateManager.cpp" />
+ <ClCompile Include="td\td\telegram\StickersManager.cpp" />
+ <ClCompile Include="td\td\telegram\StorageManager.cpp" />
+ <ClCompile Include="td\td\telegram\Td.cpp" />
+ <ClCompile Include="td\td\telegram\TdDb.cpp" />
+ <ClCompile Include="td\td\telegram\TopDialogManager.cpp" />
+ <ClCompile Include="td\td\telegram\UpdatesManager.cpp" />
+ <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\VideosManager.cpp" />
+ <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\WebPagesManager.cpp" />
+ <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\td\mtproto\AuthData.h" />
+ <ClInclude Include="td\td\mtproto\AuthKey.h" />
+ <ClInclude Include="td\td\mtproto\CryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\Handshake.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeActor.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeConnection.h" />
+ <ClInclude Include="td\td\mtproto\HttpTransport.h" />
+ <ClInclude Include="td\td\mtproto\IStreamTransport.h" />
+ <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\PacketStorer.h" />
+ <ClInclude Include="td\td\mtproto\PingConnection.h" />
+ <ClInclude Include="td\td\mtproto\RawConnection.h" />
+ <ClInclude Include="td\td\mtproto\SessionConnection.h" />
+ <ClInclude Include="td\td\mtproto\TcpTransport.h" />
+ <ClInclude Include="td\td\mtproto\Transport.h" />
+ <ClInclude Include="td\td\mtproto\utils.h" />
+ <ClInclude Include="td\td\telegram\AccessRights.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.h" />
+ <ClInclude Include="td\td\telegram\AudiosManager.h" />
+ <ClInclude Include="td\td\telegram\AuthManager.h" />
+ <ClInclude Include="td\td\telegram\CallActor.h" />
+ <ClInclude Include="td\td\telegram\CallDiscardReason.h" />
+ <ClInclude Include="td\td\telegram\CallId.h" />
+ <ClInclude Include="td\td\telegram\CallManager.h" />
+ <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\ChannelId.h" />
+ <ClInclude Include="td\td\telegram\ChatId.h" />
+ <ClInclude Include="td\td\telegram\ClientActor.h" />
+ <ClInclude Include="td\td\telegram\ConfigManager.h" />
+ <ClInclude Include="td\td\telegram\Contact.h" />
+ <ClInclude Include="td\td\telegram\ContactsManager.h" />
+ <ClInclude Include="td\td\telegram\DelayDispatcher.h" />
+ <ClInclude Include="td\td\telegram\DeviceTokenManager.h" />
+ <ClInclude Include="td\td\telegram\DhCache.h" />
+ <ClInclude Include="td\td\telegram\DhConfig.h" />
+ <ClInclude Include="td\td\telegram\DialogDb.h" />
+ <ClInclude Include="td\td\telegram\DialogId.h" />
+ <ClInclude Include="td\td\telegram\DialogParticipant.h" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileDb.h" />
+ <ClInclude Include="td\td\telegram\files\FileDownloader.h" />
+ <ClInclude Include="td\td\telegram\files\FileFromBytes.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcParameters.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileHashUploader.h" />
+ <ClInclude Include="td\td\telegram\files\FileId.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoader.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoadManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileLocation.h" />
+ <ClInclude Include="td\td\telegram\files\FileManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileStats.h" />
+ <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileUploader.h" />
+ <ClInclude Include="td\td\telegram\files\PartsManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceState.h" />
+ <ClInclude Include="td\td\telegram\Game.h" />
+ <ClInclude Include="td\td\telegram\Global.h" />
+ <ClInclude Include="td\td\telegram\HashtagHints.h" />
+ <ClInclude Include="td\td\telegram\InlineQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\Location.h" />
+ <ClInclude Include="td\td\telegram\logevent\LogEvent.h" />
+ <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" />
+ <ClInclude Include="td\td\telegram\MessageEntity.h" />
+ <ClInclude Include="td\td\telegram\MessageId.h" />
+ <ClInclude Include="td\td\telegram\MessagesManager.h" />
+ <ClInclude Include="td\td\telegram\misc.h" />
+ <ClInclude Include="td\td\telegram\net\AuthDataShared.h" />
+ <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" />
+ <ClInclude Include="td\td\telegram\net\DcAuthManager.h" />
+ <ClInclude Include="td\td\telegram\net\DcId.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptions.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" />
+ <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" />
+ <ClInclude Include="td\td\telegram\net\NetActor.h" />
+ <ClInclude Include="td\td\telegram\net\NetQuery.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" />
+ <ClInclude Include="td\td\telegram\net\NetStatsManager.h" />
+ <ClInclude Include="td\td\telegram\net\NetType.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\net\Session.h" />
+ <ClInclude Include="td\td\telegram\net\SessionProxy.h" />
+ <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" />
+ <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\PasswordManager.h" />
+ <ClInclude Include="td\td\telegram\Payments.h" />
+ <ClInclude Include="td\td\telegram\Photo.h" />
+ <ClInclude Include="td\td\telegram\PrivacyManager.h" />
+ <ClInclude Include="td\td\telegram\PtsManager.h" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.h" />
+ <ClInclude Include="td\td\telegram\SecretChatActor.h" />
+ <ClInclude Include="td\td\telegram\SecretChatId.h" />
+ <ClInclude Include="td\td\telegram\SecretChatDb.h" />
+ <ClInclude Include="td\td\telegram\SecretChatsManager.h" />
+ <ClInclude Include="td\td\telegram\SecretInputMedia.h" />
+ <ClInclude Include="td\td\telegram\SequenceDispatcher.h" />
+ <ClInclude Include="td\td\telegram\StateManager.h" />
+ <ClInclude Include="td\td\telegram\StickersManager.h" />
+ <ClInclude Include="td\td\telegram\StorageManager.h" />
+ <ClInclude Include="td\td\telegram\Td.h" />
+ <ClInclude Include="td\td\telegram\TdCallback.h" />
+ <ClInclude Include="td\td\telegram\TdDb.h" />
+ <ClInclude Include="td\td\telegram\TdParameters.h" />
+ <ClInclude Include="td\td\telegram\TopDialogManager.h" />
+ <ClInclude Include="td\td\telegram\UniqueId.h" />
+ <ClInclude Include="td\td\telegram\UpdatesManager.h" />
+ <ClInclude Include="td\td\telegram\UserId.h" />
+ <ClInclude Include="td\td\telegram\Version.h" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.h" />
+ <ClInclude Include="td\td\telegram\VideosManager.h" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.h" />
+ <ClInclude Include="td\td\telegram\WebPageId.h" />
+ <ClInclude Include="td\td\telegram\WebPagesManager.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.hpp" />
+ <ClInclude Include="td\td\telegram\AudiosManager.hpp" />
+ <ClInclude Include="td\td\telegram\AuthManager.hpp" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileId.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileManager.hpp" />
+ <ClInclude Include="td\td\telegram\Game.hpp" />
+ <ClInclude Include="td\td\telegram\Photo.hpp" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" />
+ <ClInclude Include="td\td\telegram\StickersManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideosManager.hpp" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" />
+ <ClInclude Include="td\td\tl\TlObject.h" />
+ <ClInclude Include="td\td\tl\tl_object_parse.h" />
+ <ClInclude Include="td\td\tl\tl_object_store.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{0FD26E20-5E51-396B-B4E5-98068F96B37E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{CC4593AA-1CC3-37C8-BDF9-C5986B1808BD}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tddb.vcxproj b/protocols/Telegram/tdlib/tddb.vcxproj index cb17625164..34806361c6 100644 --- a/protocols/Telegram/tdlib/tddb.vcxproj +++ b/protocols/Telegram/tdlib/tddb.vcxproj @@ -1,88 +1,88 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{F525EE11-8820-3D8A-87A5-465D50A98A64}</ProjectGuid> - <ProjectName>tddb</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\td\tddb;.\td\tdactor;.\td\tdutils;.\td\build\tdutils;.\td\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\tddb\td\db\binlog\Binlog.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\BinlogEvent.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\binlog_dump.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\ConcurrentBinlog.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteConnectionSafe.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteDb.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteKeyValue.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteStatement.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteKeyValueAsync.cpp" /> - <ClCompile Include="td\tddb\td\db\detail\RawSqliteDb.cpp" /> - <ClCompile Include="td\tddb\td\db\TQueue.cpp" /> - <ClInclude Include="td\tddb\td\db\binlog\Binlog.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogInterface.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogEvent.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogHelper.h" /> - <ClInclude Include="td\tddb\td\db\binlog\ConcurrentBinlog.h" /> - <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.h" /> - <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.h" /> - <ClInclude Include="td\tddb\td\db\BinlogKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\DbKey.h" /> - <ClInclude Include="td\tddb\td\db\KeyValueSyncInterface.h" /> - <ClInclude Include="td\tddb\td\db\SeqKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\SqliteConnectionSafe.h" /> - <ClInclude Include="td\tddb\td\db\SqliteDb.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValueAsync.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValueSafe.h" /> - <ClInclude Include="td\tddb\td\db\SqliteStatement.h" /> - <ClInclude Include="td\tddb\td\db\TQueue.h" /> - <ClInclude Include="td\tddb\td\db\TsSeqKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\detail\RawSqliteDb.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="tdactor.vcxproj"> - <Project>{85F63934-02FE-332A-8703-059040B65512}</Project> - <Name>tdactor</Name> - </ProjectReference> - <ProjectReference Include="tdutils.vcxproj"> - <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project> - <Name>tdutils</Name> - </ProjectReference> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{F525EE11-8820-3D8A-87A5-465D50A98A64}</ProjectGuid>
+ <ProjectName>tddb</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\td\tddb;.\td\tdactor;.\td\tdutils;.\td\build\tdutils;.\td\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\tddb\td\db\binlog\Binlog.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\BinlogEvent.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\binlog_dump.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\ConcurrentBinlog.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteConnectionSafe.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteDb.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteKeyValue.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteStatement.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteKeyValueAsync.cpp" />
+ <ClCompile Include="td\tddb\td\db\detail\RawSqliteDb.cpp" />
+ <ClCompile Include="td\tddb\td\db\TQueue.cpp" />
+ <ClInclude Include="td\tddb\td\db\binlog\Binlog.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogInterface.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogEvent.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogHelper.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\ConcurrentBinlog.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.h" />
+ <ClInclude Include="td\tddb\td\db\BinlogKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\DbKey.h" />
+ <ClInclude Include="td\tddb\td\db\KeyValueSyncInterface.h" />
+ <ClInclude Include="td\tddb\td\db\SeqKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteConnectionSafe.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteDb.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValueAsync.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValueSafe.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteStatement.h" />
+ <ClInclude Include="td\tddb\td\db\TQueue.h" />
+ <ClInclude Include="td\tddb\td\db\TsSeqKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\detail\RawSqliteDb.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="tdactor.vcxproj">
+ <Project>{85F63934-02FE-332A-8703-059040B65512}</Project>
+ <Name>tdactor</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdutils.vcxproj">
+ <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project>
+ <Name>tdutils</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tddb.vcxproj.filters b/protocols/Telegram/tdlib/tddb.vcxproj.filters index cf931303d3..bd37df119b 100644 --- a/protocols/Telegram/tdlib/tddb.vcxproj.filters +++ b/protocols/Telegram/tdlib/tddb.vcxproj.filters @@ -1,40 +1,40 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\tddb\td\db\binlog\Binlog.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\BinlogEvent.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\ConcurrentBinlog.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteDb.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteStatement.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteKeyValueAsync.cpp" /> - <ClCompile Include="td\tddb\td\db\detail\RawSqliteDb.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteConnectionSafe.cpp" /> - <ClCompile Include="td\tddb\td\db\SqliteKeyValue.cpp" /> - <ClCompile Include="td\tddb\td\db\TQueue.cpp" /> - <ClCompile Include="td\tddb\td\db\binlog\binlog_dump.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\tddb\td\db\binlog\Binlog.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogInterface.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogEvent.h" /> - <ClInclude Include="td\tddb\td\db\binlog\BinlogHelper.h" /> - <ClInclude Include="td\tddb\td\db\binlog\ConcurrentBinlog.h" /> - <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.h" /> - <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.h" /> - <ClInclude Include="td\tddb\td\db\BinlogKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\DbKey.h" /> - <ClInclude Include="td\tddb\td\db\KeyValueSyncInterface.h" /> - <ClInclude Include="td\tddb\td\db\SeqKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\SqliteConnectionSafe.h" /> - <ClInclude Include="td\tddb\td\db\SqliteDb.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValueAsync.h" /> - <ClInclude Include="td\tddb\td\db\SqliteKeyValueSafe.h" /> - <ClInclude Include="td\tddb\td\db\SqliteStatement.h" /> - <ClInclude Include="td\tddb\td\db\TsSeqKeyValue.h" /> - <ClInclude Include="td\tddb\td\db\detail\RawSqliteDb.h" /> - <ClInclude Include="td\tddb\td\db\TQueue.h" /> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\tddb\td\db\binlog\Binlog.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\BinlogEvent.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\ConcurrentBinlog.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteDb.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteStatement.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteKeyValueAsync.cpp" />
+ <ClCompile Include="td\tddb\td\db\detail\RawSqliteDb.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteConnectionSafe.cpp" />
+ <ClCompile Include="td\tddb\td\db\SqliteKeyValue.cpp" />
+ <ClCompile Include="td\tddb\td\db\TQueue.cpp" />
+ <ClCompile Include="td\tddb\td\db\binlog\binlog_dump.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\tddb\td\db\binlog\Binlog.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogInterface.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogEvent.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\BinlogHelper.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\ConcurrentBinlog.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsBuffer.h" />
+ <ClInclude Include="td\tddb\td\db\binlog\detail\BinlogEventsProcessor.h" />
+ <ClInclude Include="td\tddb\td\db\BinlogKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\DbKey.h" />
+ <ClInclude Include="td\tddb\td\db\KeyValueSyncInterface.h" />
+ <ClInclude Include="td\tddb\td\db\SeqKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteConnectionSafe.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteDb.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValueAsync.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteKeyValueSafe.h" />
+ <ClInclude Include="td\tddb\td\db\SqliteStatement.h" />
+ <ClInclude Include="td\tddb\td\db\TsSeqKeyValue.h" />
+ <ClInclude Include="td\tddb\td\db\detail\RawSqliteDb.h" />
+ <ClInclude Include="td\tddb\td\db\TQueue.h" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdlib.vcxproj b/protocols/Telegram/tdlib/tdlib.vcxproj index 14129c6555..18d50db4b4 100644 --- a/protocols/Telegram/tdlib/tdlib.vcxproj +++ b/protocols/Telegram/tdlib/tdlib.vcxproj @@ -1,607 +1,607 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{800E305A-3704-4617-ADA0-DEE8EAFDB804}</ProjectGuid> - <ProjectName>tdlib</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>td;td\td\generate\auto;td\tdactor;td\tdutils;td\tdnet;td\tddb;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\td\mtproto\AuthData.cpp" /> - <ClCompile Include="td\td\mtproto\ConnectionManager.cpp" /> - <ClCompile Include="td\td\mtproto\DhHandshake.cpp" /> - <ClCompile Include="td\td\mtproto\Handshake.cpp" /> - <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" /> - <ClCompile Include="td\td\mtproto\HttpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" /> - <ClCompile Include="td\td\mtproto\KDF.cpp" /> - <ClCompile Include="td\td\mtproto\Ping.cpp" /> - <ClCompile Include="td\td\mtproto\PingConnection.cpp" /> - <ClCompile Include="td\td\mtproto\ProxySecret.cpp" /> - <ClCompile Include="td\td\mtproto\RawConnection.cpp" /> - <ClCompile Include="td\td\mtproto\RSA.cpp" /> - <ClCompile Include="td\td\mtproto\SessionConnection.cpp" /> - <ClCompile Include="td\td\mtproto\TcpTransport.cpp" /> - <ClCompile Include="td\td\mtproto\TlsInit.cpp" /> - <ClCompile Include="td\td\mtproto\TlsReaderByteFlow.cpp" /> - <ClCompile Include="td\td\mtproto\Transport.cpp" /> - <ClCompile Include="td\td\mtproto\utils.cpp" /> - <ClCompile Include="td\td\telegram\Account.cpp" /> - <ClCompile Include="td\td\telegram\AnimationsManager.cpp" /> - <ClCompile Include="td\td\telegram\Application.cpp" /> - <ClCompile Include="td\td\telegram\AttachMenuManager.cpp" /> - <ClCompile Include="td\td\telegram\AudiosManager.cpp" /> - <ClCompile Include="td\td\telegram\AuthManager.cpp" /> - <ClCompile Include="td\td\telegram\AutoDownloadSettings.cpp" /> - <ClCompile Include="td\td\telegram\BackgroundManager.cpp" /> - <ClCompile Include="td\td\telegram\BackgroundType.cpp" /> - <ClCompile Include="td\td\telegram\BotCommand.cpp" /> - <ClCompile Include="td\td\telegram\BotCommandScope.cpp" /> - <ClCompile Include="td\td\telegram\BotMenuButton.cpp" /> - <ClCompile Include="td\td\telegram\CallActor.cpp" /> - <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" /> - <ClCompile Include="td\td\telegram\CallManager.cpp" /> - <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\ChannelParticipantFilter.cpp" /> - <ClCompile Include="td\td\telegram\ChatReactions.cpp" /> - <ClCompile Include="td\td\telegram\cli.cpp" /> - <ClCompile Include="td\td\telegram\Client.cpp" /> - <ClCompile Include="td\td\telegram\ClientActor.cpp" /> - <ClCompile Include="td\td\telegram\ClientJson.cpp" /> - <ClCompile Include="td\td\telegram\ConfigManager.cpp" /> - <ClCompile Include="td\td\telegram\ConnectionState.cpp" /> - <ClCompile Include="td\td\telegram\Contact.cpp" /> - <ClCompile Include="td\td\telegram\ContactsManager.cpp" /> - <ClCompile Include="td\td\telegram\CountryInfoManager.cpp" /> - <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\Dependencies.cpp" /> - <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" /> - <ClCompile Include="td\td\telegram\DhCache.cpp" /> - <ClCompile Include="td\td\telegram\DialogAction.cpp" /> - <ClCompile Include="td\td\telegram\DialogActionBar.cpp" /> - <ClCompile Include="td\td\telegram\DialogAdministrator.cpp" /> - <ClCompile Include="td\td\telegram\DialogDb.cpp" /> - <ClCompile Include="td\td\telegram\DialogEventLog.cpp" /> - <ClCompile Include="td\td\telegram\DialogFilter.cpp" /> - <ClCompile Include="td\td\telegram\DialogId.cpp" /> - <ClCompile Include="td\td\telegram\DialogInviteLink.cpp" /> - <ClCompile Include="td\td\telegram\DialogLocation.cpp" /> - <ClCompile Include="td\td\telegram\DialogNotificationSettings.cpp" /> - <ClCompile Include="td\td\telegram\DialogParticipant.cpp" /> - <ClCompile Include="td\td\telegram\DialogParticipantFilter.cpp" /> - <ClCompile Include="td\td\telegram\DialogSource.cpp" /> - <ClCompile Include="td\td\telegram\Dimensions.cpp" /> - <ClCompile Include="td\td\telegram\Document.cpp" /> - <ClCompile Include="td\td\telegram\DocumentsManager.cpp" /> - <ClCompile Include="td\td\telegram\DownloadManager.cpp" /> - <ClCompile Include="td\td\telegram\DownloadManagerCallback.cpp" /> - <ClCompile Include="td\td\telegram\DraftMessage.cpp" /> - <ClCompile Include="td\td\telegram\EmailVerification.cpp" /> - <ClCompile Include="td\td\telegram\EmojiStatus.cpp" /> - <ClCompile Include="td\td\telegram\FileReferenceManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileBitmask.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDb.cpp" /> - <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileEncryptionKey.cpp" /> - <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoader.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" /> - <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileManager.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStats.cpp" /> - <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" /> - <ClCompile Include="td\td\telegram\files\FileType.cpp" /> - <ClCompile Include="td\td\telegram\files\FileUploader.cpp" /> - <ClCompile Include="td\td\telegram\files\PartsManager.cpp" /> - <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" /> - <ClCompile Include="td\td\telegram\ForumTopic.cpp" /> - <ClCompile Include="td\td\telegram\ForumTopicEditedData.cpp" /> - <ClCompile Include="td\td\telegram\ForumTopicIcon.cpp" /> - <ClCompile Include="td\td\telegram\ForumTopicInfo.cpp" /> - <ClCompile Include="td\td\telegram\ForumTopicManager.cpp" /> - <ClCompile Include="td\td\telegram\Game.cpp" /> - <ClCompile Include="td\td\telegram\GameManager.cpp" /> - <ClCompile Include="td\td\telegram\GitCommitHash.cpp" /> - <ClCompile Include="td\td\telegram\Global.cpp" /> - <ClCompile Include="td\td\telegram\GroupCallManager.cpp" /> - <ClCompile Include="td\td\telegram\GroupCallParticipant.cpp" /> - <ClCompile Include="td\td\telegram\GroupCallParticipantOrder.cpp" /> - <ClCompile Include="td\td\telegram\GroupCallVideoPayload.cpp" /> - <ClCompile Include="td\td\telegram\HashtagHints.cpp" /> - <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" /> - <ClCompile Include="td\td\telegram\InputDialogId.cpp" /> - <ClCompile Include="td\td\telegram\InputGroupCallId.cpp" /> - <ClCompile Include="td\td\telegram\InputInvoice.cpp" /> - <ClCompile Include="td\td\telegram\InputMessageText.cpp" /> - <ClCompile Include="td\td\telegram\JsonValue.cpp" /> - <ClCompile Include="td\td\telegram\LanguagePackManager.cpp" /> - <ClCompile Include="td\td\telegram\LinkManager.cpp" /> - <ClCompile Include="td\td\telegram\Location.cpp" /> - <ClCompile Include="td\td\telegram\Log.cpp" /> - <ClCompile Include="td\td\telegram\logevent\LogEventHelper.cpp" /> - <ClCompile Include="td\td\telegram\Logging.cpp" /> - <ClCompile Include="td\td\telegram\MessageContent.cpp" /> - <ClCompile Include="td\td\telegram\MessageContentType.cpp" /> - <ClCompile Include="td\td\telegram\MessageDb.cpp" /> - <ClCompile Include="td\td\telegram\MessageEntity.cpp" /> - <ClCompile Include="td\td\telegram\MessageExtendedMedia.cpp" /> - <ClCompile Include="td\td\telegram\MessageId.cpp" /> - <ClCompile Include="td\td\telegram\MessageReaction.cpp" /> - <ClCompile Include="td\td\telegram\MessageReplyHeader.cpp" /> - <ClCompile Include="td\td\telegram\MessageReplyInfo.cpp" /> - <ClCompile Include="td\td\telegram\MessageSearchFilter.cpp" /> - <ClCompile Include="td\td\telegram\MessageSender.cpp" /> - <ClCompile Include="td\td\telegram\MessagesManager.cpp" /> - <ClCompile Include="td\td\telegram\MessageThreadDb.cpp" /> - <ClCompile Include="td\td\telegram\MessageTtl.cpp" /> - <ClCompile Include="td\td\telegram\misc.cpp" /> - <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" /> - <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" /> - <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" /> - <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" /> - <ClCompile Include="td\td\telegram\net\NetActor.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQuery.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\net\NetQueryStats.cpp" /> - <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" /> - <ClCompile Include="td\td\telegram\net\Proxy.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" /> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" /> - <ClCompile Include="td\td\telegram\net\Session.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" /> - <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" /> - <ClCompile Include="td\td\telegram\NewPasswordState.cpp" /> - <ClCompile Include="td\td\telegram\NotificationManager.cpp" /> - <ClCompile Include="td\td\telegram\NotificationSettingsManager.cpp" /> - <ClCompile Include="td\td\telegram\NotificationSettingsScope.cpp" /> - <ClCompile Include="td\td\telegram\NotificationSound.cpp" /> - <ClCompile Include="td\td\telegram\NotificationType.cpp" /> - <ClCompile Include="td\td\telegram\OptionManager.cpp" /> - <ClCompile Include="td\td\telegram\OrderInfo.cpp" /> - <ClCompile Include="td\td\telegram\Payments.cpp" /> - <ClCompile Include="td\td\telegram\PasswordManager.cpp" /> - <ClCompile Include="td\td\telegram\PhoneNumberManager.cpp" /> - <ClCompile Include="td\td\telegram\PhotoSize.cpp" /> - <ClCompile Include="td\td\telegram\PhotoSizeSource.cpp" /> - <ClCompile Include="td\td\telegram\PollManager.cpp" /> - <ClCompile Include="td\td\telegram\Premium.cpp" /> - <ClCompile Include="td\td\telegram\PremiumGiftOption.cpp" /> - <ClCompile Include="td\td\telegram\PrivacyManager.cpp" /> - <ClCompile Include="td\td\telegram\Photo.cpp" /> - <ClCompile Include="td\td\telegram\QueryCombiner.cpp" /> - <ClCompile Include="td\td\telegram\RecentDialogList.cpp" /> - <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" /> - <ClCompile Include="td\td\telegram\ReportReason.cpp" /> - <ClCompile Include="td\td\telegram\RestrictionReason.cpp" /> - <ClCompile Include="td\td\telegram\ScopeNotificationSettings.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatActor.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatDb.cpp" /> - <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" /> - <ClCompile Include="td\td\telegram\SecretInputMedia.cpp" /> - <ClCompile Include="td\td\telegram\SecureManager.cpp" /> - <ClCompile Include="td\td\telegram\SecureStorage.cpp" /> - <ClCompile Include="td\td\telegram\SecureValue.cpp" /> - <ClCompile Include="td\td\telegram\SendCodeHelper.cpp" /> - <ClCompile Include="td\td\telegram\SentEmailCode.cpp" /> - <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" /> - <ClCompile Include="td\td\telegram\SpecialStickerSetType.cpp" /> - <ClCompile Include="td\td\telegram\SponsoredMessageManager.cpp" /> - <ClCompile Include="td\td\telegram\StateManager.cpp" /> - <ClCompile Include="td\td\telegram\StickerFormat.cpp" /> - <ClCompile Include="td\td\telegram\StickersManager.cpp" /> - <ClCompile Include="td\td\telegram\StickerType.cpp" /> - <ClCompile Include="td\td\telegram\StorageManager.cpp" /> - <ClCompile Include="td\td\telegram\SuggestedAction.cpp" /> - <ClCompile Include="td\td\telegram\Support.cpp" /> - <ClCompile Include="td\td\telegram\Td.cpp" /> - <ClCompile Include="td\td\telegram\TdDb.cpp" /> - <ClCompile Include="td\td\telegram\TermsOfService.cpp" /> - <ClCompile Include="td\td\telegram\ThemeManager.cpp" /> - <ClCompile Include="td\td\telegram\TopDialogCategory.cpp" /> - <ClCompile Include="td\td\telegram\TopDialogManager.cpp" /> - <ClCompile Include="td\td\telegram\TranscriptionInfo.cpp" /> - <ClCompile Include="td\td\telegram\UpdatesManager.cpp" /> - <ClCompile Include="td\td\telegram\Usernames.cpp" /> - <ClCompile Include="td\td\telegram\Venue.cpp" /> - <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\VideosManager.cpp" /> - <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" /> - <ClCompile Include="td\td\telegram\WebPageBlock.cpp" /> - <ClCompile Include="td\td\telegram\WebPagesManager.cpp" /> - <ClInclude Include="td\td\mtproto\AuthData.h" /> - <ClInclude Include="td\td\mtproto\AuthKey.h" /> - <ClInclude Include="td\td\mtproto\ConnectionManager.h" /> - <ClInclude Include="td\td\mtproto\CryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\DhCallback.h" /> - <ClInclude Include="td\td\mtproto\DhHandshake.h" /> - <ClInclude Include="td\td\mtproto\Handshake.h" /> - <ClInclude Include="td\td\mtproto\HandshakeActor.h" /> - <ClInclude Include="td\td\mtproto\HandshakeConnection.h" /> - <ClInclude Include="td\td\mtproto\HttpTransport.h" /> - <ClInclude Include="td\td\mtproto\IStreamTransport.h" /> - <ClInclude Include="td\td\mtproto\KDF.h" /> - <ClInclude Include="td\td\mtproto\MtprotoQuery.h" /> - <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" /> - <ClInclude Include="td\td\mtproto\PacketInfo.h" /> - <ClInclude Include="td\td\mtproto\PacketStorer.h" /> - <ClInclude Include="td\td\mtproto\Ping.h" /> - <ClInclude Include="td\td\mtproto\PingConnection.h" /> - <ClInclude Include="td\td\mtproto\ProxySecret.h" /> - <ClInclude Include="td\td\mtproto\RawConnection.h" /> - <ClInclude Include="td\td\mtproto\RSA.h" /> - <ClInclude Include="td\td\mtproto\SessionConnection.h" /> - <ClInclude Include="td\td\mtproto\TcpTransport.h" /> - <ClInclude Include="td\td\mtproto\TlsInit.h" /> - <ClInclude Include="td\td\mtproto\TlsReaderByteFlow.h" /> - <ClInclude Include="td\td\mtproto\Transport.h" /> - <ClInclude Include="td\td\mtproto\TransportType.h" /> - <ClInclude Include="td\td\mtproto\utils.h" /> - <ClInclude Include="td\td\telegram\AccessRights.h" /> - <ClInclude Include="td\td\telegram\Account.h" /> - <ClInclude Include="td\td\telegram\AffectedHistory.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.h" /> - <ClInclude Include="td\td\telegram\Application.h" /> - <ClInclude Include="td\td\telegram\AttachMenuManager.h" /> - <ClInclude Include="td\td\telegram\AudiosManager.h" /> - <ClInclude Include="td\td\telegram\AuthManager.h" /> - <ClInclude Include="td\td\telegram\AutoDownloadSettings.h" /> - <ClInclude Include="td\td\telegram\BackgroundId.h" /> - <ClInclude Include="td\td\telegram\BackgroundManager.h" /> - <ClInclude Include="td\td\telegram\BackgroundType.h" /> - <ClInclude Include="td\td\telegram\BackgroundType.hpp" /> - <ClInclude Include="td\td\telegram\BotCommand.h" /> - <ClInclude Include="td\td\telegram\BotCommandScope.h" /> - <ClInclude Include="td\td\telegram\BotMenuButton.h" /> - <ClInclude Include="td\td\telegram\CallActor.h" /> - <ClInclude Include="td\td\telegram\CallDiscardReason.h" /> - <ClInclude Include="td\td\telegram\CallId.h" /> - <ClInclude Include="td\td\telegram\CallManager.h" /> - <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" /> - <ClInclude Include="td\td\telegram\ChainId.h" /> - <ClInclude Include="td\td\telegram\ChannelId.h" /> - <ClInclude Include="td\td\telegram\ChannelParticipantFilter.h" /> - <ClInclude Include="td\td\telegram\ChannelType.h" /> - <ClInclude Include="td\td\telegram\ChatId.h" /> - <ClInclude Include="td\td\telegram\ChatReactions.h" /> - <ClInclude Include="td\td\telegram\Client.h" /> - <ClInclude Include="td\td\telegram\ClientActor.h" /> - <ClInclude Include="td\td\telegram\ClientJson.h" /> - <ClInclude Include="td\td\telegram\ConfigManager.h" /> - <ClInclude Include="td\td\telegram\ConnectionState.h" /> - <ClInclude Include="td\td\telegram\Contact.h" /> - <ClInclude Include="td\td\telegram\ContactsManager.h" /> - <ClInclude Include="td\td\telegram\CountryInfoManager.h" /> - <ClInclude Include="td\td\telegram\CustomEmojiId.h" /> - <ClInclude Include="td\td\telegram\DelayDispatcher.h" /> - <ClInclude Include="td\td\telegram\Dependencies.h" /> - <ClInclude Include="td\td\telegram\DeviceTokenManager.h" /> - <ClInclude Include="td\td\telegram\DhCache.h" /> - <ClInclude Include="td\td\telegram\DhConfig.h" /> - <ClInclude Include="td\td\telegram\DialogAction.h" /> - <ClInclude Include="td\td\telegram\DialogActionBar.h" /> - <ClInclude Include="td\td\telegram\DialogAdministrator.h" /> - <ClInclude Include="td\td\telegram\DialogDate.h" /> - <ClInclude Include="td\td\telegram\DialogDb.h" /> - <ClInclude Include="td\td\telegram\DialogEventLog.h" /> - <ClInclude Include="td\td\telegram\DialogFilter.h" /> - <ClInclude Include="td\td\telegram\DialogFilter.hpp" /> - <ClInclude Include="td\td\telegram\DialogFilterId.h" /> - <ClInclude Include="td\td\telegram\DialogId.h" /> - <ClInclude Include="td\td\telegram\DialogInviteLink.h" /> - <ClInclude Include="td\td\telegram\DialogListId.h" /> - <ClInclude Include="td\td\telegram\DialogLocation.h" /> - <ClInclude Include="td\td\telegram\DialogNotificationSettings.h" /> - <ClInclude Include="td\td\telegram\DialogNotificationSettings.hpp" /> - <ClInclude Include="td\td\telegram\DialogParticipant.h" /> - <ClInclude Include="td\td\telegram\DialogParticipantFilter.h" /> - <ClInclude Include="td\td\telegram\DialogSource.h" /> - <ClInclude Include="td\td\telegram\Dimensions.h" /> - <ClInclude Include="td\td\telegram\Dimensions.hpp" /> - <ClInclude Include="td\td\telegram\Document.h" /> - <ClInclude Include="td\td\telegram\Document.hpp" /> - <ClInclude Include="td\td\telegram\DocumentsManager.h" /> - <ClInclude Include="td\td\telegram\DownloadManager.h" /> - <ClInclude Include="td\td\telegram\DownloadManagerCallback.h" /> - <ClInclude Include="td\td\telegram\DraftMessage.h" /> - <ClInclude Include="td\td\telegram\DraftMessage.hpp" /> - <ClInclude Include="td\td\telegram\EmailVerification.h" /> - <ClInclude Include="td\td\telegram\EmojiStatus.h" /> - <ClInclude Include="td\td\telegram\EncryptedFile.h" /> - <ClInclude Include="td\td\telegram\FileReferenceManager.h" /> - <ClInclude Include="td\td\telegram\FileReferenceManager.hpp" /> - <ClInclude Include="td\td\telegram\files\FileBitmask.h" /> - <ClInclude Include="td\td\telegram\files\FileData.h" /> - <ClInclude Include="td\td\telegram\files\FileData.hpp" /> - <ClInclude Include="td\td\telegram\files\FileDb.h" /> - <ClInclude Include="td\td\telegram\files\FileDbId.h" /> - <ClInclude Include="td\td\telegram\files\FileDownloader.h" /> - <ClInclude Include="td\td\telegram\files\FileEncryptionKey.h" /> - <ClInclude Include="td\td\telegram\files\FileFromBytes.h" /> - <ClInclude Include="td\td\telegram\files\FileGcParameters.h" /> - <ClInclude Include="td\td\telegram\files\FileGcWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" /> - <ClInclude Include="td\td\telegram\files\FileHashUploader.h" /> - <ClInclude Include="td\td\telegram\files\FileId.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" /> - <ClInclude Include="td\td\telegram\files\FileLoader.h" /> - <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" /> - <ClInclude Include="td\td\telegram\files\FileLoadManager.h" /> - <ClInclude Include="td\td\telegram\files\FileLocation.h" /> - <ClInclude Include="td\td\telegram\files\FileLocation.hpp" /> - <ClInclude Include="td\td\telegram\files\FileManager.h" /> - <ClInclude Include="td\td\telegram\files\FileSourceId.h" /> - <ClInclude Include="td\td\telegram\files\FileSourceId.hpp" /> - <ClInclude Include="td\td\telegram\files\FileStats.h" /> - <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" /> - <ClInclude Include="td\td\telegram\files\FileType.h" /> - <ClInclude Include="td\td\telegram\files\FileUploader.h" /> - <ClInclude Include="td\td\telegram\files\PartsManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceManager.h" /> - <ClInclude Include="td\td\telegram\files\ResourceState.h" /> - <ClInclude Include="td\td\telegram\FolderId.h" /> - <ClInclude Include="td\td\telegram\ForumTopic.h" /> - <ClInclude Include="td\td\telegram\ForumTopicEditedData.h" /> - <ClInclude Include="td\td\telegram\ForumTopicEditedData.hpp" /> - <ClInclude Include="td\td\telegram\ForumTopicIcon.h" /> - <ClInclude Include="td\td\telegram\ForumTopicIcon.hpp" /> - <ClInclude Include="td\td\telegram\ForumTopicInfo.h" /> - <ClInclude Include="td\td\telegram\ForumTopicManager.h" /> - <ClInclude Include="td\td\telegram\FullMessageId.h" /> - <ClInclude Include="td\td\telegram\Game.h" /> - <ClInclude Include="td\td\telegram\GameManager.h" /> - <ClInclude Include="td\td\telegram\GitCommitHash.h" /> - <ClInclude Include="td\td\telegram\Global.h" /> - <ClInclude Include="td\td\telegram\GroupCallId.h" /> - <ClInclude Include="td\td\telegram\GroupCallManager.h" /> - <ClInclude Include="td\td\telegram\GroupCallParticipant.h" /> - <ClInclude Include="td\td\telegram\GroupCallParticipantOrder.h" /> - <ClInclude Include="td\td\telegram\GroupCallVideoPayload.h" /> - <ClInclude Include="td\td\telegram\HashtagHints.h" /> - <ClInclude Include="td\td\telegram\InlineQueriesManager.h" /> - <ClInclude Include="td\td\telegram\InputDialogId.h" /> - <ClInclude Include="td\td\telegram\InputGroupCallId.h" /> - <ClInclude Include="td\td\telegram\InputInvoice.h" /> - <ClInclude Include="td\td\telegram\InputInvoice.hpp" /> - <ClInclude Include="td\td\telegram\InputMessageText.h" /> - <ClInclude Include="td\td\telegram\InputMessageText.hpp" /> - <ClInclude Include="td\td\telegram\JsonValue.h" /> - <ClInclude Include="td\td\telegram\LabeledPricePart.h" /> - <ClInclude Include="td\td\telegram\LanguagePackManager.h" /> - <ClInclude Include="td\td\telegram\LinkManager.h" /> - <ClInclude Include="td\td\telegram\Location.h" /> - <ClInclude Include="td\td\telegram\Log.h" /> - <ClInclude Include="td\td\telegram\logevent\LogEvent.h" /> - <ClInclude Include="td\td\telegram\logevent\LogEventHelper.h" /> - <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" /> - <ClInclude Include="td\td\telegram\Logging.h" /> - <ClInclude Include="td\td\telegram\MessageContent.h" /> - <ClInclude Include="td\td\telegram\MessageContentType.h" /> - <ClInclude Include="td\td\telegram\MessageCopyOptions.h" /> - <ClInclude Include="td\td\telegram\MessageDb.h" /> - <ClInclude Include="td\td\telegram\MessageEntity.h" /> - <ClInclude Include="td\td\telegram\MessageEntity.hpp" /> - <ClInclude Include="td\td\telegram\MessageExtendedMedia.h" /> - <ClInclude Include="td\td\telegram\MessageExtendedMedia.hpp" /> - <ClInclude Include="td\td\telegram\MessageId.h" /> - <ClInclude Include="td\td\telegram\MessageLinkInfo.h" /> - <ClInclude Include="td\td\telegram\MessageReaction.h" /> - <ClInclude Include="td\td\telegram\MessageReaction.hpp" /> - <ClInclude Include="td\td\telegram\MessageReplyHeader.h" /> - <ClInclude Include="td\td\telegram\MessageReplyInfo.h" /> - <ClInclude Include="td\td\telegram\MessageReplyInfo.hpp" /> - <ClInclude Include="td\td\telegram\MessageSearchFilter.h" /> - <ClInclude Include="td\td\telegram\MessageSender.h" /> - <ClInclude Include="td\td\telegram\MessagesManager.h" /> - <ClInclude Include="td\td\telegram\MessageThreadDb.h" /> - <ClInclude Include="td\td\telegram\MessageThreadInfo.h" /> - <ClInclude Include="td\td\telegram\MessageTtl.h" /> - <ClInclude Include="td\td\telegram\MinChannel.h" /> - <ClInclude Include="td\td\telegram\MinChannel.hpp" /> - <ClInclude Include="td\td\telegram\misc.h" /> - <ClInclude Include="td\td\telegram\net\AuthDataShared.h" /> - <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" /> - <ClInclude Include="td\td\telegram\net\DcAuthManager.h" /> - <ClInclude Include="td\td\telegram\net\DcId.h" /> - <ClInclude Include="td\td\telegram\net\DcOptions.h" /> - <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" /> - <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" /> - <ClInclude Include="td\td\telegram\net\NetActor.h" /> - <ClInclude Include="td\td\telegram\net\NetQuery.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" /> - <ClInclude Include="td\td\telegram\net\NetQueryStats.h" /> - <ClInclude Include="td\td\telegram\net\NetStatsManager.h" /> - <ClInclude Include="td\td\telegram\net\NetType.h" /> - <ClInclude Include="td\td\telegram\net\Proxy.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" /> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\net\Session.h" /> - <ClInclude Include="td\td\telegram\net\SessionProxy.h" /> - <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" /> - <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" /> - <ClInclude Include="td\td\telegram\NewPasswordState.h" /> - <ClInclude Include="td\td\telegram\Notification.h" /> - <ClInclude Include="td\td\telegram\NotificationGroupId.h" /> - <ClInclude Include="td\td\telegram\NotificationGroupKey.h" /> - <ClInclude Include="td\td\telegram\NotificationGroupType.h" /> - <ClInclude Include="td\td\telegram\NotificationId.h" /> - <ClInclude Include="td\td\telegram\NotificationManager.h" /> - <ClInclude Include="td\td\telegram\NotificationSettingsManager.h" /> - <ClInclude Include="td\td\telegram\NotificationSettingsScope.h" /> - <ClInclude Include="td\td\telegram\NotificationSound.h" /> - <ClInclude Include="td\td\telegram\NotificationSoundType.h" /> - <ClInclude Include="td\td\telegram\NotificationType.h" /> - <ClInclude Include="td\td\telegram\OptionManager.h" /> - <ClInclude Include="td\td\telegram\OrderInfo.h" /> - <ClInclude Include="td\td\telegram\OrderInfo.hpp" /> - <ClInclude Include="td\td\telegram\PasswordManager.h" /> - <ClInclude Include="td\td\telegram\Payments.h" /> - <ClInclude Include="td\td\telegram\PhoneNumberManager.h" /> - <ClInclude Include="td\td\telegram\Photo.h" /> - <ClInclude Include="td\td\telegram\PhotoFormat.h" /> - <ClInclude Include="td\td\telegram\PhotoSize.h" /> - <ClInclude Include="td\td\telegram\PhotoSize.hpp" /> - <ClInclude Include="td\td\telegram\PhotoSizeSource.h" /> - <ClInclude Include="td\td\telegram\PhotoSizeSource.hpp" /> - <ClInclude Include="td\td\telegram\PollId.h" /> - <ClInclude Include="td\td\telegram\PollId.hpp" /> - <ClInclude Include="td\td\telegram\PollManager.h" /> - <ClInclude Include="td\td\telegram\PollManager.hpp" /> - <ClInclude Include="td\td\telegram\Premium.h" /> - <ClInclude Include="td\td\telegram\PremiumGiftOption.h" /> - <ClInclude Include="td\td\telegram\PremiumGiftOption.hpp" /> - <ClInclude Include="td\td\telegram\PrivacyManager.h" /> - <ClInclude Include="td\td\telegram\PtsManager.h" /> - <ClInclude Include="td\td\telegram\PublicDialogType.h" /> - <ClInclude Include="td\td\telegram\QueryCombiner.h" /> - <ClInclude Include="td\td\telegram\RecentDialogList.h" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.h" /> - <ClInclude Include="td\td\telegram\ReportReason.h" /> - <ClInclude Include="td\td\telegram\RequestActor.h" /> - <ClInclude Include="td\td\telegram\RestrictionReason.h" /> - <ClInclude Include="td\td\telegram\ScheduledServerMessageId.h" /> - <ClInclude Include="td\td\telegram\ScopeNotificationSettings.h" /> - <ClInclude Include="td\td\telegram\ScopeNotificationSettings.hpp" /> - <ClInclude Include="td\td\telegram\SecretChatActor.h" /> - <ClInclude Include="td\td\telegram\SecretChatId.h" /> - <ClInclude Include="td\td\telegram\SecretChatDb.h" /> - <ClInclude Include="td\td\telegram\SecretChatLayer.h" /> - <ClInclude Include="td\td\telegram\SecretChatsManager.h" /> - <ClInclude Include="td\td\telegram\SecretInputMedia.h" /> - <ClInclude Include="td\td\telegram\SecureManager.h" /> - <ClInclude Include="td\td\telegram\SecureStorage.h" /> - <ClInclude Include="td\td\telegram\SecureValue.h" /> - <ClInclude Include="td\td\telegram\SecureValue.hpp" /> - <ClInclude Include="td\td\telegram\SendCodeHelper.h" /> - <ClInclude Include="td\td\telegram\SendCodeHelper.hpp" /> - <ClInclude Include="td\td\telegram\SentEmailCode.h" /> - <ClInclude Include="td\td\telegram\SequenceDispatcher.h" /> - <ClInclude Include="td\td\telegram\ServerMessageId.h" /> - <ClInclude Include="td\td\telegram\SetWithPosition.h" /> - <ClInclude Include="td\td\telegram\SpecialStickerSetType.h" /> - <ClInclude Include="td\td\telegram\SponsoredMessageManager.h" /> - <ClInclude Include="td\td\telegram\StateManager.h" /> - <ClInclude Include="td\td\telegram\StickerFormat.h" /> - <ClInclude Include="td\td\telegram\StickerSetId.h" /> - <ClInclude Include="td\td\telegram\StickerSetId.hpp" /> - <ClInclude Include="td\td\telegram\StickersManager.h" /> - <ClInclude Include="td\td\telegram\StickerType.h" /> - <ClInclude Include="td\td\telegram\StorageManager.h" /> - <ClInclude Include="td\td\telegram\SuggestedAction.h" /> - <ClInclude Include="td\td\telegram\Support.h" /> - <ClInclude Include="td\td\telegram\Td.h" /> - <ClInclude Include="td\td\telegram\TdCallback.h" /> - <ClInclude Include="td\td\telegram\TdDb.h" /> - <ClInclude Include="td\td\telegram\TdParameters.h" /> - <ClInclude Include="td\td\telegram\td_c_client.h" /> - <ClInclude Include="td\td\telegram\td_json_client.h" /> - <ClInclude Include="td\td\telegram\td_log.h" /> - <ClInclude Include="td\td\telegram\TermsOfService.h" /> - <ClInclude Include="td\td\telegram\ThemeManager.h" /> - <ClInclude Include="td\td\telegram\TopDialogCategory.h" /> - <ClInclude Include="td\td\telegram\TopDialogManager.h" /> - <ClInclude Include="td\td\telegram\TranscriptionInfo.h" /> - <ClInclude Include="td\td\telegram\TranscriptionInfo.hpp" /> - <ClInclude Include="td\td\telegram\UniqueId.h" /> - <ClInclude Include="td\td\telegram\UpdatesManager.h" /> - <ClInclude Include="td\td\telegram\UserId.h" /> - <ClInclude Include="td\td\telegram\Usernames.h" /> - <ClInclude Include="td\td\telegram\Venue.h" /> - <ClInclude Include="td\td\telegram\Version.h" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.h" /> - <ClInclude Include="td\td\telegram\VideosManager.h" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.h" /> - <ClInclude Include="td\td\telegram\WebPageBlock.h" /> - <ClInclude Include="td\td\telegram\WebPageId.h" /> - <ClInclude Include="td\td\telegram\WebPagesManager.h" /> - <ClInclude Include="td\td\telegram\AnimationsManager.hpp" /> - <ClInclude Include="td\td\telegram\AudiosManager.hpp" /> - <ClInclude Include="td\td\telegram\AuthManager.hpp" /> - <ClInclude Include="td\td\telegram\DocumentsManager.hpp" /> - <ClInclude Include="td\td\telegram\files\FileId.hpp" /> - <ClInclude Include="td\td\telegram\files\FileManager.hpp" /> - <ClInclude Include="td\td\telegram\Game.hpp" /> - <ClInclude Include="td\td\telegram\Photo.hpp" /> - <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" /> - <ClInclude Include="td\td\telegram\StickersManager.hpp" /> - <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" /> - <ClInclude Include="td\td\telegram\VideosManager.hpp" /> - <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" /> - <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" /> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" /> - <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" /> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" /> - <ClInclude Include="td\td\tl\TlObject.h" /> - <ClInclude Include="td\td\tl\tl_object_parse.h" /> - <ClInclude Include="td\td\tl\tl_object_store.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="tdactor.vcxproj"> - <Project>{85F63934-02FE-332A-8703-059040B65512}</Project> - <Name>tdactor</Name> - </ProjectReference> - <ProjectReference Include="tddb.vcxproj"> - <Project>{F525EE11-8820-3D8A-87A5-465D50A98A64}</Project> - <Name>tddb</Name> - </ProjectReference> - <ProjectReference Include="tdnet.vcxproj"> - <Project>{2246C3CF-7888-3102-984A-80214ADF418C}</Project> - <Name>tdnet</Name> - </ProjectReference> - <ProjectReference Include="tdutils.vcxproj"> - <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project> - <Name>tdutils</Name> - </ProjectReference> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{800E305A-3704-4617-ADA0-DEE8EAFDB804}</ProjectGuid>
+ <ProjectName>tdlib</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>td;td\td\generate\auto;td\tdactor;td\tdutils;td\tdnet;td\tddb;..\..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\td\mtproto\AuthData.cpp" />
+ <ClCompile Include="td\td\mtproto\ConnectionManager.cpp" />
+ <ClCompile Include="td\td\mtproto\DhHandshake.cpp" />
+ <ClCompile Include="td\td\mtproto\Handshake.cpp" />
+ <ClCompile Include="td\td\mtproto\HandshakeActor.cpp" />
+ <ClCompile Include="td\td\mtproto\HttpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\IStreamTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\KDF.cpp" />
+ <ClCompile Include="td\td\mtproto\Ping.cpp" />
+ <ClCompile Include="td\td\mtproto\PingConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\ProxySecret.cpp" />
+ <ClCompile Include="td\td\mtproto\RawConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\RSA.cpp" />
+ <ClCompile Include="td\td\mtproto\SessionConnection.cpp" />
+ <ClCompile Include="td\td\mtproto\TcpTransport.cpp" />
+ <ClCompile Include="td\td\mtproto\TlsInit.cpp" />
+ <ClCompile Include="td\td\mtproto\TlsReaderByteFlow.cpp" />
+ <ClCompile Include="td\td\mtproto\Transport.cpp" />
+ <ClCompile Include="td\td\mtproto\utils.cpp" />
+ <ClCompile Include="td\td\telegram\Account.cpp" />
+ <ClCompile Include="td\td\telegram\AnimationsManager.cpp" />
+ <ClCompile Include="td\td\telegram\Application.cpp" />
+ <ClCompile Include="td\td\telegram\AttachMenuManager.cpp" />
+ <ClCompile Include="td\td\telegram\AudiosManager.cpp" />
+ <ClCompile Include="td\td\telegram\AuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\AutoDownloadSettings.cpp" />
+ <ClCompile Include="td\td\telegram\BackgroundManager.cpp" />
+ <ClCompile Include="td\td\telegram\BackgroundType.cpp" />
+ <ClCompile Include="td\td\telegram\BotCommand.cpp" />
+ <ClCompile Include="td\td\telegram\BotCommandScope.cpp" />
+ <ClCompile Include="td\td\telegram\BotMenuButton.cpp" />
+ <ClCompile Include="td\td\telegram\CallActor.cpp" />
+ <ClCompile Include="td\td\telegram\CallDiscardReason.cpp" />
+ <ClCompile Include="td\td\telegram\CallManager.cpp" />
+ <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\ChannelParticipantFilter.cpp" />
+ <ClCompile Include="td\td\telegram\ChatReactions.cpp" />
+ <ClCompile Include="td\td\telegram\cli.cpp" />
+ <ClCompile Include="td\td\telegram\Client.cpp" />
+ <ClCompile Include="td\td\telegram\ClientActor.cpp" />
+ <ClCompile Include="td\td\telegram\ClientJson.cpp" />
+ <ClCompile Include="td\td\telegram\ConfigManager.cpp" />
+ <ClCompile Include="td\td\telegram\ConnectionState.cpp" />
+ <ClCompile Include="td\td\telegram\Contact.cpp" />
+ <ClCompile Include="td\td\telegram\ContactsManager.cpp" />
+ <ClCompile Include="td\td\telegram\CountryInfoManager.cpp" />
+ <ClCompile Include="td\td\telegram\DelayDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\Dependencies.cpp" />
+ <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp" />
+ <ClCompile Include="td\td\telegram\DhCache.cpp" />
+ <ClCompile Include="td\td\telegram\DialogAction.cpp" />
+ <ClCompile Include="td\td\telegram\DialogActionBar.cpp" />
+ <ClCompile Include="td\td\telegram\DialogAdministrator.cpp" />
+ <ClCompile Include="td\td\telegram\DialogDb.cpp" />
+ <ClCompile Include="td\td\telegram\DialogEventLog.cpp" />
+ <ClCompile Include="td\td\telegram\DialogFilter.cpp" />
+ <ClCompile Include="td\td\telegram\DialogId.cpp" />
+ <ClCompile Include="td\td\telegram\DialogInviteLink.cpp" />
+ <ClCompile Include="td\td\telegram\DialogLocation.cpp" />
+ <ClCompile Include="td\td\telegram\DialogNotificationSettings.cpp" />
+ <ClCompile Include="td\td\telegram\DialogParticipant.cpp" />
+ <ClCompile Include="td\td\telegram\DialogParticipantFilter.cpp" />
+ <ClCompile Include="td\td\telegram\DialogSource.cpp" />
+ <ClCompile Include="td\td\telegram\Dimensions.cpp" />
+ <ClCompile Include="td\td\telegram\Document.cpp" />
+ <ClCompile Include="td\td\telegram\DocumentsManager.cpp" />
+ <ClCompile Include="td\td\telegram\DownloadManager.cpp" />
+ <ClCompile Include="td\td\telegram\DownloadManagerCallback.cpp" />
+ <ClCompile Include="td\td\telegram\DraftMessage.cpp" />
+ <ClCompile Include="td\td\telegram\EmailVerification.cpp" />
+ <ClCompile Include="td\td\telegram\EmojiStatus.cpp" />
+ <ClCompile Include="td\td\telegram\FileReferenceManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileBitmask.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDb.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileDownloader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileEncryptionKey.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoader.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStats.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileType.cpp" />
+ <ClCompile Include="td\td\telegram\files\FileUploader.cpp" />
+ <ClCompile Include="td\td\telegram\files\PartsManager.cpp" />
+ <ClCompile Include="td\td\telegram\files\ResourceManager.cpp" />
+ <ClCompile Include="td\td\telegram\ForumTopic.cpp" />
+ <ClCompile Include="td\td\telegram\ForumTopicEditedData.cpp" />
+ <ClCompile Include="td\td\telegram\ForumTopicIcon.cpp" />
+ <ClCompile Include="td\td\telegram\ForumTopicInfo.cpp" />
+ <ClCompile Include="td\td\telegram\ForumTopicManager.cpp" />
+ <ClCompile Include="td\td\telegram\Game.cpp" />
+ <ClCompile Include="td\td\telegram\GameManager.cpp" />
+ <ClCompile Include="td\td\telegram\GitCommitHash.cpp" />
+ <ClCompile Include="td\td\telegram\Global.cpp" />
+ <ClCompile Include="td\td\telegram\GroupCallManager.cpp" />
+ <ClCompile Include="td\td\telegram\GroupCallParticipant.cpp" />
+ <ClCompile Include="td\td\telegram\GroupCallParticipantOrder.cpp" />
+ <ClCompile Include="td\td\telegram\GroupCallVideoPayload.cpp" />
+ <ClCompile Include="td\td\telegram\HashtagHints.cpp" />
+ <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp" />
+ <ClCompile Include="td\td\telegram\InputDialogId.cpp" />
+ <ClCompile Include="td\td\telegram\InputGroupCallId.cpp" />
+ <ClCompile Include="td\td\telegram\InputInvoice.cpp" />
+ <ClCompile Include="td\td\telegram\InputMessageText.cpp" />
+ <ClCompile Include="td\td\telegram\JsonValue.cpp" />
+ <ClCompile Include="td\td\telegram\LanguagePackManager.cpp" />
+ <ClCompile Include="td\td\telegram\LinkManager.cpp" />
+ <ClCompile Include="td\td\telegram\Location.cpp" />
+ <ClCompile Include="td\td\telegram\Log.cpp" />
+ <ClCompile Include="td\td\telegram\logevent\LogEventHelper.cpp" />
+ <ClCompile Include="td\td\telegram\Logging.cpp" />
+ <ClCompile Include="td\td\telegram\MessageContent.cpp" />
+ <ClCompile Include="td\td\telegram\MessageContentType.cpp" />
+ <ClCompile Include="td\td\telegram\MessageDb.cpp" />
+ <ClCompile Include="td\td\telegram\MessageEntity.cpp" />
+ <ClCompile Include="td\td\telegram\MessageExtendedMedia.cpp" />
+ <ClCompile Include="td\td\telegram\MessageId.cpp" />
+ <ClCompile Include="td\td\telegram\MessageReaction.cpp" />
+ <ClCompile Include="td\td\telegram\MessageReplyHeader.cpp" />
+ <ClCompile Include="td\td\telegram\MessageReplyInfo.cpp" />
+ <ClCompile Include="td\td\telegram\MessageSearchFilter.cpp" />
+ <ClCompile Include="td\td\telegram\MessageSender.cpp" />
+ <ClCompile Include="td\td\telegram\MessagesManager.cpp" />
+ <ClCompile Include="td\td\telegram\MessageThreadDb.cpp" />
+ <ClCompile Include="td\td\telegram\MessageTtl.cpp" />
+ <ClCompile Include="td\td\telegram\misc.cpp" />
+ <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp" />
+ <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetActor.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQuery.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetQueryStats.cpp" />
+ <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\net\Proxy.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp" />
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp" />
+ <ClCompile Include="td\td\telegram\net\Session.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionProxy.cpp" />
+ <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp" />
+ <ClCompile Include="td\td\telegram\NewPasswordState.cpp" />
+ <ClCompile Include="td\td\telegram\NotificationManager.cpp" />
+ <ClCompile Include="td\td\telegram\NotificationSettingsManager.cpp" />
+ <ClCompile Include="td\td\telegram\NotificationSettingsScope.cpp" />
+ <ClCompile Include="td\td\telegram\NotificationSound.cpp" />
+ <ClCompile Include="td\td\telegram\NotificationType.cpp" />
+ <ClCompile Include="td\td\telegram\OptionManager.cpp" />
+ <ClCompile Include="td\td\telegram\OrderInfo.cpp" />
+ <ClCompile Include="td\td\telegram\Payments.cpp" />
+ <ClCompile Include="td\td\telegram\PasswordManager.cpp" />
+ <ClCompile Include="td\td\telegram\PhoneNumberManager.cpp" />
+ <ClCompile Include="td\td\telegram\PhotoSize.cpp" />
+ <ClCompile Include="td\td\telegram\PhotoSizeSource.cpp" />
+ <ClCompile Include="td\td\telegram\PollManager.cpp" />
+ <ClCompile Include="td\td\telegram\Premium.cpp" />
+ <ClCompile Include="td\td\telegram\PremiumGiftOption.cpp" />
+ <ClCompile Include="td\td\telegram\PrivacyManager.cpp" />
+ <ClCompile Include="td\td\telegram\Photo.cpp" />
+ <ClCompile Include="td\td\telegram\QueryCombiner.cpp" />
+ <ClCompile Include="td\td\telegram\RecentDialogList.cpp" />
+ <ClCompile Include="td\td\telegram\ReplyMarkup.cpp" />
+ <ClCompile Include="td\td\telegram\ReportReason.cpp" />
+ <ClCompile Include="td\td\telegram\RestrictionReason.cpp" />
+ <ClCompile Include="td\td\telegram\ScopeNotificationSettings.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatActor.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatDb.cpp" />
+ <ClCompile Include="td\td\telegram\SecretChatsManager.cpp" />
+ <ClCompile Include="td\td\telegram\SecretInputMedia.cpp" />
+ <ClCompile Include="td\td\telegram\SecureManager.cpp" />
+ <ClCompile Include="td\td\telegram\SecureStorage.cpp" />
+ <ClCompile Include="td\td\telegram\SecureValue.cpp" />
+ <ClCompile Include="td\td\telegram\SendCodeHelper.cpp" />
+ <ClCompile Include="td\td\telegram\SentEmailCode.cpp" />
+ <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp" />
+ <ClCompile Include="td\td\telegram\SpecialStickerSetType.cpp" />
+ <ClCompile Include="td\td\telegram\SponsoredMessageManager.cpp" />
+ <ClCompile Include="td\td\telegram\StateManager.cpp" />
+ <ClCompile Include="td\td\telegram\StickerFormat.cpp" />
+ <ClCompile Include="td\td\telegram\StickersManager.cpp" />
+ <ClCompile Include="td\td\telegram\StickerType.cpp" />
+ <ClCompile Include="td\td\telegram\StorageManager.cpp" />
+ <ClCompile Include="td\td\telegram\SuggestedAction.cpp" />
+ <ClCompile Include="td\td\telegram\Support.cpp" />
+ <ClCompile Include="td\td\telegram\Td.cpp" />
+ <ClCompile Include="td\td\telegram\TdDb.cpp" />
+ <ClCompile Include="td\td\telegram\TermsOfService.cpp" />
+ <ClCompile Include="td\td\telegram\ThemeManager.cpp" />
+ <ClCompile Include="td\td\telegram\TopDialogCategory.cpp" />
+ <ClCompile Include="td\td\telegram\TopDialogManager.cpp" />
+ <ClCompile Include="td\td\telegram\TranscriptionInfo.cpp" />
+ <ClCompile Include="td\td\telegram\UpdatesManager.cpp" />
+ <ClCompile Include="td\td\telegram\Usernames.cpp" />
+ <ClCompile Include="td\td\telegram\Venue.cpp" />
+ <ClCompile Include="td\td\telegram\VideoNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\VideosManager.cpp" />
+ <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp" />
+ <ClCompile Include="td\td\telegram\WebPageBlock.cpp" />
+ <ClCompile Include="td\td\telegram\WebPagesManager.cpp" />
+ <ClInclude Include="td\td\mtproto\AuthData.h" />
+ <ClInclude Include="td\td\mtproto\AuthKey.h" />
+ <ClInclude Include="td\td\mtproto\ConnectionManager.h" />
+ <ClInclude Include="td\td\mtproto\CryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\DhCallback.h" />
+ <ClInclude Include="td\td\mtproto\DhHandshake.h" />
+ <ClInclude Include="td\td\mtproto\Handshake.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeActor.h" />
+ <ClInclude Include="td\td\mtproto\HandshakeConnection.h" />
+ <ClInclude Include="td\td\mtproto\HttpTransport.h" />
+ <ClInclude Include="td\td\mtproto\IStreamTransport.h" />
+ <ClInclude Include="td\td\mtproto\KDF.h" />
+ <ClInclude Include="td\td\mtproto\MtprotoQuery.h" />
+ <ClInclude Include="td\td\mtproto\NoCryptoStorer.h" />
+ <ClInclude Include="td\td\mtproto\PacketInfo.h" />
+ <ClInclude Include="td\td\mtproto\PacketStorer.h" />
+ <ClInclude Include="td\td\mtproto\Ping.h" />
+ <ClInclude Include="td\td\mtproto\PingConnection.h" />
+ <ClInclude Include="td\td\mtproto\ProxySecret.h" />
+ <ClInclude Include="td\td\mtproto\RawConnection.h" />
+ <ClInclude Include="td\td\mtproto\RSA.h" />
+ <ClInclude Include="td\td\mtproto\SessionConnection.h" />
+ <ClInclude Include="td\td\mtproto\TcpTransport.h" />
+ <ClInclude Include="td\td\mtproto\TlsInit.h" />
+ <ClInclude Include="td\td\mtproto\TlsReaderByteFlow.h" />
+ <ClInclude Include="td\td\mtproto\Transport.h" />
+ <ClInclude Include="td\td\mtproto\TransportType.h" />
+ <ClInclude Include="td\td\mtproto\utils.h" />
+ <ClInclude Include="td\td\telegram\AccessRights.h" />
+ <ClInclude Include="td\td\telegram\Account.h" />
+ <ClInclude Include="td\td\telegram\AffectedHistory.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.h" />
+ <ClInclude Include="td\td\telegram\Application.h" />
+ <ClInclude Include="td\td\telegram\AttachMenuManager.h" />
+ <ClInclude Include="td\td\telegram\AudiosManager.h" />
+ <ClInclude Include="td\td\telegram\AuthManager.h" />
+ <ClInclude Include="td\td\telegram\AutoDownloadSettings.h" />
+ <ClInclude Include="td\td\telegram\BackgroundId.h" />
+ <ClInclude Include="td\td\telegram\BackgroundManager.h" />
+ <ClInclude Include="td\td\telegram\BackgroundType.h" />
+ <ClInclude Include="td\td\telegram\BackgroundType.hpp" />
+ <ClInclude Include="td\td\telegram\BotCommand.h" />
+ <ClInclude Include="td\td\telegram\BotCommandScope.h" />
+ <ClInclude Include="td\td\telegram\BotMenuButton.h" />
+ <ClInclude Include="td\td\telegram\CallActor.h" />
+ <ClInclude Include="td\td\telegram\CallDiscardReason.h" />
+ <ClInclude Include="td\td\telegram\CallId.h" />
+ <ClInclude Include="td\td\telegram\CallManager.h" />
+ <ClInclude Include="td\td\telegram\CallbackQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\ChainId.h" />
+ <ClInclude Include="td\td\telegram\ChannelId.h" />
+ <ClInclude Include="td\td\telegram\ChannelParticipantFilter.h" />
+ <ClInclude Include="td\td\telegram\ChannelType.h" />
+ <ClInclude Include="td\td\telegram\ChatId.h" />
+ <ClInclude Include="td\td\telegram\ChatReactions.h" />
+ <ClInclude Include="td\td\telegram\Client.h" />
+ <ClInclude Include="td\td\telegram\ClientActor.h" />
+ <ClInclude Include="td\td\telegram\ClientJson.h" />
+ <ClInclude Include="td\td\telegram\ConfigManager.h" />
+ <ClInclude Include="td\td\telegram\ConnectionState.h" />
+ <ClInclude Include="td\td\telegram\Contact.h" />
+ <ClInclude Include="td\td\telegram\ContactsManager.h" />
+ <ClInclude Include="td\td\telegram\CountryInfoManager.h" />
+ <ClInclude Include="td\td\telegram\CustomEmojiId.h" />
+ <ClInclude Include="td\td\telegram\DelayDispatcher.h" />
+ <ClInclude Include="td\td\telegram\Dependencies.h" />
+ <ClInclude Include="td\td\telegram\DeviceTokenManager.h" />
+ <ClInclude Include="td\td\telegram\DhCache.h" />
+ <ClInclude Include="td\td\telegram\DhConfig.h" />
+ <ClInclude Include="td\td\telegram\DialogAction.h" />
+ <ClInclude Include="td\td\telegram\DialogActionBar.h" />
+ <ClInclude Include="td\td\telegram\DialogAdministrator.h" />
+ <ClInclude Include="td\td\telegram\DialogDate.h" />
+ <ClInclude Include="td\td\telegram\DialogDb.h" />
+ <ClInclude Include="td\td\telegram\DialogEventLog.h" />
+ <ClInclude Include="td\td\telegram\DialogFilter.h" />
+ <ClInclude Include="td\td\telegram\DialogFilter.hpp" />
+ <ClInclude Include="td\td\telegram\DialogFilterId.h" />
+ <ClInclude Include="td\td\telegram\DialogId.h" />
+ <ClInclude Include="td\td\telegram\DialogInviteLink.h" />
+ <ClInclude Include="td\td\telegram\DialogListId.h" />
+ <ClInclude Include="td\td\telegram\DialogLocation.h" />
+ <ClInclude Include="td\td\telegram\DialogNotificationSettings.h" />
+ <ClInclude Include="td\td\telegram\DialogNotificationSettings.hpp" />
+ <ClInclude Include="td\td\telegram\DialogParticipant.h" />
+ <ClInclude Include="td\td\telegram\DialogParticipantFilter.h" />
+ <ClInclude Include="td\td\telegram\DialogSource.h" />
+ <ClInclude Include="td\td\telegram\Dimensions.h" />
+ <ClInclude Include="td\td\telegram\Dimensions.hpp" />
+ <ClInclude Include="td\td\telegram\Document.h" />
+ <ClInclude Include="td\td\telegram\Document.hpp" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.h" />
+ <ClInclude Include="td\td\telegram\DownloadManager.h" />
+ <ClInclude Include="td\td\telegram\DownloadManagerCallback.h" />
+ <ClInclude Include="td\td\telegram\DraftMessage.h" />
+ <ClInclude Include="td\td\telegram\DraftMessage.hpp" />
+ <ClInclude Include="td\td\telegram\EmailVerification.h" />
+ <ClInclude Include="td\td\telegram\EmojiStatus.h" />
+ <ClInclude Include="td\td\telegram\EncryptedFile.h" />
+ <ClInclude Include="td\td\telegram\FileReferenceManager.h" />
+ <ClInclude Include="td\td\telegram\FileReferenceManager.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileBitmask.h" />
+ <ClInclude Include="td\td\telegram\files\FileData.h" />
+ <ClInclude Include="td\td\telegram\files\FileData.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileDb.h" />
+ <ClInclude Include="td\td\telegram\files\FileDbId.h" />
+ <ClInclude Include="td\td\telegram\files\FileDownloader.h" />
+ <ClInclude Include="td\td\telegram\files\FileEncryptionKey.h" />
+ <ClInclude Include="td\td\telegram\files\FileFromBytes.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcParameters.h" />
+ <ClInclude Include="td\td\telegram\files\FileGcWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileGenerateManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileHashUploader.h" />
+ <ClInclude Include="td\td\telegram\files\FileId.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderActor.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoader.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h" />
+ <ClInclude Include="td\td\telegram\files\FileLoadManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileLocation.h" />
+ <ClInclude Include="td\td\telegram\files\FileLocation.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileManager.h" />
+ <ClInclude Include="td\td\telegram\files\FileSourceId.h" />
+ <ClInclude Include="td\td\telegram\files\FileSourceId.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileStats.h" />
+ <ClInclude Include="td\td\telegram\files\FileStatsWorker.h" />
+ <ClInclude Include="td\td\telegram\files\FileType.h" />
+ <ClInclude Include="td\td\telegram\files\FileUploader.h" />
+ <ClInclude Include="td\td\telegram\files\PartsManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceManager.h" />
+ <ClInclude Include="td\td\telegram\files\ResourceState.h" />
+ <ClInclude Include="td\td\telegram\FolderId.h" />
+ <ClInclude Include="td\td\telegram\ForumTopic.h" />
+ <ClInclude Include="td\td\telegram\ForumTopicEditedData.h" />
+ <ClInclude Include="td\td\telegram\ForumTopicEditedData.hpp" />
+ <ClInclude Include="td\td\telegram\ForumTopicIcon.h" />
+ <ClInclude Include="td\td\telegram\ForumTopicIcon.hpp" />
+ <ClInclude Include="td\td\telegram\ForumTopicInfo.h" />
+ <ClInclude Include="td\td\telegram\ForumTopicManager.h" />
+ <ClInclude Include="td\td\telegram\FullMessageId.h" />
+ <ClInclude Include="td\td\telegram\Game.h" />
+ <ClInclude Include="td\td\telegram\GameManager.h" />
+ <ClInclude Include="td\td\telegram\GitCommitHash.h" />
+ <ClInclude Include="td\td\telegram\Global.h" />
+ <ClInclude Include="td\td\telegram\GroupCallId.h" />
+ <ClInclude Include="td\td\telegram\GroupCallManager.h" />
+ <ClInclude Include="td\td\telegram\GroupCallParticipant.h" />
+ <ClInclude Include="td\td\telegram\GroupCallParticipantOrder.h" />
+ <ClInclude Include="td\td\telegram\GroupCallVideoPayload.h" />
+ <ClInclude Include="td\td\telegram\HashtagHints.h" />
+ <ClInclude Include="td\td\telegram\InlineQueriesManager.h" />
+ <ClInclude Include="td\td\telegram\InputDialogId.h" />
+ <ClInclude Include="td\td\telegram\InputGroupCallId.h" />
+ <ClInclude Include="td\td\telegram\InputInvoice.h" />
+ <ClInclude Include="td\td\telegram\InputInvoice.hpp" />
+ <ClInclude Include="td\td\telegram\InputMessageText.h" />
+ <ClInclude Include="td\td\telegram\InputMessageText.hpp" />
+ <ClInclude Include="td\td\telegram\JsonValue.h" />
+ <ClInclude Include="td\td\telegram\LabeledPricePart.h" />
+ <ClInclude Include="td\td\telegram\LanguagePackManager.h" />
+ <ClInclude Include="td\td\telegram\LinkManager.h" />
+ <ClInclude Include="td\td\telegram\Location.h" />
+ <ClInclude Include="td\td\telegram\Log.h" />
+ <ClInclude Include="td\td\telegram\logevent\LogEvent.h" />
+ <ClInclude Include="td\td\telegram\logevent\LogEventHelper.h" />
+ <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h" />
+ <ClInclude Include="td\td\telegram\Logging.h" />
+ <ClInclude Include="td\td\telegram\MessageContent.h" />
+ <ClInclude Include="td\td\telegram\MessageContentType.h" />
+ <ClInclude Include="td\td\telegram\MessageCopyOptions.h" />
+ <ClInclude Include="td\td\telegram\MessageDb.h" />
+ <ClInclude Include="td\td\telegram\MessageEntity.h" />
+ <ClInclude Include="td\td\telegram\MessageEntity.hpp" />
+ <ClInclude Include="td\td\telegram\MessageExtendedMedia.h" />
+ <ClInclude Include="td\td\telegram\MessageExtendedMedia.hpp" />
+ <ClInclude Include="td\td\telegram\MessageId.h" />
+ <ClInclude Include="td\td\telegram\MessageLinkInfo.h" />
+ <ClInclude Include="td\td\telegram\MessageReaction.h" />
+ <ClInclude Include="td\td\telegram\MessageReaction.hpp" />
+ <ClInclude Include="td\td\telegram\MessageReplyHeader.h" />
+ <ClInclude Include="td\td\telegram\MessageReplyInfo.h" />
+ <ClInclude Include="td\td\telegram\MessageReplyInfo.hpp" />
+ <ClInclude Include="td\td\telegram\MessageSearchFilter.h" />
+ <ClInclude Include="td\td\telegram\MessageSender.h" />
+ <ClInclude Include="td\td\telegram\MessagesManager.h" />
+ <ClInclude Include="td\td\telegram\MessageThreadDb.h" />
+ <ClInclude Include="td\td\telegram\MessageThreadInfo.h" />
+ <ClInclude Include="td\td\telegram\MessageTtl.h" />
+ <ClInclude Include="td\td\telegram\MinChannel.h" />
+ <ClInclude Include="td\td\telegram\MinChannel.hpp" />
+ <ClInclude Include="td\td\telegram\misc.h" />
+ <ClInclude Include="td\td\telegram\net\AuthDataShared.h" />
+ <ClInclude Include="td\td\telegram\net\ConnectionCreator.h" />
+ <ClInclude Include="td\td\telegram\net\DcAuthManager.h" />
+ <ClInclude Include="td\td\telegram\net\DcId.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptions.h" />
+ <ClInclude Include="td\td\telegram\net\DcOptionsSet.h" />
+ <ClInclude Include="td\td\telegram\net\MtprotoHeader.h" />
+ <ClInclude Include="td\td\telegram\net\NetActor.h" />
+ <ClInclude Include="td\td\telegram\net\NetQuery.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCounter.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryCreator.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h" />
+ <ClInclude Include="td\td\telegram\net\NetQueryStats.h" />
+ <ClInclude Include="td\td\telegram\net\NetStatsManager.h" />
+ <ClInclude Include="td\td\telegram\net\NetType.h" />
+ <ClInclude Include="td\td\telegram\net\Proxy.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h" />
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\net\Session.h" />
+ <ClInclude Include="td\td\telegram\net\SessionProxy.h" />
+ <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h" />
+ <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h" />
+ <ClInclude Include="td\td\telegram\NewPasswordState.h" />
+ <ClInclude Include="td\td\telegram\Notification.h" />
+ <ClInclude Include="td\td\telegram\NotificationGroupId.h" />
+ <ClInclude Include="td\td\telegram\NotificationGroupKey.h" />
+ <ClInclude Include="td\td\telegram\NotificationGroupType.h" />
+ <ClInclude Include="td\td\telegram\NotificationId.h" />
+ <ClInclude Include="td\td\telegram\NotificationManager.h" />
+ <ClInclude Include="td\td\telegram\NotificationSettingsManager.h" />
+ <ClInclude Include="td\td\telegram\NotificationSettingsScope.h" />
+ <ClInclude Include="td\td\telegram\NotificationSound.h" />
+ <ClInclude Include="td\td\telegram\NotificationSoundType.h" />
+ <ClInclude Include="td\td\telegram\NotificationType.h" />
+ <ClInclude Include="td\td\telegram\OptionManager.h" />
+ <ClInclude Include="td\td\telegram\OrderInfo.h" />
+ <ClInclude Include="td\td\telegram\OrderInfo.hpp" />
+ <ClInclude Include="td\td\telegram\PasswordManager.h" />
+ <ClInclude Include="td\td\telegram\Payments.h" />
+ <ClInclude Include="td\td\telegram\PhoneNumberManager.h" />
+ <ClInclude Include="td\td\telegram\Photo.h" />
+ <ClInclude Include="td\td\telegram\PhotoFormat.h" />
+ <ClInclude Include="td\td\telegram\PhotoSize.h" />
+ <ClInclude Include="td\td\telegram\PhotoSize.hpp" />
+ <ClInclude Include="td\td\telegram\PhotoSizeSource.h" />
+ <ClInclude Include="td\td\telegram\PhotoSizeSource.hpp" />
+ <ClInclude Include="td\td\telegram\PollId.h" />
+ <ClInclude Include="td\td\telegram\PollId.hpp" />
+ <ClInclude Include="td\td\telegram\PollManager.h" />
+ <ClInclude Include="td\td\telegram\PollManager.hpp" />
+ <ClInclude Include="td\td\telegram\Premium.h" />
+ <ClInclude Include="td\td\telegram\PremiumGiftOption.h" />
+ <ClInclude Include="td\td\telegram\PremiumGiftOption.hpp" />
+ <ClInclude Include="td\td\telegram\PrivacyManager.h" />
+ <ClInclude Include="td\td\telegram\PtsManager.h" />
+ <ClInclude Include="td\td\telegram\PublicDialogType.h" />
+ <ClInclude Include="td\td\telegram\QueryCombiner.h" />
+ <ClInclude Include="td\td\telegram\RecentDialogList.h" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.h" />
+ <ClInclude Include="td\td\telegram\ReportReason.h" />
+ <ClInclude Include="td\td\telegram\RequestActor.h" />
+ <ClInclude Include="td\td\telegram\RestrictionReason.h" />
+ <ClInclude Include="td\td\telegram\ScheduledServerMessageId.h" />
+ <ClInclude Include="td\td\telegram\ScopeNotificationSettings.h" />
+ <ClInclude Include="td\td\telegram\ScopeNotificationSettings.hpp" />
+ <ClInclude Include="td\td\telegram\SecretChatActor.h" />
+ <ClInclude Include="td\td\telegram\SecretChatId.h" />
+ <ClInclude Include="td\td\telegram\SecretChatDb.h" />
+ <ClInclude Include="td\td\telegram\SecretChatLayer.h" />
+ <ClInclude Include="td\td\telegram\SecretChatsManager.h" />
+ <ClInclude Include="td\td\telegram\SecretInputMedia.h" />
+ <ClInclude Include="td\td\telegram\SecureManager.h" />
+ <ClInclude Include="td\td\telegram\SecureStorage.h" />
+ <ClInclude Include="td\td\telegram\SecureValue.h" />
+ <ClInclude Include="td\td\telegram\SecureValue.hpp" />
+ <ClInclude Include="td\td\telegram\SendCodeHelper.h" />
+ <ClInclude Include="td\td\telegram\SendCodeHelper.hpp" />
+ <ClInclude Include="td\td\telegram\SentEmailCode.h" />
+ <ClInclude Include="td\td\telegram\SequenceDispatcher.h" />
+ <ClInclude Include="td\td\telegram\ServerMessageId.h" />
+ <ClInclude Include="td\td\telegram\SetWithPosition.h" />
+ <ClInclude Include="td\td\telegram\SpecialStickerSetType.h" />
+ <ClInclude Include="td\td\telegram\SponsoredMessageManager.h" />
+ <ClInclude Include="td\td\telegram\StateManager.h" />
+ <ClInclude Include="td\td\telegram\StickerFormat.h" />
+ <ClInclude Include="td\td\telegram\StickerSetId.h" />
+ <ClInclude Include="td\td\telegram\StickerSetId.hpp" />
+ <ClInclude Include="td\td\telegram\StickersManager.h" />
+ <ClInclude Include="td\td\telegram\StickerType.h" />
+ <ClInclude Include="td\td\telegram\StorageManager.h" />
+ <ClInclude Include="td\td\telegram\SuggestedAction.h" />
+ <ClInclude Include="td\td\telegram\Support.h" />
+ <ClInclude Include="td\td\telegram\Td.h" />
+ <ClInclude Include="td\td\telegram\TdCallback.h" />
+ <ClInclude Include="td\td\telegram\TdDb.h" />
+ <ClInclude Include="td\td\telegram\TdParameters.h" />
+ <ClInclude Include="td\td\telegram\td_c_client.h" />
+ <ClInclude Include="td\td\telegram\td_json_client.h" />
+ <ClInclude Include="td\td\telegram\td_log.h" />
+ <ClInclude Include="td\td\telegram\TermsOfService.h" />
+ <ClInclude Include="td\td\telegram\ThemeManager.h" />
+ <ClInclude Include="td\td\telegram\TopDialogCategory.h" />
+ <ClInclude Include="td\td\telegram\TopDialogManager.h" />
+ <ClInclude Include="td\td\telegram\TranscriptionInfo.h" />
+ <ClInclude Include="td\td\telegram\TranscriptionInfo.hpp" />
+ <ClInclude Include="td\td\telegram\UniqueId.h" />
+ <ClInclude Include="td\td\telegram\UpdatesManager.h" />
+ <ClInclude Include="td\td\telegram\UserId.h" />
+ <ClInclude Include="td\td\telegram\Usernames.h" />
+ <ClInclude Include="td\td\telegram\Venue.h" />
+ <ClInclude Include="td\td\telegram\Version.h" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.h" />
+ <ClInclude Include="td\td\telegram\VideosManager.h" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.h" />
+ <ClInclude Include="td\td\telegram\WebPageBlock.h" />
+ <ClInclude Include="td\td\telegram\WebPageId.h" />
+ <ClInclude Include="td\td\telegram\WebPagesManager.h" />
+ <ClInclude Include="td\td\telegram\AnimationsManager.hpp" />
+ <ClInclude Include="td\td\telegram\AudiosManager.hpp" />
+ <ClInclude Include="td\td\telegram\AuthManager.hpp" />
+ <ClInclude Include="td\td\telegram\DocumentsManager.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileId.hpp" />
+ <ClInclude Include="td\td\telegram\files\FileManager.hpp" />
+ <ClInclude Include="td\td\telegram\Game.hpp" />
+ <ClInclude Include="td\td\telegram\Photo.hpp" />
+ <ClInclude Include="td\td\telegram\ReplyMarkup.hpp" />
+ <ClInclude Include="td\td\telegram\StickersManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideoNotesManager.hpp" />
+ <ClInclude Include="td\td\telegram\VideosManager.hpp" />
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp" />
+ <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h" />
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp" />
+ <ClInclude Include="td\td\tl\TlObject.h" />
+ <ClInclude Include="td\td\tl\tl_object_parse.h" />
+ <ClInclude Include="td\td\tl\tl_object_store.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="tdactor.vcxproj">
+ <Project>{85F63934-02FE-332A-8703-059040B65512}</Project>
+ <Name>tdactor</Name>
+ </ProjectReference>
+ <ProjectReference Include="tddb.vcxproj">
+ <Project>{F525EE11-8820-3D8A-87A5-465D50A98A64}</Project>
+ <Name>tddb</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdnet.vcxproj">
+ <Project>{2246C3CF-7888-3102-984A-80214ADF418C}</Project>
+ <Name>tdnet</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdutils.vcxproj">
+ <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project>
+ <Name>tdutils</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdlib.vcxproj.filters b/protocols/Telegram/tdlib/tdlib.vcxproj.filters index ee0c097760..09f9ca4b73 100644 --- a/protocols/Telegram/tdlib/tdlib.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdlib.vcxproj.filters @@ -1,1656 +1,1656 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\td\mtproto\AuthData.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\Handshake.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\HandshakeActor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\HttpTransport.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\IStreamTransport.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\RawConnection.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\SessionConnection.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\TcpTransport.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\Transport.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\utils.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\AnimationsManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\AudiosManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\AuthManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\CallActor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\CallDiscardReason.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\CallManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ClientActor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ConfigManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Contact.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ContactsManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DelayDispatcher.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DhCache.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogDb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogId.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogParticipant.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DocumentsManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Game.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Global.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\HashtagHints.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Location.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageEntity.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessagesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\misc.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Payments.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PasswordManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PrivacyManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Photo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ReplyMarkup.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecretChatActor.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecretChatDb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecretChatsManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\StateManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\StickersManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\StorageManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Td.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\TdDb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\TopDialogManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\UpdatesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\VideoNotesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\VideosManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\WebPagesManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Account.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Client.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Application.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\AttachMenuManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\AutoDownloadSettings.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\BackgroundManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\BackgroundType.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\BotCommand.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\BotCommandScope.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\BotMenuButton.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ChannelParticipantFilter.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ChatReactions.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\cli.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ClientJson.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ConnectionState.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\CountryInfoManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Dependencies.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogAction.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogActionBar.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogAdministrator.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogEventLog.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogFilter.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogInviteLink.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogLocation.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogNotificationSettings.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogParticipantFilter.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DialogSource.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Dimensions.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Document.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DownloadManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DownloadManagerCallback.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\DraftMessage.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\EmailVerification.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\EmojiStatus.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ForumTopic.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ForumTopicEditedData.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ForumTopicIcon.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ForumTopicInfo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ForumTopicManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GameManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GroupCallManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GroupCallParticipant.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GroupCallParticipantOrder.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GroupCallVideoPayload.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\InputDialogId.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\InputGroupCallId.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\InputInvoice.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\InputMessageText.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\JsonValue.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\LanguagePackManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\LinkManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Log.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Logging.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageContent.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageContentType.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageDb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageExtendedMedia.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageId.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageReaction.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageReplyHeader.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageReplyInfo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageSearchFilter.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageSender.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageThreadDb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\MessageTtl.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NewPasswordState.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NotificationManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NotificationSettingsManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NotificationSettingsScope.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NotificationSound.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\NotificationType.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\OptionManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\OrderInfo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PhoneNumberManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PhotoSize.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PhotoSizeSource.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PollManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Premium.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\PremiumGiftOption.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\QueryCombiner.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\RecentDialogList.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ReportReason.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\RestrictionReason.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ScopeNotificationSettings.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecretInputMedia.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecureManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecureStorage.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SecureValue.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SendCodeHelper.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SentEmailCode.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SpecialStickerSetType.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SponsoredMessageManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\StickerFormat.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\StickerType.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\SuggestedAction.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Support.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\TermsOfService.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\ThemeManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\TopDialogCategory.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\TranscriptionInfo.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Usernames.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\Venue.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\WebPageBlock.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetQueryStats.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\Proxy.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetActor.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetQuery.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\Session.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\net\SessionProxy.cpp"> - <Filter>Source Files\net</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\logevent\LogEventHelper.cpp"> - <Filter>Source Files\logevent</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileBitmask.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileEncryptionKey.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileType.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileDb.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileDownloader.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileLoader.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\FileReferenceManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileStats.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\FileUploader.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\PartsManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\files\ResourceManager.cpp"> - <Filter>Source Files\files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\ConnectionManager.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\DhHandshake.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\KDF.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\Ping.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\PingConnection.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\ProxySecret.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\RSA.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\TlsInit.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\mtproto\TlsReaderByteFlow.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="td\td\telegram\GitCommitHash.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\td\mtproto\AuthData.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\AuthKey.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\CryptoStorer.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\Handshake.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\HandshakeActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\HandshakeConnection.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\HttpTransport.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\IStreamTransport.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\NoCryptoStorer.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\PacketStorer.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\PingConnection.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\RawConnection.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\SessionConnection.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\TcpTransport.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\Transport.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\utils.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AccessRights.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AnimationsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AudiosManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AuthManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CallActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CallDiscardReason.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CallId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CallManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CallbackQueriesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChannelId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChatId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ClientActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ConfigManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Contact.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ContactsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DelayDispatcher.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DeviceTokenManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DhCache.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DhConfig.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogDb.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogParticipant.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DocumentsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLoaderActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLoader.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLoadManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLocation.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileStats.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileStatsWorker.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileUploader.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\ResourceState.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Game.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Global.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\HashtagHints.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InlineQueriesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Location.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageEntity.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessagesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\misc.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PasswordManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Payments.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Photo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PrivacyManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PtsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ReplyMarkup.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretChatActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretChatId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretChatDb.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretChatsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretInputMedia.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SequenceDispatcher.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StateManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickersManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StorageManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Td.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TdCallback.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TdDb.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TdParameters.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TopDialogManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\UniqueId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\UpdatesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\UserId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Version.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VideoNotesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VideosManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VoiceNotesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\WebPageId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\WebPagesManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AnimationsManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AudiosManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AuthManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DocumentsManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileId.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Game.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Photo.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ReplyMarkup.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickersManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VideoNotesManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VideosManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\tl\TlObject.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\tl\tl_object_parse.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\tl\tl_object_store.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Account.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AffectedHistory.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Application.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AttachMenuManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\AutoDownloadSettings.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BackgroundId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BackgroundManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BackgroundType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BackgroundType.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BotCommand.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BotCommandScope.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\BotMenuButton.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChainId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChannelParticipantFilter.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChannelType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ChatReactions.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Client.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ClientJson.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ConnectionState.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CountryInfoManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\CustomEmojiId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Dependencies.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogAction.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogActionBar.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogAdministrator.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogDate.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogEventLog.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogFilter.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogFilter.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogFilterId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogInviteLink.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogListId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogLocation.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogNotificationSettings.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogNotificationSettings.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogParticipantFilter.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DialogSource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Dimensions.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Dimensions.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Document.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Document.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DownloadManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DownloadManagerCallback.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DraftMessage.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\DraftMessage.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\EmailVerification.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\EmojiStatus.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\EncryptedFile.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\FileReferenceManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\FileReferenceManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\FolderId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopic.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicEditedData.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicEditedData.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicIcon.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicIcon.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ForumTopicManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\FullMessageId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GameManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GitCommitHash.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GroupCallId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GroupCallManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GroupCallParticipant.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GroupCallParticipantOrder.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\GroupCallVideoPayload.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputDialogId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputGroupCallId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputInvoice.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputInvoice.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputMessageText.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\InputMessageText.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\JsonValue.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\LabeledPricePart.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\LanguagePackManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\LinkManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Log.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Logging.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageContent.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageContentType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageCopyOptions.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageDb.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageEntity.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageExtendedMedia.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageExtendedMedia.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageLinkInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageReaction.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageReaction.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageReplyHeader.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageReplyInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageReplyInfo.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageSearchFilter.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageSender.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageThreadDb.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageThreadInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MessageTtl.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MinChannel.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\MinChannel.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NewPasswordState.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Notification.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationGroupId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationGroupKey.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationGroupType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationSettingsManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationSettingsScope.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationSound.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationSoundType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\NotificationType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\OptionManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\OrderInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\OrderInfo.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhoneNumberManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhotoFormat.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhotoSize.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhotoSize.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhotoSizeSource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PhotoSizeSource.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PollId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PollId.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PollManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PollManager.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Premium.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PremiumGiftOption.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PremiumGiftOption.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\PublicDialogType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\QueryCombiner.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\RecentDialogList.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ReportReason.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\RequestActor.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\RestrictionReason.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ScheduledServerMessageId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ScopeNotificationSettings.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ScopeNotificationSettings.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecretChatLayer.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecureManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecureStorage.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecureValue.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SecureValue.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SendCodeHelper.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SendCodeHelper.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SentEmailCode.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ServerMessageId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SetWithPosition.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SpecialStickerSetType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SponsoredMessageManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickerFormat.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickerSetId.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickerSetId.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\StickerType.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\SuggestedAction.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Support.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\td_c_client.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\td_json_client.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\td_log.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TermsOfService.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\ThemeManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TopDialogCategory.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TranscriptionInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\TranscriptionInfo.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Usernames.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\Venue.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\WebPageBlock.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQueryStats.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\Proxy.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\AuthDataShared.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\ConnectionCreator.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\DcAuthManager.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\DcId.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\DcOptions.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\DcOptionsSet.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\MtprotoHeader.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetActor.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQuery.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQueryCounter.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQueryCreator.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetStatsManager.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\NetType.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\Session.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\net\SessionProxy.h"> - <Filter>Source Files\net</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\logevent\LogEventHelper.h"> - <Filter>Source Files\logevent</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\logevent\LogEvent.h"> - <Filter>Source Files\logevent</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h"> - <Filter>Source Files\logevent</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileBitmask.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileData.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileData.hpp"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileDbId.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileEncryptionKey.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileLocation.hpp"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileSourceId.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileSourceId.hpp"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileType.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileDb.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileDownloader.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileFromBytes.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileGcParameters.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileGcWorker.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileGenerateManager.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\FileHashUploader.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\PartsManager.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\telegram\files\ResourceManager.h"> - <Filter>Source Files\files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\ConnectionManager.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\DhCallback.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\DhHandshake.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\KDF.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\MtprotoQuery.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\PacketInfo.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\Ping.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\ProxySecret.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\RSA.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\TlsInit.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\TlsReaderByteFlow.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="td\td\mtproto\TransportType.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <Filter Include="Header Files"> - <UniqueIdentifier>{0FD26E20-5E51-396B-B4E5-98068F96B37E}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files"> - <UniqueIdentifier>{CC4593AA-1CC3-37C8-BDF9-C5986B1808BD}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files\net"> - <UniqueIdentifier>{cd939197-1880-4e6c-8611-971cb070e878}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files\logevent"> - <UniqueIdentifier>{c2c002f7-0b68-47b7-886e-03a433ca7017}</UniqueIdentifier> - </Filter> - <Filter Include="Source Files\files"> - <UniqueIdentifier>{514d7959-632a-4de8-8df3-0eeeadaaacbf}</UniqueIdentifier> - </Filter> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\td\mtproto\AuthData.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\Handshake.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\HandshakeActor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\HttpTransport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\IStreamTransport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\RawConnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\SessionConnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\TcpTransport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\Transport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\AnimationsManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\AudiosManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\AuthManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\CallActor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\CallDiscardReason.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\CallManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\CallbackQueriesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ClientActor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ConfigManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Contact.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ContactsManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DelayDispatcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DeviceTokenManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DhCache.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogDb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogId.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogParticipant.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DocumentsManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Game.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Global.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\HashtagHints.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\InlineQueriesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Location.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageEntity.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessagesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\misc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Payments.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PasswordManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PrivacyManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Photo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ReplyMarkup.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecretChatActor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecretChatDb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecretChatsManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SequenceDispatcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\StateManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\StickersManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\StorageManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Td.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\TdDb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\TopDialogManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\UpdatesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\VideoNotesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\VideosManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\VoiceNotesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\WebPagesManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\generate\auto\td\mtproto\mtproto_api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\generate\auto\td\telegram\td_api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\generate\auto\td\telegram\telegram_api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\generate\auto\td\telegram\secret_api.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Account.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Client.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Application.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\AttachMenuManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\AutoDownloadSettings.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\BackgroundManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\BackgroundType.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\BotCommand.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\BotCommandScope.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\BotMenuButton.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ChannelParticipantFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ChatReactions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\cli.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ClientJson.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ConnectionState.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\CountryInfoManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Dependencies.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogAction.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogActionBar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogAdministrator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogEventLog.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogInviteLink.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogLocation.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogNotificationSettings.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogParticipantFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DialogSource.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Dimensions.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Document.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DownloadManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DownloadManagerCallback.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\DraftMessage.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\EmailVerification.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\EmojiStatus.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ForumTopic.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ForumTopicEditedData.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ForumTopicIcon.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ForumTopicInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ForumTopicManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GameManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GroupCallManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GroupCallParticipant.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GroupCallParticipantOrder.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GroupCallVideoPayload.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\InputDialogId.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\InputGroupCallId.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\InputInvoice.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\InputMessageText.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\JsonValue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\LanguagePackManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\LinkManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Log.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Logging.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageContent.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageContentType.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageDb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageExtendedMedia.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageId.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageReaction.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageReplyHeader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageReplyInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageSearchFilter.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageSender.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageThreadDb.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\MessageTtl.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NewPasswordState.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NotificationManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NotificationSettingsManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NotificationSettingsScope.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NotificationSound.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\NotificationType.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\OptionManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\OrderInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PhoneNumberManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PhotoSize.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PhotoSizeSource.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PollManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Premium.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\PremiumGiftOption.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\QueryCombiner.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\RecentDialogList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ReportReason.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\RestrictionReason.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ScopeNotificationSettings.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecretInputMedia.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecureManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecureStorage.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SecureValue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SendCodeHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SentEmailCode.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SpecialStickerSetType.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SponsoredMessageManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\StickerFormat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\StickerType.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\SuggestedAction.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Support.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\TermsOfService.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\ThemeManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\TopDialogCategory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\TranscriptionInfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Usernames.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\Venue.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\WebPageBlock.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetQueryStats.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\Proxy.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\AuthDataShared.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\ConnectionCreator.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\DcAuthManager.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\DcOptionsSet.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\MtprotoHeader.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetActor.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetQuery.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetQueryCreator.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetQueryDelayer.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetQueryDispatcher.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\NetStatsManager.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyShared.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\PublicRsaKeyWatchdog.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\Session.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\SessionMultiProxy.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\net\SessionProxy.cpp">
+ <Filter>Source Files\net</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\logevent\LogEventHelper.cpp">
+ <Filter>Source Files\logevent</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileBitmask.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileEncryptionKey.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileType.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileDb.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileDownloader.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileFromBytes.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileGcParameters.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileGcWorker.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileGenerateManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileHashUploader.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileLoader.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileLoaderUtils.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileLoadManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\FileReferenceManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileStats.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileStatsWorker.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\FileUploader.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\PartsManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\files\ResourceManager.cpp">
+ <Filter>Source Files\files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\ConnectionManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\DhHandshake.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\KDF.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\Ping.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\PingConnection.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\ProxySecret.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\RSA.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\TlsInit.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\mtproto\TlsReaderByteFlow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="td\td\telegram\GitCommitHash.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\td\mtproto\AuthData.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\AuthKey.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\CryptoStorer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\Handshake.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\HandshakeActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\HandshakeConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\HttpTransport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\IStreamTransport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\NoCryptoStorer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\PacketStorer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\PingConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\RawConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\SessionConnection.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\TcpTransport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\Transport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\utils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AccessRights.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AnimationsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AudiosManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AuthManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CallActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CallDiscardReason.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CallId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CallManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CallbackQueriesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChannelId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChatId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ClientActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ConfigManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Contact.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ContactsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DelayDispatcher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DeviceTokenManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DhCache.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DhConfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogDb.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogParticipant.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DocumentsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLoaderActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLoader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLoaderUtils.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLoadManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLocation.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileStats.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileStatsWorker.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileUploader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\ResourceState.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Game.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Global.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\HashtagHints.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InlineQueriesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Location.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageEntity.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessagesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\misc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\TempAuthKeyWatchdog.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PasswordManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Payments.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Photo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PrivacyManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PtsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ReplyMarkup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretChatActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretChatId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretChatDb.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretChatsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretInputMedia.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SequenceDispatcher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StateManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickersManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StorageManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Td.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TdCallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TdDb.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TdParameters.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TopDialogManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\UniqueId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\UpdatesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\UserId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VideoNotesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VideosManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\WebPageId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\WebPagesManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AnimationsManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AudiosManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AuthManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DocumentsManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileId.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Game.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Photo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ReplyMarkup.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickersManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VideoNotesManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VideosManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\VoiceNotesManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\mtproto\mtproto_api.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\td_api.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\telegram_api.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\generate\auto\td\telegram\secret_api.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\tl\TlObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\tl\tl_object_parse.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\tl\tl_object_store.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Account.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AffectedHistory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Application.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AttachMenuManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\AutoDownloadSettings.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BackgroundId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BackgroundManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BackgroundType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BackgroundType.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BotCommand.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BotCommandScope.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\BotMenuButton.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChainId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChannelParticipantFilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChannelType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ChatReactions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Client.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ClientJson.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ConnectionState.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CountryInfoManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\CustomEmojiId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Dependencies.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogAction.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogActionBar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogAdministrator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogDate.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogEventLog.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogFilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogFilter.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogFilterId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogInviteLink.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogListId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogLocation.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogNotificationSettings.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogNotificationSettings.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogParticipantFilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DialogSource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Dimensions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Dimensions.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Document.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Document.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DownloadManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DownloadManagerCallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DraftMessage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\DraftMessage.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\EmailVerification.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\EmojiStatus.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\EncryptedFile.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\FileReferenceManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\FileReferenceManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\FolderId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopic.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicEditedData.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicEditedData.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicIcon.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicIcon.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ForumTopicManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\FullMessageId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GameManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GitCommitHash.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GroupCallId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GroupCallManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GroupCallParticipant.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GroupCallParticipantOrder.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\GroupCallVideoPayload.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputDialogId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputGroupCallId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputInvoice.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputInvoice.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputMessageText.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\InputMessageText.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\JsonValue.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\LabeledPricePart.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\LanguagePackManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\LinkManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Log.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Logging.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageContent.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageContentType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageCopyOptions.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageDb.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageEntity.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageExtendedMedia.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageExtendedMedia.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageLinkInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageReaction.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageReaction.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageReplyHeader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageReplyInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageReplyInfo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageSearchFilter.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageSender.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageThreadDb.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageThreadInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MessageTtl.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MinChannel.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\MinChannel.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NewPasswordState.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Notification.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationGroupId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationGroupKey.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationGroupType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationSettingsManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationSettingsScope.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationSound.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationSoundType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\NotificationType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\OptionManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\OrderInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\OrderInfo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhoneNumberManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhotoFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhotoSize.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhotoSize.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhotoSizeSource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PhotoSizeSource.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PollId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PollId.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PollManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PollManager.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Premium.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PremiumGiftOption.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PremiumGiftOption.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\PublicDialogType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\QueryCombiner.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\RecentDialogList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ReportReason.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\RequestActor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\RestrictionReason.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ScheduledServerMessageId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ScopeNotificationSettings.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ScopeNotificationSettings.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecretChatLayer.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecureManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecureStorage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecureValue.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SecureValue.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SendCodeHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SendCodeHelper.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SentEmailCode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ServerMessageId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SetWithPosition.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SpecialStickerSetType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SponsoredMessageManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickerFormat.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickerSetId.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickerSetId.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\StickerType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\SuggestedAction.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Support.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\td_c_client.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\td_json_client.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\td_log.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TermsOfService.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\ThemeManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TopDialogCategory.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TranscriptionInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\TranscriptionInfo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Usernames.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\Venue.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\WebPageBlock.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQueryStats.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\Proxy.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\AuthDataShared.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\ConnectionCreator.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\DcAuthManager.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\DcId.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\DcOptions.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\DcOptionsSet.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\MtprotoHeader.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetActor.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQuery.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQueryCounter.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQueryCreator.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQueryDelayer.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetQueryDispatcher.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetStatsManager.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\NetType.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyShared.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\PublicRsaKeyWatchdog.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\Session.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\SessionMultiProxy.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\net\SessionProxy.h">
+ <Filter>Source Files\net</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\logevent\LogEventHelper.h">
+ <Filter>Source Files\logevent</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\logevent\LogEvent.h">
+ <Filter>Source Files\logevent</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\logevent\SecretChatEvent.h">
+ <Filter>Source Files\logevent</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileBitmask.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileData.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileData.hpp">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileDbId.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileEncryptionKey.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileLocation.hpp">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileSourceId.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileSourceId.hpp">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileType.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileDb.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileDownloader.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileFromBytes.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileGcParameters.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileGcWorker.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileGenerateManager.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\FileHashUploader.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\PartsManager.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\telegram\files\ResourceManager.h">
+ <Filter>Source Files\files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\ConnectionManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\DhCallback.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\DhHandshake.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\KDF.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\MtprotoQuery.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\PacketInfo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\Ping.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\ProxySecret.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\RSA.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\TlsInit.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\TlsReaderByteFlow.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="td\td\mtproto\TransportType.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{0FD26E20-5E51-396B-B4E5-98068F96B37E}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{CC4593AA-1CC3-37C8-BDF9-C5986B1808BD}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\net">
+ <UniqueIdentifier>{cd939197-1880-4e6c-8611-971cb070e878}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\logevent">
+ <UniqueIdentifier>{c2c002f7-0b68-47b7-886e-03a433ca7017}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\files">
+ <UniqueIdentifier>{514d7959-632a-4de8-8df3-0eeeadaaacbf}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdnet.vcxproj b/protocols/Telegram/tdlib/tdnet.vcxproj index ba945968c0..9a84f80874 100644 --- a/protocols/Telegram/tdlib/tdnet.vcxproj +++ b/protocols/Telegram/tdlib/tdnet.vcxproj @@ -1,89 +1,89 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{2246C3CF-7888-3102-984A-80214ADF418C}</ProjectGuid> - <ProjectName>tdnet</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\td\tdnet;..\..\..\include;.\td\tdutils;.\td\tdactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\tdnet\td\net\GetHostByNameActor.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpChunkedByteFlow.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpConnectionBase.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpContentLengthByteFlow.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpFile.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpInboundConnection.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpOutboundConnection.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpProxy.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpQuery.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpReader.cpp" /> - <ClCompile Include="td\tdnet\td\net\Socks5.cpp" /> - <ClCompile Include="td\tdnet\td\net\SslCtx.cpp" /> - <ClCompile Include="td\tdnet\td\net\SslStream.cpp" /> - <ClCompile Include="td\tdnet\td\net\TcpListener.cpp" /> - <ClCompile Include="td\tdnet\td\net\TransparentProxy.cpp" /> - <ClCompile Include="td\tdnet\td\net\Wget.cpp" /> - <ClInclude Include="td\tdnet\td\net\GetHostByNameActor.h" /> - <ClInclude Include="td\tdnet\td\net\HttpChunkedByteFlow.h" /> - <ClInclude Include="td\tdnet\td\net\HttpConnectionBase.h" /> - <ClInclude Include="td\tdnet\td\net\HttpContentLengthByteFlow.h" /> - <ClInclude Include="td\tdnet\td\net\HttpFile.h" /> - <ClInclude Include="td\tdnet\td\net\HttpHeaderCreator.h" /> - <ClInclude Include="td\tdnet\td\net\HttpInboundConnection.h" /> - <ClInclude Include="td\tdnet\td\net\HttpOutboundConnection.h" /> - <ClInclude Include="td\tdnet\td\net\HttpProxy.h" /> - <ClInclude Include="td\tdnet\td\net\HttpQuery.h" /> - <ClInclude Include="td\tdnet\td\net\HttpReader.h" /> - <ClInclude Include="td\tdnet\td\net\NetStats.h" /> - <ClInclude Include="td\tdnet\td\net\Socks5.h" /> - <ClInclude Include="td\tdnet\td\net\SslCtx.h" /> - <ClInclude Include="td\tdnet\td\net\SslStream.h" /> - <ClInclude Include="td\tdnet\td\net\TcpListener.h" /> - <ClInclude Include="td\tdnet\td\net\TransparentProxy.h" /> - <ClInclude Include="td\tdnet\td\net\Wget.h" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="tdactor.vcxproj"> - <Project>{85F63934-02FE-332A-8703-059040B65512}</Project> - <Name>tdactor</Name> - </ProjectReference> - <ProjectReference Include="tdutils.vcxproj"> - <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project> - <Name>tdutils</Name> - </ProjectReference> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{2246C3CF-7888-3102-984A-80214ADF418C}</ProjectGuid>
+ <ProjectName>tdnet</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\td\tdnet;..\..\..\include;.\td\tdutils;.\td\tdactor;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\tdnet\td\net\GetHostByNameActor.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpChunkedByteFlow.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpConnectionBase.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpContentLengthByteFlow.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpFile.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpInboundConnection.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpOutboundConnection.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpProxy.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpQuery.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpReader.cpp" />
+ <ClCompile Include="td\tdnet\td\net\Socks5.cpp" />
+ <ClCompile Include="td\tdnet\td\net\SslCtx.cpp" />
+ <ClCompile Include="td\tdnet\td\net\SslStream.cpp" />
+ <ClCompile Include="td\tdnet\td\net\TcpListener.cpp" />
+ <ClCompile Include="td\tdnet\td\net\TransparentProxy.cpp" />
+ <ClCompile Include="td\tdnet\td\net\Wget.cpp" />
+ <ClInclude Include="td\tdnet\td\net\GetHostByNameActor.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpChunkedByteFlow.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpConnectionBase.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpContentLengthByteFlow.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpFile.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpHeaderCreator.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpInboundConnection.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpOutboundConnection.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpProxy.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpQuery.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpReader.h" />
+ <ClInclude Include="td\tdnet\td\net\NetStats.h" />
+ <ClInclude Include="td\tdnet\td\net\Socks5.h" />
+ <ClInclude Include="td\tdnet\td\net\SslCtx.h" />
+ <ClInclude Include="td\tdnet\td\net\SslStream.h" />
+ <ClInclude Include="td\tdnet\td\net\TcpListener.h" />
+ <ClInclude Include="td\tdnet\td\net\TransparentProxy.h" />
+ <ClInclude Include="td\tdnet\td\net\Wget.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="tdactor.vcxproj">
+ <Project>{85F63934-02FE-332A-8703-059040B65512}</Project>
+ <Name>tdactor</Name>
+ </ProjectReference>
+ <ProjectReference Include="tdutils.vcxproj">
+ <Project>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</Project>
+ <Name>tdutils</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdnet.vcxproj.filters b/protocols/Telegram/tdlib/tdnet.vcxproj.filters index 87decdbf04..1ea9fed8c4 100644 --- a/protocols/Telegram/tdlib/tdnet.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdnet.vcxproj.filters @@ -1,41 +1,41 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\tdnet\td\net\GetHostByNameActor.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpChunkedByteFlow.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpConnectionBase.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpContentLengthByteFlow.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpFile.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpInboundConnection.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpOutboundConnection.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpQuery.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpReader.cpp" /> - <ClCompile Include="td\tdnet\td\net\Socks5.cpp" /> - <ClCompile Include="td\tdnet\td\net\TcpListener.cpp" /> - <ClCompile Include="td\tdnet\td\net\Wget.cpp" /> - <ClCompile Include="td\tdnet\td\net\HttpProxy.cpp" /> - <ClCompile Include="td\tdnet\td\net\SslCtx.cpp" /> - <ClCompile Include="td\tdnet\td\net\SslStream.cpp" /> - <ClCompile Include="td\tdnet\td\net\TransparentProxy.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\tdnet\td\net\GetHostByNameActor.h" /> - <ClInclude Include="td\tdnet\td\net\HttpChunkedByteFlow.h" /> - <ClInclude Include="td\tdnet\td\net\HttpConnectionBase.h" /> - <ClInclude Include="td\tdnet\td\net\HttpContentLengthByteFlow.h" /> - <ClInclude Include="td\tdnet\td\net\HttpFile.h" /> - <ClInclude Include="td\tdnet\td\net\HttpHeaderCreator.h" /> - <ClInclude Include="td\tdnet\td\net\HttpInboundConnection.h" /> - <ClInclude Include="td\tdnet\td\net\HttpOutboundConnection.h" /> - <ClInclude Include="td\tdnet\td\net\HttpQuery.h" /> - <ClInclude Include="td\tdnet\td\net\HttpReader.h" /> - <ClInclude Include="td\tdnet\td\net\NetStats.h" /> - <ClInclude Include="td\tdnet\td\net\Socks5.h" /> - <ClInclude Include="td\tdnet\td\net\TcpListener.h" /> - <ClInclude Include="td\tdnet\td\net\Wget.h" /> - <ClInclude Include="td\tdnet\td\net\HttpProxy.h" /> - <ClInclude Include="td\tdnet\td\net\SslCtx.h" /> - <ClInclude Include="td\tdnet\td\net\SslStream.h" /> - <ClInclude Include="td\tdnet\td\net\TransparentProxy.h" /> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\tdnet\td\net\GetHostByNameActor.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpChunkedByteFlow.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpConnectionBase.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpContentLengthByteFlow.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpFile.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpInboundConnection.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpOutboundConnection.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpQuery.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpReader.cpp" />
+ <ClCompile Include="td\tdnet\td\net\Socks5.cpp" />
+ <ClCompile Include="td\tdnet\td\net\TcpListener.cpp" />
+ <ClCompile Include="td\tdnet\td\net\Wget.cpp" />
+ <ClCompile Include="td\tdnet\td\net\HttpProxy.cpp" />
+ <ClCompile Include="td\tdnet\td\net\SslCtx.cpp" />
+ <ClCompile Include="td\tdnet\td\net\SslStream.cpp" />
+ <ClCompile Include="td\tdnet\td\net\TransparentProxy.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\tdnet\td\net\GetHostByNameActor.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpChunkedByteFlow.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpConnectionBase.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpContentLengthByteFlow.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpFile.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpHeaderCreator.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpInboundConnection.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpOutboundConnection.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpQuery.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpReader.h" />
+ <ClInclude Include="td\tdnet\td\net\NetStats.h" />
+ <ClInclude Include="td\tdnet\td\net\Socks5.h" />
+ <ClInclude Include="td\tdnet\td\net\TcpListener.h" />
+ <ClInclude Include="td\tdnet\td\net\Wget.h" />
+ <ClInclude Include="td\tdnet\td\net\HttpProxy.h" />
+ <ClInclude Include="td\tdnet\td\net\SslCtx.h" />
+ <ClInclude Include="td\tdnet\td\net\SslStream.h" />
+ <ClInclude Include="td\tdnet\td\net\TransparentProxy.h" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdutils.vcxproj b/protocols/Telegram/tdlib/tdutils.vcxproj index db5abf5030..4db92aa0fb 100644 --- a/protocols/Telegram/tdlib/tdutils.vcxproj +++ b/protocols/Telegram/tdlib/tdutils.vcxproj @@ -1,293 +1,293 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="15.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"> - <ProjectGuid>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</ProjectGuid> - <ProjectName>tdutils</ProjectName> - </PropertyGroup> - <PropertyGroup Label="Configuration"> - <PlatformToolset>v141_xp</PlatformToolset> - </PropertyGroup> - <Import Project="..\..\..\build\vc.common\slib.props" /> - <PropertyGroup> - <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir> - <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir> - </PropertyGroup> - <ItemDefinitionGroup> - <ClCompile> - <AdditionalIncludeDirectories>.\td\tdutils;..\..\..\include;..\..\..\libs\zlib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions> - <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings> - <PrecompiledHeader>NotUsing</PrecompiledHeader> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClCompile Include="td\tdutils\td\utils\AsyncFileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\BufferedUdp.cpp" /> - <ClCompile Include="td\tdutils\td\utils\check.cpp" /> - <ClCompile Include="td\tdutils\td\utils\emoji.cpp" /> - <ClCompile Include="td\tdutils\td\utils\ExitGuard.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FlatHashTable.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FloodControlGlobal.cpp" /> - <ClCompile Include="td\tdutils\td\utils\MpmcQueue.cpp" /> - <ClCompile Include="td\tdutils\td\utils\OptionParser.cpp" /> - <ClCompile Include="td\tdutils\td\utils\PathView.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\Clocks.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Iocp.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\NativeFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\FileFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\inet_ntop.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\IPAddress.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\MemoryMapping.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\path.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\platform.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\PollFlags.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\rlimit.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\RwMutex.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\ServerSocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\signals.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\sleep.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\SocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\stacktrace.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\Stat.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\StdStreams.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\thread_local.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\UdpSocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\uname.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\user.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\wstring_convert.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Epoll.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdBsd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdLinux.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdWindows.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\KQueue.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Poll.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Select.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\WineventPoll.cpp" /> - <ClCompile Include="td\tdutils\generate\auto\mime_type_to_extension.cpp" /> - <ClCompile Include="td\tdutils\generate\auto\extension_to_mime_type.cpp" /> - <ClCompile Include="td\tdutils\td\utils\base64.cpp" /> - <ClCompile Include="td\tdutils\td\utils\BigNum.cpp" /> - <ClCompile Include="td\tdutils\td\utils\buffer.cpp" /> - <ClCompile Include="td\tdutils\td\utils\crypto.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\filesystem.cpp" /> - <ClCompile Include="td\tdutils\td\utils\find_boundary.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Gzip.cpp" /> - <ClCompile Include="td\tdutils\td\utils\GzipByteFlow.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Hints.cpp" /> - <ClCompile Include="td\tdutils\td\utils\HttpUrl.cpp" /> - <ClCompile Include="td\tdutils\td\utils\JsonBuilder.cpp" /> - <ClCompile Include="td\tdutils\td\utils\logging.cpp" /> - <ClCompile Include="td\tdutils\td\utils\misc.cpp" /> - <ClCompile Include="td\tdutils\td\utils\MimeType.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Random.cpp" /> - <ClCompile Include="td\tdutils\td\utils\SharedSlice.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Slice.cpp" /> - <ClCompile Include="td\tdutils\td\utils\StackAllocator.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Status.cpp" /> - <ClCompile Include="td\tdutils\td\utils\StringBuilder.cpp" /> - <ClCompile Include="td\tdutils\td\utils\tests.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Time.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Timer.cpp" /> - <ClCompile Include="td\tdutils\td\utils\tl_parsers.cpp" /> - <ClCompile Include="td\tdutils\td\utils\translit.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsCerr.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsFileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\unicode.cpp" /> - <ClCompile Include="td\tdutils\td\utils\utf8.cpp" /> - <ClInclude Include="td\tdutils\td\utils\algorithm.h" /> - <ClInclude Include="td\tdutils\td\utils\as.h" /> - <ClInclude Include="td\tdutils\td\utils\AsyncFileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\AtomicRead.h" /> - <ClInclude Include="td\tdutils\td\utils\bits.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedUdp.h" /> - <ClInclude Include="td\tdutils\td\utils\CancellationToken.h" /> - <ClInclude Include="td\tdutils\td\utils\ChainScheduler.h" /> - <ClInclude Include="td\tdutils\td\utils\check.h" /> - <ClInclude Include="td\tdutils\td\utils\CombinedLog.h" /> - <ClInclude Include="td\tdutils\td\utils\ConcurrentHashTable.h" /> - <ClInclude Include="td\tdutils\td\utils\config.h" /> - <ClInclude Include="td\tdutils\td\utils\Context.h" /> - <ClInclude Include="td\tdutils\td\utils\DecTree.h" /> - <ClInclude Include="td\tdutils\td\utils\Destructor.h" /> - <ClInclude Include="td\tdutils\td\utils\emoji.h" /> - <ClInclude Include="td\tdutils\td\utils\EpochBasedMemoryReclamation.h" /> - <ClInclude Include="td\tdutils\td\utils\ExitGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\fixed_vector.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashMapChunks.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashTable.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlGlobal.h" /> - <ClInclude Include="td\tdutils\td\utils\Hash.h" /> - <ClInclude Include="td\tdutils\td\utils\HashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\HashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\HashTableUtils.h" /> - <ClInclude Include="td\tdutils\td\utils\MapNode.h" /> - <ClInclude Include="td\tdutils\td\utils\NullLog.h" /> - <ClInclude Include="td\tdutils\td\utils\OptionParser.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Clocks.h" /> - <ClInclude Include="td\tdutils\td\utils\port\config.h" /> - <ClInclude Include="td\tdutils\td\utils\port\CxCli.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Iocp.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\NativeFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\PollableFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\skip_eintr.h" /> - <ClInclude Include="td\tdutils\td\utils\port\EventFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\EventFdBase.h" /> - <ClInclude Include="td\tdutils\td\utils\port\FileFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\FromApp.h" /> - <ClInclude Include="td\tdutils\td\utils\port\IoSlice.h" /> - <ClInclude Include="td\tdutils\td\utils\port\IPAddress.h" /> - <ClInclude Include="td\tdutils\td\utils\port\MemoryMapping.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Mutex.h" /> - <ClInclude Include="td\tdutils\td\utils\port\path.h" /> - <ClInclude Include="td\tdutils\td\utils\port\platform.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Poll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\PollBase.h" /> - <ClInclude Include="td\tdutils\td\utils\port\PollFlags.h" /> - <ClInclude Include="td\tdutils\td\utils\port\rlimit.h" /> - <ClInclude Include="td\tdutils\td\utils\port\RwMutex.h" /> - <ClInclude Include="td\tdutils\td\utils\port\ServerSocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\signals.h" /> - <ClInclude Include="td\tdutils\td\utils\port\sleep.h" /> - <ClInclude Include="td\tdutils\td\utils\port\SocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\stacktrace.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Stat.h" /> - <ClInclude Include="td\tdutils\td\utils\port\StdStreams.h" /> - <ClInclude Include="td\tdutils\td\utils\port\thread.h" /> - <ClInclude Include="td\tdutils\td\utils\port\thread_local.h" /> - <ClInclude Include="td\tdutils\td\utils\port\UdpSocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\uname.h" /> - <ClInclude Include="td\tdutils\td\utils\port\user.h" /> - <ClInclude Include="td\tdutils\td\utils\port\wstring_convert.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Epoll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdBsd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdLinux.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdWindows.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\KQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Poll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Select.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadStl.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\WineventPoll.h" /> - <ClInclude Include="td\tdutils\td\utils\AesCtrByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\base64.h" /> - <ClInclude Include="td\tdutils\td\utils\benchmark.h" /> - <ClInclude Include="td\tdutils\td\utils\BigNum.h" /> - <ClInclude Include="td\tdutils\td\utils\buffer.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedFd.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedReader.h" /> - <ClInclude Include="td\tdutils\td\utils\ByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\ChangesProcessor.h" /> - <ClInclude Include="td\tdutils\td\utils\Closure.h" /> - <ClInclude Include="td\tdutils\td\utils\common.h" /> - <ClInclude Include="td\tdutils\td\utils\Container.h" /> - <ClInclude Include="td\tdutils\td\utils\crypto.h" /> - <ClInclude Include="td\tdutils\td\utils\Enumerator.h" /> - <ClInclude Include="td\tdutils\td\utils\FileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\filesystem.h" /> - <ClInclude Include="td\tdutils\td\utils\find_boundary.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlFast.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlStrict.h" /> - <ClInclude Include="td\tdutils\td\utils\format.h" /> - <ClInclude Include="td\tdutils\td\utils\Gzip.h" /> - <ClInclude Include="td\tdutils\td\utils\GzipByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\HazardPointers.h" /> - <ClInclude Include="td\tdutils\td\utils\Heap.h" /> - <ClInclude Include="td\tdutils\td\utils\Hints.h" /> - <ClInclude Include="td\tdutils\td\utils\HttpUrl.h" /> - <ClInclude Include="td\tdutils\td\utils\int_types.h" /> - <ClInclude Include="td\tdutils\td\utils\invoke.h" /> - <ClInclude Include="td\tdutils\td\utils\JsonBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\List.h" /> - <ClInclude Include="td\tdutils\td\utils\logging.h" /> - <ClInclude Include="td\tdutils\td\utils\MemoryLog.h" /> - <ClInclude Include="td\tdutils\td\utils\MimeType.h" /> - <ClInclude Include="td\tdutils\td\utils\misc.h" /> - <ClInclude Include="td\tdutils\td\utils\MovableValue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpmcQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpmcWaiter.h" /> - <ClInclude Include="td\tdutils\td\utils\MpscPollableQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpscLinkQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\Named.h" /> - <ClInclude Include="td\tdutils\td\utils\ObjectPool.h" /> - <ClInclude Include="td\tdutils\td\utils\Observer.h" /> - <ClInclude Include="td\tdutils\td\utils\optional.h" /> - <ClInclude Include="td\tdutils\td\utils\OptionsParser.h" /> - <ClInclude Include="td\tdutils\td\utils\OrderedEventsProcessor.h" /> - <ClInclude Include="td\tdutils\td\utils\overloaded.h" /> - <ClInclude Include="td\tdutils\td\utils\Parser.h" /> - <ClInclude Include="td\tdutils\td\utils\PathView.h" /> - <ClInclude Include="td\tdutils\td\utils\Promise.h" /> - <ClInclude Include="td\tdutils\td\utils\queue.h" /> - <ClInclude Include="td\tdutils\td\utils\Random.h" /> - <ClInclude Include="td\tdutils\td\utils\ScopeGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\SetNode.h" /> - <ClInclude Include="td\tdutils\td\utils\SharedObjectPool.h" /> - <ClInclude Include="td\tdutils\td\utils\SharedSlice.h" /> - <ClInclude Include="td\tdutils\td\utils\Slice-decl.h" /> - <ClInclude Include="td\tdutils\td\utils\Slice.h" /> - <ClInclude Include="td\tdutils\td\utils\SliceBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\Span.h" /> - <ClInclude Include="td\tdutils\td\utils\SpinLock.h" /> - <ClInclude Include="td\tdutils\td\utils\StackAllocator.h" /> - <ClInclude Include="td\tdutils\td\utils\Status.h" /> - <ClInclude Include="td\tdutils\td\utils\StealingQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\Storer.h" /> - <ClInclude Include="td\tdutils\td\utils\StorerBase.h" /> - <ClInclude Include="td\tdutils\td\utils\StringBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\tests.h" /> - <ClInclude Include="td\tdutils\td\utils\ThreadLocalStorage.h" /> - <ClInclude Include="td\tdutils\td\utils\ThreadSafeCounter.h" /> - <ClInclude Include="td\tdutils\td\utils\Time.h" /> - <ClInclude Include="td\tdutils\td\utils\TimedStat.h" /> - <ClInclude Include="td\tdutils\td\utils\Timer.h" /> - <ClInclude Include="td\tdutils\td\utils\TlDowncastHelper.h" /> - <ClInclude Include="td\tdutils\td\utils\TlStorerToString.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_helpers.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_parsers.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_storers.h" /> - <ClInclude Include="td\tdutils\td\utils\translit.h" /> - <ClInclude Include="td\tdutils\td\utils\TsCerr.h" /> - <ClInclude Include="td\tdutils\td\utils\TsFileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\TsList.h" /> - <ClInclude Include="td\tdutils\td\utils\TsLog.h" /> - <ClInclude Include="td\tdutils\td\utils\type_traits.h" /> - <ClInclude Include="td\tdutils\td\utils\UInt.h" /> - <ClInclude Include="td\tdutils\td\utils\uint128.h" /> - <ClInclude Include="td\tdutils\td\utils\unicode.h" /> - <ClInclude Include="td\tdutils\td\utils\unique_ptr.h" /> - <ClInclude Include="td\tdutils\td\utils\utf8.h" /> - <ClInclude Include="td\tdutils\td\utils\Variant.h" /> - <ClInclude Include="td\tdutils\td\utils\VectorQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeHashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeHashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeVector.h" /> - </ItemGroup> - <ItemGroup> - <None Include="td\tdutils\td\utils\config.h.in" /> - </ItemGroup> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.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">
+ <ProjectGuid>{D21C6A0F-BED1-3377-9659-7FC7D82EFC4F}</ProjectGuid>
+ <ProjectName>tdutils</ProjectName>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration">
+ <PlatformToolset>v141_xp</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="..\..\..\build\vc.common\slib.props" />
+ <PropertyGroup>
+ <OutDir Condition="'$(Platform)'=='Win32'">$(ProjectDir)lib\$(Configuration)32\</OutDir>
+ <OutDir Condition="'$(Platform)'=='x64'">$(ProjectDir)lib\$(Configuration)64\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <AdditionalIncludeDirectories>.\td\tdutils;..\..\..\include;..\..\..\libs\zlib\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
+ <DisableSpecificWarnings>4100;4127;4324;4505;4702</DisableSpecificWarnings>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="td\tdutils\td\utils\AsyncFileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\BufferedUdp.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\check.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\emoji.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\ExitGuard.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FlatHashTable.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FloodControlGlobal.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\MpmcQueue.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\OptionParser.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\PathView.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\Clocks.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Iocp.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\NativeFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\FileFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\inet_ntop.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\IPAddress.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\MemoryMapping.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\path.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\platform.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\PollFlags.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\rlimit.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\RwMutex.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\ServerSocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\signals.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\sleep.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\SocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\stacktrace.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\Stat.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\StdStreams.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\thread_local.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\UdpSocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\uname.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\user.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\wstring_convert.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Epoll.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdBsd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdLinux.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdWindows.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\KQueue.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Poll.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Select.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\WineventPoll.cpp" />
+ <ClCompile Include="td\tdutils\generate\auto\mime_type_to_extension.cpp" />
+ <ClCompile Include="td\tdutils\generate\auto\extension_to_mime_type.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\base64.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\BigNum.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\buffer.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\crypto.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\filesystem.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\find_boundary.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Gzip.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\GzipByteFlow.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Hints.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\HttpUrl.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\JsonBuilder.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\logging.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\misc.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\MimeType.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Random.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\SharedSlice.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Slice.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\StackAllocator.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Status.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\StringBuilder.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\tests.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Time.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Timer.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\tl_parsers.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\translit.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsCerr.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsFileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\unicode.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\utf8.cpp" />
+ <ClInclude Include="td\tdutils\td\utils\algorithm.h" />
+ <ClInclude Include="td\tdutils\td\utils\as.h" />
+ <ClInclude Include="td\tdutils\td\utils\AsyncFileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\AtomicRead.h" />
+ <ClInclude Include="td\tdutils\td\utils\bits.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedUdp.h" />
+ <ClInclude Include="td\tdutils\td\utils\CancellationToken.h" />
+ <ClInclude Include="td\tdutils\td\utils\ChainScheduler.h" />
+ <ClInclude Include="td\tdutils\td\utils\check.h" />
+ <ClInclude Include="td\tdutils\td\utils\CombinedLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\ConcurrentHashTable.h" />
+ <ClInclude Include="td\tdutils\td\utils\config.h" />
+ <ClInclude Include="td\tdutils\td\utils\Context.h" />
+ <ClInclude Include="td\tdutils\td\utils\DecTree.h" />
+ <ClInclude Include="td\tdutils\td\utils\Destructor.h" />
+ <ClInclude Include="td\tdutils\td\utils\emoji.h" />
+ <ClInclude Include="td\tdutils\td\utils\EpochBasedMemoryReclamation.h" />
+ <ClInclude Include="td\tdutils\td\utils\ExitGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\fixed_vector.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashMapChunks.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashTable.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlGlobal.h" />
+ <ClInclude Include="td\tdutils\td\utils\Hash.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashTableUtils.h" />
+ <ClInclude Include="td\tdutils\td\utils\MapNode.h" />
+ <ClInclude Include="td\tdutils\td\utils\NullLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\OptionParser.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Clocks.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\config.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\CxCli.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Iocp.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\NativeFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\PollableFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\skip_eintr.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\EventFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\EventFdBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\FileFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\FromApp.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\IoSlice.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\IPAddress.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\MemoryMapping.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Mutex.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\path.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\platform.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Poll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\PollBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\PollFlags.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\rlimit.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\RwMutex.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\ServerSocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\signals.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\sleep.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\SocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\stacktrace.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Stat.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\StdStreams.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\thread.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\thread_local.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\UdpSocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\uname.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\user.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\wstring_convert.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Epoll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdBsd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdLinux.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdWindows.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\KQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Poll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Select.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadStl.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\WineventPoll.h" />
+ <ClInclude Include="td\tdutils\td\utils\AesCtrByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\base64.h" />
+ <ClInclude Include="td\tdutils\td\utils\benchmark.h" />
+ <ClInclude Include="td\tdutils\td\utils\BigNum.h" />
+ <ClInclude Include="td\tdutils\td\utils\buffer.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedReader.h" />
+ <ClInclude Include="td\tdutils\td\utils\ByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\ChangesProcessor.h" />
+ <ClInclude Include="td\tdutils\td\utils\Closure.h" />
+ <ClInclude Include="td\tdutils\td\utils\common.h" />
+ <ClInclude Include="td\tdutils\td\utils\Container.h" />
+ <ClInclude Include="td\tdutils\td\utils\crypto.h" />
+ <ClInclude Include="td\tdutils\td\utils\Enumerator.h" />
+ <ClInclude Include="td\tdutils\td\utils\FileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\filesystem.h" />
+ <ClInclude Include="td\tdutils\td\utils\find_boundary.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlFast.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlStrict.h" />
+ <ClInclude Include="td\tdutils\td\utils\format.h" />
+ <ClInclude Include="td\tdutils\td\utils\Gzip.h" />
+ <ClInclude Include="td\tdutils\td\utils\GzipByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\HazardPointers.h" />
+ <ClInclude Include="td\tdutils\td\utils\Heap.h" />
+ <ClInclude Include="td\tdutils\td\utils\Hints.h" />
+ <ClInclude Include="td\tdutils\td\utils\HttpUrl.h" />
+ <ClInclude Include="td\tdutils\td\utils\int_types.h" />
+ <ClInclude Include="td\tdutils\td\utils\invoke.h" />
+ <ClInclude Include="td\tdutils\td\utils\JsonBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\List.h" />
+ <ClInclude Include="td\tdutils\td\utils\logging.h" />
+ <ClInclude Include="td\tdutils\td\utils\MemoryLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\MimeType.h" />
+ <ClInclude Include="td\tdutils\td\utils\misc.h" />
+ <ClInclude Include="td\tdutils\td\utils\MovableValue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpmcQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpmcWaiter.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpscPollableQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpscLinkQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\Named.h" />
+ <ClInclude Include="td\tdutils\td\utils\ObjectPool.h" />
+ <ClInclude Include="td\tdutils\td\utils\Observer.h" />
+ <ClInclude Include="td\tdutils\td\utils\optional.h" />
+ <ClInclude Include="td\tdutils\td\utils\OptionsParser.h" />
+ <ClInclude Include="td\tdutils\td\utils\OrderedEventsProcessor.h" />
+ <ClInclude Include="td\tdutils\td\utils\overloaded.h" />
+ <ClInclude Include="td\tdutils\td\utils\Parser.h" />
+ <ClInclude Include="td\tdutils\td\utils\PathView.h" />
+ <ClInclude Include="td\tdutils\td\utils\Promise.h" />
+ <ClInclude Include="td\tdutils\td\utils\queue.h" />
+ <ClInclude Include="td\tdutils\td\utils\Random.h" />
+ <ClInclude Include="td\tdutils\td\utils\ScopeGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\SetNode.h" />
+ <ClInclude Include="td\tdutils\td\utils\SharedObjectPool.h" />
+ <ClInclude Include="td\tdutils\td\utils\SharedSlice.h" />
+ <ClInclude Include="td\tdutils\td\utils\Slice-decl.h" />
+ <ClInclude Include="td\tdutils\td\utils\Slice.h" />
+ <ClInclude Include="td\tdutils\td\utils\SliceBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\Span.h" />
+ <ClInclude Include="td\tdutils\td\utils\SpinLock.h" />
+ <ClInclude Include="td\tdutils\td\utils\StackAllocator.h" />
+ <ClInclude Include="td\tdutils\td\utils\Status.h" />
+ <ClInclude Include="td\tdutils\td\utils\StealingQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\Storer.h" />
+ <ClInclude Include="td\tdutils\td\utils\StorerBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\StringBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\tests.h" />
+ <ClInclude Include="td\tdutils\td\utils\ThreadLocalStorage.h" />
+ <ClInclude Include="td\tdutils\td\utils\ThreadSafeCounter.h" />
+ <ClInclude Include="td\tdutils\td\utils\Time.h" />
+ <ClInclude Include="td\tdutils\td\utils\TimedStat.h" />
+ <ClInclude Include="td\tdutils\td\utils\Timer.h" />
+ <ClInclude Include="td\tdutils\td\utils\TlDowncastHelper.h" />
+ <ClInclude Include="td\tdutils\td\utils\TlStorerToString.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_helpers.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_parsers.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_storers.h" />
+ <ClInclude Include="td\tdutils\td\utils\translit.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsCerr.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsFileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsList.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\type_traits.h" />
+ <ClInclude Include="td\tdutils\td\utils\UInt.h" />
+ <ClInclude Include="td\tdutils\td\utils\uint128.h" />
+ <ClInclude Include="td\tdutils\td\utils\unicode.h" />
+ <ClInclude Include="td\tdutils\td\utils\unique_ptr.h" />
+ <ClInclude Include="td\tdutils\td\utils\utf8.h" />
+ <ClInclude Include="td\tdutils\td\utils\Variant.h" />
+ <ClInclude Include="td\tdutils\td\utils\VectorQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeHashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeHashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeVector.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="td\tdutils\td\utils\config.h.in" />
+ </ItemGroup>
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
</Project>
\ No newline at end of file diff --git a/protocols/Telegram/tdlib/tdutils.vcxproj.filters b/protocols/Telegram/tdlib/tdutils.vcxproj.filters index 5aa66dd4d0..c7b27bd63d 100644 --- a/protocols/Telegram/tdlib/tdutils.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdutils.vcxproj.filters @@ -1,255 +1,255 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClCompile Include="td\tdutils\td\utils\port\Clocks.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\FileFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\IPAddress.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\path.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\ServerSocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\signals.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\sleep.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\SocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\Stat.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\thread_local.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\wstring_convert.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Epoll.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdBsd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdLinux.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdWindows.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\KQueue.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Poll.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Select.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\WineventPoll.cpp" /> - <ClCompile Include="td\tdutils\generate\auto\mime_type_to_extension.cpp" /> - <ClCompile Include="td\tdutils\generate\auto\extension_to_mime_type.cpp" /> - <ClCompile Include="td\tdutils\td\utils\base64.cpp" /> - <ClCompile Include="td\tdutils\td\utils\BigNum.cpp" /> - <ClCompile Include="td\tdutils\td\utils\buffer.cpp" /> - <ClCompile Include="td\tdutils\td\utils\crypto.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\filesystem.cpp" /> - <ClCompile Include="td\tdutils\td\utils\find_boundary.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Gzip.cpp" /> - <ClCompile Include="td\tdutils\td\utils\GzipByteFlow.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Hints.cpp" /> - <ClCompile Include="td\tdutils\td\utils\HttpUrl.cpp" /> - <ClCompile Include="td\tdutils\td\utils\JsonBuilder.cpp" /> - <ClCompile Include="td\tdutils\td\utils\logging.cpp" /> - <ClCompile Include="td\tdutils\td\utils\misc.cpp" /> - <ClCompile Include="td\tdutils\td\utils\MimeType.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Random.cpp" /> - <ClCompile Include="td\tdutils\td\utils\StackAllocator.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Status.cpp" /> - <ClCompile Include="td\tdutils\td\utils\StringBuilder.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Time.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Timer.cpp" /> - <ClCompile Include="td\tdutils\td\utils\tl_parsers.cpp" /> - <ClCompile Include="td\tdutils\td\utils\unicode.cpp" /> - <ClCompile Include="td\tdutils\td\utils\utf8.cpp" /> - <ClCompile Include="td\tdutils\td\utils\check.cpp" /> - <ClCompile Include="td\tdutils\td\utils\AsyncFileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\BufferedUdp.cpp" /> - <ClCompile Include="td\tdutils\td\utils\emoji.cpp" /> - <ClCompile Include="td\tdutils\td\utils\ExitGuard.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FlatHashTable.cpp" /> - <ClCompile Include="td\tdutils\td\utils\FloodControlGlobal.cpp" /> - <ClCompile Include="td\tdutils\td\utils\MpmcQueue.cpp" /> - <ClCompile Include="td\tdutils\td\utils\OptionParser.cpp" /> - <ClCompile Include="td\tdutils\td\utils\PathView.cpp" /> - <ClCompile Include="td\tdutils\td\utils\SharedSlice.cpp" /> - <ClCompile Include="td\tdutils\td\utils\Slice.cpp" /> - <ClCompile Include="td\tdutils\td\utils\tests.cpp" /> - <ClCompile Include="td\tdutils\td\utils\translit.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsCerr.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsFileLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\TsLog.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\MemoryMapping.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\platform.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\PollFlags.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\rlimit.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\stacktrace.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\StdStreams.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\UdpSocketFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\uname.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\user.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\Iocp.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\detail\NativeFd.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\RwMutex.cpp" /> - <ClCompile Include="td\tdutils\td\utils\port\inet_ntop.cpp" /> - </ItemGroup> - <ItemGroup> - <ClInclude Include="td\tdutils\td\utils\port\Clocks.h" /> - <ClInclude Include="td\tdutils\td\utils\port\config.h" /> - <ClInclude Include="td\tdutils\td\utils\port\CxCli.h" /> - <ClInclude Include="td\tdutils\td\utils\port\EventFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\EventFdBase.h" /> - <ClInclude Include="td\tdutils\td\utils\port\FileFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\IPAddress.h" /> - <ClInclude Include="td\tdutils\td\utils\port\path.h" /> - <ClInclude Include="td\tdutils\td\utils\port\platform.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Poll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\PollBase.h" /> - <ClInclude Include="td\tdutils\td\utils\port\RwMutex.h" /> - <ClInclude Include="td\tdutils\td\utils\port\ServerSocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\signals.h" /> - <ClInclude Include="td\tdutils\td\utils\port\sleep.h" /> - <ClInclude Include="td\tdutils\td\utils\port\SocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Stat.h" /> - <ClInclude Include="td\tdutils\td\utils\port\thread.h" /> - <ClInclude Include="td\tdutils\td\utils\port\thread_local.h" /> - <ClInclude Include="td\tdutils\td\utils\port\wstring_convert.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Epoll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdBsd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdLinux.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdWindows.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\KQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Poll.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Select.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadStl.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\WineventPoll.h" /> - <ClInclude Include="td\tdutils\td\utils\AesCtrByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\base64.h" /> - <ClInclude Include="td\tdutils\td\utils\benchmark.h" /> - <ClInclude Include="td\tdutils\td\utils\BigNum.h" /> - <ClInclude Include="td\tdutils\td\utils\buffer.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedFd.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedReader.h" /> - <ClInclude Include="td\tdutils\td\utils\ByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\ChangesProcessor.h" /> - <ClInclude Include="td\tdutils\td\utils\Closure.h" /> - <ClInclude Include="td\tdutils\td\utils\common.h" /> - <ClInclude Include="td\tdutils\td\utils\Container.h" /> - <ClInclude Include="td\tdutils\td\utils\crypto.h" /> - <ClInclude Include="td\tdutils\td\utils\Enumerator.h" /> - <ClInclude Include="td\tdutils\td\utils\FileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\filesystem.h" /> - <ClInclude Include="td\tdutils\td\utils\find_boundary.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlFast.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlStrict.h" /> - <ClInclude Include="td\tdutils\td\utils\format.h" /> - <ClInclude Include="td\tdutils\td\utils\Gzip.h" /> - <ClInclude Include="td\tdutils\td\utils\GzipByteFlow.h" /> - <ClInclude Include="td\tdutils\td\utils\HazardPointers.h" /> - <ClInclude Include="td\tdutils\td\utils\Heap.h" /> - <ClInclude Include="td\tdutils\td\utils\Hints.h" /> - <ClInclude Include="td\tdutils\td\utils\HttpUrl.h" /> - <ClInclude Include="td\tdutils\td\utils\int_types.h" /> - <ClInclude Include="td\tdutils\td\utils\invoke.h" /> - <ClInclude Include="td\tdutils\td\utils\JsonBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\List.h" /> - <ClInclude Include="td\tdutils\td\utils\logging.h" /> - <ClInclude Include="td\tdutils\td\utils\MemoryLog.h" /> - <ClInclude Include="td\tdutils\td\utils\MimeType.h" /> - <ClInclude Include="td\tdutils\td\utils\misc.h" /> - <ClInclude Include="td\tdutils\td\utils\MovableValue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpmcQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpmcWaiter.h" /> - <ClInclude Include="td\tdutils\td\utils\MpscPollableQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\MpscLinkQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\Named.h" /> - <ClInclude Include="td\tdutils\td\utils\ObjectPool.h" /> - <ClInclude Include="td\tdutils\td\utils\Observer.h" /> - <ClInclude Include="td\tdutils\td\utils\optional.h" /> - <ClInclude Include="td\tdutils\td\utils\OptionsParser.h" /> - <ClInclude Include="td\tdutils\td\utils\OrderedEventsProcessor.h" /> - <ClInclude Include="td\tdutils\td\utils\overloaded.h" /> - <ClInclude Include="td\tdutils\td\utils\Parser.h" /> - <ClInclude Include="td\tdutils\td\utils\PathView.h" /> - <ClInclude Include="td\tdutils\td\utils\queue.h" /> - <ClInclude Include="td\tdutils\td\utils\Random.h" /> - <ClInclude Include="td\tdutils\td\utils\ScopeGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\SharedObjectPool.h" /> - <ClInclude Include="td\tdutils\td\utils\Slice-decl.h" /> - <ClInclude Include="td\tdutils\td\utils\Slice.h" /> - <ClInclude Include="td\tdutils\td\utils\SpinLock.h" /> - <ClInclude Include="td\tdutils\td\utils\StackAllocator.h" /> - <ClInclude Include="td\tdutils\td\utils\Status.h" /> - <ClInclude Include="td\tdutils\td\utils\Storer.h" /> - <ClInclude Include="td\tdutils\td\utils\StorerBase.h" /> - <ClInclude Include="td\tdutils\td\utils\StringBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\tests.h" /> - <ClInclude Include="td\tdutils\td\utils\Time.h" /> - <ClInclude Include="td\tdutils\td\utils\TimedStat.h" /> - <ClInclude Include="td\tdutils\td\utils\Timer.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_helpers.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_parsers.h" /> - <ClInclude Include="td\tdutils\td\utils\tl_storers.h" /> - <ClInclude Include="td\tdutils\td\utils\type_traits.h" /> - <ClInclude Include="td\tdutils\td\utils\unicode.h" /> - <ClInclude Include="td\tdutils\td\utils\utf8.h" /> - <ClInclude Include="td\tdutils\td\utils\Variant.h" /> - <ClInclude Include="td\tdutils\td\utils\check.h" /> - <ClInclude Include="td\tdutils\td\utils\algorithm.h" /> - <ClInclude Include="td\tdutils\td\utils\as.h" /> - <ClInclude Include="td\tdutils\td\utils\AsyncFileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\AtomicRead.h" /> - <ClInclude Include="td\tdutils\td\utils\bits.h" /> - <ClInclude Include="td\tdutils\td\utils\BufferedUdp.h" /> - <ClInclude Include="td\tdutils\td\utils\CancellationToken.h" /> - <ClInclude Include="td\tdutils\td\utils\ChainScheduler.h" /> - <ClInclude Include="td\tdutils\td\utils\CombinedLog.h" /> - <ClInclude Include="td\tdutils\td\utils\ConcurrentHashTable.h" /> - <ClInclude Include="td\tdutils\td\utils\config.h" /> - <ClInclude Include="td\tdutils\td\utils\Context.h" /> - <ClInclude Include="td\tdutils\td\utils\DecTree.h" /> - <ClInclude Include="td\tdutils\td\utils\Destructor.h" /> - <ClInclude Include="td\tdutils\td\utils\emoji.h" /> - <ClInclude Include="td\tdutils\td\utils\EpochBasedMemoryReclamation.h" /> - <ClInclude Include="td\tdutils\td\utils\ExitGuard.h" /> - <ClInclude Include="td\tdutils\td\utils\fixed_vector.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashMapChunks.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\FlatHashTable.h" /> - <ClInclude Include="td\tdutils\td\utils\FloodControlGlobal.h" /> - <ClInclude Include="td\tdutils\td\utils\Hash.h" /> - <ClInclude Include="td\tdutils\td\utils\HashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\HashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\HashTableUtils.h" /> - <ClInclude Include="td\tdutils\td\utils\MapNode.h" /> - <ClInclude Include="td\tdutils\td\utils\NullLog.h" /> - <ClInclude Include="td\tdutils\td\utils\OptionParser.h" /> - <ClInclude Include="td\tdutils\td\utils\Promise.h" /> - <ClInclude Include="td\tdutils\td\utils\SetNode.h" /> - <ClInclude Include="td\tdutils\td\utils\SharedSlice.h" /> - <ClInclude Include="td\tdutils\td\utils\SliceBuilder.h" /> - <ClInclude Include="td\tdutils\td\utils\Span.h" /> - <ClInclude Include="td\tdutils\td\utils\StealingQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\ThreadLocalStorage.h" /> - <ClInclude Include="td\tdutils\td\utils\ThreadSafeCounter.h" /> - <ClInclude Include="td\tdutils\td\utils\TlDowncastHelper.h" /> - <ClInclude Include="td\tdutils\td\utils\TlStorerToString.h" /> - <ClInclude Include="td\tdutils\td\utils\translit.h" /> - <ClInclude Include="td\tdutils\td\utils\TsCerr.h" /> - <ClInclude Include="td\tdutils\td\utils\TsFileLog.h" /> - <ClInclude Include="td\tdutils\td\utils\TsList.h" /> - <ClInclude Include="td\tdutils\td\utils\TsLog.h" /> - <ClInclude Include="td\tdutils\td\utils\UInt.h" /> - <ClInclude Include="td\tdutils\td\utils\uint128.h" /> - <ClInclude Include="td\tdutils\td\utils\unique_ptr.h" /> - <ClInclude Include="td\tdutils\td\utils\VectorQueue.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeHashMap.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeHashSet.h" /> - <ClInclude Include="td\tdutils\td\utils\WaitFreeVector.h" /> - <ClInclude Include="td\tdutils\td\utils\port\FromApp.h" /> - <ClInclude Include="td\tdutils\td\utils\port\IoSlice.h" /> - <ClInclude Include="td\tdutils\td\utils\port\MemoryMapping.h" /> - <ClInclude Include="td\tdutils\td\utils\port\Mutex.h" /> - <ClInclude Include="td\tdutils\td\utils\port\PollFlags.h" /> - <ClInclude Include="td\tdutils\td\utils\port\rlimit.h" /> - <ClInclude Include="td\tdutils\td\utils\port\stacktrace.h" /> - <ClInclude Include="td\tdutils\td\utils\port\StdStreams.h" /> - <ClInclude Include="td\tdutils\td\utils\port\UdpSocketFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\uname.h" /> - <ClInclude Include="td\tdutils\td\utils\port\user.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\Iocp.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\NativeFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\PollableFd.h" /> - <ClInclude Include="td\tdutils\td\utils\port\detail\skip_eintr.h" /> - </ItemGroup> - <ItemGroup> - <None Include="td\tdutils\td\utils\config.h.in" /> - </ItemGroup> +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="td\tdutils\td\utils\port\Clocks.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\FileFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\IPAddress.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\path.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\ServerSocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\signals.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\sleep.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\SocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\Stat.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\thread_local.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\wstring_convert.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Epoll.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdBsd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdLinux.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\EventFdWindows.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\KQueue.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Poll.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Select.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\WineventPoll.cpp" />
+ <ClCompile Include="td\tdutils\generate\auto\mime_type_to_extension.cpp" />
+ <ClCompile Include="td\tdutils\generate\auto\extension_to_mime_type.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\base64.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\BigNum.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\buffer.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\crypto.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\filesystem.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\find_boundary.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Gzip.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\GzipByteFlow.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Hints.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\HttpUrl.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\JsonBuilder.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\logging.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\misc.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\MimeType.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Random.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\StackAllocator.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Status.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\StringBuilder.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Time.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Timer.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\tl_parsers.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\unicode.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\utf8.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\check.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\AsyncFileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\BufferedUdp.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\emoji.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\ExitGuard.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FlatHashTable.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\FloodControlGlobal.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\MpmcQueue.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\OptionParser.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\PathView.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\SharedSlice.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\Slice.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\tests.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\translit.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsCerr.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsFileLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\TsLog.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\MemoryMapping.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\platform.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\PollFlags.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\rlimit.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\stacktrace.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\StdStreams.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\UdpSocketFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\uname.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\user.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\Iocp.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\detail\NativeFd.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\RwMutex.cpp" />
+ <ClCompile Include="td\tdutils\td\utils\port\inet_ntop.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="td\tdutils\td\utils\port\Clocks.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\config.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\CxCli.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\EventFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\EventFdBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\FileFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\IPAddress.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\path.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\platform.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Poll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\PollBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\RwMutex.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\ServerSocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\signals.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\sleep.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\SocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Stat.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\thread.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\thread_local.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\wstring_convert.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Epoll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdBsd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdLinux.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\EventFdWindows.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\KQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Poll.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Select.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadIdGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\ThreadStl.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\WineventPoll.h" />
+ <ClInclude Include="td\tdutils\td\utils\AesCtrByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\base64.h" />
+ <ClInclude Include="td\tdutils\td\utils\benchmark.h" />
+ <ClInclude Include="td\tdutils\td\utils\BigNum.h" />
+ <ClInclude Include="td\tdutils\td\utils\buffer.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedReader.h" />
+ <ClInclude Include="td\tdutils\td\utils\ByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\ChangesProcessor.h" />
+ <ClInclude Include="td\tdutils\td\utils\Closure.h" />
+ <ClInclude Include="td\tdutils\td\utils\common.h" />
+ <ClInclude Include="td\tdutils\td\utils\Container.h" />
+ <ClInclude Include="td\tdutils\td\utils\crypto.h" />
+ <ClInclude Include="td\tdutils\td\utils\Enumerator.h" />
+ <ClInclude Include="td\tdutils\td\utils\FileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\filesystem.h" />
+ <ClInclude Include="td\tdutils\td\utils\find_boundary.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlFast.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlStrict.h" />
+ <ClInclude Include="td\tdutils\td\utils\format.h" />
+ <ClInclude Include="td\tdutils\td\utils\Gzip.h" />
+ <ClInclude Include="td\tdutils\td\utils\GzipByteFlow.h" />
+ <ClInclude Include="td\tdutils\td\utils\HazardPointers.h" />
+ <ClInclude Include="td\tdutils\td\utils\Heap.h" />
+ <ClInclude Include="td\tdutils\td\utils\Hints.h" />
+ <ClInclude Include="td\tdutils\td\utils\HttpUrl.h" />
+ <ClInclude Include="td\tdutils\td\utils\int_types.h" />
+ <ClInclude Include="td\tdutils\td\utils\invoke.h" />
+ <ClInclude Include="td\tdutils\td\utils\JsonBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\List.h" />
+ <ClInclude Include="td\tdutils\td\utils\logging.h" />
+ <ClInclude Include="td\tdutils\td\utils\MemoryLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\MimeType.h" />
+ <ClInclude Include="td\tdutils\td\utils\misc.h" />
+ <ClInclude Include="td\tdutils\td\utils\MovableValue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpmcQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpmcWaiter.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpscPollableQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\MpscLinkQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\Named.h" />
+ <ClInclude Include="td\tdutils\td\utils\ObjectPool.h" />
+ <ClInclude Include="td\tdutils\td\utils\Observer.h" />
+ <ClInclude Include="td\tdutils\td\utils\optional.h" />
+ <ClInclude Include="td\tdutils\td\utils\OptionsParser.h" />
+ <ClInclude Include="td\tdutils\td\utils\OrderedEventsProcessor.h" />
+ <ClInclude Include="td\tdutils\td\utils\overloaded.h" />
+ <ClInclude Include="td\tdutils\td\utils\Parser.h" />
+ <ClInclude Include="td\tdutils\td\utils\PathView.h" />
+ <ClInclude Include="td\tdutils\td\utils\queue.h" />
+ <ClInclude Include="td\tdutils\td\utils\Random.h" />
+ <ClInclude Include="td\tdutils\td\utils\ScopeGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\SharedObjectPool.h" />
+ <ClInclude Include="td\tdutils\td\utils\Slice-decl.h" />
+ <ClInclude Include="td\tdutils\td\utils\Slice.h" />
+ <ClInclude Include="td\tdutils\td\utils\SpinLock.h" />
+ <ClInclude Include="td\tdutils\td\utils\StackAllocator.h" />
+ <ClInclude Include="td\tdutils\td\utils\Status.h" />
+ <ClInclude Include="td\tdutils\td\utils\Storer.h" />
+ <ClInclude Include="td\tdutils\td\utils\StorerBase.h" />
+ <ClInclude Include="td\tdutils\td\utils\StringBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\tests.h" />
+ <ClInclude Include="td\tdutils\td\utils\Time.h" />
+ <ClInclude Include="td\tdutils\td\utils\TimedStat.h" />
+ <ClInclude Include="td\tdutils\td\utils\Timer.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_helpers.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_parsers.h" />
+ <ClInclude Include="td\tdutils\td\utils\tl_storers.h" />
+ <ClInclude Include="td\tdutils\td\utils\type_traits.h" />
+ <ClInclude Include="td\tdutils\td\utils\unicode.h" />
+ <ClInclude Include="td\tdutils\td\utils\utf8.h" />
+ <ClInclude Include="td\tdutils\td\utils\Variant.h" />
+ <ClInclude Include="td\tdutils\td\utils\check.h" />
+ <ClInclude Include="td\tdutils\td\utils\algorithm.h" />
+ <ClInclude Include="td\tdutils\td\utils\as.h" />
+ <ClInclude Include="td\tdutils\td\utils\AsyncFileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\AtomicRead.h" />
+ <ClInclude Include="td\tdutils\td\utils\bits.h" />
+ <ClInclude Include="td\tdutils\td\utils\BufferedUdp.h" />
+ <ClInclude Include="td\tdutils\td\utils\CancellationToken.h" />
+ <ClInclude Include="td\tdutils\td\utils\ChainScheduler.h" />
+ <ClInclude Include="td\tdutils\td\utils\CombinedLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\ConcurrentHashTable.h" />
+ <ClInclude Include="td\tdutils\td\utils\config.h" />
+ <ClInclude Include="td\tdutils\td\utils\Context.h" />
+ <ClInclude Include="td\tdutils\td\utils\DecTree.h" />
+ <ClInclude Include="td\tdutils\td\utils\Destructor.h" />
+ <ClInclude Include="td\tdutils\td\utils\emoji.h" />
+ <ClInclude Include="td\tdutils\td\utils\EpochBasedMemoryReclamation.h" />
+ <ClInclude Include="td\tdutils\td\utils\ExitGuard.h" />
+ <ClInclude Include="td\tdutils\td\utils\fixed_vector.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashMapChunks.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\FlatHashTable.h" />
+ <ClInclude Include="td\tdutils\td\utils\FloodControlGlobal.h" />
+ <ClInclude Include="td\tdutils\td\utils\Hash.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\HashTableUtils.h" />
+ <ClInclude Include="td\tdutils\td\utils\MapNode.h" />
+ <ClInclude Include="td\tdutils\td\utils\NullLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\OptionParser.h" />
+ <ClInclude Include="td\tdutils\td\utils\Promise.h" />
+ <ClInclude Include="td\tdutils\td\utils\SetNode.h" />
+ <ClInclude Include="td\tdutils\td\utils\SharedSlice.h" />
+ <ClInclude Include="td\tdutils\td\utils\SliceBuilder.h" />
+ <ClInclude Include="td\tdutils\td\utils\Span.h" />
+ <ClInclude Include="td\tdutils\td\utils\StealingQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\ThreadLocalStorage.h" />
+ <ClInclude Include="td\tdutils\td\utils\ThreadSafeCounter.h" />
+ <ClInclude Include="td\tdutils\td\utils\TlDowncastHelper.h" />
+ <ClInclude Include="td\tdutils\td\utils\TlStorerToString.h" />
+ <ClInclude Include="td\tdutils\td\utils\translit.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsCerr.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsFileLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsList.h" />
+ <ClInclude Include="td\tdutils\td\utils\TsLog.h" />
+ <ClInclude Include="td\tdutils\td\utils\UInt.h" />
+ <ClInclude Include="td\tdutils\td\utils\uint128.h" />
+ <ClInclude Include="td\tdutils\td\utils\unique_ptr.h" />
+ <ClInclude Include="td\tdutils\td\utils\VectorQueue.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeHashMap.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeHashSet.h" />
+ <ClInclude Include="td\tdutils\td\utils\WaitFreeVector.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\FromApp.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\IoSlice.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\MemoryMapping.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\Mutex.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\PollFlags.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\rlimit.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\stacktrace.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\StdStreams.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\UdpSocketFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\uname.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\user.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\Iocp.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\NativeFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\PollableFd.h" />
+ <ClInclude Include="td\tdutils\td\utils\port\detail\skip_eintr.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="td\tdutils\td\utils\config.h.in" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp index d298f880d2..9607045131 100644 --- a/protocols/WhatsApp/src/appsync.cpp +++ b/protocols/WhatsApp/src/appsync.cpp @@ -1,322 +1,322 @@ -/* - -WhatsApp plugin for Miranda NG -Copyright © 2019-23 George Hazan - -*/ - -#include "stdafx.h" - -////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::InitSync() -{ - m_arCollections.insert(new WACollection("regular")); - m_arCollections.insert(new WACollection("regular_high")); - m_arCollections.insert(new WACollection("regular_low")); - m_arCollections.insert(new WACollection("critical_block")); - m_arCollections.insert(new WACollection("critical_unblock_low")); - - for (auto &it : m_arCollections) { - CMStringW wszPath(GetTmpFileName("collection", it->szName)); - wszPath.Append(L".json"); - if (_waccess(wszPath, 0)) - continue; - - JSONNode root = JSONNode::parse(file2string(wszPath)); - it->version = root["version"].as_int(); - - auto szHash = decodeBinStr(root["hash"].as_string()); - if (szHash.size() == sizeof(it->hash.hash)) - memcpy(it->hash.hash, szHash.c_str(), sizeof(it->hash.hash)); - - for (auto &val : root["indexValueMap"]) - it->indexValueMap[decodeBinStr(val.name())] = decodeBinStr(val.as_string()); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::OnServerSync(const WANode &node) -{ - OBJLIST<WACollection> task(1); - - for (auto &it : node.getChildren()) - if (it->title == "collection") - task.insert(new WACollection(it->getAttr("name"), it->getAttrInt("version"))); - - ResyncServer(task); - SendAck(node); -} - -void WhatsAppProto::ResyncAll() -{ - ResyncServer(m_arCollections); -} - -void WhatsAppProto::ResyncServer(const OBJLIST<WACollection> &task) -{ - WANodeIq iq(IQ::SET, "w:sync:app:state"); - - auto *pList = iq.addChild("sync"); - for (auto &it : task) { - auto *pCollection = m_arCollections.find(it); - if (pCollection == nullptr) - m_arCollections.insert(pCollection = new WACollection(it->szName, 0)); - - if (!pCollection->version || pCollection->version < it->version) { - auto *pNode = pList->addChild("collection"); - *pNode << CHAR_PARAM("name", it->szName) << INT_PARAM("version", pCollection->version) - << CHAR_PARAM("return_snapshot", (!pCollection->version) ? "true" : "false"); - } - } - - if (pList->getFirstChild() != nullptr) - WSSendNode(iq, &WhatsAppProto::OnIqServerSync); -} - -void WhatsAppProto::OnIqServerSync(const WANode &node) -{ - for (auto &coll : node.getChild("sync")->getChildren()) { - if (coll->title != "collection") - continue; - - auto *pszName = coll->getAttr("name"); - - auto *pCollection = FindCollection(pszName); - if (pCollection == nullptr) { - pCollection = new WACollection(pszName, 0); - m_arCollections.insert(pCollection); - } - - int dwVersion = 0; - - CMStringW wszSnapshotPath(GetTmpFileName("collection", pszName)); - if (auto *pSnapshot = coll->getChild("snapshot")) { - proto::ExternalBlobReference body(pSnapshot->content); - if (!body->directpath || !body->has_mediakey) { - debugLogA("Invalid snapshot data, skipping"); - continue; - } - - MBinBuffer buf = DownloadEncryptedFile(directPath2url(body->directpath), body->mediakey, "App State"); - if (buf.isEmpty()) { - debugLogA("Invalid downloaded snapshot data, skipping"); - continue; - } - - proto::SyncdSnapshot snapshot(unpadBuffer16(buf)); - if (!snapshot) { - debugLogA("%s: unable to decode snapshot, skipping"); - continue; - } - - dwVersion = snapshot->version->version; - if (dwVersion > pCollection->version) { - pCollection->hash.init(); - debugLogA("%s: applying snapshot of version %d", pCollection->szName.get(), dwVersion); - for (int i=0; i < snapshot->n_records; i++) - ParsePatch(pCollection, snapshot->records[i], true); - } - else debugLogA("%s: skipping snapshot of version %d", pCollection->szName.get(), dwVersion); - } - - if (auto *pPatchList = coll->getChild("patches")) { - for (auto &it : pPatchList->getChildren()) { - proto::SyncdPatch patch(it->content); - if (!patch) { - debugLogA("%s: unable to decode patch, skipping"); - continue; - } - - dwVersion = patch->version->version; - if (dwVersion > pCollection->version) { - debugLogA("%s: applying patch of version %d", pCollection->szName.get(), dwVersion); - for (int i = 0; i < patch->n_mutations; i++) { - auto &jt = *patch->mutations[i]; - ParsePatch(pCollection, jt.record, jt.operation == WA__SYNCD_MUTATION__SYNCD_OPERATION__SET); - } - } - else debugLogA("%s: skipping patch of version %d", pCollection->szName.get(), dwVersion); - } - } - - JSONNode jsonRoot, jsonMap; - for (auto &it : pCollection->indexValueMap) - jsonMap << CHAR_PARAM(ptrA(mir_base64_encode(it.first.c_str(), it.first.size())), ptrA(mir_base64_encode(it.second.c_str(), it.second.size()))); - jsonRoot << INT_PARAM("version", dwVersion) << CHAR_PARAM("hash", ptrA(mir_base64_encode(pCollection->hash.hash, sizeof(pCollection->hash.hash)))) - << JSON_PARAM("indexValueMap", jsonMap); - - string2file(jsonRoot.write(), GetTmpFileName("collection", CMStringA(pszName) + ".json")); - } -} - -static uint8_t sttMutationInfo[] = "WhatsApp Mutation Keys"; - -void WhatsAppProto::ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec, bool bSet) -{ - int id = decodeBigEndian(rec->keyid->id); - auto &indexBlob = rec->index->blob; - auto &value = rec->value->blob; - - auto *macValue = value.data + value.len - 32; - std::string index((char *)indexBlob.data, indexBlob.len); - - MBinBuffer key(getBlob(CMStringA(FORMAT, "AppSyncKey%d", id))); - if (key.isEmpty()) { - debugLogA("No key with id=%d to decode a patch"); - return; - } - - struct - { - uint8_t indexKey[32]; - uint8_t encKey[32]; - uint8_t macKey[32]; - uint8_t snapshotMacKey[32]; - uint8_t patchMacKey[32]; - - } mutationKeys; - - HKDF(EVP_sha256(), (BYTE *)"", 0, key.data(), key.length(), sttMutationInfo, sizeof(sttMutationInfo) - 1, (BYTE *)&mutationKeys, sizeof(mutationKeys)); - - MBinBuffer decoded = aesDecrypt(EVP_aes_256_cbc(), mutationKeys.encKey, value.data, value.data + 16, value.len - 32); - if (decoded.isEmpty()) { - debugLogA("Unable to decode patch with key id=%d", id); - return; - } - - proto::SyncActionData data(unpadBuffer16(decoded)); - if (!data) { - debugLogA("Unable to decode action data with id=%d", id); - return; - } - - JSONNode jsonRoot = JSONNode::parse((char *)data->index.data); - - if (bSet) { - ApplyPatch(jsonRoot, data->value); - - pColl->hash.add(macValue, 32); - pColl->indexValueMap[index] = std::string((char*)macValue, 32); - } - else { - debugLogA("Removing data with index: %s", jsonRoot.write().c_str()); - - auto &prevVal = pColl->indexValueMap.find(index); - if (prevVal != pColl->indexValueMap.end()) { - pColl->hash.sub(prevVal->second.c_str(), prevVal->second.size()); - pColl->indexValueMap.erase(prevVal); - } - } -} - -void WhatsAppProto::ApplyPatch(const JSONNode &index, const Wa__SyncActionValue *data) -{ - debugLogA("Applying patch for %s: %s", index.write().c_str(), protobuf_c_text_to_string(data).c_str()); - - auto title = index.at((json_index_t)0).as_string(); - - if (title == "contact" && data->contactaction) { - auto *pUser = AddUser(index.at(1).as_string().c_str(), false); - - auto *pAction = data->contactaction; - auto &fullName = pAction->fullname; - if (fullName) - setUString(pUser->hContact, "Nick", fullName); - - if (pAction->firstname) { - CMStringA str(pAction->firstname); - str.TrimRight(); - setUString(pUser->hContact, "FirstName", str.c_str()); - setUString(pUser->hContact, "LastName", fullName + str.GetLength() + 1); - } - else if (fullName != nullptr) { - auto *p = strrchr(fullName, ' '); - if (p != 0) { - *p = 0; - setUString(pUser->hContact, "FirstName", fullName); - setUString(pUser->hContact, "LastName", p+1); - } - else { - setUString(pUser->hContact, "FirstName", ""); - setUString(pUser->hContact, "LastName", fullName); - } - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::ProcessHistorySync(const Wa__HistorySync *pSync) -{ - debugLogA("Got history sync: %s", protobuf_c_text_to_string(pSync).c_str()); - - switch (pSync->synctype) { - case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_BOOTSTRAP: - case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__RECENT: - for (int i = 0; i < pSync->n_conversations; i++) { - auto *pChat = pSync->conversations[i]; - - auto *pUser = AddUser(pChat->id, false); - for (int j = 0; j < pChat->n_messages; j++) { - auto *pMessage = pChat->messages[j]; - if (!pMessage->message) - continue; - - MEVENT hEvent = db_event_getById(m_szModuleName, pMessage->message->key->id); - if (hEvent) { - debugLogA("Event %s is already processed", pMessage->message->key->id); - continue; - } - - CMStringA szMessageText(GetMessageText(pMessage->message->message)); - if (!szMessageText.IsEmpty()) { - auto *key = pMessage->message->key; - - PROTORECVEVENT pre = {}; - pre.timestamp = pMessage->message->messagetimestamp; - pre.szMessage = szMessageText.GetBuffer(); - pre.szMsgId = key->id; - pre.flags = PREF_CREATEREAD; - if (key->fromme) - pre.flags |= PREF_SENT; - ProtoChainRecvMsg(pUser->hContact, &pre); - - if (pUser->bIsGroupChat) { - if (pChat->name) - setUString(pUser->hContact, "Nick", pChat->name); - - GCEVENT gce = {m_szModuleName, 0, GC_EVENT_MESSAGE}; - gce.dwFlags = GCEF_UTF8; - gce.pszID.a = pUser->szId; - gce.pszUID.a = key->participant; - gce.bIsMe = key->fromme; - gce.pszText.a = szMessageText.GetBuffer(); - gce.time = pMessage->message->messagetimestamp; - Chat_Event(&gce); - } - } - } - } - - if (pSync->synctype == WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_BOOTSTRAP) - GC_RefreshMetadata(); - break; - - case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__PUSH_NAME: - for (int i = 0; i < pSync->n_pushnames; i++) { - auto *pName = pSync->pushnames[i]; - if (auto *pUser = AddUser(pName->id, false)) - setUString(pUser->hContact, "Nick", pName->pushname); - } - break; - - case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_STATUS_V3: - for (int i = 0; i < pSync->n_statusv3messages; i++) { - // TODO - // auto *pStatus = pSync->statusv3messages[i]; - } - break; - } -} +/*
+
+WhatsApp plugin for Miranda NG
+Copyright © 2019-23 George Hazan
+
+*/
+
+#include "stdafx.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::InitSync()
+{
+ m_arCollections.insert(new WACollection("regular"));
+ m_arCollections.insert(new WACollection("regular_high"));
+ m_arCollections.insert(new WACollection("regular_low"));
+ m_arCollections.insert(new WACollection("critical_block"));
+ m_arCollections.insert(new WACollection("critical_unblock_low"));
+
+ for (auto &it : m_arCollections) {
+ CMStringW wszPath(GetTmpFileName("collection", it->szName));
+ wszPath.Append(L".json");
+ if (_waccess(wszPath, 0))
+ continue;
+
+ JSONNode root = JSONNode::parse(file2string(wszPath));
+ it->version = root["version"].as_int();
+
+ auto szHash = decodeBinStr(root["hash"].as_string());
+ if (szHash.size() == sizeof(it->hash.hash))
+ memcpy(it->hash.hash, szHash.c_str(), sizeof(it->hash.hash));
+
+ for (auto &val : root["indexValueMap"])
+ it->indexValueMap[decodeBinStr(val.name())] = decodeBinStr(val.as_string());
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnServerSync(const WANode &node)
+{
+ OBJLIST<WACollection> task(1);
+
+ for (auto &it : node.getChildren())
+ if (it->title == "collection")
+ task.insert(new WACollection(it->getAttr("name"), it->getAttrInt("version")));
+
+ ResyncServer(task);
+ SendAck(node);
+}
+
+void WhatsAppProto::ResyncAll()
+{
+ ResyncServer(m_arCollections);
+}
+
+void WhatsAppProto::ResyncServer(const OBJLIST<WACollection> &task)
+{
+ WANodeIq iq(IQ::SET, "w:sync:app:state");
+
+ auto *pList = iq.addChild("sync");
+ for (auto &it : task) {
+ auto *pCollection = m_arCollections.find(it);
+ if (pCollection == nullptr)
+ m_arCollections.insert(pCollection = new WACollection(it->szName, 0));
+
+ if (!pCollection->version || pCollection->version < it->version) {
+ auto *pNode = pList->addChild("collection");
+ *pNode << CHAR_PARAM("name", it->szName) << INT_PARAM("version", pCollection->version)
+ << CHAR_PARAM("return_snapshot", (!pCollection->version) ? "true" : "false");
+ }
+ }
+
+ if (pList->getFirstChild() != nullptr)
+ WSSendNode(iq, &WhatsAppProto::OnIqServerSync);
+}
+
+void WhatsAppProto::OnIqServerSync(const WANode &node)
+{
+ for (auto &coll : node.getChild("sync")->getChildren()) {
+ if (coll->title != "collection")
+ continue;
+
+ auto *pszName = coll->getAttr("name");
+
+ auto *pCollection = FindCollection(pszName);
+ if (pCollection == nullptr) {
+ pCollection = new WACollection(pszName, 0);
+ m_arCollections.insert(pCollection);
+ }
+
+ int dwVersion = 0;
+
+ CMStringW wszSnapshotPath(GetTmpFileName("collection", pszName));
+ if (auto *pSnapshot = coll->getChild("snapshot")) {
+ proto::ExternalBlobReference body(pSnapshot->content);
+ if (!body->directpath || !body->has_mediakey) {
+ debugLogA("Invalid snapshot data, skipping");
+ continue;
+ }
+
+ MBinBuffer buf = DownloadEncryptedFile(directPath2url(body->directpath), body->mediakey, "App State");
+ if (buf.isEmpty()) {
+ debugLogA("Invalid downloaded snapshot data, skipping");
+ continue;
+ }
+
+ proto::SyncdSnapshot snapshot(unpadBuffer16(buf));
+ if (!snapshot) {
+ debugLogA("%s: unable to decode snapshot, skipping");
+ continue;
+ }
+
+ dwVersion = snapshot->version->version;
+ if (dwVersion > pCollection->version) {
+ pCollection->hash.init();
+ debugLogA("%s: applying snapshot of version %d", pCollection->szName.get(), dwVersion);
+ for (int i=0; i < snapshot->n_records; i++)
+ ParsePatch(pCollection, snapshot->records[i], true);
+ }
+ else debugLogA("%s: skipping snapshot of version %d", pCollection->szName.get(), dwVersion);
+ }
+
+ if (auto *pPatchList = coll->getChild("patches")) {
+ for (auto &it : pPatchList->getChildren()) {
+ proto::SyncdPatch patch(it->content);
+ if (!patch) {
+ debugLogA("%s: unable to decode patch, skipping");
+ continue;
+ }
+
+ dwVersion = patch->version->version;
+ if (dwVersion > pCollection->version) {
+ debugLogA("%s: applying patch of version %d", pCollection->szName.get(), dwVersion);
+ for (int i = 0; i < patch->n_mutations; i++) {
+ auto &jt = *patch->mutations[i];
+ ParsePatch(pCollection, jt.record, jt.operation == WA__SYNCD_MUTATION__SYNCD_OPERATION__SET);
+ }
+ }
+ else debugLogA("%s: skipping patch of version %d", pCollection->szName.get(), dwVersion);
+ }
+ }
+
+ JSONNode jsonRoot, jsonMap;
+ for (auto &it : pCollection->indexValueMap)
+ jsonMap << CHAR_PARAM(ptrA(mir_base64_encode(it.first.c_str(), it.first.size())), ptrA(mir_base64_encode(it.second.c_str(), it.second.size())));
+ jsonRoot << INT_PARAM("version", dwVersion) << CHAR_PARAM("hash", ptrA(mir_base64_encode(pCollection->hash.hash, sizeof(pCollection->hash.hash))))
+ << JSON_PARAM("indexValueMap", jsonMap);
+
+ string2file(jsonRoot.write(), GetTmpFileName("collection", CMStringA(pszName) + ".json"));
+ }
+}
+
+static uint8_t sttMutationInfo[] = "WhatsApp Mutation Keys";
+
+void WhatsAppProto::ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec, bool bSet)
+{
+ int id = decodeBigEndian(rec->keyid->id);
+ auto &indexBlob = rec->index->blob;
+ auto &value = rec->value->blob;
+
+ auto *macValue = value.data + value.len - 32;
+ std::string index((char *)indexBlob.data, indexBlob.len);
+
+ MBinBuffer key(getBlob(CMStringA(FORMAT, "AppSyncKey%d", id)));
+ if (key.isEmpty()) {
+ debugLogA("No key with id=%d to decode a patch");
+ return;
+ }
+
+ struct
+ {
+ uint8_t indexKey[32];
+ uint8_t encKey[32];
+ uint8_t macKey[32];
+ uint8_t snapshotMacKey[32];
+ uint8_t patchMacKey[32];
+
+ } mutationKeys;
+
+ HKDF(EVP_sha256(), (BYTE *)"", 0, key.data(), key.length(), sttMutationInfo, sizeof(sttMutationInfo) - 1, (BYTE *)&mutationKeys, sizeof(mutationKeys));
+
+ MBinBuffer decoded = aesDecrypt(EVP_aes_256_cbc(), mutationKeys.encKey, value.data, value.data + 16, value.len - 32);
+ if (decoded.isEmpty()) {
+ debugLogA("Unable to decode patch with key id=%d", id);
+ return;
+ }
+
+ proto::SyncActionData data(unpadBuffer16(decoded));
+ if (!data) {
+ debugLogA("Unable to decode action data with id=%d", id);
+ return;
+ }
+
+ JSONNode jsonRoot = JSONNode::parse((char *)data->index.data);
+
+ if (bSet) {
+ ApplyPatch(jsonRoot, data->value);
+
+ pColl->hash.add(macValue, 32);
+ pColl->indexValueMap[index] = std::string((char*)macValue, 32);
+ }
+ else {
+ debugLogA("Removing data with index: %s", jsonRoot.write().c_str());
+
+ auto &prevVal = pColl->indexValueMap.find(index);
+ if (prevVal != pColl->indexValueMap.end()) {
+ pColl->hash.sub(prevVal->second.c_str(), prevVal->second.size());
+ pColl->indexValueMap.erase(prevVal);
+ }
+ }
+}
+
+void WhatsAppProto::ApplyPatch(const JSONNode &index, const Wa__SyncActionValue *data)
+{
+ debugLogA("Applying patch for %s: %s", index.write().c_str(), protobuf_c_text_to_string(data).c_str());
+
+ auto title = index.at((json_index_t)0).as_string();
+
+ if (title == "contact" && data->contactaction) {
+ auto *pUser = AddUser(index.at(1).as_string().c_str(), false);
+
+ auto *pAction = data->contactaction;
+ auto &fullName = pAction->fullname;
+ if (fullName)
+ setUString(pUser->hContact, "Nick", fullName);
+
+ if (pAction->firstname) {
+ CMStringA str(pAction->firstname);
+ str.TrimRight();
+ setUString(pUser->hContact, "FirstName", str.c_str());
+ setUString(pUser->hContact, "LastName", fullName + str.GetLength() + 1);
+ }
+ else if (fullName != nullptr) {
+ auto *p = strrchr(fullName, ' ');
+ if (p != 0) {
+ *p = 0;
+ setUString(pUser->hContact, "FirstName", fullName);
+ setUString(pUser->hContact, "LastName", p+1);
+ }
+ else {
+ setUString(pUser->hContact, "FirstName", "");
+ setUString(pUser->hContact, "LastName", fullName);
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::ProcessHistorySync(const Wa__HistorySync *pSync)
+{
+ debugLogA("Got history sync: %s", protobuf_c_text_to_string(pSync).c_str());
+
+ switch (pSync->synctype) {
+ case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_BOOTSTRAP:
+ case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__RECENT:
+ for (int i = 0; i < pSync->n_conversations; i++) {
+ auto *pChat = pSync->conversations[i];
+
+ auto *pUser = AddUser(pChat->id, false);
+ for (int j = 0; j < pChat->n_messages; j++) {
+ auto *pMessage = pChat->messages[j];
+ if (!pMessage->message)
+ continue;
+
+ MEVENT hEvent = db_event_getById(m_szModuleName, pMessage->message->key->id);
+ if (hEvent) {
+ debugLogA("Event %s is already processed", pMessage->message->key->id);
+ continue;
+ }
+
+ CMStringA szMessageText(GetMessageText(pMessage->message->message));
+ if (!szMessageText.IsEmpty()) {
+ auto *key = pMessage->message->key;
+
+ PROTORECVEVENT pre = {};
+ pre.timestamp = pMessage->message->messagetimestamp;
+ pre.szMessage = szMessageText.GetBuffer();
+ pre.szMsgId = key->id;
+ pre.flags = PREF_CREATEREAD;
+ if (key->fromme)
+ pre.flags |= PREF_SENT;
+ ProtoChainRecvMsg(pUser->hContact, &pre);
+
+ if (pUser->bIsGroupChat) {
+ if (pChat->name)
+ setUString(pUser->hContact, "Nick", pChat->name);
+
+ GCEVENT gce = {m_szModuleName, 0, GC_EVENT_MESSAGE};
+ gce.dwFlags = GCEF_UTF8;
+ gce.pszID.a = pUser->szId;
+ gce.pszUID.a = key->participant;
+ gce.bIsMe = key->fromme;
+ gce.pszText.a = szMessageText.GetBuffer();
+ gce.time = pMessage->message->messagetimestamp;
+ Chat_Event(&gce);
+ }
+ }
+ }
+ }
+
+ if (pSync->synctype == WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_BOOTSTRAP)
+ GC_RefreshMetadata();
+ break;
+
+ case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__PUSH_NAME:
+ for (int i = 0; i < pSync->n_pushnames; i++) {
+ auto *pName = pSync->pushnames[i];
+ if (auto *pUser = AddUser(pName->id, false))
+ setUString(pUser->hContact, "Nick", pName->pushname);
+ }
+ break;
+
+ case WA__HISTORY_SYNC__HISTORY_SYNC_TYPE__INITIAL_STATUS_V3:
+ for (int i = 0; i < pSync->n_statusv3messages; i++) {
+ // TODO
+ // auto *pStatus = pSync->statusv3messages[i];
+ }
+ break;
+ }
+}
diff --git a/protocols/WhatsApp/src/chats.cpp b/protocols/WhatsApp/src/chats.cpp index 59f98d4548..b0423e5b20 100644 --- a/protocols/WhatsApp/src/chats.cpp +++ b/protocols/WhatsApp/src/chats.cpp @@ -1,188 +1,188 @@ -/* - -WhatsApp plugin for Miranda NG -Copyright © 2019-23 George Hazan - -*/ - -#include "stdafx.h" - -void WhatsAppProto::GC_RefreshMetadata() -{ - for (auto &it : m_arUsers) { - if (it->bIsGroupChat) { - GC_GetAllMetadata(); - break; - } - } -} - -void WhatsAppProto::GC_GetAllMetadata() -{ - WANodeIq iq(IQ::GET, "w:g2", "@g.us"); - auto *pRoot = iq.addChild("participating"); - *pRoot << XCHILD("participants") << XCHILD("description"); - WSSendNode(iq, &WhatsAppProto::OnIqGcGetAllMetadata); -} - -void WhatsAppProto::OnIqGcGetAllMetadata(const WANode &node) -{ - if (auto *pGroup = node.getChild("groups")) - for (auto &it : pGroup->getChildren()) - GC_ParseMetadata(it); -} - -void WhatsAppProto::GC_ParseMetadata(const WANode *pGroup) -{ - auto *pszId = pGroup->getAttr("id"); - if (pszId == nullptr) - return; - - auto *pChatUser = AddUser(CMStringA(pszId) + "@g.us", false); - if (pChatUser == nullptr) - return; - - CMStringW wszId(Utf2T(pChatUser->szId)); - - pChatUser->si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, getMStringW(pChatUser->hContact, "Nick")); - - Chat_AddGroup(pChatUser->si, TranslateT("Owner")); - Chat_AddGroup(pChatUser->si, TranslateT("SuperAdmin")); - Chat_AddGroup(pChatUser->si, TranslateT("Admin")); - Chat_AddGroup(pChatUser->si, TranslateT("Participant")); - - CMStringA szOwner(pGroup->getAttr("creator")), szNick, szRole; - - for (auto &it : pGroup->getChildren()) { - if (it->title == "description") { - CMStringA szDescr = it->getBody(); - if (!szDescr.IsEmpty()) { - GCEVENT gce = {m_szModuleName, 0, GC_EVENT_INFORMATION}; - gce.dwFlags = GCEF_UTF8; - gce.pszID.a = pChatUser->szId; - gce.pszText.a = szDescr.c_str(); - Chat_Event(&gce); - } - } - else if (it->title == "member_add_mode") { - szRole = it->getBody(); - } - else if (it->title == "participant") { - auto *jid = it->getAttr("jid"); - - // if role isn't specified, use the default one - auto *role = it->getAttr("type"); - if (role == nullptr) - role = szRole; - - GCEVENT gce = {m_szModuleName, 0, GC_EVENT_JOIN}; - gce.dwFlags = GCEF_UTF8; - gce.pszID.a = pChatUser->szId; - gce.pszUID.a = jid; - gce.bIsMe = (jid == m_szJid); - - if (jid == szOwner) - gce.pszStatus.a = "Owner"; - else if (!mir_strcmp(role, "superadmin")) - gce.pszStatus.a = "SuperAdmin"; - else if (!mir_strcmp(role, "adminadd")) - gce.pszStatus.a = "Admin"; - else - gce.pszStatus.a = "Participant"; - - if (gce.bIsMe) - szNick = ptrA(getUStringA(DBKEY_NICK)); - else if (auto *pUser = FindUser(jid)) - szNick = T2Utf(Clist_GetContactDisplayName(pUser->hContact)).get(); - else - szNick = WAJid(jid).user; - - gce.pszNick.a = szNick; - Chat_Event(&gce); - } - } - - if (auto *pszSubject = pGroup->getAttr("subject")) { - time_t iSubjectTime = pGroup->getAttrInt("s_t"); - auto *pszUser = pGroup->getAttr("s_o"); - if (m_szJid == pszUser) - szNick = ptrA(getUStringA(DBKEY_NICK)); - else if (auto *pUser = FindUser(pszUser)) - szNick = T2Utf(Clist_GetContactDisplayName(pUser->hContact)).get(); - else - szNick = WAJid(pszUser).user; - - GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC }; - gce.dwFlags = GCEF_UTF8; - gce.pszID.a = pChatUser->szId; - gce.pszUID.a = pszUser; - gce.pszText.a = pszSubject; - gce.time = iSubjectTime; - Chat_Event(&gce); - - setUString(pChatUser->hContact, "Nick", pszSubject); - } - - pChatUser->bInited = true; - Chat_Control(m_szModuleName, wszId, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); - Chat_Control(m_szModuleName, wszId, SESSION_ONLINE); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int WhatsAppProto::GcEventHook(WPARAM, LPARAM lParam) -{ - GCHOOK *gch = (GCHOOK*)lParam; - if (gch == nullptr) - return 0; - - if (mir_strcmpi(gch->si->pszModule, m_szModuleName)) - return 0; - - auto *pUser = FindUser(T2Utf(gch->si->ptszID)); - if (pUser == nullptr) - return 0; - - switch (gch->iType) { - case GC_USER_MESSAGE: - if (gch->ptszText && mir_wstrlen(gch->ptszText) > 0) { - rtrimw(gch->ptszText); - Chat_UnescapeTags(gch->ptszText); - SendTextMessage(pUser->szId, T2Utf(gch->ptszText)); - } - break; - - case GC_USER_PRIVMESS: - break; - - case GC_USER_LOGMENU: - break; - - case GC_USER_NICKLISTMENU: - break; - } - - return 1; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int WhatsAppProto::GcMenuHook(WPARAM, LPARAM lParam) -{ - GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam; - if (gcmi == nullptr) - return 0; - - if (mir_strcmpi(gcmi->pszModule, m_szModuleName)) - return 0; - - auto *pUser = FindUser(T2Utf(gcmi->pszID)); - if (pUser == nullptr) - return 0; - - if (gcmi->Type == MENU_ON_LOG) { - } - else if (gcmi->Type == MENU_ON_NICKLIST) { - } - return 0; -} +/*
+
+WhatsApp plugin for Miranda NG
+Copyright © 2019-23 George Hazan
+
+*/
+
+#include "stdafx.h"
+
+void WhatsAppProto::GC_RefreshMetadata()
+{
+ for (auto &it : m_arUsers) {
+ if (it->bIsGroupChat) {
+ GC_GetAllMetadata();
+ break;
+ }
+ }
+}
+
+void WhatsAppProto::GC_GetAllMetadata()
+{
+ WANodeIq iq(IQ::GET, "w:g2", "@g.us");
+ auto *pRoot = iq.addChild("participating");
+ *pRoot << XCHILD("participants") << XCHILD("description");
+ WSSendNode(iq, &WhatsAppProto::OnIqGcGetAllMetadata);
+}
+
+void WhatsAppProto::OnIqGcGetAllMetadata(const WANode &node)
+{
+ if (auto *pGroup = node.getChild("groups"))
+ for (auto &it : pGroup->getChildren())
+ GC_ParseMetadata(it);
+}
+
+void WhatsAppProto::GC_ParseMetadata(const WANode *pGroup)
+{
+ auto *pszId = pGroup->getAttr("id");
+ if (pszId == nullptr)
+ return;
+
+ auto *pChatUser = AddUser(CMStringA(pszId) + "@g.us", false);
+ if (pChatUser == nullptr)
+ return;
+
+ CMStringW wszId(Utf2T(pChatUser->szId));
+
+ pChatUser->si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, getMStringW(pChatUser->hContact, "Nick"));
+
+ Chat_AddGroup(pChatUser->si, TranslateT("Owner"));
+ Chat_AddGroup(pChatUser->si, TranslateT("SuperAdmin"));
+ Chat_AddGroup(pChatUser->si, TranslateT("Admin"));
+ Chat_AddGroup(pChatUser->si, TranslateT("Participant"));
+
+ CMStringA szOwner(pGroup->getAttr("creator")), szNick, szRole;
+
+ for (auto &it : pGroup->getChildren()) {
+ if (it->title == "description") {
+ CMStringA szDescr = it->getBody();
+ if (!szDescr.IsEmpty()) {
+ GCEVENT gce = {m_szModuleName, 0, GC_EVENT_INFORMATION};
+ gce.dwFlags = GCEF_UTF8;
+ gce.pszID.a = pChatUser->szId;
+ gce.pszText.a = szDescr.c_str();
+ Chat_Event(&gce);
+ }
+ }
+ else if (it->title == "member_add_mode") {
+ szRole = it->getBody();
+ }
+ else if (it->title == "participant") {
+ auto *jid = it->getAttr("jid");
+
+ // if role isn't specified, use the default one
+ auto *role = it->getAttr("type");
+ if (role == nullptr)
+ role = szRole;
+
+ GCEVENT gce = {m_szModuleName, 0, GC_EVENT_JOIN};
+ gce.dwFlags = GCEF_UTF8;
+ gce.pszID.a = pChatUser->szId;
+ gce.pszUID.a = jid;
+ gce.bIsMe = (jid == m_szJid);
+
+ if (jid == szOwner)
+ gce.pszStatus.a = "Owner";
+ else if (!mir_strcmp(role, "superadmin"))
+ gce.pszStatus.a = "SuperAdmin";
+ else if (!mir_strcmp(role, "adminadd"))
+ gce.pszStatus.a = "Admin";
+ else
+ gce.pszStatus.a = "Participant";
+
+ if (gce.bIsMe)
+ szNick = ptrA(getUStringA(DBKEY_NICK));
+ else if (auto *pUser = FindUser(jid))
+ szNick = T2Utf(Clist_GetContactDisplayName(pUser->hContact)).get();
+ else
+ szNick = WAJid(jid).user;
+
+ gce.pszNick.a = szNick;
+ Chat_Event(&gce);
+ }
+ }
+
+ if (auto *pszSubject = pGroup->getAttr("subject")) {
+ time_t iSubjectTime = pGroup->getAttrInt("s_t");
+ auto *pszUser = pGroup->getAttr("s_o");
+ if (m_szJid == pszUser)
+ szNick = ptrA(getUStringA(DBKEY_NICK));
+ else if (auto *pUser = FindUser(pszUser))
+ szNick = T2Utf(Clist_GetContactDisplayName(pUser->hContact)).get();
+ else
+ szNick = WAJid(pszUser).user;
+
+ GCEVENT gce = { m_szModuleName, 0, GC_EVENT_TOPIC };
+ gce.dwFlags = GCEF_UTF8;
+ gce.pszID.a = pChatUser->szId;
+ gce.pszUID.a = pszUser;
+ gce.pszText.a = pszSubject;
+ gce.time = iSubjectTime;
+ Chat_Event(&gce);
+
+ setUString(pChatUser->hContact, "Nick", pszSubject);
+ }
+
+ pChatUser->bInited = true;
+ Chat_Control(m_szModuleName, wszId, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE);
+ Chat_Control(m_szModuleName, wszId, SESSION_ONLINE);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int WhatsAppProto::GcEventHook(WPARAM, LPARAM lParam)
+{
+ GCHOOK *gch = (GCHOOK*)lParam;
+ if (gch == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gch->si->pszModule, m_szModuleName))
+ return 0;
+
+ auto *pUser = FindUser(T2Utf(gch->si->ptszID));
+ if (pUser == nullptr)
+ return 0;
+
+ switch (gch->iType) {
+ case GC_USER_MESSAGE:
+ if (gch->ptszText && mir_wstrlen(gch->ptszText) > 0) {
+ rtrimw(gch->ptszText);
+ Chat_UnescapeTags(gch->ptszText);
+ SendTextMessage(pUser->szId, T2Utf(gch->ptszText));
+ }
+ break;
+
+ case GC_USER_PRIVMESS:
+ break;
+
+ case GC_USER_LOGMENU:
+ break;
+
+ case GC_USER_NICKLISTMENU:
+ break;
+ }
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int WhatsAppProto::GcMenuHook(WPARAM, LPARAM lParam)
+{
+ GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam;
+ if (gcmi == nullptr)
+ return 0;
+
+ if (mir_strcmpi(gcmi->pszModule, m_szModuleName))
+ return 0;
+
+ auto *pUser = FindUser(T2Utf(gcmi->pszID));
+ if (pUser == nullptr)
+ return 0;
+
+ if (gcmi->Type == MENU_ON_LOG) {
+ }
+ else if (gcmi->Type == MENU_ON_NICKLIST) {
+ }
+ return 0;
+}
diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp index 006f78dfc0..8fabeb098b 100644 --- a/protocols/WhatsApp/src/proto.cpp +++ b/protocols/WhatsApp/src/proto.cpp @@ -1,308 +1,308 @@ -/* - -WhatsApp plugin for Miranda NG -Copyright © 2019-23 George Hazan - -*/ - -#include "stdafx.h" - -struct SearchParam -{ - SearchParam(const wchar_t *_jid, LONG _id) : - jid(_jid), id(_id) - {} - - std::wstring jid; - LONG id; -}; - -static int CompareOwnMsgs(const WAOwnMessage *p1, const WAOwnMessage *p2) -{ - return strcmp(p1->szMessageId, p2->szMessageId); -} - -static int CompareUsers(const WAUser *p1, const WAUser *p2) -{ - return strcmp(p1->szId, p2->szId); -} - -static int CompareCollections(const WACollection *p1, const WACollection *p2) -{ - return strcmp(p1->szName, p2->szName); -} - -static int CompareRequests(const WARequestBase *p1, const WARequestBase *p2) -{ - return strcmp(p1->szPacketId, p2->szPacketId); -} - -WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) : - PROTO<WhatsAppProto>(proto_name, username), - m_impl(*this), - m_signalStore(this, ""), - m_szJid(getMStringA(DBKEY_ID)), - m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)), - m_arUsers(10, CompareUsers), - m_arOwnMsgs(1, CompareOwnMsgs), - m_arPersistent(1), - m_arPacketQueue(10, CompareRequests), - m_arCollections(10, CompareCollections), - - m_wszNick(this, "Nick"), - m_wszDeviceName(this, "DeviceName", L"Miranda NG"), - m_wszDefaultGroup(this, "DefaultGroup", L"WhatsApp"), - m_bUsePopups(this, "UsePopups", true), - m_bUseBbcodes(this, "UseBbcodes", true), - m_bHideGroupchats(this, "HideChats", true) -{ - db_set_resident(m_szModuleName, "StatusMsg"); - - CreateProtoService(PS_CREATEACCMGRUI, &WhatsAppProto::SvcCreateAccMgrUI); - - CreateProtoService(PS_GETAVATARINFO, &WhatsAppProto::GetAvatarInfo); - CreateProtoService(PS_GETAVATARCAPS, &WhatsAppProto::GetAvatarCaps); - CreateProtoService(PS_GETMYAVATAR, &WhatsAppProto::GetMyAvatar); - CreateProtoService(PS_SETMYAVATAR, &WhatsAppProto::SetMyAvatar); - - HookProtoEvent(ME_OPT_INITIALISE, &WhatsAppProto::OnOptionsInit); - - InitSync(); - InitPopups(); - InitPersistentHandlers(); - - // Create standard network connection - wchar_t descr[512]; - mir_snwprintf(descr, TranslateT("%s (server)"), m_tszUserName); - - NETLIBUSER nlu = {}; - nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; - nlu.szSettingsModule = m_szModuleName; - nlu.szDescriptiveName.w = descr; - m_hNetlibUser = Netlib_RegisterUser(&nlu); - - // Temporary folder - CreateDirectoryTreeW(CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName)); - - // Avatars folder - m_tszAvatarFolder = CMStringW(VARSW(L"%miranda_avatarcache%")) + L"\\" + _A2T(m_szModuleName); - DWORD dwAttributes = GetFileAttributes(m_tszAvatarFolder.c_str()); - if (dwAttributes == 0xffffffff || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) - CreateDirectoryTreeW(m_tszAvatarFolder.c_str()); - - // default contacts group - if (m_tszDefaultGroup == NULL) - m_tszDefaultGroup = mir_wstrdup(L"WhatsApp"); - Clist_GroupCreate(0, m_tszDefaultGroup); - - // groupchat initialization - GCREGISTER gcr = {}; - gcr.dwFlags = GC_TYPNOTIF | GC_DATABASE; - gcr.ptszDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - Chat_Register(&gcr); - - HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::GcEventHook); - HookProtoEvent(ME_GC_BUILDMENU, &WhatsAppProto::GcMenuHook); -} - -WhatsAppProto::~WhatsAppProto() -{ -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnErase - remove temporary folder for account - -const char *pszNeededItems[] = { - "AM_BaseProto", "DefaultGroup", "DeviceName", "HideChats", "NLlog", "Nick" -}; - -static int sttEnumFunc(const char *szSetting, void *param) -{ - for (auto &it : pszNeededItems) - if (!mir_strcmp(it, szSetting)) - return 0; - - auto *pList = (LIST<char>*)param; - pList->insert(mir_strdup(szSetting)); - return 0; -} - -void WhatsAppProto::OnErase() -{ - m_bUnregister = true; - ServerThreadWorker(); - - // remove all temporary data from database & disk folder - LIST<char> arSettings(50); - db_enum_settings(0, sttEnumFunc, m_szModuleName, &arSettings); - for (auto &it : arSettings) { - delSetting(it); - mir_free(it); - } - - DeleteDirectoryTreeW(CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName), false); - - m_szJid.Empty(); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// OnModulesLoaded emulator for an account - -void WhatsAppProto::OnModulesLoaded() -{ - // initialize contacts cache - if (!m_szJid.IsEmpty()) - m_arUsers.insert(new WAUser(0, m_szJid, false)); - - for (auto &cc : AccContacts()) { - bool bIsChat = isChatRoom(cc); - CMStringA szId(getMStringA(cc, bIsChat ? "ChatRoomID" : DBKEY_ID)); - if (!szId.IsEmpty()) - m_arUsers.insert(new WAUser(cc, szId, bIsChat)); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// PROTO_INTERFACE implementation - -MCONTACT WhatsAppProto::AddToList(int flags, PROTOSEARCHRESULT *psr) -{ - if (psr->id.w == nullptr) - return NULL; - - auto *pUser = AddUser(T2Utf(psr->id.w), (flags & PALF_TEMPORARY) != 0); - db_unset(pUser->hContact, "CList", "NotOnList"); - - return pUser->hContact; -} - -INT_PTR WhatsAppProto::GetCaps(int type, MCONTACT) -{ - switch (type) { - case PFLAGNUM_1: - return PF1_IM | PF1_FILE | PF1_CHAT | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSGRECV; - case PFLAGNUM_2: - return PF2_ONLINE; - case PFLAGNUM_3: - return 0; - case PFLAGNUM_4: - return PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_OFFLINEFILES | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID; - case PFLAGNUM_5: - return 0; - case PFLAG_UNIQUEIDTEXT: - return (DWORD_PTR)L"WhatsApp ID"; - } - return 0; -} - -int WhatsAppProto::SetStatus(int iNewStatus) -{ - if (m_iDesiredStatus == iNewStatus) - return 0; - - if (!mir_wstrlen(m_wszNick)) { - Popup(0, LPGENW("Connection cannot be established! You have not completed all necessary fields (Nick)."), LPGENW("Error")); - return 0; - } - - int oldStatus = m_iStatus; - - // Routing statuses not supported by WhatsApp - switch (iNewStatus) { - case ID_STATUS_OFFLINE: - m_iDesiredStatus = iNewStatus; - break; - - case ID_STATUS_ONLINE: - case ID_STATUS_FREECHAT: - default: - m_iDesiredStatus = ID_STATUS_ONLINE; - break; - } - - if (m_iDesiredStatus == ID_STATUS_OFFLINE) { - SetServerStatus(m_iDesiredStatus); - - if (m_hServerConn != nullptr) - Netlib_Shutdown(m_hServerConn); - - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - } - else if (m_hServerConn == nullptr && !IsStatusConnecting(m_iStatus)) { - m_iStatus = ID_STATUS_CONNECTING; - ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - - ForkThread(&WhatsAppProto::ServerThread); - } - else if (m_hServerConn != nullptr) { - SetServerStatus(m_iDesiredStatus); - - m_iStatus = m_iDesiredStatus; - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - } - else ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus); - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg) -{ - ptrA jid(getStringA(hContact, DBKEY_ID)); - if (jid == nullptr || pszMsg == nullptr) - return 0; - - if (!isOnline()) { - debugLogA("No connection"); - return 0; - } - - return SendTextMessage(jid, pszMsg); -} - -int WhatsAppProto::UserIsTyping(MCONTACT hContact, int type) -{ - if (hContact && isOnline()) { - ptrA jid(getStringA(hContact, DBKEY_ID)); - if (jid && isOnline()) { - WSSendNode( - WANode("chatstates") << CHAR_PARAM("to", jid) << XCHILD((type == PROTOTYPE_SELFTYPING_ON) ? "composing" : "paused")); - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// contacts search - -void WhatsAppProto::SearchAckThread(void *targ) -{ - Sleep(100); - - SearchParam *param = (SearchParam*)targ; - PROTOSEARCHRESULT psr = {}; - psr.cbSize = sizeof(psr); - psr.flags = PSR_UNICODE; - psr.nick.w = psr.firstName.w = psr.lastName.w = L""; - psr.id.w = (wchar_t*)param->jid.c_str(); - - ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)param->id, (LPARAM)&psr); - ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)param->id, 0); - - delete param; -} - -HANDLE WhatsAppProto::SearchBasic(const wchar_t* id) -{ - if (!isOnline()) - return nullptr; - - // fake - we always accept search - SearchParam *param = new SearchParam(id, -1); - ForkThread(&WhatsAppProto::SearchAckThread, param); - return (HANDLE)param->id; -} +/*
+
+WhatsApp plugin for Miranda NG
+Copyright © 2019-23 George Hazan
+
+*/
+
+#include "stdafx.h"
+
+struct SearchParam
+{
+ SearchParam(const wchar_t *_jid, LONG _id) :
+ jid(_jid), id(_id)
+ {}
+
+ std::wstring jid;
+ LONG id;
+};
+
+static int CompareOwnMsgs(const WAOwnMessage *p1, const WAOwnMessage *p2)
+{
+ return strcmp(p1->szMessageId, p2->szMessageId);
+}
+
+static int CompareUsers(const WAUser *p1, const WAUser *p2)
+{
+ return strcmp(p1->szId, p2->szId);
+}
+
+static int CompareCollections(const WACollection *p1, const WACollection *p2)
+{
+ return strcmp(p1->szName, p2->szName);
+}
+
+static int CompareRequests(const WARequestBase *p1, const WARequestBase *p2)
+{
+ return strcmp(p1->szPacketId, p2->szPacketId);
+}
+
+WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) :
+ PROTO<WhatsAppProto>(proto_name, username),
+ m_impl(*this),
+ m_signalStore(this, ""),
+ m_szJid(getMStringA(DBKEY_ID)),
+ m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)),
+ m_arUsers(10, CompareUsers),
+ m_arOwnMsgs(1, CompareOwnMsgs),
+ m_arPersistent(1),
+ m_arPacketQueue(10, CompareRequests),
+ m_arCollections(10, CompareCollections),
+
+ m_wszNick(this, "Nick"),
+ m_wszDeviceName(this, "DeviceName", L"Miranda NG"),
+ m_wszDefaultGroup(this, "DefaultGroup", L"WhatsApp"),
+ m_bUsePopups(this, "UsePopups", true),
+ m_bUseBbcodes(this, "UseBbcodes", true),
+ m_bHideGroupchats(this, "HideChats", true)
+{
+ db_set_resident(m_szModuleName, "StatusMsg");
+
+ CreateProtoService(PS_CREATEACCMGRUI, &WhatsAppProto::SvcCreateAccMgrUI);
+
+ CreateProtoService(PS_GETAVATARINFO, &WhatsAppProto::GetAvatarInfo);
+ CreateProtoService(PS_GETAVATARCAPS, &WhatsAppProto::GetAvatarCaps);
+ CreateProtoService(PS_GETMYAVATAR, &WhatsAppProto::GetMyAvatar);
+ CreateProtoService(PS_SETMYAVATAR, &WhatsAppProto::SetMyAvatar);
+
+ HookProtoEvent(ME_OPT_INITIALISE, &WhatsAppProto::OnOptionsInit);
+
+ InitSync();
+ InitPopups();
+ InitPersistentHandlers();
+
+ // Create standard network connection
+ wchar_t descr[512];
+ mir_snwprintf(descr, TranslateT("%s (server)"), m_tszUserName);
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.szDescriptiveName.w = descr;
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ // Temporary folder
+ CreateDirectoryTreeW(CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName));
+
+ // Avatars folder
+ m_tszAvatarFolder = CMStringW(VARSW(L"%miranda_avatarcache%")) + L"\\" + _A2T(m_szModuleName);
+ DWORD dwAttributes = GetFileAttributes(m_tszAvatarFolder.c_str());
+ if (dwAttributes == 0xffffffff || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ CreateDirectoryTreeW(m_tszAvatarFolder.c_str());
+
+ // default contacts group
+ if (m_tszDefaultGroup == NULL)
+ m_tszDefaultGroup = mir_wstrdup(L"WhatsApp");
+ Clist_GroupCreate(0, m_tszDefaultGroup);
+
+ // groupchat initialization
+ GCREGISTER gcr = {};
+ gcr.dwFlags = GC_TYPNOTIF | GC_DATABASE;
+ gcr.ptszDispName = m_tszUserName;
+ gcr.pszModule = m_szModuleName;
+ Chat_Register(&gcr);
+
+ HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::GcEventHook);
+ HookProtoEvent(ME_GC_BUILDMENU, &WhatsAppProto::GcMenuHook);
+}
+
+WhatsAppProto::~WhatsAppProto()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnErase - remove temporary folder for account
+
+const char *pszNeededItems[] = {
+ "AM_BaseProto", "DefaultGroup", "DeviceName", "HideChats", "NLlog", "Nick"
+};
+
+static int sttEnumFunc(const char *szSetting, void *param)
+{
+ for (auto &it : pszNeededItems)
+ if (!mir_strcmp(it, szSetting))
+ return 0;
+
+ auto *pList = (LIST<char>*)param;
+ pList->insert(mir_strdup(szSetting));
+ return 0;
+}
+
+void WhatsAppProto::OnErase()
+{
+ m_bUnregister = true;
+ ServerThreadWorker();
+
+ // remove all temporary data from database & disk folder
+ LIST<char> arSettings(50);
+ db_enum_settings(0, sttEnumFunc, m_szModuleName, &arSettings);
+ for (auto &it : arSettings) {
+ delSetting(it);
+ mir_free(it);
+ }
+
+ DeleteDirectoryTreeW(CMStringW(VARSW(L"%miranda_userdata%")) + L"\\" + _A2T(m_szModuleName), false);
+
+ m_szJid.Empty();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded emulator for an account
+
+void WhatsAppProto::OnModulesLoaded()
+{
+ // initialize contacts cache
+ if (!m_szJid.IsEmpty())
+ m_arUsers.insert(new WAUser(0, m_szJid, false));
+
+ for (auto &cc : AccContacts()) {
+ bool bIsChat = isChatRoom(cc);
+ CMStringA szId(getMStringA(cc, bIsChat ? "ChatRoomID" : DBKEY_ID));
+ if (!szId.IsEmpty())
+ m_arUsers.insert(new WAUser(cc, szId, bIsChat));
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PROTO_INTERFACE implementation
+
+MCONTACT WhatsAppProto::AddToList(int flags, PROTOSEARCHRESULT *psr)
+{
+ if (psr->id.w == nullptr)
+ return NULL;
+
+ auto *pUser = AddUser(T2Utf(psr->id.w), (flags & PALF_TEMPORARY) != 0);
+ db_unset(pUser->hContact, "CList", "NotOnList");
+
+ return pUser->hContact;
+}
+
+INT_PTR WhatsAppProto::GetCaps(int type, MCONTACT)
+{
+ switch (type) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_FILE | PF1_CHAT | PF1_BASICSEARCH | PF1_ADDSEARCHRES | PF1_MODEMSGRECV;
+ case PFLAGNUM_2:
+ return PF2_ONLINE;
+ case PFLAGNUM_3:
+ return 0;
+ case PFLAGNUM_4:
+ return PF4_NOCUSTOMAUTH | PF4_NOAUTHDENYREASON | PF4_IMSENDOFFLINE | PF4_OFFLINEFILES | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID;
+ case PFLAGNUM_5:
+ return 0;
+ case PFLAG_UNIQUEIDTEXT:
+ return (DWORD_PTR)L"WhatsApp ID";
+ }
+ return 0;
+}
+
+int WhatsAppProto::SetStatus(int iNewStatus)
+{
+ if (m_iDesiredStatus == iNewStatus)
+ return 0;
+
+ if (!mir_wstrlen(m_wszNick)) {
+ Popup(0, LPGENW("Connection cannot be established! You have not completed all necessary fields (Nick)."), LPGENW("Error"));
+ return 0;
+ }
+
+ int oldStatus = m_iStatus;
+
+ // Routing statuses not supported by WhatsApp
+ switch (iNewStatus) {
+ case ID_STATUS_OFFLINE:
+ m_iDesiredStatus = iNewStatus;
+ break;
+
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_FREECHAT:
+ default:
+ m_iDesiredStatus = ID_STATUS_ONLINE;
+ break;
+ }
+
+ if (m_iDesiredStatus == ID_STATUS_OFFLINE) {
+ SetServerStatus(m_iDesiredStatus);
+
+ if (m_hServerConn != nullptr)
+ Netlib_Shutdown(m_hServerConn);
+
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ else if (m_hServerConn == nullptr && !IsStatusConnecting(m_iStatus)) {
+ m_iStatus = ID_STATUS_CONNECTING;
+ ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+
+ ForkThread(&WhatsAppProto::ServerThread);
+ }
+ else if (m_hServerConn != nullptr) {
+ SetServerStatus(m_iDesiredStatus);
+
+ m_iStatus = m_iDesiredStatus;
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+ }
+ else ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, m_iStatus);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg)
+{
+ ptrA jid(getStringA(hContact, DBKEY_ID));
+ if (jid == nullptr || pszMsg == nullptr)
+ return 0;
+
+ if (!isOnline()) {
+ debugLogA("No connection");
+ return 0;
+ }
+
+ return SendTextMessage(jid, pszMsg);
+}
+
+int WhatsAppProto::UserIsTyping(MCONTACT hContact, int type)
+{
+ if (hContact && isOnline()) {
+ ptrA jid(getStringA(hContact, DBKEY_ID));
+ if (jid && isOnline()) {
+ WSSendNode(
+ WANode("chatstates") << CHAR_PARAM("to", jid) << XCHILD((type == PROTOTYPE_SELFTYPING_ON) ? "composing" : "paused"));
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// contacts search
+
+void WhatsAppProto::SearchAckThread(void *targ)
+{
+ Sleep(100);
+
+ SearchParam *param = (SearchParam*)targ;
+ PROTOSEARCHRESULT psr = {};
+ psr.cbSize = sizeof(psr);
+ psr.flags = PSR_UNICODE;
+ psr.nick.w = psr.firstName.w = psr.lastName.w = L"";
+ psr.id.w = (wchar_t*)param->jid.c_str();
+
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)param->id, (LPARAM)&psr);
+ ProtoBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)param->id, 0);
+
+ delete param;
+}
+
+HANDLE WhatsAppProto::SearchBasic(const wchar_t* id)
+{
+ if (!isOnline())
+ return nullptr;
+
+ // fake - we always accept search
+ SearchParam *param = new SearchParam(id, -1);
+ ForkThread(&WhatsAppProto::SearchAckThread, param);
+ return (HANDLE)param->id;
+}
diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h index dbcf57b597..8ec4593767 100644 --- a/protocols/WhatsApp/src/proto.h +++ b/protocols/WhatsApp/src/proto.h @@ -1,508 +1,508 @@ -/* - -WhatsApp plugin for Miranda NG -Copyright © 2019-23 George Hazan - -*/ - -#if !defined(PROTO_H) -#define PROTO_H - -#define S_WHATSAPP_NET "@s.whatsapp.net" -#define APP_VERSION "2.2230.15" -#define KEY_BUNDLE_TYPE "\x05" - -class WhatsAppProto; -typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const WANode &node); -typedef void (WhatsAppProto:: *WA_PKT_HANDLER_FULL)(const WANode &node, void *pUserInfo); - -struct WAMSG -{ - union { - uint32_t dwFlags = 0; - struct { - bool bPrivateChat : 1; - bool bGroupChat : 1; - bool bDirectStatus : 1; - bool bOtherStatus : 1; - bool bPeerBroadcast : 1; - bool bOtherBroadcast : 1; - bool bOffline : 1; - }; - }; -}; - -struct WAMediaKeys -{ - WAMediaKeys(const uint8_t *pKey, size_t keyLen, const char *pszMediaType); - - uint8_t iv[16]; - uint8_t cipherKey[32]; - uint8_t macKey[64]; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// own requests - -struct WARequestBase -{ - WARequestBase(const CMStringA &_1) : - szPacketId(_1) - {} - virtual ~WARequestBase() {} - - CMStringA szPacketId; - - virtual void Execute(WhatsAppProto *ppro, const WANode &node) = 0; -}; - -class WARequestSimple : public WARequestBase -{ - WA_PKT_HANDLER pHandler; - -public: - WARequestSimple(const CMStringA &_1, WA_PKT_HANDLER _2) : - WARequestBase(_1), - pHandler(_2) - {} - - void Execute(WhatsAppProto *ppro, const WANode &node) override - { - (ppro->*pHandler)(node); - } -}; - -class WARequestParam : public WARequestBase -{ - WA_PKT_HANDLER_FULL pHandler; - void *pUserInfo; - -public: - WARequestParam(const CMStringA &_1, WA_PKT_HANDLER_FULL _2, void *_3) : - WARequestBase(_1), - pHandler(_2), - pUserInfo(_3) - {} - - void Execute(WhatsAppProto *ppro, const WANode &node) override - { - (ppro->*pHandler)(node, pUserInfo); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -struct WAPersistentHandler -{ - WAPersistentHandler(const char *_1, const char *_2, const char *_3, const char *_4, WA_PKT_HANDLER _5) : - pszTitle(_1), pszType(_2), pszXmlns(_3), pszChild(_4), pHandler(_5) - {} - - const char *pszTitle, *pszType, *pszXmlns, *pszChild; - WA_PKT_HANDLER pHandler; -}; - -struct WAUser -{ - WAUser(MCONTACT _1, const char *_2, bool _3 = false) : - hContact(_1), - szId(mir_strdup(_2)), - bIsGroupChat(_3), - arDevices(1) - { - } - - ~WAUser() - { - mir_free(szId); - } - - MCONTACT hContact; - DWORD dwModifyTag = 0; - char *szId; - bool bInited = false, bIsGroupChat, bDeviceInit = false; - SESSION_INFO *si = 0; - OBJLIST<WAJid> arDevices; - time_t m_timer1 = 0, m_timer2 = 0; -}; - -struct WAOwnMessage -{ - WAOwnMessage(int _1, const char *_2, const char *_3) : - pktId(_1), - szJid(_2), - szMessageId(_3) - {} - - int pktId; - CMStringA szJid, szMessageId; -}; - -struct WACollection -{ - WACollection(const char *_1, int _2 = 0) : - szName(mir_strdup(_1)), - version(_2) - {} - - ptrA szName; - int version; - - LT_HASH hash; - std::map<std::string, std::string> indexValueMap; -}; - -class WANoise -{ - friend class WhatsAppProto; - - WhatsAppProto *ppro; - uint32_t readCounter = 0, writeCounter = 0; - bool bInitFinished = false, bSendIntro = false; - MBinBuffer salt, encKey, decKey; - uint8_t hash[32]; - - struct { - MBinBuffer priv, pub; - } noiseKeys, ephemeral; - - void deriveKey(const void *pData, size_t cbLen, MBinBuffer &write, MBinBuffer &read); - void mixIntoKey(const void *n, const void *p); - void updateHash(const void *pData, size_t cbLen); - -public: - WANoise(WhatsAppProto *_ppro); - - void finish(); - void init(); - - MBinBuffer decrypt(const void *pData, size_t cbLen); - MBinBuffer encrypt(const void *pData, size_t cbLen); - - size_t decodeFrame(const uint8_t *&pData, size_t &cbLen); - MBinBuffer encodeFrame(const void *pData, size_t cbLen); -}; - -class MSignalSession : public MZeroedObject -{ - friend class MSignalStore; - signal_protocol_address address; - session_cipher *cipher = nullptr; - -public: - CMStringA szName; - MBinBuffer sessionData; - - MSignalSession(const CMStringA &_1, int _2); - ~MSignalSession(); - - bool hasAddress(const char *name, size_t name_len) const; - - __forceinline session_cipher* getCipher(void) const { return cipher; } - __forceinline int getDeviceId() const { return address.device_id; } - CMStringA getSetting() const; -}; - -class MSignalStore -{ - void init(); - - signal_context *m_pContext; - signal_protocol_store_context *m_pStore; - - void importPublicKey(ec_public_key **result, MBinBuffer &buf); - -public: - PROTO_INTERFACE *pProto; - const char *prefix; - - OBJLIST<MSignalSession> arSessions; - - struct - { - MBinBuffer priv, pub; - } - signedIdentity; - - struct - { - MBinBuffer priv, pub, signature; - uint32_t keyid; - } - preKey; - - MSignalStore(PROTO_INTERFACE *_1, const char *_2); - ~MSignalStore(); - - __forceinline signal_context *CTX() const { return m_pContext; } - - MSignalSession* createSession(const CMStringA &szName, int deviceId); - MSignalSession* getSession(const signal_protocol_address *address); - void injectSession(const char *szJid, const WANode *pNode, const WANode *pKey); - - MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted); - MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted); - - MBinBuffer encryptSenderKey(const WAJid &to, const CMStringA &from, const MBinBuffer &buf, MBinBuffer &skmsgKey); - MBinBuffer encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type); - - MBinBuffer encodeSignedIdentity(bool); - void generatePrekeys(int count); - - void logError(int code, const char *szMessage); - - void processSenderKeyMessage(const CMStringA &author, const Wa__Message__SenderKeyDistributionMessage *msg); -}; - -class WhatsAppProto : public PROTO<WhatsAppProto> -{ - friend class WANoise; - friend class CWhatsAppQRDlg; - friend class COptionsDlg; - - class CWhatsAppProtoImpl - { - friend class WhatsAppProto; - WhatsAppProto &m_proto; - - CTimer m_keepAlive, m_resyncApp; - void OnKeepAlive(CTimer *) - { m_proto.SendKeepAlive(); - } - void OnResync(CTimer *pTimer) - { - pTimer->Stop(); - m_proto.ResyncAll(); - } - - CWhatsAppProtoImpl(WhatsAppProto &pro) : - m_proto(pro), - m_keepAlive(Miranda_GetSystemWindow(), UINT_PTR(this)), - m_resyncApp(Miranda_GetSystemWindow(), UINT_PTR(this)+1) - { - m_keepAlive.OnEvent = Callback(this, &CWhatsAppProtoImpl::OnKeepAlive); - m_resyncApp.OnEvent = Callback(this, &CWhatsAppProtoImpl::OnResync); - } - } m_impl; - - bool m_bTerminated, m_bRespawn, m_bUpdatedPrekeys, m_bUnregister; - ptrW m_tszDefaultGroup; - - CMStringA m_szJid; - CMStringW m_tszAvatarFolder; - - EVP_PKEY *m_pKeys; // private & public keys - WANoise *m_noise; - - void UploadMorePrekeys(); - - // App state management - OBJLIST<WACollection> m_arCollections; - - void InitSync(void); - void ApplyPatch(const JSONNode &index, const Wa__SyncActionValue *data); - void ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec, bool bSet); - void ProcessHistorySync(const Wa__HistorySync *pSync); - void ResyncServer(const OBJLIST<WACollection> &task); - void ResyncAll(void); - - __forceinline WACollection *FindCollection(const char *pszName) - { return m_arCollections.find((WACollection *)&pszName); - } - - // Contacts management ///////////////////////////////////////////////////////////////// - - mir_cs m_csUsers; - OBJLIST<WAUser> m_arUsers; - - mir_cs m_csOwnMessages; - OBJLIST<WAOwnMessage> m_arOwnMsgs; - - WAUser* FindUser(const char *szId); - WAUser* AddUser(const char *szId, bool bTemporary); - - // Group chats ///////////////////////////////////////////////////////////////////////// - - void GC_RefreshMetadata(); - void GC_GetAllMetadata(); - void GC_ParseMetadata(const WANode *pGroup); - - int __cdecl GcEventHook(WPARAM, LPARAM); - int __cdecl GcMenuHook(WPARAM, LPARAM); - - // UI ////////////////////////////////////////////////////////////////////////////////// - - void CloseQrDialog(); - bool ShowQrCode(const CMStringA &ref); - - /// Network //////////////////////////////////////////////////////////////////////////// - - time_t m_lastRecvTime; - HNETLIBCONN m_hServerConn; - - mir_cs m_csPacketQueue; - OBJLIST<WARequestBase> m_arPacketQueue; - - LIST<WAPersistentHandler> m_arPersistent; - WA_PKT_HANDLER FindPersistentHandler(const WANode &node); - - int m_iPacketId; - uint16_t m_wMsgPrefix[2]; - CMStringA GenerateMessageId(); - CMStringA GetMessageText(const Wa__Message *pMessage); - void GetMessageContent(CMStringA &txt, const char *szType, const char *szUrl, const char *szMimetype, const char *szDirectPath, const ProtobufCBinaryData &szMediaKey, const char *szCaption = nullptr); - void ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg); - bool CreateMsgParticipant(WANode *pParticipants, const WAJid &jid, const MBinBuffer &orig); - - void ProcessReceipt(MCONTACT hContact, const char *msgId, bool bRead); - - bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf); - int WSSend(const ProtobufCMessage &msg); - int WSSendNode(WANode &node); - int WSSendNode(WANode &node, WA_PKT_HANDLER); - int WSSendNode(WANode &node, WA_PKT_HANDLER_FULL, void *pUserInfo); - - MBinBuffer DownloadEncryptedFile(const char *url, const ProtobufCBinaryData &mediaKeys, const char *pszType); - CMStringW GetTmpFileName(const char *pszClass, const char *addition); - - void OnLoggedIn(void); - void OnLoggedOut(void); - void ProcessFailure(int code); - void ServerThreadWorker(void); - void ShutdownSession(void); - - void SendAck(const WANode &node); - void SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType); - void SendKeepAlive(void); - int SendTextMessage(const char *jid, const char *pszMsg); - void SendUnregister(void); - void SendUsync(const LIST<char> &jids, void *pUserInfo); - void SetServerStatus(int iStatus); - - void FinishTask(WASendTask *pTask); - void SendTask(WASendTask *pTask); - - /// Popups ///////////////////////////////////////////////////////////////////////////// - - HANDLE m_hPopupClass; - CMOption<bool> m_bUsePopups; - - void InitPopups(void); - void Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle); - - /// Request handlers /////////////////////////////////////////////////////////////////// - - void OnProcessHandshake(const uint8_t *pData, int cbLen); - - void InitPersistentHandlers(); - void OnAccountSync(const WANode &node); - void OnIqBlockList(const WANode &node); - void OnIqCountPrekeys(const WANode &node); - void OnIqDoNothing(const WANode &node); - void OnIqGcGetAllMetadata(const WANode &node); - void OnIqGetAvatar(const WANode &node); - void OnIqGetKeys(const WANode &node, void *pUserInfo); - void OnIqGetUsync(const WANode &node, void *pUserInfo); - void OnIqPairDevice(const WANode &node); - void OnIqPairSuccess(const WANode &node); - void OnIqResult(const WANode &node); - void OnIqServerSync(const WANode &node); - void OnNotifyAny(const WANode &node); - void OnNotifyDevices(const WANode &node); - void OnNotifyEncrypt(const WANode &node); - void OnNotifyPicture(const WANode &node); - void OnReceiveAck(const WANode &node); - void OnReceiveChatState(const WANode &node); - void OnReceiveFailure(const WANode &node); - void OnReceiveInfo(const WANode &node); - void OnReceiveMessage(const WANode &node); - void OnReceiveReceipt(const WANode &node); - void OnServerSync(const WANode &node); - void OnStreamError(const WANode &node); - void OnSuccess(const WANode &node); - - // Signal - MSignalStore m_signalStore; - - // Binary packets - void ProcessBinaryPacket(const uint8_t *pData, size_t cbLen); - - // unzip operations - MBinBuffer unzip(const MBinBuffer &src); - - /// Avatars //////////////////////////////////////////////////////////////////////////// - CMStringW GetAvatarFileName(MCONTACT hContact); - void ServerFetchAvatar(const char *jid); - - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); - INT_PTR __cdecl SetMyAvatar(WPARAM, LPARAM); - -public: - WhatsAppProto(const char *proto_name, const wchar_t *username); - ~WhatsAppProto(); - - __forceinline bool isOnline() const - { return m_hServerConn != 0; - } - - __forceinline void writeStr(const char *pszSetting, const JSONNode &node) - { - CMStringW str(node.as_mstring()); - if (!str.IsEmpty()) - setWString(pszSetting, str); - } - - class CWhatsAppQRDlg *m_pQRDlg; - - // PROTO_INTERFACE ///////////////////////////////////////////////////////////////////// - - MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override; - INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; - HANDLE SearchBasic(const wchar_t* id) override; - int SendMsg(MCONTACT hContact, int flags, const char* msg) override; - int SetStatus(int iNewStatus) override; - int UserIsTyping(MCONTACT hContact, int type) override; - - void OnErase() override; - void OnModulesLoaded() override; - - // Services //////////////////////////////////////////////////////////////////////////// - - INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); - - // Events ////////////////////////////////////////////////////////////////////////////// - - int __cdecl OnOptionsInit(WPARAM, LPARAM); - int __cdecl OnBuildStatusMenu(WPARAM, LPARAM); - - // Options ///////////////////////////////////////////////////////////////////////////// - - CMOption<wchar_t*> m_wszNick; // your nick name in presence - CMOption<wchar_t*> m_wszDeviceName; // how do you see Miranda in mobile phone - CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts - CMOption<bool> m_bHideGroupchats; // do not open chat windows on creation - CMOption<bool> m_bUseBbcodes; // use extended markup for messages - - // Processing Threads ////////////////////////////////////////////////////////////////// - - void __cdecl SearchAckThread(void*); - void __cdecl ServerThread(void*); -}; - -struct CMPlugin : public ACCPROTOPLUGIN<WhatsAppProto> -{ - HNETLIBUSER hAvatarUser = nullptr; - HNETLIBCONN hAvatarConn = nullptr; - bool SaveFile(const char *pszUrl, PROTO_AVATAR_INFORMATION &ai); - - bool bHasMessageState = false; - - CMPlugin(); - - int Load() override; - int Unload() override; -}; - -#endif +/*
+
+WhatsApp plugin for Miranda NG
+Copyright © 2019-23 George Hazan
+
+*/
+
+#if !defined(PROTO_H)
+#define PROTO_H
+
+#define S_WHATSAPP_NET "@s.whatsapp.net"
+#define APP_VERSION "2.2230.15"
+#define KEY_BUNDLE_TYPE "\x05"
+
+class WhatsAppProto;
+typedef void (WhatsAppProto:: *WA_PKT_HANDLER)(const WANode &node);
+typedef void (WhatsAppProto:: *WA_PKT_HANDLER_FULL)(const WANode &node, void *pUserInfo);
+
+struct WAMSG
+{
+ union {
+ uint32_t dwFlags = 0;
+ struct {
+ bool bPrivateChat : 1;
+ bool bGroupChat : 1;
+ bool bDirectStatus : 1;
+ bool bOtherStatus : 1;
+ bool bPeerBroadcast : 1;
+ bool bOtherBroadcast : 1;
+ bool bOffline : 1;
+ };
+ };
+};
+
+struct WAMediaKeys
+{
+ WAMediaKeys(const uint8_t *pKey, size_t keyLen, const char *pszMediaType);
+
+ uint8_t iv[16];
+ uint8_t cipherKey[32];
+ uint8_t macKey[64];
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// own requests
+
+struct WARequestBase
+{
+ WARequestBase(const CMStringA &_1) :
+ szPacketId(_1)
+ {}
+ virtual ~WARequestBase() {}
+
+ CMStringA szPacketId;
+
+ virtual void Execute(WhatsAppProto *ppro, const WANode &node) = 0;
+};
+
+class WARequestSimple : public WARequestBase
+{
+ WA_PKT_HANDLER pHandler;
+
+public:
+ WARequestSimple(const CMStringA &_1, WA_PKT_HANDLER _2) :
+ WARequestBase(_1),
+ pHandler(_2)
+ {}
+
+ void Execute(WhatsAppProto *ppro, const WANode &node) override
+ {
+ (ppro->*pHandler)(node);
+ }
+};
+
+class WARequestParam : public WARequestBase
+{
+ WA_PKT_HANDLER_FULL pHandler;
+ void *pUserInfo;
+
+public:
+ WARequestParam(const CMStringA &_1, WA_PKT_HANDLER_FULL _2, void *_3) :
+ WARequestBase(_1),
+ pHandler(_2),
+ pUserInfo(_3)
+ {}
+
+ void Execute(WhatsAppProto *ppro, const WANode &node) override
+ {
+ (ppro->*pHandler)(node, pUserInfo);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct WAPersistentHandler
+{
+ WAPersistentHandler(const char *_1, const char *_2, const char *_3, const char *_4, WA_PKT_HANDLER _5) :
+ pszTitle(_1), pszType(_2), pszXmlns(_3), pszChild(_4), pHandler(_5)
+ {}
+
+ const char *pszTitle, *pszType, *pszXmlns, *pszChild;
+ WA_PKT_HANDLER pHandler;
+};
+
+struct WAUser
+{
+ WAUser(MCONTACT _1, const char *_2, bool _3 = false) :
+ hContact(_1),
+ szId(mir_strdup(_2)),
+ bIsGroupChat(_3),
+ arDevices(1)
+ {
+ }
+
+ ~WAUser()
+ {
+ mir_free(szId);
+ }
+
+ MCONTACT hContact;
+ DWORD dwModifyTag = 0;
+ char *szId;
+ bool bInited = false, bIsGroupChat, bDeviceInit = false;
+ SESSION_INFO *si = 0;
+ OBJLIST<WAJid> arDevices;
+ time_t m_timer1 = 0, m_timer2 = 0;
+};
+
+struct WAOwnMessage
+{
+ WAOwnMessage(int _1, const char *_2, const char *_3) :
+ pktId(_1),
+ szJid(_2),
+ szMessageId(_3)
+ {}
+
+ int pktId;
+ CMStringA szJid, szMessageId;
+};
+
+struct WACollection
+{
+ WACollection(const char *_1, int _2 = 0) :
+ szName(mir_strdup(_1)),
+ version(_2)
+ {}
+
+ ptrA szName;
+ int version;
+
+ LT_HASH hash;
+ std::map<std::string, std::string> indexValueMap;
+};
+
+class WANoise
+{
+ friend class WhatsAppProto;
+
+ WhatsAppProto *ppro;
+ uint32_t readCounter = 0, writeCounter = 0;
+ bool bInitFinished = false, bSendIntro = false;
+ MBinBuffer salt, encKey, decKey;
+ uint8_t hash[32];
+
+ struct {
+ MBinBuffer priv, pub;
+ } noiseKeys, ephemeral;
+
+ void deriveKey(const void *pData, size_t cbLen, MBinBuffer &write, MBinBuffer &read);
+ void mixIntoKey(const void *n, const void *p);
+ void updateHash(const void *pData, size_t cbLen);
+
+public:
+ WANoise(WhatsAppProto *_ppro);
+
+ void finish();
+ void init();
+
+ MBinBuffer decrypt(const void *pData, size_t cbLen);
+ MBinBuffer encrypt(const void *pData, size_t cbLen);
+
+ size_t decodeFrame(const uint8_t *&pData, size_t &cbLen);
+ MBinBuffer encodeFrame(const void *pData, size_t cbLen);
+};
+
+class MSignalSession : public MZeroedObject
+{
+ friend class MSignalStore;
+ signal_protocol_address address;
+ session_cipher *cipher = nullptr;
+
+public:
+ CMStringA szName;
+ MBinBuffer sessionData;
+
+ MSignalSession(const CMStringA &_1, int _2);
+ ~MSignalSession();
+
+ bool hasAddress(const char *name, size_t name_len) const;
+
+ __forceinline session_cipher* getCipher(void) const { return cipher; }
+ __forceinline int getDeviceId() const { return address.device_id; }
+ CMStringA getSetting() const;
+};
+
+class MSignalStore
+{
+ void init();
+
+ signal_context *m_pContext;
+ signal_protocol_store_context *m_pStore;
+
+ void importPublicKey(ec_public_key **result, MBinBuffer &buf);
+
+public:
+ PROTO_INTERFACE *pProto;
+ const char *prefix;
+
+ OBJLIST<MSignalSession> arSessions;
+
+ struct
+ {
+ MBinBuffer priv, pub;
+ }
+ signedIdentity;
+
+ struct
+ {
+ MBinBuffer priv, pub, signature;
+ uint32_t keyid;
+ }
+ preKey;
+
+ MSignalStore(PROTO_INTERFACE *_1, const char *_2);
+ ~MSignalStore();
+
+ __forceinline signal_context *CTX() const { return m_pContext; }
+
+ MSignalSession* createSession(const CMStringA &szName, int deviceId);
+ MSignalSession* getSession(const signal_protocol_address *address);
+ void injectSession(const char *szJid, const WANode *pNode, const WANode *pKey);
+
+ MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted);
+ MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted);
+
+ MBinBuffer encryptSenderKey(const WAJid &to, const CMStringA &from, const MBinBuffer &buf, MBinBuffer &skmsgKey);
+ MBinBuffer encryptSignalProto(const WAJid &to, const MBinBuffer &buf, int &type);
+
+ MBinBuffer encodeSignedIdentity(bool);
+ void generatePrekeys(int count);
+
+ void logError(int code, const char *szMessage);
+
+ void processSenderKeyMessage(const CMStringA &author, const Wa__Message__SenderKeyDistributionMessage *msg);
+};
+
+class WhatsAppProto : public PROTO<WhatsAppProto>
+{
+ friend class WANoise;
+ friend class CWhatsAppQRDlg;
+ friend class COptionsDlg;
+
+ class CWhatsAppProtoImpl
+ {
+ friend class WhatsAppProto;
+ WhatsAppProto &m_proto;
+
+ CTimer m_keepAlive, m_resyncApp;
+ void OnKeepAlive(CTimer *)
+ { m_proto.SendKeepAlive();
+ }
+ void OnResync(CTimer *pTimer)
+ {
+ pTimer->Stop();
+ m_proto.ResyncAll();
+ }
+
+ CWhatsAppProtoImpl(WhatsAppProto &pro) :
+ m_proto(pro),
+ m_keepAlive(Miranda_GetSystemWindow(), UINT_PTR(this)),
+ m_resyncApp(Miranda_GetSystemWindow(), UINT_PTR(this)+1)
+ {
+ m_keepAlive.OnEvent = Callback(this, &CWhatsAppProtoImpl::OnKeepAlive);
+ m_resyncApp.OnEvent = Callback(this, &CWhatsAppProtoImpl::OnResync);
+ }
+ } m_impl;
+
+ bool m_bTerminated, m_bRespawn, m_bUpdatedPrekeys, m_bUnregister;
+ ptrW m_tszDefaultGroup;
+
+ CMStringA m_szJid;
+ CMStringW m_tszAvatarFolder;
+
+ EVP_PKEY *m_pKeys; // private & public keys
+ WANoise *m_noise;
+
+ void UploadMorePrekeys();
+
+ // App state management
+ OBJLIST<WACollection> m_arCollections;
+
+ void InitSync(void);
+ void ApplyPatch(const JSONNode &index, const Wa__SyncActionValue *data);
+ void ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec, bool bSet);
+ void ProcessHistorySync(const Wa__HistorySync *pSync);
+ void ResyncServer(const OBJLIST<WACollection> &task);
+ void ResyncAll(void);
+
+ __forceinline WACollection *FindCollection(const char *pszName)
+ { return m_arCollections.find((WACollection *)&pszName);
+ }
+
+ // Contacts management /////////////////////////////////////////////////////////////////
+
+ mir_cs m_csUsers;
+ OBJLIST<WAUser> m_arUsers;
+
+ mir_cs m_csOwnMessages;
+ OBJLIST<WAOwnMessage> m_arOwnMsgs;
+
+ WAUser* FindUser(const char *szId);
+ WAUser* AddUser(const char *szId, bool bTemporary);
+
+ // Group chats /////////////////////////////////////////////////////////////////////////
+
+ void GC_RefreshMetadata();
+ void GC_GetAllMetadata();
+ void GC_ParseMetadata(const WANode *pGroup);
+
+ int __cdecl GcEventHook(WPARAM, LPARAM);
+ int __cdecl GcMenuHook(WPARAM, LPARAM);
+
+ // UI //////////////////////////////////////////////////////////////////////////////////
+
+ void CloseQrDialog();
+ bool ShowQrCode(const CMStringA &ref);
+
+ /// Network ////////////////////////////////////////////////////////////////////////////
+
+ time_t m_lastRecvTime;
+ HNETLIBCONN m_hServerConn;
+
+ mir_cs m_csPacketQueue;
+ OBJLIST<WARequestBase> m_arPacketQueue;
+
+ LIST<WAPersistentHandler> m_arPersistent;
+ WA_PKT_HANDLER FindPersistentHandler(const WANode &node);
+
+ int m_iPacketId;
+ uint16_t m_wMsgPrefix[2];
+ CMStringA GenerateMessageId();
+ CMStringA GetMessageText(const Wa__Message *pMessage);
+ void GetMessageContent(CMStringA &txt, const char *szType, const char *szUrl, const char *szMimetype, const char *szDirectPath, const ProtobufCBinaryData &szMediaKey, const char *szCaption = nullptr);
+ void ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg);
+ bool CreateMsgParticipant(WANode *pParticipants, const WAJid &jid, const MBinBuffer &orig);
+
+ void ProcessReceipt(MCONTACT hContact, const char *msgId, bool bRead);
+
+ bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf);
+ int WSSend(const ProtobufCMessage &msg);
+ int WSSendNode(WANode &node);
+ int WSSendNode(WANode &node, WA_PKT_HANDLER);
+ int WSSendNode(WANode &node, WA_PKT_HANDLER_FULL, void *pUserInfo);
+
+ MBinBuffer DownloadEncryptedFile(const char *url, const ProtobufCBinaryData &mediaKeys, const char *pszType);
+ CMStringW GetTmpFileName(const char *pszClass, const char *addition);
+
+ void OnLoggedIn(void);
+ void OnLoggedOut(void);
+ void ProcessFailure(int code);
+ void ServerThreadWorker(void);
+ void ShutdownSession(void);
+
+ void SendAck(const WANode &node);
+ void SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType);
+ void SendKeepAlive(void);
+ int SendTextMessage(const char *jid, const char *pszMsg);
+ void SendUnregister(void);
+ void SendUsync(const LIST<char> &jids, void *pUserInfo);
+ void SetServerStatus(int iStatus);
+
+ void FinishTask(WASendTask *pTask);
+ void SendTask(WASendTask *pTask);
+
+ /// Popups /////////////////////////////////////////////////////////////////////////////
+
+ HANDLE m_hPopupClass;
+ CMOption<bool> m_bUsePopups;
+
+ void InitPopups(void);
+ void Popup(MCONTACT hContact, const wchar_t *szMsg, const wchar_t *szTitle);
+
+ /// Request handlers ///////////////////////////////////////////////////////////////////
+
+ void OnProcessHandshake(const uint8_t *pData, int cbLen);
+
+ void InitPersistentHandlers();
+ void OnAccountSync(const WANode &node);
+ void OnIqBlockList(const WANode &node);
+ void OnIqCountPrekeys(const WANode &node);
+ void OnIqDoNothing(const WANode &node);
+ void OnIqGcGetAllMetadata(const WANode &node);
+ void OnIqGetAvatar(const WANode &node);
+ void OnIqGetKeys(const WANode &node, void *pUserInfo);
+ void OnIqGetUsync(const WANode &node, void *pUserInfo);
+ void OnIqPairDevice(const WANode &node);
+ void OnIqPairSuccess(const WANode &node);
+ void OnIqResult(const WANode &node);
+ void OnIqServerSync(const WANode &node);
+ void OnNotifyAny(const WANode &node);
+ void OnNotifyDevices(const WANode &node);
+ void OnNotifyEncrypt(const WANode &node);
+ void OnNotifyPicture(const WANode &node);
+ void OnReceiveAck(const WANode &node);
+ void OnReceiveChatState(const WANode &node);
+ void OnReceiveFailure(const WANode &node);
+ void OnReceiveInfo(const WANode &node);
+ void OnReceiveMessage(const WANode &node);
+ void OnReceiveReceipt(const WANode &node);
+ void OnServerSync(const WANode &node);
+ void OnStreamError(const WANode &node);
+ void OnSuccess(const WANode &node);
+
+ // Signal
+ MSignalStore m_signalStore;
+
+ // Binary packets
+ void ProcessBinaryPacket(const uint8_t *pData, size_t cbLen);
+
+ // unzip operations
+ MBinBuffer unzip(const MBinBuffer &src);
+
+ /// Avatars ////////////////////////////////////////////////////////////////////////////
+ CMStringW GetAvatarFileName(MCONTACT hContact);
+ void ServerFetchAvatar(const char *jid);
+
+ INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
+ INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM);
+ INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM);
+ INT_PTR __cdecl SetMyAvatar(WPARAM, LPARAM);
+
+public:
+ WhatsAppProto(const char *proto_name, const wchar_t *username);
+ ~WhatsAppProto();
+
+ __forceinline bool isOnline() const
+ { return m_hServerConn != 0;
+ }
+
+ __forceinline void writeStr(const char *pszSetting, const JSONNode &node)
+ {
+ CMStringW str(node.as_mstring());
+ if (!str.IsEmpty())
+ setWString(pszSetting, str);
+ }
+
+ class CWhatsAppQRDlg *m_pQRDlg;
+
+ // PROTO_INTERFACE /////////////////////////////////////////////////////////////////////
+
+ MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr) override;
+ INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
+ HANDLE SearchBasic(const wchar_t* id) override;
+ int SendMsg(MCONTACT hContact, int flags, const char* msg) override;
+ int SetStatus(int iNewStatus) override;
+ int UserIsTyping(MCONTACT hContact, int type) override;
+
+ void OnErase() override;
+ void OnModulesLoaded() override;
+
+ // Services ////////////////////////////////////////////////////////////////////////////
+
+ INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM);
+
+ // Events //////////////////////////////////////////////////////////////////////////////
+
+ int __cdecl OnOptionsInit(WPARAM, LPARAM);
+ int __cdecl OnBuildStatusMenu(WPARAM, LPARAM);
+
+ // Options /////////////////////////////////////////////////////////////////////////////
+
+ CMOption<wchar_t*> m_wszNick; // your nick name in presence
+ CMOption<wchar_t*> m_wszDeviceName; // how do you see Miranda in mobile phone
+ CMOption<wchar_t*> m_wszDefaultGroup; // clist group to store contacts
+ CMOption<bool> m_bHideGroupchats; // do not open chat windows on creation
+ CMOption<bool> m_bUseBbcodes; // use extended markup for messages
+
+ // Processing Threads //////////////////////////////////////////////////////////////////
+
+ void __cdecl SearchAckThread(void*);
+ void __cdecl ServerThread(void*);
+};
+
+struct CMPlugin : public ACCPROTOPLUGIN<WhatsAppProto>
+{
+ HNETLIBUSER hAvatarUser = nullptr;
+ HNETLIBCONN hAvatarConn = nullptr;
+ bool SaveFile(const char *pszUrl, PROTO_AVATAR_INFORMATION &ai);
+
+ bool bHasMessageState = false;
+
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+#endif
diff --git a/protocols/WhatsApp/src/server.cpp b/protocols/WhatsApp/src/server.cpp index 7512b05caf..24d64e5aa7 100644 --- a/protocols/WhatsApp/src/server.cpp +++ b/protocols/WhatsApp/src/server.cpp @@ -1,418 +1,418 @@ -/* - -WhatsApp plugin for Miranda NG -Copyright © 2019-23 George Hazan - -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// gateway worker thread - -void WhatsAppProto::ServerThread(void *) -{ - do { - m_bRespawn = m_bUnregister = false; - ServerThreadWorker(); - } - while (m_bRespawn); - - OnLoggedOut(); -} - -void WhatsAppProto::ServerThreadWorker() -{ - // connect websocket - NETLIBHTTPHEADER hdrs[] = - { - { "Origin", "https://web.whatsapp.com" }, - { 0, 0 } - }; - - NLHR_PTR pReply(WebSocket_Connect(m_hNetlibUser, "web.whatsapp.com/ws/chat", hdrs)); - if (pReply == nullptr) { - debugLogA("Server connection failed, exiting"); - return; - } - - if (pReply->resultCode != 101) - return; - - delete m_noise; - m_noise = new WANoise(this); - m_noise->init(); - - debugLogA("Server connection succeeded"); - m_hServerConn = pReply->nlc; - m_lastRecvTime = time(0); - m_iPacketId = 1; - - Utils_GetRandom(m_wMsgPrefix, sizeof(m_wMsgPrefix)); - - Wa__HandshakeMessage__ClientHello client; - client.ephemeral = {m_noise->ephemeral.pub.length(), m_noise->ephemeral.pub.data()}; - client.has_ephemeral = true; - - Wa__HandshakeMessage msg; - msg.clienthello = &client; - WSSend(msg); - - MBinBuffer netbuf; - - for (m_bTerminated = false; !m_bTerminated;) { - unsigned char buf[2048]; - int bufSize = Netlib_Recv(m_hServerConn, (char *)buf, _countof(buf), MSG_NODUMP); - if (bufSize == 0) { - debugLogA("Gateway connection gracefully closed"); - break; - } - if (bufSize < 0) { - debugLogA("Gateway connection error, exiting"); - break; - } - - netbuf.append(buf, bufSize); - - WSHeader hdr; - if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) - continue; - - // we lack some data, let's read them - if (netbuf.length() < hdr.headerSize + hdr.payloadSize) - if (!WSReadPacket(hdr, netbuf)) - break; - - // debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", - // netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); - // Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0); - - m_lastRecvTime = time(0); - - // read all payloads from the current buffer, one by one - while (true) { - MBinBuffer currPacket; - currPacket.assign(netbuf.data() + hdr.headerSize, hdr.payloadSize); - - switch (hdr.opCode) { - case 1: // json packet - debugLogA("Text packet, skipping"); - /* - currPacket.append("", 1); // add 0 to use strchr safely - CMStringA szJson(pos, (int)dataSize); - - JSONNode root = JSONNode::parse(szJson); - if (root) { - debugLogA("JSON received:\n%s", start); - - CMStringA szPrefix(start, int(pos - start - 1)); - auto *pReq = m_arPacketQueue.find((WARequest *)&szPrefix); - if (pReq != nullptr) { - root << CHAR_PARAM("$id$", szPrefix); - } - } - } - */ - break; - - case 2: // binary packet - if (hdr.payloadSize > 32) - ProcessBinaryPacket(currPacket.data(), hdr.payloadSize); - break; - - case 8: // close - debugLogA("server required to exit"); - m_bRespawn = m_bTerminated = true; // simply reconnect, don't exit - break; - - default: - Netlib_Dump(m_hServerConn, currPacket.data(), hdr.payloadSize, false, 0); - } - - netbuf.remove(hdr.headerSize + hdr.payloadSize); - // debugLogA("%d bytes removed from network buffer, %d bytes remain", hdr.headerSize + hdr.payloadSize, netbuf.length()); - if (netbuf.length() == 0) - break; - - // if we have not enough data for header, continue reading - if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) { - debugLogA("not enough data for header, continue reading"); - break; - } - - // if we have not enough data for data, continue reading - if (hdr.headerSize + hdr.payloadSize > netbuf.length()) { - debugLogA("not enough place for data (%d+%d > %d), continue reading", hdr.headerSize, hdr.payloadSize, netbuf.length()); - break; - } - - debugLogA("Got inner packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d", - netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked); - } - } - - debugLogA("Server connection dropped"); - Netlib_CloseHandle(m_hServerConn); - m_hServerConn = nullptr; -} - -bool WhatsAppProto::WSReadPacket(const WSHeader &hdr, MBinBuffer &res) -{ - size_t currPacketSize = res.length() - hdr.headerSize; - - char buf[1024]; - while (currPacketSize < hdr.payloadSize) { - int result = Netlib_Recv(m_hServerConn, buf, _countof(buf), MSG_NODUMP); - if (result == 0) { - debugLogA("Gateway connection gracefully closed"); - return false; - } - if (result < 0) { - debugLogA("Gateway connection error, exiting"); - return false; - } - - currPacketSize += result; - res.append(buf, result); - } - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Binary data processing - -void WhatsAppProto::ProcessBinaryPacket(const uint8_t *pData, size_t cbDataLen) -{ - while (size_t payloadLen = m_noise->decodeFrame(pData, cbDataLen)) { - if (m_noise->bInitFinished) { - MBinBuffer buf = m_noise->decrypt(pData, payloadLen); - - WAReader rdr(buf.data(), buf.length()); - auto b = rdr.readInt8(); - if (b & 2) { - buf.remove(1); - buf = unzip(buf); - rdr = WAReader(buf.data(), buf.length()); - } - - if (WANode *pNode = rdr.readNode()) { - CMStringA szText; - pNode->print(szText); - debugLogA("Got binary node:\n%s", szText.c_str()); - - auto pHandler = FindPersistentHandler(*pNode); - if (pHandler) - (this->*pHandler)(*pNode); - else - debugLogA("cannot handle incoming message"); - - delete pNode; - } - else { - debugLogA("wrong or broken payload"); - Netlib_Dump(m_hServerConn, pData, cbDataLen, false, 0); - } - } - else OnProcessHandshake(pData, (int)payloadLen); - - pData = (BYTE*)pData + payloadLen; - cbDataLen -= payloadLen; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::ProcessFailure(int code) -{ - switch (code) { - case 401: - debugLogA("Connection logged out from another device, exiting"); - Popup(0, TranslateT("This account was logged out from mobile phone, you need to link it again"), m_tszUserName); - - OnErase(); - break; - - case 408: - debugLogA("Connection lost, exiting"); - break; - - case 411: - debugLogA("Conflict between two devices, exiting"); - break; - - case 428: - debugLogA("Connection forcibly closed by the server, exiting"); - break; - - case 440: - debugLogA("Connection replaced from another device, exiting"); - break; - - case 515: - debugLogA("Server required to restart immediately, leaving thread"); - m_bRespawn = true; - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::OnLoggedIn() -{ - debugLogA("WhatsAppProto::OnLoggedIn"); - - if (m_bUnregister) { - SendUnregister(); - m_bTerminated = true; - return; - } - - SetServerStatus(m_iDesiredStatus); - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); - m_iStatus = m_iDesiredStatus; - m_bUpdatedPrekeys = false; - - m_impl.m_keepAlive.Start(1000); - - // retrieve initial info - WANodeIq abt(IQ::GET, "abt"); - abt.addChild("props")->addAttr("protocol", "1"); - WSSendNode(abt, &WhatsAppProto::OnIqDoNothing); - - WSSendNode( - WANodeIq(IQ::GET, "w") << XCHILD("props"), - &WhatsAppProto::OnIqDoNothing); - - WSSendNode( - WANodeIq(IQ::GET, "blocklist"), - &WhatsAppProto::OnIqBlockList); - - WSSendNode( - WANodeIq(IQ::GET, "privacy") << XCHILD("privacy"), - &WhatsAppProto::OnIqDoNothing); - - GC_RefreshMetadata(); -} - -void WhatsAppProto::OnLoggedOut(void) -{ - m_impl.m_keepAlive.Stop(); - - debugLogA("WhatsAppProto::OnLoggedOut"); - m_bTerminated = true; - - ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); - m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; - - setAllContactStatuses(ID_STATUS_OFFLINE, false); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Service packets sending - -void WhatsAppProto::SendAck(const WANode &node) -{ - WANode ack("ack"); - ack << CHAR_PARAM("to", node.getAttr("from")) << CHAR_PARAM("id", node.getAttr("id")) << CHAR_PARAM("class", node.title); - if (node.title != "message") - if (auto *param = node.getAttr("type")) - ack << CHAR_PARAM("type", param); - if (auto *param = node.getAttr("participant")) - ack << CHAR_PARAM("participant", param); - if (auto *param = node.getAttr("recipient")) - ack << CHAR_PARAM("recipient", param); - WSSendNode(ack); -} - -void WhatsAppProto::SendKeepAlive() -{ - time_t now = time(0); - if (now - m_lastRecvTime > 20) { - WSSendNode(WANodeIq(IQ::GET, "w:p") << XCHILD("ping"), &WhatsAppProto::OnIqDoNothing); - - m_lastRecvTime = now; - } - - for (auto &it : m_arUsers) { - if (it->m_timer1 && now - it->m_timer1 > 600) { - it->m_timer1 = 0; - it->m_timer2 = now; - setWord(it->hContact, "Status", ID_STATUS_AWAY); - } - else if (it->m_timer2 && now - it->m_timer2 > 600) { - it->m_timer2 = 0; - setWord(it->hContact, "Status", ID_STATUS_OFFLINE); - } - } -} - -void WhatsAppProto::SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType) -{ - WANode receipt("receipt"); - receipt << CHAR_PARAM("id", pszId); - - if (!mir_strcmp(pszType, "read") || !mir_strcmp(pszType, "read-self")) - receipt << INT_PARAM("t", time(0)); - - if (!mir_strcmp(pszType, "sender") && WAJid(pszTo).isUser()) - receipt << CHAR_PARAM("to", pszParticipant) << CHAR_PARAM("recipient", pszTo); - else { - receipt << CHAR_PARAM("to", pszTo); - if (pszParticipant) - receipt << CHAR_PARAM("participant", pszParticipant); - } - - if (pszType) - receipt << CHAR_PARAM("type", pszType); - WSSendNode(receipt); -} - -void WhatsAppProto::SetServerStatus(int iStatus) -{ - if (mir_wstrlen(m_wszNick)) - WSSendNode( - WANode("presence") << CHAR_PARAM("name", T2Utf(m_wszNick)) << CHAR_PARAM("type", (iStatus == ID_STATUS_ONLINE) ? "available" : "unavailable"), - &WhatsAppProto::OnIqDoNothing); -} - -void WhatsAppProto::SendUnregister() -{ - WANodeIq iq(IQ::SET, "md"); - *iq.addChild("remove-companion-device") << CHAR_PARAM("jid", WAJid(m_szJid, getDword(DBKEY_DEVICE_ID)).toString()) << CHAR_PARAM("reason", "user's decision"); - WSSendNode(iq, &WhatsAppProto::OnIqDoNothing); - - m_bTerminated = true; -} - -void WhatsAppProto::SendUsync(const LIST<char> &jids, void *pUserInfo) -{ - WANodeIq iq(IQ::GET, "usync"); - - auto *pNode1 = iq.addChild("usync"); - *pNode1 << CHAR_PARAM("sid", GenerateMessageId()) << CHAR_PARAM("mode", "query") << CHAR_PARAM("last", "true") - << CHAR_PARAM("index", "0") << CHAR_PARAM("context", "message"); - - pNode1->addChild("query")->addChild("devices")->addAttr("version", "2"); - auto *pList = pNode1->addChild("list"); - for (auto &it : jids) - pList->addChild("user")->addAttr("jid", it); - - WSSendNode(iq, &WhatsAppProto::OnIqGetUsync, pUserInfo); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void WhatsAppProto::ShutdownSession() -{ - if (m_bTerminated) - return; - - debugLogA("WhatsAppProto::ShutdownSession"); - - // shutdown all resources - if (m_hServerConn) - Netlib_Shutdown(m_hServerConn); - - OnLoggedOut(); -} +/*
+
+WhatsApp plugin for Miranda NG
+Copyright © 2019-23 George Hazan
+
+*/
+
+#include "stdafx.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// gateway worker thread
+
+void WhatsAppProto::ServerThread(void *)
+{
+ do {
+ m_bRespawn = m_bUnregister = false;
+ ServerThreadWorker();
+ }
+ while (m_bRespawn);
+
+ OnLoggedOut();
+}
+
+void WhatsAppProto::ServerThreadWorker()
+{
+ // connect websocket
+ NETLIBHTTPHEADER hdrs[] =
+ {
+ { "Origin", "https://web.whatsapp.com" },
+ { 0, 0 }
+ };
+
+ NLHR_PTR pReply(WebSocket_Connect(m_hNetlibUser, "web.whatsapp.com/ws/chat", hdrs));
+ if (pReply == nullptr) {
+ debugLogA("Server connection failed, exiting");
+ return;
+ }
+
+ if (pReply->resultCode != 101)
+ return;
+
+ delete m_noise;
+ m_noise = new WANoise(this);
+ m_noise->init();
+
+ debugLogA("Server connection succeeded");
+ m_hServerConn = pReply->nlc;
+ m_lastRecvTime = time(0);
+ m_iPacketId = 1;
+
+ Utils_GetRandom(m_wMsgPrefix, sizeof(m_wMsgPrefix));
+
+ Wa__HandshakeMessage__ClientHello client;
+ client.ephemeral = {m_noise->ephemeral.pub.length(), m_noise->ephemeral.pub.data()};
+ client.has_ephemeral = true;
+
+ Wa__HandshakeMessage msg;
+ msg.clienthello = &client;
+ WSSend(msg);
+
+ MBinBuffer netbuf;
+
+ for (m_bTerminated = false; !m_bTerminated;) {
+ unsigned char buf[2048];
+ int bufSize = Netlib_Recv(m_hServerConn, (char *)buf, _countof(buf), MSG_NODUMP);
+ if (bufSize == 0) {
+ debugLogA("Gateway connection gracefully closed");
+ break;
+ }
+ if (bufSize < 0) {
+ debugLogA("Gateway connection error, exiting");
+ break;
+ }
+
+ netbuf.append(buf, bufSize);
+
+ WSHeader hdr;
+ if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length()))
+ continue;
+
+ // we lack some data, let's read them
+ if (netbuf.length() < hdr.headerSize + hdr.payloadSize)
+ if (!WSReadPacket(hdr, netbuf))
+ break;
+
+ // debugLogA("Got packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d",
+ // netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked);
+ // Netlib_Dump(m_hServerConn, netbuf.data(), netbuf.length(), false, 0);
+
+ m_lastRecvTime = time(0);
+
+ // read all payloads from the current buffer, one by one
+ while (true) {
+ MBinBuffer currPacket;
+ currPacket.assign(netbuf.data() + hdr.headerSize, hdr.payloadSize);
+
+ switch (hdr.opCode) {
+ case 1: // json packet
+ debugLogA("Text packet, skipping");
+ /*
+ currPacket.append("", 1); // add 0 to use strchr safely
+ CMStringA szJson(pos, (int)dataSize);
+
+ JSONNode root = JSONNode::parse(szJson);
+ if (root) {
+ debugLogA("JSON received:\n%s", start);
+
+ CMStringA szPrefix(start, int(pos - start - 1));
+ auto *pReq = m_arPacketQueue.find((WARequest *)&szPrefix);
+ if (pReq != nullptr) {
+ root << CHAR_PARAM("$id$", szPrefix);
+ }
+ }
+ }
+ */
+ break;
+
+ case 2: // binary packet
+ if (hdr.payloadSize > 32)
+ ProcessBinaryPacket(currPacket.data(), hdr.payloadSize);
+ break;
+
+ case 8: // close
+ debugLogA("server required to exit");
+ m_bRespawn = m_bTerminated = true; // simply reconnect, don't exit
+ break;
+
+ default:
+ Netlib_Dump(m_hServerConn, currPacket.data(), hdr.payloadSize, false, 0);
+ }
+
+ netbuf.remove(hdr.headerSize + hdr.payloadSize);
+ // debugLogA("%d bytes removed from network buffer, %d bytes remain", hdr.headerSize + hdr.payloadSize, netbuf.length());
+ if (netbuf.length() == 0)
+ break;
+
+ // if we have not enough data for header, continue reading
+ if (!WebSocket_InitHeader(hdr, netbuf.data(), netbuf.length())) {
+ debugLogA("not enough data for header, continue reading");
+ break;
+ }
+
+ // if we have not enough data for data, continue reading
+ if (hdr.headerSize + hdr.payloadSize > netbuf.length()) {
+ debugLogA("not enough place for data (%d+%d > %d), continue reading", hdr.headerSize, hdr.payloadSize, netbuf.length());
+ break;
+ }
+
+ debugLogA("Got inner packet: buffer = %d, opcode = %d, headerSize = %d, payloadSize = %d, final = %d, masked = %d",
+ netbuf.length(), hdr.opCode, hdr.headerSize, hdr.payloadSize, hdr.bIsFinal, hdr.bIsMasked);
+ }
+ }
+
+ debugLogA("Server connection dropped");
+ Netlib_CloseHandle(m_hServerConn);
+ m_hServerConn = nullptr;
+}
+
+bool WhatsAppProto::WSReadPacket(const WSHeader &hdr, MBinBuffer &res)
+{
+ size_t currPacketSize = res.length() - hdr.headerSize;
+
+ char buf[1024];
+ while (currPacketSize < hdr.payloadSize) {
+ int result = Netlib_Recv(m_hServerConn, buf, _countof(buf), MSG_NODUMP);
+ if (result == 0) {
+ debugLogA("Gateway connection gracefully closed");
+ return false;
+ }
+ if (result < 0) {
+ debugLogA("Gateway connection error, exiting");
+ return false;
+ }
+
+ currPacketSize += result;
+ res.append(buf, result);
+ }
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Binary data processing
+
+void WhatsAppProto::ProcessBinaryPacket(const uint8_t *pData, size_t cbDataLen)
+{
+ while (size_t payloadLen = m_noise->decodeFrame(pData, cbDataLen)) {
+ if (m_noise->bInitFinished) {
+ MBinBuffer buf = m_noise->decrypt(pData, payloadLen);
+
+ WAReader rdr(buf.data(), buf.length());
+ auto b = rdr.readInt8();
+ if (b & 2) {
+ buf.remove(1);
+ buf = unzip(buf);
+ rdr = WAReader(buf.data(), buf.length());
+ }
+
+ if (WANode *pNode = rdr.readNode()) {
+ CMStringA szText;
+ pNode->print(szText);
+ debugLogA("Got binary node:\n%s", szText.c_str());
+
+ auto pHandler = FindPersistentHandler(*pNode);
+ if (pHandler)
+ (this->*pHandler)(*pNode);
+ else
+ debugLogA("cannot handle incoming message");
+
+ delete pNode;
+ }
+ else {
+ debugLogA("wrong or broken payload");
+ Netlib_Dump(m_hServerConn, pData, cbDataLen, false, 0);
+ }
+ }
+ else OnProcessHandshake(pData, (int)payloadLen);
+
+ pData = (BYTE*)pData + payloadLen;
+ cbDataLen -= payloadLen;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::ProcessFailure(int code)
+{
+ switch (code) {
+ case 401:
+ debugLogA("Connection logged out from another device, exiting");
+ Popup(0, TranslateT("This account was logged out from mobile phone, you need to link it again"), m_tszUserName);
+
+ OnErase();
+ break;
+
+ case 408:
+ debugLogA("Connection lost, exiting");
+ break;
+
+ case 411:
+ debugLogA("Conflict between two devices, exiting");
+ break;
+
+ case 428:
+ debugLogA("Connection forcibly closed by the server, exiting");
+ break;
+
+ case 440:
+ debugLogA("Connection replaced from another device, exiting");
+ break;
+
+ case 515:
+ debugLogA("Server required to restart immediately, leaving thread");
+ m_bRespawn = true;
+ break;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::OnLoggedIn()
+{
+ debugLogA("WhatsAppProto::OnLoggedIn");
+
+ if (m_bUnregister) {
+ SendUnregister();
+ m_bTerminated = true;
+ return;
+ }
+
+ SetServerStatus(m_iDesiredStatus);
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus);
+ m_iStatus = m_iDesiredStatus;
+ m_bUpdatedPrekeys = false;
+
+ m_impl.m_keepAlive.Start(1000);
+
+ // retrieve initial info
+ WANodeIq abt(IQ::GET, "abt");
+ abt.addChild("props")->addAttr("protocol", "1");
+ WSSendNode(abt, &WhatsAppProto::OnIqDoNothing);
+
+ WSSendNode(
+ WANodeIq(IQ::GET, "w") << XCHILD("props"),
+ &WhatsAppProto::OnIqDoNothing);
+
+ WSSendNode(
+ WANodeIq(IQ::GET, "blocklist"),
+ &WhatsAppProto::OnIqBlockList);
+
+ WSSendNode(
+ WANodeIq(IQ::GET, "privacy") << XCHILD("privacy"),
+ &WhatsAppProto::OnIqDoNothing);
+
+ GC_RefreshMetadata();
+}
+
+void WhatsAppProto::OnLoggedOut(void)
+{
+ m_impl.m_keepAlive.Stop();
+
+ debugLogA("WhatsAppProto::OnLoggedOut");
+ m_bTerminated = true;
+
+ ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE);
+ m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE;
+
+ setAllContactStatuses(ID_STATUS_OFFLINE, false);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Service packets sending
+
+void WhatsAppProto::SendAck(const WANode &node)
+{
+ WANode ack("ack");
+ ack << CHAR_PARAM("to", node.getAttr("from")) << CHAR_PARAM("id", node.getAttr("id")) << CHAR_PARAM("class", node.title);
+ if (node.title != "message")
+ if (auto *param = node.getAttr("type"))
+ ack << CHAR_PARAM("type", param);
+ if (auto *param = node.getAttr("participant"))
+ ack << CHAR_PARAM("participant", param);
+ if (auto *param = node.getAttr("recipient"))
+ ack << CHAR_PARAM("recipient", param);
+ WSSendNode(ack);
+}
+
+void WhatsAppProto::SendKeepAlive()
+{
+ time_t now = time(0);
+ if (now - m_lastRecvTime > 20) {
+ WSSendNode(WANodeIq(IQ::GET, "w:p") << XCHILD("ping"), &WhatsAppProto::OnIqDoNothing);
+
+ m_lastRecvTime = now;
+ }
+
+ for (auto &it : m_arUsers) {
+ if (it->m_timer1 && now - it->m_timer1 > 600) {
+ it->m_timer1 = 0;
+ it->m_timer2 = now;
+ setWord(it->hContact, "Status", ID_STATUS_AWAY);
+ }
+ else if (it->m_timer2 && now - it->m_timer2 > 600) {
+ it->m_timer2 = 0;
+ setWord(it->hContact, "Status", ID_STATUS_OFFLINE);
+ }
+ }
+}
+
+void WhatsAppProto::SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType)
+{
+ WANode receipt("receipt");
+ receipt << CHAR_PARAM("id", pszId);
+
+ if (!mir_strcmp(pszType, "read") || !mir_strcmp(pszType, "read-self"))
+ receipt << INT_PARAM("t", time(0));
+
+ if (!mir_strcmp(pszType, "sender") && WAJid(pszTo).isUser())
+ receipt << CHAR_PARAM("to", pszParticipant) << CHAR_PARAM("recipient", pszTo);
+ else {
+ receipt << CHAR_PARAM("to", pszTo);
+ if (pszParticipant)
+ receipt << CHAR_PARAM("participant", pszParticipant);
+ }
+
+ if (pszType)
+ receipt << CHAR_PARAM("type", pszType);
+ WSSendNode(receipt);
+}
+
+void WhatsAppProto::SetServerStatus(int iStatus)
+{
+ if (mir_wstrlen(m_wszNick))
+ WSSendNode(
+ WANode("presence") << CHAR_PARAM("name", T2Utf(m_wszNick)) << CHAR_PARAM("type", (iStatus == ID_STATUS_ONLINE) ? "available" : "unavailable"),
+ &WhatsAppProto::OnIqDoNothing);
+}
+
+void WhatsAppProto::SendUnregister()
+{
+ WANodeIq iq(IQ::SET, "md");
+ *iq.addChild("remove-companion-device") << CHAR_PARAM("jid", WAJid(m_szJid, getDword(DBKEY_DEVICE_ID)).toString()) << CHAR_PARAM("reason", "user's decision");
+ WSSendNode(iq, &WhatsAppProto::OnIqDoNothing);
+
+ m_bTerminated = true;
+}
+
+void WhatsAppProto::SendUsync(const LIST<char> &jids, void *pUserInfo)
+{
+ WANodeIq iq(IQ::GET, "usync");
+
+ auto *pNode1 = iq.addChild("usync");
+ *pNode1 << CHAR_PARAM("sid", GenerateMessageId()) << CHAR_PARAM("mode", "query") << CHAR_PARAM("last", "true")
+ << CHAR_PARAM("index", "0") << CHAR_PARAM("context", "message");
+
+ pNode1->addChild("query")->addChild("devices")->addAttr("version", "2");
+ auto *pList = pNode1->addChild("list");
+ for (auto &it : jids)
+ pList->addChild("user")->addAttr("jid", it);
+
+ WSSendNode(iq, &WhatsAppProto::OnIqGetUsync, pUserInfo);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void WhatsAppProto::ShutdownSession()
+{
+ if (m_bTerminated)
+ return;
+
+ debugLogA("WhatsAppProto::ShutdownSession");
+
+ // shutdown all resources
+ if (m_hServerConn)
+ Netlib_Shutdown(m_hServerConn);
+
+ OnLoggedOut();
+}
diff --git a/protocols/YAMN/YAMN.vcxproj b/protocols/YAMN/YAMN.vcxproj index 213c4df7c1..203ab9c98b 100644 --- a/protocols/YAMN/YAMN.vcxproj +++ b/protocols/YAMN/YAMN.vcxproj @@ -1,97 +1,97 @@ -<?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>YAMN</ProjectName> - <ProjectGuid>{C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}</ProjectGuid> - </PropertyGroup> - <ImportGroup Label="PropertySheets"> - <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" /> - </ImportGroup> - <ItemGroup> - <ClCompile Include="src\account.cpp" /> - <ClCompile Include="src\browser\badconnect.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\browser\mailbrowser.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\debug.cpp" /> - <ClCompile Include="src\filterplugin.cpp" /> - <ClCompile Include="src\mails\decode.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\mails\mails.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\mails\mime.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\main.cpp" /> - <ClCompile Include="src\protoplugin.cpp" /> - <ClCompile Include="src\proto\netlib.cpp"> - <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3.cpp"> - <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3comm.cpp"> - <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3opt.cpp"> - <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile> - </ClCompile> - <ClCompile Include="src\services.cpp" /> - <ClCompile Include="src\stdafx.cxx"> - <PrecompiledHeader>Create</PrecompiledHeader> - </ClCompile> - <ClCompile Include="src\synchro.cpp" /> - <ClCompile Include="src\yamn.cpp" /> - <ClInclude Include="src\browser\browser.h" /> - <ClInclude Include="src\mails\decode.h" /> - <ClInclude Include="src\proto\netclient.h" /> - <ClInclude Include="src\proto\netlib.h" /> - <ClInclude Include="src\proto\pop3\pop3.h" /> - <ClInclude Include="src\proto\pop3\pop3comm.h" /> - <ClInclude Include="src\proto\pop3\pop3opt.h" /> - <ClInclude Include="src\resource.h" /> - <ClInclude Include="src\stdafx.h" /> - <ClInclude Include="src\version.h" /> - </ItemGroup> - <ItemDefinitionGroup> - <ClCompile> - <ExceptionHandling>Sync</ExceptionHandling> - </ClCompile> - </ItemDefinitionGroup> - <ItemGroup> - <ClInclude Include="src\debug.h" /> - <ClInclude Include="src\main.h" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Version.rc" /> - <ResourceCompile Include="res\YAMN.rc" /> - </ItemGroup> - <ItemGroup> - <Image Include="res\badconnect.ico" /> - <Image Include="res\checkmail.ico" /> - <Image Include="res\launchapp.ico" /> - <Image Include="res\newmail.ico" /> - </ItemGroup> +<?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>YAMN</ProjectName>
+ <ProjectGuid>{C5A87409-F08C-4A07-A8F9-1F5D52BA6D72}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+ <ItemGroup>
+ <ClCompile Include="src\account.cpp" />
+ <ClCompile Include="src\browser\badconnect.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\browser\mailbrowser.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\debug.cpp" />
+ <ClCompile Include="src\filterplugin.cpp" />
+ <ClCompile Include="src\mails\decode.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\mails\mails.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\mails\mime.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\main.cpp" />
+ <ClCompile Include="src\protoplugin.cpp" />
+ <ClCompile Include="src\proto\netlib.cpp">
+ <PrecompiledHeaderFile>..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3.cpp">
+ <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3comm.cpp">
+ <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3opt.cpp">
+ <PrecompiledHeaderFile>..\..\stdafx.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ClCompile Include="src\services.cpp" />
+ <ClCompile Include="src\stdafx.cxx">
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="src\synchro.cpp" />
+ <ClCompile Include="src\yamn.cpp" />
+ <ClInclude Include="src\browser\browser.h" />
+ <ClInclude Include="src\mails\decode.h" />
+ <ClInclude Include="src\proto\netclient.h" />
+ <ClInclude Include="src\proto\netlib.h" />
+ <ClInclude Include="src\proto\pop3\pop3.h" />
+ <ClInclude Include="src\proto\pop3\pop3comm.h" />
+ <ClInclude Include="src\proto\pop3\pop3opt.h" />
+ <ClInclude Include="src\resource.h" />
+ <ClInclude Include="src\stdafx.h" />
+ <ClInclude Include="src\version.h" />
+ </ItemGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="src\debug.h" />
+ <ClInclude Include="src\main.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Version.rc" />
+ <ResourceCompile Include="res\YAMN.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="res\badconnect.ico" />
+ <Image Include="res\checkmail.ico" />
+ <Image Include="res\launchapp.ico" />
+ <Image Include="res\newmail.ico" />
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/YAMN/YAMN.vcxproj.filters b/protocols/YAMN/YAMN.vcxproj.filters index eed1e0e317..0f2b3632b4 100644 --- a/protocols/YAMN/YAMN.vcxproj.filters +++ b/protocols/YAMN/YAMN.vcxproj.filters @@ -1,120 +1,120 @@ -<?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" /> - <ItemGroup> - <ClCompile Include="src\account.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\browser\badconnect.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\browser\mailbrowser.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\debug.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\filterplugin.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\mails\decode.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\mails\mails.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\mails\mime.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\main.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\protoplugin.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\proto\netlib.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3comm.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\proto\pop3\pop3opt.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\services.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\stdafx.cxx"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\synchro.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - <ClCompile Include="src\yamn.cpp"> - <Filter>Source Files</Filter> - </ClCompile> - </ItemGroup> - <ItemGroup> - <ClInclude Include="src\browser\browser.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\mails\decode.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\proto\netclient.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\proto\netlib.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\proto\pop3\pop3.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\proto\pop3\pop3comm.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\proto\pop3\pop3opt.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\resource.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\stdafx.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\version.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\debug.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="src\main.h"> - <Filter>Header Files</Filter> - </ClInclude> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="res\Version.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - <ResourceCompile Include="res\YAMN.rc"> - <Filter>Resource Files</Filter> - </ResourceCompile> - </ItemGroup> - <ItemGroup> - <Image Include="res\checkmail.ico"> - <Filter>Resource Files</Filter> - </Image> - <Image Include="res\launchapp.ico"> - <Filter>Resource Files</Filter> - </Image> - <Image Include="res\badconnect.ico"> - <Filter>Resource Files</Filter> - </Image> - <Image Include="res\newmail.ico"> - <Filter>Resource Files</Filter> - </Image> - </ItemGroup> +<?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" />
+ <ItemGroup>
+ <ClCompile Include="src\account.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\browser\badconnect.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\browser\mailbrowser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\filterplugin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\mails\decode.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\mails\mails.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\mails\mime.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\protoplugin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\proto\netlib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3comm.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\proto\pop3\pop3opt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\services.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\stdafx.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\synchro.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="src\yamn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="src\browser\browser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\mails\decode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\proto\netclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\proto\netlib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\proto\pop3\pop3.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\proto\pop3\pop3comm.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\proto\pop3\pop3opt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="src\main.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="res\Version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="res\YAMN.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Image Include="res\checkmail.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ <Image Include="res\launchapp.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ <Image Include="res\badconnect.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ <Image Include="res\newmail.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
+ </ItemGroup>
</Project>
\ No newline at end of file diff --git a/protocols/YAMN/res/YAMN.rc b/protocols/YAMN/res/YAMN.rc index 1268b0dc8a..de075e62a2 100644 --- a/protocols/YAMN/res/YAMN.rc +++ b/protocols/YAMN/res/YAMN.rc @@ -1,305 +1,305 @@ -// 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 - -///////////////////////////////////////////////////////////////////////////// -// Neutral resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU) -LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -#pragma code_page(1252) - -#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 - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_DLGVIEWMESSAGES, DIALOG - BEGIN - LEFTMARGIN, 5 - RIGHTMARGIN, 455 - TOPMARGIN, 5 - BOTTOMMARGIN, 105 - END - - IDD_DLGBADCONNECT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 43 - END - - IDD_POP3ACCOUNTOPT, DIALOG - BEGIN - VERTGUIDE, 155 - VERTGUIDE, 236 - END - - IDD_CHOOSESTATUSMODES, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 219 - TOPMARGIN, 7 - BOTTOMMARGIN, 147 - END - - IDD_YAMNOPT, DIALOG - BEGIN - RIGHTMARGIN, 310 - VERTGUIDE, 8 - END - - IDD_POP3ACCOUNTPOPUP, DIALOG - BEGIN - VERTGUIDE, 155 - VERTGUIDE, 236 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_DLGVIEWMESSAGES DIALOG 50, 200, 460, 110 -STYLE DS_SETFONT | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -FONT 8, "MS Shell Dlg" -BEGIN - CONTROL "List4",IDC_LISTMAILS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70 - DEFPUSHBUTTON "",IDC_BTNOK,395,90,60,15 - PUSHBUTTON "",IDC_BTNAPP,263,90,114,15 - PUSHBUTTON "",IDC_BTNDEL,5,90,114,15 - LTEXT "",IDC_STSTATUS,5,75,450,10 - PUSHBUTTON "",IDC_BTNCHECKALL,150,91,92,14 -END - -IDD_DLGSHOWMESSAGE DIALOGEX 50, 200, 460, 132 -STYLE DS_SETFONT | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - CONTROL "List5",IDC_LISTHEADERS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70 - CONTROL "",IDC_SPLITTER,"Static",SS_ENHMETAFILE | WS_TABSTOP,0,80,187,2,WS_EX_STATICEDGE - EDITTEXT IDC_EDITBODY,3,84,454,45,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL -END - -IDD_DLGBADCONNECT DIALOG 0, 0, 186, 76 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -FONT 8, "MS Shell Dlg" -BEGIN - DEFPUSHBUTTON "OK",IDC_BTNOK,69,55,50,14 - LTEXT "",IDC_STATICMSG,7,7,172,37 -END - -IDD_POP3ACCOUNTOPT DIALOGEX 0, 0, 310, 230 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_COMBOACCOUNT,4,6,106,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "+",IDC_BTNADD,118,6,15,13 - PUSHBUTTON "-",IDC_BTNDEL,140,6,15,13 - GROUPBOX "Account",IDC_STATIC,4,22,151,120 - LTEXT "Name:",IDC_STATIC,10,34,44,10 - EDITTEXT IDC_EDITNAME,56,32,92,12,ES_AUTOHSCROLL - LTEXT "Server:",IDC_STATIC,10,50,44,8 - EDITTEXT IDC_EDITSERVER,56,48,92,12,ES_AUTOHSCROLL | WS_GROUP - LTEXT "Port:",IDC_STATIC,10,65,44,8,SS_CENTERIMAGE - EDITTEXT IDC_EDITPORT,57,64,27,12,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP - CONTROL "SSL",IDC_CHECKSSL,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,87,66,27,10 - CONTROL "APOP",IDC_CHECKAPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,66,34,10 - LTEXT "User Name:",IDC_STATIC,10,82,44,8 - EDITTEXT IDC_EDITLOGIN,57,80,92,12,ES_AUTOHSCROLL | WS_GROUP - LTEXT "Password:",IDC_STATIC,10,96,44,8 - EDITTEXT IDC_EDITPASS,57,94,92,12,ES_PASSWORD | ES_AUTOHSCROLL | WS_GROUP - LTEXT "Codepage:",IDC_STATIC,10,111,44,8 - COMBOBOX IDC_COMBOCP,57,108,92,130,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Default",IDC_BTNDEFAULT,9,124,54,13 - CONTROL "Disable STLS",IDC_CHECKNOTLS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,83,125,69,10 - LTEXT "Status:",IDC_STATIC,164,2,80,8 - LTEXT "",IDC_STSTATUS,164,13,143,8,SS_CENTERIMAGE - GROUPBOX "Options",IDC_STATIC,161,22,147,120 - CONTROL "Check this account",IDC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,32,118,10,WS_EX_TRANSPARENT - CONTROL "Startup check",IDC_CHECKSTART,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,167,43,78,10 - LTEXT "Check interval [min]:",IDC_STATIC,168,56,94,8 - EDITTEXT IDC_EDITINTERVAL,259,53,20,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_TRANSPARENT - PUSHBUTTON "Only check when...",IDC_BTNSTATUS,195,69,81,13 - CONTROL "Auto retrieve body",IDC_AUTOBODY,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,86,137,10 - CONTROL "Check from menu",IDC_CHECKFORCE,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,97,137,8 - CONTROL "Use contact notification for this account",IDC_CHECKCONTACT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,107,138,10,WS_EX_TRANSPARENT - CONTROL "Replace nickname",IDC_CHECKCONTACTNICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,117,117,10,WS_EX_TRANSPARENT - CONTROL "Disable Events",IDC_CHECKCONTACTNOEVENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,128,115,10,WS_EX_TRANSPARENT - GROUPBOX "Notifications",IDC_GBNEWMAIL,4,143,304,87 - GROUPBOX "New Mail",IDC_STATIC,7,153,149,73 - CONTROL "Sound",IDC_CHECKSND,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,162,60,10 - CONTROL "Message",IDC_CHECKMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,174,135,10 - CONTROL "Keyboard Flash",IDC_CHECKKBN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,186,132,9 - CONTROL "Tray Icon",IDC_CHECKICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,85,163,65,10 - CONTROL "Execute Application",IDC_CHECKAPP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,198,135,8 - PUSHBUTTON "...",IDC_BTNAPP,19,209,16,12 - EDITTEXT IDC_EDITAPP,41,209,65,12,ES_AUTOHSCROLL - EDITTEXT IDC_EDITAPPPARAM,111,209,40,12,ES_AUTOHSCROLL - GROUPBOX "Errors",IDC_STATIC,161,153,143,44 - CONTROL "Sound notification if failed",IDC_CHECKFSND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,163,135,10 - CONTROL "Message notification if failed",IDC_CHECKFMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,174,135,10 - CONTROL "Tray icon notification if failed",IDC_CHECKFICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,186,135,10 - PUSHBUTTON "Reset counter",IDC_BTNRESET,161,200,75,13 - LTEXT "",IDC_STTIMELEFT,163,216,141,8 -END - -IDD_CHOOSESTATUSMODES DIALOG 0, 0, 226, 154 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Check while..." -FONT 8, "MS Shell Dlg" -BEGIN - DEFPUSHBUTTON "OK",IDOK,112,133,50,14 - PUSHBUTTON "Cancel",IDCANCEL,169,133,50,14 - GROUPBOX "Choose modes",IDC_STATUSGROUP,7,7,212,119 - CONTROL "Offline",IDC_CHECKST0,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,19,70,9 - CONTROL "Online",IDC_CHECKST1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,39,70,9 - CONTROL "Away",IDC_CHECKST2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,62,70,9 - CONTROL "Not available",IDC_CHECKST3,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,83,70,9 - CONTROL "Occupied",IDC_CHECKST4,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,104,70,9 - CONTROL "Do not disturb",IDC_CHECKST5,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,19,70,9 - CONTROL "Free for chat",IDC_CHECKST6,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,39,70,9 - CONTROL "Invisible",IDC_CHECKST7,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,62,70,9 -END - -IDD_YAMNOPT DIALOGEX 0, 0, 312, 121 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - GROUPBOX "YAMN General Options",IDC_STATIC,3,2,303,45 - CONTROL "TopToolBar button ""Check mail""",IDC_CHECKTTB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,15,294,11 - GROUPBOX "MailBrowser Options",IDC_STATIC,3,48,151,68 - CONTROL "Enable Close on Delete Button",IDC_CLOSEONDELETE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,60,143,11 - CONTROL "Show long localized date",IDC_LONGDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,65,129,8 - CONTROL "Don't show today's date",IDC_SMARTDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,80,129,8 - GROUPBOX "Date/Time Representation",IDC_STATIC,159,48,148,68 - CONTROL "Don't show seconds",IDC_NOSECONDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,94,129,8 -END - -IDD_POP3ACCOUNTPOPUP DIALOGEX 0, 0, 315, 230 -STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - COMBOBOX IDC_COMBOACCOUNT,4,4,140,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Mail Notifications",IDC_GBNEWMAIL,5,23,300,76 - CONTROL "Popup",IDC_CHECKPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,32,108,10 - CONTROL "Single popup",IDC_RADIOPOP1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,43,95,10 - CONTROL "Multi popup",IDC_RADIOPOPN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,55,95,10 - CONTROL "Use custom color",IDC_CHECKCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,83,107,10 - CONTROL "",IDC_CPB,"ColourPicker",WS_TABSTOP,145,66,29,12 - CONTROL "",IDC_CPT,"ColourPicker",WS_TABSTOP,145,83,29,12 - EDITTEXT IDC_EDITPOPS,23,65,20,12,ES_AUTOHSCROLL - GROUPBOX "No new mail notifications",IDC_GBNONEWMAIL,5,152,300,62 - CONTROL "Popup if no mail",IDC_CHECKNPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,161,94,10 - CONTROL "Persistent message",IDC_CHECKNMSGP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,188,110,10 - CONTROL "Use custom color",IDC_CHECKNCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,201,107,10 - CONTROL "",IDC_CPNB,"ColourPicker",WS_TABSTOP,145,181,29,12 - CONTROL "",IDC_CPNT,"ColourPicker",WS_TABSTOP,145,198,29,12 - EDITTEXT IDC_EDITNPOPS,23,173,20,12,ES_AUTOHSCROLL - GROUPBOX "Connection failure notifications",IDC_GBBADCONNECT,5,101,300,49 - CONTROL "Popup notification if failed",IDC_CHECKFPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,110,118,10 - CONTROL "Use custom color",IDC_CHECKFCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,136,95,10 - CONTROL "",IDC_CPFB,"ColourPicker",WS_TABSTOP,145,118,29,12 - CONTROL "",IDC_CPFT,"ColourPicker",WS_TABSTOP,145,134,29,12 - EDITTEXT IDC_EDITFPOPS,23,121,20,12,ES_AUTOHSCROLL - LTEXT "..s Popup duration",IDC_STATIC,45,67,70,8 - LTEXT "..s Popup duration",IDC_STATIC,45,176,70,8 - LTEXT "..s Popup duration",IDC_STATIC,45,122,70,8 - PUSHBUTTON "Preview",IDC_PREVIEW,255,215,49,13 - LTEXT "Background color",IDC_STATIC,177,184,108,10 - LTEXT "Text color",IDC_STATIC,177,200,107,10 - LTEXT "Background color",IDC_STATIC,177,120,108,10 - LTEXT "Text color",IDC_STATIC,177,136,107,10 - LTEXT "Background color",IDC_STATIC,177,69,108,10 - LTEXT "Text color",IDC_STATIC,177,85,107,10 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_CHECKMAIL ICON "checkmail.ico" - -IDI_LAUNCHAPP ICON "launchapp.ico" - -IDI_BADCONNECT ICON "badconnect.ico" - -IDI_NEWMAIL ICON "newmail.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// AFX_DIALOG_LAYOUT -// - -IDD_YAMNOPT AFX_DIALOG_LAYOUT -BEGIN - 0 -END - -#endif // Neutral resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// 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
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1252)
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_DLGVIEWMESSAGES, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 455
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 105
+ END
+
+ IDD_DLGBADCONNECT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 43
+ END
+
+ IDD_POP3ACCOUNTOPT, DIALOG
+ BEGIN
+ VERTGUIDE, 155
+ VERTGUIDE, 236
+ END
+
+ IDD_CHOOSESTATUSMODES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 219
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_YAMNOPT, DIALOG
+ BEGIN
+ RIGHTMARGIN, 310
+ VERTGUIDE, 8
+ END
+
+ IDD_POP3ACCOUNTPOPUP, DIALOG
+ BEGIN
+ VERTGUIDE, 155
+ VERTGUIDE, 236
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DLGVIEWMESSAGES DIALOG 50, 200, 460, 110
+STYLE DS_SETFONT | DS_3DLOOK | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "List4",IDC_LISTMAILS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70
+ DEFPUSHBUTTON "",IDC_BTNOK,395,90,60,15
+ PUSHBUTTON "",IDC_BTNAPP,263,90,114,15
+ PUSHBUTTON "",IDC_BTNDEL,5,90,114,15
+ LTEXT "",IDC_STSTATUS,5,75,450,10
+ PUSHBUTTON "",IDC_BTNCHECKALL,150,91,92,14
+END
+
+IDD_DLGSHOWMESSAGE DIALOGEX 50, 200, 460, 132
+STYLE DS_SETFONT | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List5",IDC_LISTHEADERS,"SysListView32",LVS_REPORT | LVS_EDITLABELS | WS_BORDER | WS_TABSTOP,5,5,450,70
+ CONTROL "",IDC_SPLITTER,"Static",SS_ENHMETAFILE | WS_TABSTOP,0,80,187,2,WS_EX_STATICEDGE
+ EDITTEXT IDC_EDITBODY,3,84,454,45,ES_MULTILINE | ES_READONLY | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+END
+
+IDD_DLGBADCONNECT DIALOG 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK",IDC_BTNOK,69,55,50,14
+ LTEXT "",IDC_STATICMSG,7,7,172,37
+END
+
+IDD_POP3ACCOUNTOPT DIALOGEX 0, 0, 310, 230
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_COMBOACCOUNT,4,6,106,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "+",IDC_BTNADD,118,6,15,13
+ PUSHBUTTON "-",IDC_BTNDEL,140,6,15,13
+ GROUPBOX "Account",IDC_STATIC,4,22,151,120
+ LTEXT "Name:",IDC_STATIC,10,34,44,10
+ EDITTEXT IDC_EDITNAME,56,32,92,12,ES_AUTOHSCROLL
+ LTEXT "Server:",IDC_STATIC,10,50,44,8
+ EDITTEXT IDC_EDITSERVER,56,48,92,12,ES_AUTOHSCROLL | WS_GROUP
+ LTEXT "Port:",IDC_STATIC,10,65,44,8,SS_CENTERIMAGE
+ EDITTEXT IDC_EDITPORT,57,64,27,12,ES_AUTOHSCROLL | ES_NUMBER | WS_GROUP
+ CONTROL "SSL",IDC_CHECKSSL,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,87,66,27,10
+ CONTROL "APOP",IDC_CHECKAPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,119,66,34,10
+ LTEXT "User Name:",IDC_STATIC,10,82,44,8
+ EDITTEXT IDC_EDITLOGIN,57,80,92,12,ES_AUTOHSCROLL | WS_GROUP
+ LTEXT "Password:",IDC_STATIC,10,96,44,8
+ EDITTEXT IDC_EDITPASS,57,94,92,12,ES_PASSWORD | ES_AUTOHSCROLL | WS_GROUP
+ LTEXT "Codepage:",IDC_STATIC,10,111,44,8
+ COMBOBOX IDC_COMBOCP,57,108,92,130,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Default",IDC_BTNDEFAULT,9,124,54,13
+ CONTROL "Disable STLS",IDC_CHECKNOTLS,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,83,125,69,10
+ LTEXT "Status:",IDC_STATIC,164,2,80,8
+ LTEXT "",IDC_STSTATUS,164,13,143,8,SS_CENTERIMAGE
+ GROUPBOX "Options",IDC_STATIC,161,22,147,120
+ CONTROL "Check this account",IDC_CHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,167,32,118,10,WS_EX_TRANSPARENT
+ CONTROL "Startup check",IDC_CHECKSTART,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,167,43,78,10
+ LTEXT "Check interval [min]:",IDC_STATIC,168,56,94,8
+ EDITTEXT IDC_EDITINTERVAL,259,53,20,12,ES_AUTOHSCROLL | ES_NUMBER,WS_EX_TRANSPARENT
+ PUSHBUTTON "Only check when...",IDC_BTNSTATUS,195,69,81,13
+ CONTROL "Auto retrieve body",IDC_AUTOBODY,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,86,137,10
+ CONTROL "Check from menu",IDC_CHECKFORCE,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,166,97,137,8
+ CONTROL "Use contact notification for this account",IDC_CHECKCONTACT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,107,138,10,WS_EX_TRANSPARENT
+ CONTROL "Replace nickname",IDC_CHECKCONTACTNICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,117,117,10,WS_EX_TRANSPARENT
+ CONTROL "Disable Events",IDC_CHECKCONTACTNOEVENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,187,128,115,10,WS_EX_TRANSPARENT
+ GROUPBOX "Notifications",IDC_GBNEWMAIL,4,143,304,87
+ GROUPBOX "New Mail",IDC_STATIC,7,153,149,73
+ CONTROL "Sound",IDC_CHECKSND,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,12,162,60,10
+ CONTROL "Message",IDC_CHECKMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,174,135,10
+ CONTROL "Keyboard Flash",IDC_CHECKKBN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,186,132,9
+ CONTROL "Tray Icon",IDC_CHECKICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,85,163,65,10
+ CONTROL "Execute Application",IDC_CHECKAPP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,198,135,8
+ PUSHBUTTON "...",IDC_BTNAPP,19,209,16,12
+ EDITTEXT IDC_EDITAPP,41,209,65,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDITAPPPARAM,111,209,40,12,ES_AUTOHSCROLL
+ GROUPBOX "Errors",IDC_STATIC,161,153,143,44
+ CONTROL "Sound notification if failed",IDC_CHECKFSND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,163,135,10
+ CONTROL "Message notification if failed",IDC_CHECKFMSG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,174,135,10
+ CONTROL "Tray icon notification if failed",IDC_CHECKFICO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,166,186,135,10
+ PUSHBUTTON "Reset counter",IDC_BTNRESET,161,200,75,13
+ LTEXT "",IDC_STTIMELEFT,163,216,141,8
+END
+
+IDD_CHOOSESTATUSMODES DIALOG 0, 0, 226, 154
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Check while..."
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,112,133,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,169,133,50,14
+ GROUPBOX "Choose modes",IDC_STATUSGROUP,7,7,212,119
+ CONTROL "Offline",IDC_CHECKST0,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,19,70,9
+ CONTROL "Online",IDC_CHECKST1,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,39,70,9
+ CONTROL "Away",IDC_CHECKST2,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,62,70,9
+ CONTROL "Not available",IDC_CHECKST3,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,83,70,9
+ CONTROL "Occupied",IDC_CHECKST4,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,15,104,70,9
+ CONTROL "Do not disturb",IDC_CHECKST5,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,19,70,9
+ CONTROL "Free for chat",IDC_CHECKST6,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,39,70,9
+ CONTROL "Invisible",IDC_CHECKST7,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_TABSTOP,134,62,70,9
+END
+
+IDD_YAMNOPT DIALOGEX 0, 0, 312, 121
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "YAMN General Options",IDC_STATIC,3,2,303,45
+ CONTROL "TopToolBar button ""Check mail""",IDC_CHECKTTB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,15,294,11
+ GROUPBOX "MailBrowser Options",IDC_STATIC,3,48,151,68
+ CONTROL "Enable Close on Delete Button",IDC_CLOSEONDELETE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,60,143,11
+ CONTROL "Show long localized date",IDC_LONGDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,65,129,8
+ CONTROL "Don't show today's date",IDC_SMARTDATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,80,129,8
+ GROUPBOX "Date/Time Representation",IDC_STATIC,159,48,148,68
+ CONTROL "Don't show seconds",IDC_NOSECONDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,170,94,129,8
+END
+
+IDD_POP3ACCOUNTPOPUP DIALOGEX 0, 0, 315, 230
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_COMBOACCOUNT,4,4,140,65,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Mail Notifications",IDC_GBNEWMAIL,5,23,300,76
+ CONTROL "Popup",IDC_CHECKPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,32,108,10
+ CONTROL "Single popup",IDC_RADIOPOP1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,43,95,10
+ CONTROL "Multi popup",IDC_RADIOPOPN,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,23,55,95,10
+ CONTROL "Use custom color",IDC_CHECKCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,83,107,10
+ CONTROL "",IDC_CPB,"ColourPicker",WS_TABSTOP,145,66,29,12
+ CONTROL "",IDC_CPT,"ColourPicker",WS_TABSTOP,145,83,29,12
+ EDITTEXT IDC_EDITPOPS,23,65,20,12,ES_AUTOHSCROLL
+ GROUPBOX "No new mail notifications",IDC_GBNONEWMAIL,5,152,300,62
+ CONTROL "Popup if no mail",IDC_CHECKNPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,161,94,10
+ CONTROL "Persistent message",IDC_CHECKNMSGP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,188,110,10
+ CONTROL "Use custom color",IDC_CHECKNCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,201,107,10
+ CONTROL "",IDC_CPNB,"ColourPicker",WS_TABSTOP,145,181,29,12
+ CONTROL "",IDC_CPNT,"ColourPicker",WS_TABSTOP,145,198,29,12
+ EDITTEXT IDC_EDITNPOPS,23,173,20,12,ES_AUTOHSCROLL
+ GROUPBOX "Connection failure notifications",IDC_GBBADCONNECT,5,101,300,49
+ CONTROL "Popup notification if failed",IDC_CHECKFPOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,110,118,10
+ CONTROL "Use custom color",IDC_CHECKFCOL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,136,95,10
+ CONTROL "",IDC_CPFB,"ColourPicker",WS_TABSTOP,145,118,29,12
+ CONTROL "",IDC_CPFT,"ColourPicker",WS_TABSTOP,145,134,29,12
+ EDITTEXT IDC_EDITFPOPS,23,121,20,12,ES_AUTOHSCROLL
+ LTEXT "..s Popup duration",IDC_STATIC,45,67,70,8
+ LTEXT "..s Popup duration",IDC_STATIC,45,176,70,8
+ LTEXT "..s Popup duration",IDC_STATIC,45,122,70,8
+ PUSHBUTTON "Preview",IDC_PREVIEW,255,215,49,13
+ LTEXT "Background color",IDC_STATIC,177,184,108,10
+ LTEXT "Text color",IDC_STATIC,177,200,107,10
+ LTEXT "Background color",IDC_STATIC,177,120,108,10
+ LTEXT "Text color",IDC_STATIC,177,136,107,10
+ LTEXT "Background color",IDC_STATIC,177,69,108,10
+ LTEXT "Text color",IDC_STATIC,177,85,107,10
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_CHECKMAIL ICON "checkmail.ico"
+
+IDI_LAUNCHAPP ICON "launchapp.ico"
+
+IDI_BADCONNECT ICON "badconnect.ico"
+
+IDI_NEWMAIL ICON "newmail.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_YAMNOPT AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/YAMN/src/account.cpp b/protocols/YAMN/src/account.cpp index 91b57ad544..46b7782ab0 100644 --- a/protocols/YAMN/src/account.cpp +++ b/protocols/YAMN/src/account.cpp @@ -1,1051 +1,1051 @@ -/* - * This code implements manipulation with accounts - * such as reading accounts from file, writing them to file, - * finding account by name etc. - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - // Account status CS - // When we check some account, thread should change status of account to idle, connecting etc. - // So if we want to read status, we have to successfully write and then read. -static mir_cs csAccountStatusCS; - -// File Writing CS -// When 2 threads want to write to file... -static mir_cs csFileWritingCS; - -struct CExportedFunctions AccountExportedFcn[] = -{ - {YAMN_GETSTATUSID, (void *)GetStatusFcn}, - {YAMN_SETSTATUSID, (void *)SetStatusFcn}, -}; - -struct CExportedServices AccountExportedSvc[] = -{ - {MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc}, - {MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc}, - {MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc}, - {MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc}, - {MS_YAMN_DELETEACCOUNT, DeletePluginAccountSvc}, - {MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc}, - {MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - uint32_t AccountVersion = (uint32_t)lParam; - - //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) - if (AccountVersion != YAMN_ACCOUNTVERSION) - return NULL; - - if (Plugin != nullptr) { - CAccount *NewAccount; - if (Plugin->Fcn->NewAccountFcnPtr != nullptr) - //Let plugin create its own structure, which can be derived from CAccount structure - NewAccount = Plugin->Fcn->NewAccountFcnPtr(Plugin, YAMN_ACCOUNTVERSION); - else - //We suggest plugin uses standard CAccount structure, so we create it - NewAccount = new struct CAccount; - - //If not created successfully - if (NewAccount == nullptr) - return NULL; - - NewAccount->Plugin = Plugin; - //Init every members of structure, used by YAMN - InitAccount(NewAccount); - - return (INT_PTR)NewAccount; - } - return NULL; -} - -INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM) -{ - CAccount *OldAccount = (CAccount *)wParam; - - if (OldAccount->Plugin->Fcn != nullptr) { - // Deinit every members and allocated fields of structure used by YAMN - DeInitAccount(OldAccount); - if (OldAccount->Plugin->Fcn->DeleteAccountFcnPtr != nullptr) { - // Let plugin delete its own CAccount derived structure - OldAccount->Plugin->Fcn->DeleteAccountFcnPtr(OldAccount); - } - else { - delete OldAccount; //consider account as standard YAMN CAccount *and use its own destructor - } - return 1; - } - delete OldAccount; //consider account as standard YAMN CAccount *, not initialized before and use its own destructor - return 1; -} - -int InitAccount(CAccount *Which) -{ - //initialize synchronizing objects - Which->AccountAccessSO = new SWMRG; - SWMRGInitialize(Which->AccountAccessSO, nullptr); - Which->MessagesAccessSO = new SWMRG; - SWMRGInitialize(Which->MessagesAccessSO, nullptr); - Which->UsingThreads = new SCOUNTER; - SWMRGInitialize(Which->MessagesAccessSO, nullptr); - - //zero memory, where timestamps are stored - memset(&Which->LastChecked, 0, sizeof(Which->LastChecked)); - memset(&Which->LastSChecked, 0, sizeof(Which->LastSChecked)); - memset(&Which->LastSynchronised, 0, sizeof(Which->LastSynchronised)); - memset(&Which->LastMail, 0, sizeof(Which->LastMail)); - - Which->Name = nullptr; - Which->Mails = nullptr; - Which->Interval = 0; - Which->Flags = 0; - Which->StatusFlags = YAMN_ACC_ST1 + YAMN_ACC_ST7; - Which->Next = nullptr; - - Which->Server = new struct CServer; - Which->AbleToWork = TRUE; - - return 1; -} - -void DeInitAccount(CAccount *Which) -{ - //delete YAMN allocated fields - if (Which->Name != nullptr) - delete[] Which->Name; - if (Which->Server != nullptr) { - if (Which->Server->Name != nullptr) - delete[] Which->Server->Name; - if (Which->Server->Login != nullptr) - delete[] Which->Server->Login; - if (Which->Server->Passwd != nullptr) - delete[] Which->Server->Passwd; - delete[] Which->Server; - } - - SWMRGDelete(Which->AccountAccessSO); - delete Which->AccountAccessSO; - SWMRGDelete(Which->MessagesAccessSO); - delete Which->MessagesAccessSO; - delete Which->UsingThreads; - DeleteMessagesToEndFcn(Which, (HYAMNMAIL)Which->Mails); -} - -void StopSignalFcn(CAccount *Which) -//set event that we are going to delete account -{ - Which->AbleToWork = FALSE; - //do not use synchronizing objects anymore - //any access to these objects then ends with WAIT_FAILED - SetEvent(Which->AccountAccessSO->hFinishEV); - SetEvent(Which->MessagesAccessSO->hFinishEV); -} - -void CodeDecodeString(char *Dest, BOOL Encrypt) -{ - wchar_t Code = STARTCODEPSW; - - if (Dest == nullptr) - return; - - for (; *Dest != (wchar_t)0; Dest++) { - if (Encrypt) - *Dest = *Dest + Code; - else - *Dest = *Dest - Code; - Code += (wchar_t)ADDCODEPSW; - } -} - -static uint32_t PostFileToMemory(HANDLE File, char **MemFile, char **End) -{ - DWORD FileSize, ReadBytes; - if (!(FileSize = GetFileSize(File, nullptr))) { - CloseHandle(File); - return EACC_FILESIZE; - } - - //allocate space in memory, where we copy the whole file - if (nullptr == (*MemFile = new char[FileSize])) { - CloseHandle(File); - return EACC_ALLOC; - } - - //copy file to memory - if (!ReadFile(File, (LPVOID)*MemFile, FileSize, &ReadBytes, nullptr)) { - CloseHandle(File); - delete[] * MemFile; - return EACC_SYSTEM; - } - CloseHandle(File); - *End = *MemFile + FileSize; - return 0; -} - -uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End) -{ - HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - return EACC_SYSTEM; - - return PostFileToMemory(hFile, MemFile, End); -} - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemory(char **Parser, wchar_t *End, char **StoreTo, wchar_t *DebugString) -{ - //This is the debug version of ReadStringFromMemory function. This version shows MessageBox where - //read string is displayed - wchar_t *Dest, *Finder; - uint32_t Size; - wchar_t Debug[65536]; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++; - mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, End - Finder); - MessageBox(NULL, Debug, L"debug", MB_OK); - if (Finder >= End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (NULL == (Dest = *StoreTo = new wchar_t[Size + 1])) - return EACC_ALLOC; - for (; *Parser <= Finder; (*Parser)++, Dest++) - *Dest = **Parser; - } - else { - *StoreTo = NULL; - (*Parser)++; - } - return 0; -} -#endif - -uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo) -{ - char *Dest, *Finder; - uint32_t Size; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++; - if (Finder >= End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (nullptr == (Dest = *StoreTo = new char[Size + 1])) - return EACC_ALLOC; - for (; *Parser <= Finder; (*Parser)++, Dest++) - *Dest = **Parser; - } - else { - *StoreTo = nullptr; - (*Parser)++; - } - return 0; -} - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo, wchar_t *DebugString) -{ - //This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where - //read string is displayed - wchar_t *Dest, *Finder; - uint32_t Size; - wchar_t Debug[65536]; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++; - mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, (wchar_t *)End - Finder); - MessageBoxW(NULL, Debug, L"debug", MB_OK); - if (Finder >= (wchar_t *)End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (NULL == (Dest = *StoreTo = new wchar_t[Size + 1])) - return EACC_ALLOC; - for (; *Parser <= Finder; (*Parser)++, Dest++) - *Dest = **Parser; - } - else { - *StoreTo = NULL; - (*Parser)++; - } - return 0; -} -#endif //if defined(DEBUG...) - -uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo) -{ - wchar_t *Dest, *Finder; - uint32_t Size; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++; - if (Finder >= (wchar_t *)End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (nullptr == (Dest = *StoreTo = new wchar_t[Size + 1])) - return EACC_ALLOC; - for (; *Parser <= Finder; (*Parser)++, Dest++) - *Dest = **Parser; - } - else { - *StoreTo = nullptr; - (*Parser)++; - } - return 0; -} - -static uint32_t ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which) -{ - uint32_t Stat; - #ifdef DEBUG_FILEREAD - wchar_t Debug[65536]; - #endif - - Which->Flags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"NFlags: %04x, remaining %d chars", Which->Flags, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - - Which->PopupB = *(COLORREF *)(*Parser); - (*Parser) += sizeof(COLORREF); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"PopupB: %04x, remaining %d chars", Which->PopupB, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - Which->PopupT = *(COLORREF *)(*Parser); - (*Parser) += sizeof(COLORREF); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"PopupT: %04x, remaining %d chars", Which->PopupT, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - Which->PopupTime = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"PopupTime: %04x, remaining %d chars", Which->PopupTime, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App, L"App")) - #else - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App)) - #endif - return Stat; - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam, L"AppParam")) - #else - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam)) - #endif - return Stat; - return 0; -} - -uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End) -{ - char *Finder; - uint32_t Size, Stat; - HYAMNMAIL ActualMail = nullptr; - struct CMimeItem *items; - char *ReadString; - - #ifdef DEBUG_FILEREAD - MessageBox(NULL, L"going to read messages, if any...", L"debug", MB_OK); - #endif - do { - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++; - if (Finder >= End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (Which->Mails == nullptr) //First message in queue - { - if (nullptr == (Which->Mails = ActualMail = CreateAccountMail(Which))) - return EACC_ALLOC; - } - else { - if (nullptr == (ActualMail->Next = CreateAccountMail(Which))) { - return EACC_ALLOC; - } - ActualMail = ActualMail->Next; - } - items = nullptr; - #ifdef DEBUG_FILEREADMESSAGES - if (Stat = ReadStringFromMemory(Parser, End, &ActualMail->ID, L"ID")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &ActualMail->ID)) - #endif - return Stat; - // ActualMail->MailData=new MAILDATA; !!! mem leake !!! this is alloc by CreateAccountMail, no need for doubble alloc !!!! - - ActualMail->MailData->Size = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - ActualMail->Flags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - ActualMail->Number = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->ReadMailOptsFcnPtr)) - Which->Plugin->MailFcn->ReadMailOptsFcnPtr(ActualMail, Parser, End); //read plugin mail settings from file - - do { - #if defined(DEBUG_FILEREADMESSAGES) || defined(DEBUG_FILEREAD) - if (Stat = ReadStringFromMemory(Parser, End, &ReadString, L"Name")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &ReadString)) - #endif - return Stat; - if (ReadString == nullptr) - break; - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<read name>%s</read name>", ReadString); - #endif - - if (items == nullptr) - items = ActualMail->MailData->TranslatedHeader = new struct CMimeItem; - else { - items->Next = new struct CMimeItem; - items = items->Next; - } - if (items == nullptr) - return EACC_ALLOC; - items->name = ReadString; - - #ifdef DEBUG_FILEREADMESSAGES - if (Stat = ReadStringFromMemory(Parser, End, &ReadString, L"Value")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &ReadString)) - #endif - return Stat; - items->value = ReadString; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<read value>%s</read value>\n", ReadString); - #endif - } while (1); - } - else - break; //no next messages, new account! - - } while (1); - (*Parser)++; - return 0; -} - -uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, char *End) -{ - uint32_t Stat; - #ifdef DEBUG_FILEREAD - wchar_t Debug[65536]; - #endif - //Read name of account - - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemory(Parser, End, &Which->Name, L"Name")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &Which->Name)) - #endif - return Stat; - if (Which->Name == nullptr) - return EACC_FILECOMPATIBILITY; - - //Read server parameters - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Name, L"Server")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Name)) - #endif - return Stat; - Which->Server->Port = *(uint16_t *)(*Parser); - (*Parser) += sizeof(uint16_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"Port: %d, remaining %d chars", Which->Server->Port, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login, L"Login")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login)) - #endif - return Stat; - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Passwd, L"Password")) - #else - if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Passwd)) - #endif - return Stat; - CodeDecodeString(Which->Server->Passwd, FALSE); - - //Read account flags - Which->Flags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"Flags: %04x, remaining %d chars", Which->Flags, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - Which->StatusFlags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"STFlags: %04x, remaining %d chars", Which->StatusFlags, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - Which->PluginFlags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"PFlags: %04x, remaining %d chars", Which->PluginFlags, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - - //Read account miscellaneous parameters - Which->Interval = *(uint16_t *)(*Parser); - Which->TimeLeft = Which->Interval; //check on loading - (*Parser) += sizeof(uint16_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"Interval: %d, remaining %d chars", Which->Interval, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - - //Read notification parameters - if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NewMailN)) - return Stat; - if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NoNewMailN)) - return Stat; - if (Stat = ReadNotificationFromMemory(Parser, End, &Which->BadConnectN)) - return Stat; - - //Let plugin read its own data stored in file - if (Which->Plugin->Fcn != nullptr && Which->Plugin->Fcn->ReadPluginOptsFcnPtr != nullptr) - if (Stat = Which->Plugin->Fcn->ReadPluginOptsFcnPtr(Which, Parser, End)) - return Stat; - - // Read mails - WaitToWriteFcn(Which->MessagesAccessSO); - - if (Stat = ReadMessagesFromMemory(Which, Parser, End)) { - WriteDoneFcn(Which->MessagesAccessSO); - return Stat; - } - - WriteDoneFcn(Which->MessagesAccessSO); - - // Read timestamps - Which->LastChecked = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastSChecked = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastSynchronised = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastMail = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser > End) //WARNING! There's only > at the end of testing - return EACC_FILECOMPATIBILITY; - - if (*Parser == End) - return EACC_ENDOFFILE; - return 0; -} - -static INT_PTR PerformAccountReading(HYAMNPROTOPLUGIN Plugin, char *MemFile, char *End) -{ - // Retrieve info for account from memory - char *Parser; - uint32_t Ver, Stat; - - CAccount *ActualAccount, *FirstAllocatedAccount; - - Ver = *(uint32_t *)MemFile; - if (Ver > YAMN_ACCOUNTFILEVERSION) { - delete[] MemFile; - return EACC_FILEVERSION; - } - Parser = MemFile + sizeof(Ver); - - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - if (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) { - SWMRGDoneWriting(Plugin->AccountBrowserSO); - delete[] MemFile; - return EACC_ALLOC; - } - - FirstAllocatedAccount = ActualAccount; - - do { - CAccount *Temp; - - WaitToWriteFcn(ActualAccount->AccountAccessSO); - Stat = ReadAccountFromMemory(ActualAccount, &Parser, End); - - if (ActualAccount->StatusFlags & (YAMN_ACC_STARTA | YAMN_ACC_STARTS)) - ActualAccount->TimeLeft = 1; //check on loading - - if (Stat && (Stat != EACC_ENDOFFILE)) { - for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) { - Temp = ActualAccount->Next; - delete ActualAccount; - } - delete[] MemFile; - if (Plugin->FirstAccount == FirstAllocatedAccount) - Plugin->FirstAccount = nullptr; - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return (INT_PTR)Stat; - } - - WriteDoneFcn(ActualAccount->AccountAccessSO); - - if ((Stat != EACC_ENDOFFILE) && (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION)))) { - for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) { - Temp = ActualAccount->Next; - delete ActualAccount; - } - delete[] MemFile; - if (Plugin->FirstAccount == FirstAllocatedAccount) - Plugin->FirstAccount = nullptr; - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return EACC_ALLOC; - } - } while (Stat != EACC_ENDOFFILE); - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - delete[] MemFile; - return 0; -} - -// Add accounts from file to memory -INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam) -{ - char *MemFile, *End; - uint32_t Stat = FileToMemory((wchar_t *)lParam, &MemFile, &End); - if (Stat != NO_ERROR) - return (INT_PTR)Stat; - - return PerformAccountReading((HYAMNPROTOPLUGIN)wParam, MemFile, End); -} - -uint32_t WriteStringToFile(HANDLE File, char *Source) -{ - DWORD Length, WrittenBytes; - char null = 0; - - if ((Source == nullptr) || !(Length = (uint32_t)mir_strlen(Source))) { - if (!WriteFile(File, &null, 1, &WrittenBytes, nullptr)) { - CloseHandle(File); - return EACC_SYSTEM; - } - } - else if (!WriteFile(File, Source, (Length + 1), &WrittenBytes, nullptr)) { - CloseHandle(File); - return EACC_SYSTEM; - } - return 0; -} - -uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source) -{ - DWORD Length, WrittenBytes; - wchar_t null = (wchar_t)0; - - if ((Source == nullptr) || !(Length = (uint32_t)mir_wstrlen(Source))) { - if (!WriteFile(File, &null, sizeof(wchar_t), &WrittenBytes, nullptr)) { - CloseHandle(File); - return EACC_SYSTEM; - } - } - else if (!WriteFile(File, Source, (Length + 1) * sizeof(wchar_t), &WrittenBytes, nullptr)) - return EACC_SYSTEM; - return 0; -} - -DWORD WriteMessagesToFile(HANDLE File, CAccount *Which) -{ - DWORD WrittenBytes, Stat; - HYAMNMAIL ActualMail = (HYAMNMAIL)Which->Mails; - struct CMimeItem *items; - - while (ActualMail != nullptr) { - if (Stat = WriteStringToFile(File, ActualMail->ID)) - return Stat; - - if (!WriteFile(File, (char *)&ActualMail->MailData->Size, sizeof(ActualMail->MailData->Size), &WrittenBytes, nullptr) || - !WriteFile(File, (char *)&ActualMail->Flags, sizeof(ActualMail->Flags), &WrittenBytes, nullptr) || - !WriteFile(File, (char *)&ActualMail->Number, sizeof(ActualMail->Number), &WrittenBytes, nullptr)) - return EACC_SYSTEM; - if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->WriteMailOptsFcnPtr)) - Which->Plugin->MailFcn->WriteMailOptsFcnPtr(File, ActualMail); //write plugin mail options to file - for (items = ActualMail->MailData->TranslatedHeader; items != nullptr; items = items->Next) { - if (Stat = WriteStringToFile(File, items->name)) - return Stat; - if (Stat = WriteStringToFile(File, items->value)) - return Stat; - } - if (Stat = WriteStringToFile(File, "")) - return Stat; - ActualMail = ActualMail->Next; - } - if (Stat = WriteStringToFile(File, "")) - return Stat; - return 0; -} - -static INT_PTR PerformAccountWriting(HYAMNPROTOPLUGIN Plugin, HANDLE File) -{ - DWORD WrittenBytes, Stat; - CAccount *ActualAccount; - uint32_t Ver = YAMN_ACCOUNTFILEVERSION; - BOOL Writed = FALSE; - uint32_t ReturnValue = 0, EnterCode; - - SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); - - try { - for (ActualAccount = Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - EnterCode = WaitToReadFcn(ActualAccount->AccountAccessSO); - if (EnterCode == WAIT_FINISH) //account is about to delete - { - ActualAccount = ActualAccount->Next; - continue; - } - if (EnterCode == WAIT_FAILED) //account is deleted - break; - - if ((ActualAccount->Name == nullptr) || (*ActualAccount->Name == (wchar_t)0)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - - if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - Writed = TRUE; - - if (Stat = WriteStringToFile(File, ActualAccount->Name)) - throw (uint32_t)Stat; - - if (Stat = WriteStringToFile(File, ActualAccount->Server->Name)) - throw (uint32_t)Stat; - - if (!WriteFile(File, (char *)&ActualAccount->Server->Port, 2, &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFile(File, ActualAccount->Server->Login))) - throw (uint32_t)Stat; - - CodeDecodeString(ActualAccount->Server->Passwd, TRUE); - - if (Stat = WriteStringToFile(File, ActualAccount->Server->Passwd)) { - CodeDecodeString(ActualAccount->Server->Passwd, FALSE); - throw (uint32_t)Stat; - } - CodeDecodeString(ActualAccount->Server->Passwd, FALSE); - - if ((!WriteFile(File, (char *)&ActualAccount->Flags, sizeof(uint32_t), &WrittenBytes, nullptr) || - (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(uint32_t), &WrittenBytes, nullptr)))) - throw (uint32_t)EACC_SYSTEM; - - if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(uint16_t), &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->NewMailN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->NewMailN.AppParam))) - throw (uint32_t)Stat; - - if ((!WriteFile(File, (char *)&ActualAccount->NoNewMailN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.AppParam))) - throw (uint32_t)Stat; - - if ((!WriteFile(File, (char *)&ActualAccount->BadConnectN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.AppParam))) - throw (uint32_t)Stat; - - //Let plugin write its own values into file - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr != nullptr) - if (Stat = ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr(File, ActualAccount)) - throw (uint32_t)Stat; - - WaitToReadFcn(ActualAccount->MessagesAccessSO); - - if (Stat = WriteMessagesToFile(File, ActualAccount)) { - - ReadDoneFcn(ActualAccount->MessagesAccessSO); - throw (uint32_t)Stat; - } - - ReadDoneFcn(ActualAccount->MessagesAccessSO); - - if ((!WriteFile(File, (char *)&ActualAccount->LastChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->LastSChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->LastSynchronised, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->LastMail, sizeof(SYSTEMTIME), &WrittenBytes, nullptr))) - throw (uint32_t)Stat; - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - catch (uint32_t ErrorCode) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - ReturnValue = ErrorCode; - } - - SWMRGDoneReading(Plugin->AccountBrowserSO); - CloseHandle(File); - return 0; -} - -// Writes accounts to file -INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - - mir_cslock lck(csFileWritingCS); - HANDLE hFile = CreateFile((wchar_t *)lParam, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); - if (hFile == INVALID_HANDLE_VALUE) - return EACC_SYSTEM; - - return PerformAccountWriting(Plugin, hFile); -} - -INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - char *SearchedAccount = (char *)lParam; - CAccount *Finder; - - SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); - - for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) - if ((Finder->Name != nullptr) && (0 == mir_strcmp(SearchedAccount, Finder->Name))) - break; - - SWMRGDoneReading(Plugin->AccountBrowserSO); - return (INT_PTR)Finder; -} - -INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - CAccount *Finder; - - if (Plugin->FirstAccount == nullptr) { - Plugin->FirstAccount = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); - return (INT_PTR)Plugin->FirstAccount; - } - for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; Finder = Finder->Next); - Finder->Next = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); - return (INT_PTR)Finder->Next; -} - -INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM lParam) -{ - //Deleting account works on these steps: - //1. set signal that account should stop activity (set event) - // setting this event we achieve, that any access to account is failed, - // so threads do not start any work with accounts (better saying threads of plugins should not start) - //2. wait to get write access to chained list of accounts - //3. we can write to chained list, so we change chain not to show to actual account - // now, any thread browsing list of accounts does not browse through actual account - // actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue)) - //Now, we should delete account from memory, BUT!!! - // Any thread can still be waked up and start asking account synchronizing object - // If account is deleted, asking about access to read account can throw memory exception (reading for - // a synchronizing object from memory, that was deleted) - //So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore - // (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?) - // This deleting is achieved in 2 ways: - // We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account - // 1. Any thread using account first increment UsingThread, so we know that account is used - // 2. If thread is about to close, it should decrement UsingThread - // 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not - // increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using - // account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then - // new thread is going to read account...). - //4. wait until UsingThread Event is signaled - //5. delete account from memory - - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - CAccount *Which = (CAccount *)lParam; - CAccount *Finder; - - //1. set stop signal - StopSignalFcn(Which); - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Which, 0); - if (Plugin->Fcn->StopAccountFcnPtr != nullptr) - Plugin->Fcn->StopAccountFcnPtr(Which); - - //2. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - //3. remove from queue (chained list) - if (Plugin->FirstAccount == nullptr) { - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return 0; - } - if (Plugin->FirstAccount == Which) { - Finder = Plugin->FirstAccount->Next; - Plugin->FirstAccount = Finder; - } - else { - for (Finder = Plugin->FirstAccount; Which != Finder->Next; Finder = Finder->Next); - Finder->Next = Finder->Next->Next; - } - - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - - //4. wait while event "UsingThread" is not signaled - // And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so - // other threads do not start any new work with actual account) We will wait in blocked state? - // No, of course not. We will create new thread, that will wait and additionally remove our thread in background. - //5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread - - if ((Plugin->Fcn != nullptr) && (Plugin->Fcn->WriteAccountsFcnPtr != nullptr)) - Plugin->Fcn->WriteAccountsFcnPtr(); - CloseHandle(mir_forkthread(DeleteAccountInBackground, (void *)Which)); - - //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using - //event UsingThreads. - return 1; -} - -void __cdecl DeleteAccountInBackground(void *Value) -{ - CAccount *Which = (CAccount *)Value; - WaitForSingleObject(Which->UsingThreads->Event, INFINITE); - CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 0); -} - -int StopAccounts(HYAMNPROTOPLUGIN Plugin) -{ - CAccount *Finder; - - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - //2. set stop signal - StopSignalFcn(Finder); - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Finder, 0); - if (Plugin->Fcn->StopAccountFcnPtr != nullptr) - Plugin->Fcn->StopAccountFcnPtr(Finder); - } - - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - - //Now, account is stopped. It can be removed from memory... - return 1; -} - -int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess) -{ - if (GetAccountBrowserAccess) { - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - } - for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - //2. wait for signal that account is not in use - WaitForSingleObject(Finder->UsingThreads->Event, INFINITE); - SetEvent(Finder->UsingThreads->Event); - } - if (GetAccountBrowserAccess) { - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - } - - return 1; -} - -int DeleteAccounts(HYAMNPROTOPLUGIN Plugin) -{ - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - WaitForAllAccounts(Plugin, FALSE); - - for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr;) { - CAccount *Next = Finder->Next; - DeletePluginAccountSvc((WPARAM)Finder, 0); - Finder = Next; - } - - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return 1; -} - -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value) -{ - if (Which == nullptr) - return; - - mir_cslock lck(csAccountStatusCS); - mir_wstrcpy(Value, Which->Status); -} - -void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value) -{ - if (Which != nullptr) { - mir_cslock lck(csAccountStatusCS); - mir_wstrcpy(Which->Status, Value); - } - - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUS, (WPARAM)Which, 0); -} +/*
+ * This code implements manipulation with accounts
+ * such as reading accounts from file, writing them to file,
+ * finding account by name etc.
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ // Account status CS
+ // When we check some account, thread should change status of account to idle, connecting etc.
+ // So if we want to read status, we have to successfully write and then read.
+static mir_cs csAccountStatusCS;
+
+// File Writing CS
+// When 2 threads want to write to file...
+static mir_cs csFileWritingCS;
+
+struct CExportedFunctions AccountExportedFcn[] =
+{
+ {YAMN_GETSTATUSID, (void *)GetStatusFcn},
+ {YAMN_SETSTATUSID, (void *)SetStatusFcn},
+};
+
+struct CExportedServices AccountExportedSvc[] =
+{
+ {MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc},
+ {MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc},
+ {MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc},
+ {MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc},
+ {MS_YAMN_DELETEACCOUNT, DeletePluginAccountSvc},
+ {MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc},
+ {MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ uint32_t AccountVersion = (uint32_t)lParam;
+
+ //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match)
+ if (AccountVersion != YAMN_ACCOUNTVERSION)
+ return NULL;
+
+ if (Plugin != nullptr) {
+ CAccount *NewAccount;
+ if (Plugin->Fcn->NewAccountFcnPtr != nullptr)
+ //Let plugin create its own structure, which can be derived from CAccount structure
+ NewAccount = Plugin->Fcn->NewAccountFcnPtr(Plugin, YAMN_ACCOUNTVERSION);
+ else
+ //We suggest plugin uses standard CAccount structure, so we create it
+ NewAccount = new struct CAccount;
+
+ //If not created successfully
+ if (NewAccount == nullptr)
+ return NULL;
+
+ NewAccount->Plugin = Plugin;
+ //Init every members of structure, used by YAMN
+ InitAccount(NewAccount);
+
+ return (INT_PTR)NewAccount;
+ }
+ return NULL;
+}
+
+INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM)
+{
+ CAccount *OldAccount = (CAccount *)wParam;
+
+ if (OldAccount->Plugin->Fcn != nullptr) {
+ // Deinit every members and allocated fields of structure used by YAMN
+ DeInitAccount(OldAccount);
+ if (OldAccount->Plugin->Fcn->DeleteAccountFcnPtr != nullptr) {
+ // Let plugin delete its own CAccount derived structure
+ OldAccount->Plugin->Fcn->DeleteAccountFcnPtr(OldAccount);
+ }
+ else {
+ delete OldAccount; //consider account as standard YAMN CAccount *and use its own destructor
+ }
+ return 1;
+ }
+ delete OldAccount; //consider account as standard YAMN CAccount *, not initialized before and use its own destructor
+ return 1;
+}
+
+int InitAccount(CAccount *Which)
+{
+ //initialize synchronizing objects
+ Which->AccountAccessSO = new SWMRG;
+ SWMRGInitialize(Which->AccountAccessSO, nullptr);
+ Which->MessagesAccessSO = new SWMRG;
+ SWMRGInitialize(Which->MessagesAccessSO, nullptr);
+ Which->UsingThreads = new SCOUNTER;
+ SWMRGInitialize(Which->MessagesAccessSO, nullptr);
+
+ //zero memory, where timestamps are stored
+ memset(&Which->LastChecked, 0, sizeof(Which->LastChecked));
+ memset(&Which->LastSChecked, 0, sizeof(Which->LastSChecked));
+ memset(&Which->LastSynchronised, 0, sizeof(Which->LastSynchronised));
+ memset(&Which->LastMail, 0, sizeof(Which->LastMail));
+
+ Which->Name = nullptr;
+ Which->Mails = nullptr;
+ Which->Interval = 0;
+ Which->Flags = 0;
+ Which->StatusFlags = YAMN_ACC_ST1 + YAMN_ACC_ST7;
+ Which->Next = nullptr;
+
+ Which->Server = new struct CServer;
+ Which->AbleToWork = TRUE;
+
+ return 1;
+}
+
+void DeInitAccount(CAccount *Which)
+{
+ //delete YAMN allocated fields
+ if (Which->Name != nullptr)
+ delete[] Which->Name;
+ if (Which->Server != nullptr) {
+ if (Which->Server->Name != nullptr)
+ delete[] Which->Server->Name;
+ if (Which->Server->Login != nullptr)
+ delete[] Which->Server->Login;
+ if (Which->Server->Passwd != nullptr)
+ delete[] Which->Server->Passwd;
+ delete[] Which->Server;
+ }
+
+ SWMRGDelete(Which->AccountAccessSO);
+ delete Which->AccountAccessSO;
+ SWMRGDelete(Which->MessagesAccessSO);
+ delete Which->MessagesAccessSO;
+ delete Which->UsingThreads;
+ DeleteMessagesToEndFcn(Which, (HYAMNMAIL)Which->Mails);
+}
+
+void StopSignalFcn(CAccount *Which)
+//set event that we are going to delete account
+{
+ Which->AbleToWork = FALSE;
+ //do not use synchronizing objects anymore
+ //any access to these objects then ends with WAIT_FAILED
+ SetEvent(Which->AccountAccessSO->hFinishEV);
+ SetEvent(Which->MessagesAccessSO->hFinishEV);
+}
+
+void CodeDecodeString(char *Dest, BOOL Encrypt)
+{
+ wchar_t Code = STARTCODEPSW;
+
+ if (Dest == nullptr)
+ return;
+
+ for (; *Dest != (wchar_t)0; Dest++) {
+ if (Encrypt)
+ *Dest = *Dest + Code;
+ else
+ *Dest = *Dest - Code;
+ Code += (wchar_t)ADDCODEPSW;
+ }
+}
+
+static uint32_t PostFileToMemory(HANDLE File, char **MemFile, char **End)
+{
+ DWORD FileSize, ReadBytes;
+ if (!(FileSize = GetFileSize(File, nullptr))) {
+ CloseHandle(File);
+ return EACC_FILESIZE;
+ }
+
+ //allocate space in memory, where we copy the whole file
+ if (nullptr == (*MemFile = new char[FileSize])) {
+ CloseHandle(File);
+ return EACC_ALLOC;
+ }
+
+ //copy file to memory
+ if (!ReadFile(File, (LPVOID)*MemFile, FileSize, &ReadBytes, nullptr)) {
+ CloseHandle(File);
+ delete[] * MemFile;
+ return EACC_SYSTEM;
+ }
+ CloseHandle(File);
+ *End = *MemFile + FileSize;
+ return 0;
+}
+
+uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End)
+{
+ HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return EACC_SYSTEM;
+
+ return PostFileToMemory(hFile, MemFile, End);
+}
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemory(char **Parser, wchar_t *End, char **StoreTo, wchar_t *DebugString)
+{
+ //This is the debug version of ReadStringFromMemory function. This version shows MessageBox where
+ //read string is displayed
+ wchar_t *Dest, *Finder;
+ uint32_t Size;
+ wchar_t Debug[65536];
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++;
+ mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, End - Finder);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ if (Finder >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (NULL == (Dest = *StoreTo = new wchar_t[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else {
+ *StoreTo = NULL;
+ (*Parser)++;
+ }
+ return 0;
+}
+#endif
+
+uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo)
+{
+ char *Dest, *Finder;
+ uint32_t Size;
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++;
+ if (Finder >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (nullptr == (Dest = *StoreTo = new char[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else {
+ *StoreTo = nullptr;
+ (*Parser)++;
+ }
+ return 0;
+}
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo, wchar_t *DebugString)
+{
+ //This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where
+ //read string is displayed
+ wchar_t *Dest, *Finder;
+ uint32_t Size;
+ wchar_t Debug[65536];
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++;
+ mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, (wchar_t *)End - Finder);
+ MessageBoxW(NULL, Debug, L"debug", MB_OK);
+ if (Finder >= (wchar_t *)End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (NULL == (Dest = *StoreTo = new wchar_t[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else {
+ *StoreTo = NULL;
+ (*Parser)++;
+ }
+ return 0;
+}
+#endif //if defined(DEBUG...)
+
+uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo)
+{
+ wchar_t *Dest, *Finder;
+ uint32_t Size;
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++;
+ if (Finder >= (wchar_t *)End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (nullptr == (Dest = *StoreTo = new wchar_t[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else {
+ *StoreTo = nullptr;
+ (*Parser)++;
+ }
+ return 0;
+}
+
+static uint32_t ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which)
+{
+ uint32_t Stat;
+ #ifdef DEBUG_FILEREAD
+ wchar_t Debug[65536];
+ #endif
+
+ Which->Flags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"NFlags: %04x, remaining %d chars", Which->Flags, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+
+ Which->PopupB = *(COLORREF *)(*Parser);
+ (*Parser) += sizeof(COLORREF);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupB: %04x, remaining %d chars", Which->PopupB, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ Which->PopupT = *(COLORREF *)(*Parser);
+ (*Parser) += sizeof(COLORREF);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupT: %04x, remaining %d chars", Which->PopupT, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ Which->PopupTime = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PopupTime: %04x, remaining %d chars", Which->PopupTime, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App, L"App"))
+ #else
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App))
+ #endif
+ return Stat;
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam, L"AppParam"))
+ #else
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam))
+ #endif
+ return Stat;
+ return 0;
+}
+
+uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End)
+{
+ char *Finder;
+ uint32_t Size, Stat;
+ HYAMNMAIL ActualMail = nullptr;
+ struct CMimeItem *items;
+ char *ReadString;
+
+ #ifdef DEBUG_FILEREAD
+ MessageBox(NULL, L"going to read messages, if any...", L"debug", MB_OK);
+ #endif
+ do {
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++;
+ if (Finder >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (Which->Mails == nullptr) //First message in queue
+ {
+ if (nullptr == (Which->Mails = ActualMail = CreateAccountMail(Which)))
+ return EACC_ALLOC;
+ }
+ else {
+ if (nullptr == (ActualMail->Next = CreateAccountMail(Which))) {
+ return EACC_ALLOC;
+ }
+ ActualMail = ActualMail->Next;
+ }
+ items = nullptr;
+ #ifdef DEBUG_FILEREADMESSAGES
+ if (Stat = ReadStringFromMemory(Parser, End, &ActualMail->ID, L"ID"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &ActualMail->ID))
+ #endif
+ return Stat;
+ // ActualMail->MailData=new MAILDATA; !!! mem leake !!! this is alloc by CreateAccountMail, no need for doubble alloc !!!!
+
+ ActualMail->MailData->Size = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ ActualMail->Flags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ ActualMail->Number = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->ReadMailOptsFcnPtr))
+ Which->Plugin->MailFcn->ReadMailOptsFcnPtr(ActualMail, Parser, End); //read plugin mail settings from file
+
+ do {
+ #if defined(DEBUG_FILEREADMESSAGES) || defined(DEBUG_FILEREAD)
+ if (Stat = ReadStringFromMemory(Parser, End, &ReadString, L"Name"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &ReadString))
+ #endif
+ return Stat;
+ if (ReadString == nullptr)
+ break;
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<read name>%s</read name>", ReadString);
+ #endif
+
+ if (items == nullptr)
+ items = ActualMail->MailData->TranslatedHeader = new struct CMimeItem;
+ else {
+ items->Next = new struct CMimeItem;
+ items = items->Next;
+ }
+ if (items == nullptr)
+ return EACC_ALLOC;
+ items->name = ReadString;
+
+ #ifdef DEBUG_FILEREADMESSAGES
+ if (Stat = ReadStringFromMemory(Parser, End, &ReadString, L"Value"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &ReadString))
+ #endif
+ return Stat;
+ items->value = ReadString;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<read value>%s</read value>\n", ReadString);
+ #endif
+ } while (1);
+ }
+ else
+ break; //no next messages, new account!
+
+ } while (1);
+ (*Parser)++;
+ return 0;
+}
+
+uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, char *End)
+{
+ uint32_t Stat;
+ #ifdef DEBUG_FILEREAD
+ wchar_t Debug[65536];
+ #endif
+ //Read name of account
+
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Name, L"Name"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Name))
+ #endif
+ return Stat;
+ if (Which->Name == nullptr)
+ return EACC_FILECOMPATIBILITY;
+
+ //Read server parameters
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Name, L"Server"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Name))
+ #endif
+ return Stat;
+ Which->Server->Port = *(uint16_t *)(*Parser);
+ (*Parser) += sizeof(uint16_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"Port: %d, remaining %d chars", Which->Server->Port, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login, L"Login"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login))
+ #endif
+ return Stat;
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Passwd, L"Password"))
+ #else
+ if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Passwd))
+ #endif
+ return Stat;
+ CodeDecodeString(Which->Server->Passwd, FALSE);
+
+ //Read account flags
+ Which->Flags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"Flags: %04x, remaining %d chars", Which->Flags, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ Which->StatusFlags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"STFlags: %04x, remaining %d chars", Which->StatusFlags, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ Which->PluginFlags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"PFlags: %04x, remaining %d chars", Which->PluginFlags, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+
+ //Read account miscellaneous parameters
+ Which->Interval = *(uint16_t *)(*Parser);
+ Which->TimeLeft = Which->Interval; //check on loading
+ (*Parser) += sizeof(uint16_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"Interval: %d, remaining %d chars", Which->Interval, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+
+ //Read notification parameters
+ if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NewMailN))
+ return Stat;
+ if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NoNewMailN))
+ return Stat;
+ if (Stat = ReadNotificationFromMemory(Parser, End, &Which->BadConnectN))
+ return Stat;
+
+ //Let plugin read its own data stored in file
+ if (Which->Plugin->Fcn != nullptr && Which->Plugin->Fcn->ReadPluginOptsFcnPtr != nullptr)
+ if (Stat = Which->Plugin->Fcn->ReadPluginOptsFcnPtr(Which, Parser, End))
+ return Stat;
+
+ // Read mails
+ WaitToWriteFcn(Which->MessagesAccessSO);
+
+ if (Stat = ReadMessagesFromMemory(Which, Parser, End)) {
+ WriteDoneFcn(Which->MessagesAccessSO);
+ return Stat;
+ }
+
+ WriteDoneFcn(Which->MessagesAccessSO);
+
+ // Read timestamps
+ Which->LastChecked = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastSChecked = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastSynchronised = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastMail = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser > End) //WARNING! There's only > at the end of testing
+ return EACC_FILECOMPATIBILITY;
+
+ if (*Parser == End)
+ return EACC_ENDOFFILE;
+ return 0;
+}
+
+static INT_PTR PerformAccountReading(HYAMNPROTOPLUGIN Plugin, char *MemFile, char *End)
+{
+ // Retrieve info for account from memory
+ char *Parser;
+ uint32_t Ver, Stat;
+
+ CAccount *ActualAccount, *FirstAllocatedAccount;
+
+ Ver = *(uint32_t *)MemFile;
+ if (Ver > YAMN_ACCOUNTFILEVERSION) {
+ delete[] MemFile;
+ return EACC_FILEVERSION;
+ }
+ Parser = MemFile + sizeof(Ver);
+
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ if (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) {
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ delete[] MemFile;
+ return EACC_ALLOC;
+ }
+
+ FirstAllocatedAccount = ActualAccount;
+
+ do {
+ CAccount *Temp;
+
+ WaitToWriteFcn(ActualAccount->AccountAccessSO);
+ Stat = ReadAccountFromMemory(ActualAccount, &Parser, End);
+
+ if (ActualAccount->StatusFlags & (YAMN_ACC_STARTA | YAMN_ACC_STARTS))
+ ActualAccount->TimeLeft = 1; //check on loading
+
+ if (Stat && (Stat != EACC_ENDOFFILE)) {
+ for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) {
+ Temp = ActualAccount->Next;
+ delete ActualAccount;
+ }
+ delete[] MemFile;
+ if (Plugin->FirstAccount == FirstAllocatedAccount)
+ Plugin->FirstAccount = nullptr;
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return (INT_PTR)Stat;
+ }
+
+ WriteDoneFcn(ActualAccount->AccountAccessSO);
+
+ if ((Stat != EACC_ENDOFFILE) && (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION)))) {
+ for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) {
+ Temp = ActualAccount->Next;
+ delete ActualAccount;
+ }
+ delete[] MemFile;
+ if (Plugin->FirstAccount == FirstAllocatedAccount)
+ Plugin->FirstAccount = nullptr;
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return EACC_ALLOC;
+ }
+ } while (Stat != EACC_ENDOFFILE);
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ delete[] MemFile;
+ return 0;
+}
+
+// Add accounts from file to memory
+INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam)
+{
+ char *MemFile, *End;
+ uint32_t Stat = FileToMemory((wchar_t *)lParam, &MemFile, &End);
+ if (Stat != NO_ERROR)
+ return (INT_PTR)Stat;
+
+ return PerformAccountReading((HYAMNPROTOPLUGIN)wParam, MemFile, End);
+}
+
+uint32_t WriteStringToFile(HANDLE File, char *Source)
+{
+ DWORD Length, WrittenBytes;
+ char null = 0;
+
+ if ((Source == nullptr) || !(Length = (uint32_t)mir_strlen(Source))) {
+ if (!WriteFile(File, &null, 1, &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ }
+ else if (!WriteFile(File, Source, (Length + 1), &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ return 0;
+}
+
+uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source)
+{
+ DWORD Length, WrittenBytes;
+ wchar_t null = (wchar_t)0;
+
+ if ((Source == nullptr) || !(Length = (uint32_t)mir_wstrlen(Source))) {
+ if (!WriteFile(File, &null, sizeof(wchar_t), &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ }
+ else if (!WriteFile(File, Source, (Length + 1) * sizeof(wchar_t), &WrittenBytes, nullptr))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WriteMessagesToFile(HANDLE File, CAccount *Which)
+{
+ DWORD WrittenBytes, Stat;
+ HYAMNMAIL ActualMail = (HYAMNMAIL)Which->Mails;
+ struct CMimeItem *items;
+
+ while (ActualMail != nullptr) {
+ if (Stat = WriteStringToFile(File, ActualMail->ID))
+ return Stat;
+
+ if (!WriteFile(File, (char *)&ActualMail->MailData->Size, sizeof(ActualMail->MailData->Size), &WrittenBytes, nullptr) ||
+ !WriteFile(File, (char *)&ActualMail->Flags, sizeof(ActualMail->Flags), &WrittenBytes, nullptr) ||
+ !WriteFile(File, (char *)&ActualMail->Number, sizeof(ActualMail->Number), &WrittenBytes, nullptr))
+ return EACC_SYSTEM;
+ if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->WriteMailOptsFcnPtr))
+ Which->Plugin->MailFcn->WriteMailOptsFcnPtr(File, ActualMail); //write plugin mail options to file
+ for (items = ActualMail->MailData->TranslatedHeader; items != nullptr; items = items->Next) {
+ if (Stat = WriteStringToFile(File, items->name))
+ return Stat;
+ if (Stat = WriteStringToFile(File, items->value))
+ return Stat;
+ }
+ if (Stat = WriteStringToFile(File, ""))
+ return Stat;
+ ActualMail = ActualMail->Next;
+ }
+ if (Stat = WriteStringToFile(File, ""))
+ return Stat;
+ return 0;
+}
+
+static INT_PTR PerformAccountWriting(HYAMNPROTOPLUGIN Plugin, HANDLE File)
+{
+ DWORD WrittenBytes, Stat;
+ CAccount *ActualAccount;
+ uint32_t Ver = YAMN_ACCOUNTFILEVERSION;
+ BOOL Writed = FALSE;
+ uint32_t ReturnValue = 0, EnterCode;
+
+ SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE);
+
+ try {
+ for (ActualAccount = Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ EnterCode = WaitToReadFcn(ActualAccount->AccountAccessSO);
+ if (EnterCode == WAIT_FINISH) //account is about to delete
+ {
+ ActualAccount = ActualAccount->Next;
+ continue;
+ }
+ if (EnterCode == WAIT_FAILED) //account is deleted
+ break;
+
+ if ((ActualAccount->Name == nullptr) || (*ActualAccount->Name == (wchar_t)0)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+
+ if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ Writed = TRUE;
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Name))
+ throw (uint32_t)Stat;
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Server->Name))
+ throw (uint32_t)Stat;
+
+ if (!WriteFile(File, (char *)&ActualAccount->Server->Port, 2, &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFile(File, ActualAccount->Server->Login)))
+ throw (uint32_t)Stat;
+
+ CodeDecodeString(ActualAccount->Server->Passwd, TRUE);
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Server->Passwd)) {
+ CodeDecodeString(ActualAccount->Server->Passwd, FALSE);
+ throw (uint32_t)Stat;
+ }
+ CodeDecodeString(ActualAccount->Server->Passwd, FALSE);
+
+ if ((!WriteFile(File, (char *)&ActualAccount->Flags, sizeof(uint32_t), &WrittenBytes, nullptr) ||
+ (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(uint32_t), &WrittenBytes, nullptr))))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(uint16_t), &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->NewMailN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->NewMailN.AppParam)))
+ throw (uint32_t)Stat;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->NoNewMailN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.AppParam)))
+ throw (uint32_t)Stat;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->BadConnectN.Flags, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupTime, sizeof(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.AppParam)))
+ throw (uint32_t)Stat;
+
+ //Let plugin write its own values into file
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr != nullptr)
+ if (Stat = ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr(File, ActualAccount))
+ throw (uint32_t)Stat;
+
+ WaitToReadFcn(ActualAccount->MessagesAccessSO);
+
+ if (Stat = WriteMessagesToFile(File, ActualAccount)) {
+
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+ throw (uint32_t)Stat;
+ }
+
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+
+ if ((!WriteFile(File, (char *)&ActualAccount->LastChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastSChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastSynchronised, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->LastMail, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)))
+ throw (uint32_t)Stat;
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ catch (uint32_t ErrorCode) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ ReturnValue = ErrorCode;
+ }
+
+ SWMRGDoneReading(Plugin->AccountBrowserSO);
+ CloseHandle(File);
+ return 0;
+}
+
+// Writes accounts to file
+INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+
+ mir_cslock lck(csFileWritingCS);
+ HANDLE hFile = CreateFile((wchar_t *)lParam, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return EACC_SYSTEM;
+
+ return PerformAccountWriting(Plugin, hFile);
+}
+
+INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ char *SearchedAccount = (char *)lParam;
+ CAccount *Finder;
+
+ SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE);
+
+ for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next)
+ if ((Finder->Name != nullptr) && (0 == mir_strcmp(SearchedAccount, Finder->Name)))
+ break;
+
+ SWMRGDoneReading(Plugin->AccountBrowserSO);
+ return (INT_PTR)Finder;
+}
+
+INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ CAccount *Finder;
+
+ if (Plugin->FirstAccount == nullptr) {
+ Plugin->FirstAccount = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam);
+ return (INT_PTR)Plugin->FirstAccount;
+ }
+ for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; Finder = Finder->Next);
+ Finder->Next = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam);
+ return (INT_PTR)Finder->Next;
+}
+
+INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM lParam)
+{
+ //Deleting account works on these steps:
+ //1. set signal that account should stop activity (set event)
+ // setting this event we achieve, that any access to account is failed,
+ // so threads do not start any work with accounts (better saying threads of plugins should not start)
+ //2. wait to get write access to chained list of accounts
+ //3. we can write to chained list, so we change chain not to show to actual account
+ // now, any thread browsing list of accounts does not browse through actual account
+ // actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue))
+ //Now, we should delete account from memory, BUT!!!
+ // Any thread can still be waked up and start asking account synchronizing object
+ // If account is deleted, asking about access to read account can throw memory exception (reading for
+ // a synchronizing object from memory, that was deleted)
+ //So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore
+ // (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?)
+ // This deleting is achieved in 2 ways:
+ // We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account
+ // 1. Any thread using account first increment UsingThread, so we know that account is used
+ // 2. If thread is about to close, it should decrement UsingThread
+ // 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not
+ // increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using
+ // account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then
+ // new thread is going to read account...).
+ //4. wait until UsingThread Event is signaled
+ //5. delete account from memory
+
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ CAccount *Which = (CAccount *)lParam;
+ CAccount *Finder;
+
+ //1. set stop signal
+ StopSignalFcn(Which);
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Which, 0);
+ if (Plugin->Fcn->StopAccountFcnPtr != nullptr)
+ Plugin->Fcn->StopAccountFcnPtr(Which);
+
+ //2. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ //3. remove from queue (chained list)
+ if (Plugin->FirstAccount == nullptr) {
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return 0;
+ }
+ if (Plugin->FirstAccount == Which) {
+ Finder = Plugin->FirstAccount->Next;
+ Plugin->FirstAccount = Finder;
+ }
+ else {
+ for (Finder = Plugin->FirstAccount; Which != Finder->Next; Finder = Finder->Next);
+ Finder->Next = Finder->Next->Next;
+ }
+
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+
+ //4. wait while event "UsingThread" is not signaled
+ // And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so
+ // other threads do not start any new work with actual account) We will wait in blocked state?
+ // No, of course not. We will create new thread, that will wait and additionally remove our thread in background.
+ //5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread
+
+ if ((Plugin->Fcn != nullptr) && (Plugin->Fcn->WriteAccountsFcnPtr != nullptr))
+ Plugin->Fcn->WriteAccountsFcnPtr();
+ CloseHandle(mir_forkthread(DeleteAccountInBackground, (void *)Which));
+
+ //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using
+ //event UsingThreads.
+ return 1;
+}
+
+void __cdecl DeleteAccountInBackground(void *Value)
+{
+ CAccount *Which = (CAccount *)Value;
+ WaitForSingleObject(Which->UsingThreads->Event, INFINITE);
+ CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 0);
+}
+
+int StopAccounts(HYAMNPROTOPLUGIN Plugin)
+{
+ CAccount *Finder;
+
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ //2. set stop signal
+ StopSignalFcn(Finder);
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Finder, 0);
+ if (Plugin->Fcn->StopAccountFcnPtr != nullptr)
+ Plugin->Fcn->StopAccountFcnPtr(Finder);
+ }
+
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+
+ //Now, account is stopped. It can be removed from memory...
+ return 1;
+}
+
+int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess)
+{
+ if (GetAccountBrowserAccess) {
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+ }
+ for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ //2. wait for signal that account is not in use
+ WaitForSingleObject(Finder->UsingThreads->Event, INFINITE);
+ SetEvent(Finder->UsingThreads->Event);
+ }
+ if (GetAccountBrowserAccess) {
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ }
+
+ return 1;
+}
+
+int DeleteAccounts(HYAMNPROTOPLUGIN Plugin)
+{
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ WaitForAllAccounts(Plugin, FALSE);
+
+ for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr;) {
+ CAccount *Next = Finder->Next;
+ DeletePluginAccountSvc((WPARAM)Finder, 0);
+ Finder = Next;
+ }
+
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return 1;
+}
+
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value)
+{
+ if (Which == nullptr)
+ return;
+
+ mir_cslock lck(csAccountStatusCS);
+ mir_wstrcpy(Value, Which->Status);
+}
+
+void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value)
+{
+ if (Which != nullptr) {
+ mir_cslock lck(csAccountStatusCS);
+ mir_wstrcpy(Which->Status, Value);
+ }
+
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUS, (WPARAM)Which, 0);
+}
diff --git a/protocols/YAMN/src/browser/badconnect.cpp b/protocols/YAMN/src/browser/badconnect.cpp index 5f9118eb18..d871fa2eea 100644 --- a/protocols/YAMN/src/browser/badconnect.cpp +++ b/protocols/YAMN/src/browser/badconnect.cpp @@ -1,251 +1,251 @@ -/* - * This code implements window handling (connection error) - * - * (c) majvan 2002,2004 - */ - -#include "../stdafx.h" - -#define BADCONNECTTITLE LPGEN("%s - connection error") -#define BADCONNECTMSG LPGEN("An error occurred. Error code: %d")//is in use? - -//-------------------------------------------------------------------------------------------------- - -LRESULT CALLBACK BadConnectPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_COMMAND: - // if clicked and it's new mail popup window - if ((HIWORD(wParam) == STN_CLICKED) && (PUGetPluginData(hWnd))) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - CAccount *ActualAccount = (CAccount *)PUGetPluginData(hWnd); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->BadConnectN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->BadConnectN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + mir_wstrlen(ActualAccount->BadConnectN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->BadConnectN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->BadConnectN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->BadConnectN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - - PUDeletePopup(hWnd); - } - break; - - case UM_FREEPLUGINDATA: - //Here we'd free our own data, if we had it. - return FALSE; - - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - break; - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -INT_PTR CALLBACK DlgProcYAMNBadConnection(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - { - BOOL ShowPopup, ShowMsg, ShowIco; - CAccount *ActualAccount; - uint32_t ErrorCode; - char *TitleStrA; - char *Message1A = nullptr; - wchar_t *Message1W = nullptr; - POPUPDATAW BadConnectPopup = {}; - - ActualAccount = ((struct BadConnectionParam *)lParam)->account; - ErrorCode = ((struct BadConnectionParam *)lParam)->errcode; - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - return FALSE; - - int size = (int)(mir_strlen(ActualAccount->Name) + mir_strlen(Translate(BADCONNECTTITLE))); - TitleStrA = new char[size]; - mir_snprintf(TitleStrA, size, Translate(BADCONNECTTITLE), ActualAccount->Name); - - ShowPopup = ActualAccount->BadConnectN.Flags & YAMN_ACC_POP; - ShowMsg = ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG; - ShowIco = ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO; - - if (ShowPopup) { - BadConnectPopup.lchIcon = g_plugin.getIcon(IDI_BADCONNECT); - BadConnectPopup.colorBack = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupB : GetSysColor(COLOR_BTNFACE); - BadConnectPopup.colorText = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupT : GetSysColor(COLOR_WINDOWTEXT); - BadConnectPopup.iSeconds = ActualAccount->BadConnectN.PopupTime; - - BadConnectPopup.PluginWindowProc = BadConnectPopupProc; - BadConnectPopup.PluginData = ActualAccount; - mir_wstrncpy(BadConnectPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(BadConnectPopup.lpwzContactName)); - } - - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr != nullptr) { - Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - else if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr != nullptr) { - Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - else { - Message1W = TranslateT("Unknown error"); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - - if (!ShowMsg && !ShowIco) - DestroyWindow(hDlg); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - SetWindowTextA(hDlg, TitleStrA); - delete[] TitleStrA; - if (Message1A != nullptr) - delete[] Message1A; - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1A != nullptr) - ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A); - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1W != nullptr) - ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W); - return 0; - } - case WM_DESTROY: - { - NOTIFYICONDATA nid; - - memset(&nid, 0, sizeof(NOTIFYICONDATA)); - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - Shell_NotifyIcon(NIM_DELETE, &nid); - PostQuitMessage(0); - break; - } - case WM_YAMN_NOTIFYICON: - switch (lParam) { - case WM_LBUTTONDBLCLK: - ShowWindow(hDlg, SW_SHOWNORMAL); - SetForegroundWindow(hDlg); - break; - } - return 0; - case WM_CHAR: - switch ((wchar_t)wParam) { - case 27: - case 13: - DestroyWindow(hDlg); - break; - } - break; - case WM_SYSCOMMAND: - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - } - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_BTNOK: - DestroyWindow(hDlg); - } - break; - } - return 0; -} - -void __cdecl BadConnection(void *Param) -{ - MSG msg; - HWND hBadConnect; - CAccount *ActualAccount; - - struct BadConnectionParam MyParam = *(struct BadConnectionParam *)Param; - ActualAccount = MyParam.account; - - SCIncFcn(ActualAccount->UsingThreads); - - // we will not use params in stack anymore - SetEvent(MyParam.ThreadRunningEV); - - __try { - hBadConnect = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DLGBADCONNECT), nullptr, DlgProcYAMNBadConnection, (LPARAM)&MyParam); - Window_SetIcon_IcoLib(hBadConnect, g_plugin.getIconHandle(IDI_BADCONNECT)); - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - __leave; - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) - Skin_PlaySound(YAMN_CONNECTFAILSOUND); - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) - ShowWindow(hBadConnect, SW_SHOWNORMAL); - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) { - NOTIFYICONDATA nid = {}; - nid.cbSize = sizeof(nid); - nid.hWnd = hBadConnect; - nid.hIcon = g_plugin.getIcon(IDI_BADCONNECT); - nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - nid.uCallbackMessage = WM_YAMN_NOTIFYICON; - mir_snwprintf(nid.szTip, L"%S%s", ActualAccount->Name, TranslateT(" - connection error")); - Shell_NotifyIcon(NIM_ADD, &nid); - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - UpdateWindow(hBadConnect); - while (GetMessage(&msg, nullptr, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - // now, write to file. Why? Because we want to write when was new mail last checked - if ((ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork) - ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); - } - __finally { - SCDecFcn(ActualAccount->UsingThreads); - } -} - -int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo) -{ - BadConnectionParam param = {CreateEvent(nullptr, FALSE, FALSE, nullptr), acc, iErrorCode, pUserInfo}; - - HANDLE NewThread = mir_forkthread(BadConnection, ¶m); - if (nullptr == NewThread) - return 0; - - WaitForSingleObject(param.ThreadRunningEV, INFINITE); - CloseHandle(param.ThreadRunningEV); - return 1; -} +/*
+ * This code implements window handling (connection error)
+ *
+ * (c) majvan 2002,2004
+ */
+
+#include "../stdafx.h"
+
+#define BADCONNECTTITLE LPGEN("%s - connection error")
+#define BADCONNECTMSG LPGEN("An error occurred. Error code: %d")//is in use?
+
+//--------------------------------------------------------------------------------------------------
+
+LRESULT CALLBACK BadConnectPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ // if clicked and it's new mail popup window
+ if ((HIWORD(wParam) == STN_CLICKED) && (PUGetPluginData(hWnd))) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ CAccount *ActualAccount = (CAccount *)PUGetPluginData(hWnd);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->BadConnectN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + mir_wstrlen(ActualAccount->BadConnectN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->BadConnectN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->BadConnectN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+
+ PUDeletePopup(hWnd);
+ }
+ break;
+
+ case UM_FREEPLUGINDATA:
+ //Here we'd free our own data, if we had it.
+ return FALSE;
+
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ break;
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+INT_PTR CALLBACK DlgProcYAMNBadConnection(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ BOOL ShowPopup, ShowMsg, ShowIco;
+ CAccount *ActualAccount;
+ uint32_t ErrorCode;
+ char *TitleStrA;
+ char *Message1A = nullptr;
+ wchar_t *Message1W = nullptr;
+ POPUPDATAW BadConnectPopup = {};
+
+ ActualAccount = ((struct BadConnectionParam *)lParam)->account;
+ ErrorCode = ((struct BadConnectionParam *)lParam)->errcode;
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ return FALSE;
+
+ int size = (int)(mir_strlen(ActualAccount->Name) + mir_strlen(Translate(BADCONNECTTITLE)));
+ TitleStrA = new char[size];
+ mir_snprintf(TitleStrA, size, Translate(BADCONNECTTITLE), ActualAccount->Name);
+
+ ShowPopup = ActualAccount->BadConnectN.Flags & YAMN_ACC_POP;
+ ShowMsg = ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG;
+ ShowIco = ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO;
+
+ if (ShowPopup) {
+ BadConnectPopup.lchIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ BadConnectPopup.colorBack = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupB : GetSysColor(COLOR_BTNFACE);
+ BadConnectPopup.colorText = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupT : GetSysColor(COLOR_WINDOWTEXT);
+ BadConnectPopup.iSeconds = ActualAccount->BadConnectN.PopupTime;
+
+ BadConnectPopup.PluginWindowProc = BadConnectPopupProc;
+ BadConnectPopup.PluginData = ActualAccount;
+ mir_wstrncpy(BadConnectPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(BadConnectPopup.lpwzContactName));
+ }
+
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else {
+ Message1W = TranslateT("Unknown error");
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+
+ if (!ShowMsg && !ShowIco)
+ DestroyWindow(hDlg);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ SetWindowTextA(hDlg, TitleStrA);
+ delete[] TitleStrA;
+ if (Message1A != nullptr)
+ delete[] Message1A;
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1A != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A);
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1W != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W);
+ return 0;
+ }
+ case WM_DESTROY:
+ {
+ NOTIFYICONDATA nid;
+
+ memset(&nid, 0, sizeof(NOTIFYICONDATA));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ PostQuitMessage(0);
+ break;
+ }
+ case WM_YAMN_NOTIFYICON:
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ SetForegroundWindow(hDlg);
+ break;
+ }
+ return 0;
+ case WM_CHAR:
+ switch ((wchar_t)wParam) {
+ case 27:
+ case 13:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_BTNOK:
+ DestroyWindow(hDlg);
+ }
+ break;
+ }
+ return 0;
+}
+
+void __cdecl BadConnection(void *Param)
+{
+ MSG msg;
+ HWND hBadConnect;
+ CAccount *ActualAccount;
+
+ struct BadConnectionParam MyParam = *(struct BadConnectionParam *)Param;
+ ActualAccount = MyParam.account;
+
+ SCIncFcn(ActualAccount->UsingThreads);
+
+ // we will not use params in stack anymore
+ SetEvent(MyParam.ThreadRunningEV);
+
+ __try {
+ hBadConnect = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DLGBADCONNECT), nullptr, DlgProcYAMNBadConnection, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hBadConnect, g_plugin.getIconHandle(IDI_BADCONNECT));
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ __leave;
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_CONNECTFAILSOUND);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG)
+ ShowWindow(hBadConnect, SW_SHOWNORMAL);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) {
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hBadConnect;
+ nid.hIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S%s", ActualAccount->Name, TranslateT(" - connection error"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ UpdateWindow(hBadConnect);
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ // now, write to file. Why? Because we want to write when was new mail last checked
+ if ((ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork)
+ ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr();
+ }
+ __finally {
+ SCDecFcn(ActualAccount->UsingThreads);
+ }
+}
+
+int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo)
+{
+ BadConnectionParam param = {CreateEvent(nullptr, FALSE, FALSE, nullptr), acc, iErrorCode, pUserInfo};
+
+ HANDLE NewThread = mir_forkthread(BadConnection, ¶m);
+ if (nullptr == NewThread)
+ return 0;
+
+ WaitForSingleObject(param.ThreadRunningEV, INFINITE);
+ CloseHandle(param.ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/browser/browser.h b/protocols/YAMN/src/browser/browser.h index 6707d50621..0cb3f1a248 100644 --- a/protocols/YAMN/src/browser/browser.h +++ b/protocols/YAMN/src/browser/browser.h @@ -1,38 +1,38 @@ -#ifndef __MAILBROWSER_H -#define __MAILBROWSER_H - -typedef struct MailBrowserWinParam -{ -#define YAMN_MAILBROWSERVERSION 1 - HANDLE ThreadRunningEV; - CAccount *account; - uint32_t nflags; //flags YAMN_ACC_??? when new mails - uint32_t nnflags; //flags YAMN_ACC_??? when no new mails - void *Param; -} YAMN_MAILBROWSERPARAM,*PYAMN_MAILBROWSERPARAM; - -typedef struct MailShowMsgWinParam -{ - HANDLE ThreadRunningEV; - CAccount *account; - HYAMNMAIL mail; -} YAMN_MAILSHOWPARAM, *PYAMN_MAILSHOWPARAM; - -typedef struct NoNewMailParam -{ -#define YAMN_NONEWMAILVERSION 1 - HANDLE ThreadRunningEV; - CAccount *account; - uint32_t flags; - void *Param; -} YAMN_NONEWMAILPARAM,*PYAMN_NONEWMAILPARAM; - -struct BadConnectionParam -{ - HANDLE ThreadRunningEV; - CAccount *account; - UINT_PTR errcode; - void *Param; -}; - -#endif +#ifndef __MAILBROWSER_H
+#define __MAILBROWSER_H
+
+typedef struct MailBrowserWinParam
+{
+#define YAMN_MAILBROWSERVERSION 1
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ uint32_t nflags; //flags YAMN_ACC_??? when new mails
+ uint32_t nnflags; //flags YAMN_ACC_??? when no new mails
+ void *Param;
+} YAMN_MAILBROWSERPARAM,*PYAMN_MAILBROWSERPARAM;
+
+typedef struct MailShowMsgWinParam
+{
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ HYAMNMAIL mail;
+} YAMN_MAILSHOWPARAM, *PYAMN_MAILSHOWPARAM;
+
+typedef struct NoNewMailParam
+{
+#define YAMN_NONEWMAILVERSION 1
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ uint32_t flags;
+ void *Param;
+} YAMN_NONEWMAILPARAM,*PYAMN_NONEWMAILPARAM;
+
+struct BadConnectionParam
+{
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ UINT_PTR errcode;
+ void *Param;
+};
+
+#endif
diff --git a/protocols/YAMN/src/browser/mailbrowser.cpp b/protocols/YAMN/src/browser/mailbrowser.cpp index 1d62ad00dc..7b1b68e35a 100644 --- a/protocols/YAMN/src/browser/mailbrowser.cpp +++ b/protocols/YAMN/src/browser/mailbrowser.cpp @@ -1,2247 +1,2247 @@ -/* - * This code implements window handling (new mail) - * - * (c) majvan 2002-2004 - */ - /* There can be problems when compiling this file, because in this file - * we are using both unicode and no-unicode functions and compiler does not - * like it in one file - * When you got errors, try to comment the #define <stdio.h> and compile, then - * put it back to uncommented and compile again :) - */ - -#include "../stdafx.h" - -#define TIMER_FLASHING 0x09061979 -#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window -#define MAILBROWSER_MINYSIZE 130 - -#define MAILBROWSERTITLE LPGEN("%s - %d new mail messages, %d total") - -void __cdecl ShowEmailThread(void *Param); - -//-------------------------------------------------------------------------------------------------- -char *s_MonthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -bool bDate = false, bSub = false, bSize = false, bFrom = false; -int PosX = 0, PosY = 0, SizeX = 460, SizeY = 100; -int HeadSizeX = 0x2b2, HeadSizeY = 0x0b5, HeadPosX = 100, HeadPosY = 100; -int HeadSplitPos = 250; // per-mils of the size -static int FromWidth = 250, SubjectWidth = 280, SizeWidth = 50, SizeDate = 205; -unsigned char optDateTime = (SHOWDATELONG | SHOWDATENOTODAY); - -struct CMailNumbersSub -{ - int Total; //any mail - int New; //uses YAMN_MSG_NEW flag - int UnSeen; //uses YAMN_MSG_UNSEEN flag - // int Browser; //uses YAMN_MSG_BROWSER flag - int BrowserUC; //uses YAMN_MSG_BROWSER flag and YAMN_MSG_UNSEEN flag - int Display; //uses YAMN_MSG_DISPLAY flag - int DisplayTC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag - int DisplayUC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag and YAMN_MSG_UNSEEN flag - int Popup; //uses YAMN_MSG_POPUP flag - int PopupTC; //uses YAMN_MSG_POPUPC flag - int PopupNC; //uses YAMN_MSG_POPUPC flag and YAMN_MSG_NEW flag - int PopupRun; //uses YAMN_MSG_POPUP flag and YAMN_MSG_NEW flag - int PopupSL2NC; //uses YAMN_MSG_SPAML2 flag and YAMN_MSG_NEW flag - int PopupSL3NC; //uses YAMN_MSG_SPAML3 flag and YAMN_MSG_NEW flag - // int SysTray; //uses YAMN_MSG_SYSTRAY flag - int SysTrayUC; //uses YAMN_MSG_SYSTRAY flag and YAMN_MSG_UNSEEN flag - // int Sound; //uses YAMN_MSG_SOUND flag - int SoundNC; //uses YAMN_MSG_SOUND flag and YAMN_MSG_NEW flag - // int App; //uses YAMN_MSG_APP flag - int AppNC; //uses YAMN_MSG_APP flag and YAMN_MSG_NEW flag - int EventNC; //uses YAMN_MSG_NEVENT flag and YAMN_MSG_NEW flag -}; - -struct CMailNumbers -{ - struct CMailNumbersSub Real; - struct CMailNumbersSub Virtual; -}; - -struct CMailWinUserInfo -{ - CAccount *Account; - int TrayIconState; - BOOL UpdateMailsMessagesAccess; - BOOL Seen; - BOOL RunFirstTime; -}; - -struct CChangeContent -{ - uint32_t nflags; - uint32_t nnflags; -}; - -struct CUpdateMails -{ - struct CChangeContent *Flags; - BOOL Waiting; - HANDLE Copied; -}; - -struct CSortList -{ - HWND hDlg; - int iSubItem; -}; - -// Retrieves CAccount *, whose mails are displayed in ListMails -// hLM- handle of dialog window -// returns handle of account -inline CAccount *GetWindowAccount(HWND hDialog); - -// Looks to mail flags and increment mail counter (e.g. if mail is new, increments the new mail counter -// msgq- mail, which increments the counters -// MN- counnters structure -void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN); - -enum -{ - UPDATE_FAIL = 0, //function failed - UPDATE_NONE, //none update has been performed - UPDATE_OK, //some changes occured, update performed -}; - -// Just looks for mail changes in account and update the mail browser window -// hDlg- dialog handle -// ActualAccount- account handle -// nflags- flags what to do when new mail arrives -// nnflags- flags what to do when no new mail arrives -// returns one of UPDATE_XXX value(not implemented yet) -int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags); - -// When new mail occurs, shows window, plays sound, runs application... -// hDlg- dialog handle. Dialog of mailbrowser is already created and actions are performed over this window -// ActualAccount- handle of account, whose mails are to be notified -// MN- statistics of mails in account -// nflags- what to do or not to do (e.g. to show mailbrowser window or prohibit to show) -// nflags- flags what to do when new mail arrives -// nnflags- flags what to do when no new mail arrives -void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags); - -// Looks for items in mailbrowser and if they were deleted, delete them from browser window -// hListView- handle of listview window -// ActualAccount- handle of account, whose mails are show -// MailNumbers- pointer to structure, in which function stores numbers of mails with some property -// returns one of UPDATE_XXX value (not implemented yet) -int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount); - -// Adds new mails to ListView and if any new, shows multi popup (every new message is new popup window created by popup plugin) -// hListView- handle of listview window -// ActualAccount- handle of account, whose mails are show -// NewMailPopup- pointer to prepared structure for popup plugin, can be NULL if no popup show -// MailNumbers- pointer to structure, in which function stores numbers of mails with some property -// nflags- flags what to do when new mail arrives -// returns one of UPDATE_XXX value (not implemented yet) -int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags); - -// Window callback procedure for popup window (created by popup plugin) -LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Window callback procedure for popup window (created by popup plugin) -LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Dialog callback procedure for mail browser -INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -// MailBrowser thread function creates window if needed, tray icon and plays sound -void __cdecl MailBrowser(void *Param); - -LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Runs mail browser in new thread -INT_PTR RunMailBrowserSvc(WPARAM, LPARAM); - -#define YAMN_BROWSER_SHOWPOPUP 0x01 - -// list view items' order criteria -#define LVORDER_NOORDER -1 -#define LVORDER_STRING 0 -#define LVORDER_NUMERIC 1 -#define LVORDER_DATETIME 2 - -// list view order direction -#define LVORDER_ASCENDING 1 -#define LVORDER_NONE 0 -#define LVORDER_DESCENDING -1 - -// list view sort type -#define LVSORTPRIORITY_NONE -1 - -// List view column info. -typedef struct _SAMPLELISTVIEWCOLUMN -{ - UINT uCXCol; // index - int nSortType; // sorting type (STRING = 0, NUMERIC, DATE, DATETIME) - int nSortOrder; // sorting order (ASCENDING = -1, NONE, DESCENDING) - int nPriority; // sort priority (-1 for none, 0, 1, ..., nColumns - 1 maximum) - wchar_t lpszName[128]; // column name -} SAMPLELISTVIEWCOLUMN; - -// Compare priority -typedef struct _LVCOMPAREINFO -{ - int iIdx; // Index - int iPriority; // Priority -} LVCOMPAREINFO, *LPLVCOMPAREINFO; - -//-------------------------------------------------------------------------------------------------- - -LPARAM readItemLParam(HWND hwnd, uint32_t iItem) -{ - LVITEM item; - item.mask = LVIF_PARAM; - item.iItem = iItem; - item.iSubItem = 0; - SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item); - return item.lParam; -} - -inline CAccount *GetWindowAccount(HWND hDlg) -{ - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - return (mwui == nullptr) ? nullptr : mwui->Account; -} - -void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN) -{ - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Total++; - else - MN->Real.Total++; - - if (msgq->Flags & YAMN_MSG_NEW) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.New++; - else - MN->Real.New++; - if (msgq->Flags & YAMN_MSG_UNSEEN) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.UnSeen++; - else - MN->Real.UnSeen++; - if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) == (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.BrowserUC++; - else - MN->Real.BrowserUC++; - if (msgq->Flags & YAMN_MSG_DISPLAY) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Display++; - else - MN->Real.Display++; - if ((msgq->Flags & (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.DisplayTC++; - else - MN->Real.DisplayTC++; - if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.DisplayUC++; - else - MN->Real.DisplayUC++; - if (msgq->Flags & YAMN_MSG_POPUP) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Popup++; - else - MN->Real.Popup++; - if ((msgq->Flags & YAMN_MSG_POPUPC) == YAMN_MSG_POPUPC) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupTC++; - else - MN->Real.PopupTC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) == (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupNC++; - else - MN->Real.PopupNC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUP)) == (YAMN_MSG_NEW | YAMN_MSG_POPUP)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupRun++; - else - MN->Real.PopupRun++; - if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML2)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupSL2NC++; - else - MN->Real.PopupSL2NC++; - if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML3)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupSL3NC++; - else - MN->Real.PopupSL3NC++; - /* if (msgq->MailData->Flags & YAMN_MSG_SYSTRAY) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SysTray++; - else - MN->Real.SysTray++; - */ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SysTrayUC++; - else - MN->Real.SysTrayUC++; - /* if (msgq->MailData->Flags & YAMN_MSG_SOUND) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Sound++; - else - MN->Real.Sound++; - */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_SOUND)) == (YAMN_MSG_NEW | YAMN_MSG_SOUND)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SoundNC++; - else - MN->Real.SoundNC++; - /* if (msgq->MailData->Flags & YAMN_MSG_APP) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.App++; - else - MN->Real.App++; - */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_APP)) == (YAMN_MSG_NEW | YAMN_MSG_APP)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.AppNC++; - else - MN->Real.AppNC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) == (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.EventNC++; - else - MN->Real.EventNC++; -} - -int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags) -{ - struct CMailNumbers MN; - - BOOL Loaded; - BOOL RunMailBrowser, RunPopups; - - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - //now we ensure read access for account and write access for its mails - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - PostMessage(hDlg, WM_DESTROY, 0, 0); - return UPDATE_FAIL; - } - - if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - PostMessage(hDlg, WM_DESTROY, 0, 0); - return UPDATE_FAIL; - } - - memset(&MN, 0, sizeof(MN)); - - for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next) { - if (!LoadedMailData(msgq)) //check if mail is already in memory - { - Loaded = false; - if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it - continue; - } - else - Loaded = true; - - IncrementMailCounters(msgq, &MN); - - if (!Loaded) - UnloadMailData(msgq); //do not keep data for mail in memory - } - - if (mwui != nullptr) - mwui->UpdateMailsMessagesAccess = TRUE; - - //Now we are going to check if extracting data from mail headers are needed. - //If popups will be displayed or mailbrowser window - if ((((mwui != nullptr) && !(mwui->RunFirstTime)) && - ( - ((nnflags & YAMN_ACC_MSGP) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || - ((nflags & YAMN_ACC_MSGP) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) - ) - ) || //if mail window was displayed before and flag YAMN_ACC_MSGP is set - ((nnflags & YAMN_ACC_MSG) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if needed to run mailbrowser when no unseen and no unseen mail found - ((nflags & YAMN_ACC_MSG) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if unseen mails found, we sure run mailbrowser - ((nflags & YAMN_ACC_ICO) && (MN.Real.SysTrayUC + MN.Virtual.SysTrayUC)) - ) //if needed to run systray - RunMailBrowser = TRUE; - else - RunMailBrowser = FALSE; - - // if some popups with mails are needed to show - if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (MN.Real.PopupNC + MN.Virtual.PopupNC)) - RunPopups = TRUE; - else RunPopups = FALSE; - - if (RunMailBrowser) - ChangeExistingMailStatus(GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount); - if (RunMailBrowser || RunPopups) - AddNewMailsToListView(hDlg == nullptr ? nullptr : GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount, nflags); - - if (RunMailBrowser) { - size_t len = mir_strlen(ActualAccount->Name) + mir_strlen(Translate(MAILBROWSERTITLE)) + 10; //+10 chars for numbers - char *TitleStrA = new char[len]; - wchar_t *TitleStrW = new wchar_t[len]; - - mir_snprintf(TitleStrA, len, Translate(MAILBROWSERTITLE), ActualAccount->Name, MN.Real.DisplayUC + MN.Virtual.DisplayUC, MN.Real.Display + MN.Virtual.Display); - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, TitleStrA, -1, TitleStrW, (int)mir_strlen(TitleStrA) + 1); - SetWindowTextW(hDlg, TitleStrW); - delete[] TitleStrA; - delete[] TitleStrW; - } - - DoMailActions(hDlg, ActualAccount, &MN, nflags, nnflags); - - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_NEW, 0, YAMN_MSG_NEW, YAMN_FLAG_REMOVE); //rempve the new flag - if (!RunMailBrowser) - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_UNSEEN, YAMN_MSG_STAYUNSEEN, YAMN_MSG_UNSEEN, YAMN_FLAG_REMOVE); //remove the unseen flag when it was not displayed and it has not "stay unseen" flag set - - if (mwui != nullptr) { - mwui->UpdateMailsMessagesAccess = FALSE; - mwui->RunFirstTime = FALSE; - } - - WriteDoneFcn(ActualAccount->MessagesAccessSO); - ReadDoneFcn(ActualAccount->AccountAccessSO); - - if (RunMailBrowser) - UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS)); - else if (hDlg != nullptr) - DestroyWindow(hDlg); - - return 1; -} - -int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount) -{ - LVITEM item; - HYAMNMAIL mail, msgq; - - int in = ListView_GetItemCount(hListView); - item.mask = LVIF_PARAM; - - for (int i = 0; i < in; i++) { - item.iItem = i; - item.iSubItem = 0; - if (TRUE == ListView_GetItem(hListView, &item)) - mail = (HYAMNMAIL)item.lParam; - else - continue; - for (msgq = (HYAMNMAIL)ActualAccount->Mails; (msgq != nullptr) && (msgq != mail); msgq = msgq->Next); //found the same mail in account queue - if (msgq == nullptr) //if mail was not found - if (TRUE == ListView_DeleteItem(hListView, i)) { - in--; i--; - continue; - } - } - - return TRUE; -} - -void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout); -int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags) -{ - wchar_t *FromStr; - wchar_t SizeStr[20]; - wchar_t LocalDateStr[128]; - - LVITEMW item; - LVFINDINFO fi; - - int foundi = 0, lfoundi = 0; - struct CHeader UnicodeHeader; - BOOL Loaded, Extracted, FromStrNew = FALSE; - - memset(&item, 0, sizeof(item)); - memset(&UnicodeHeader, 0, sizeof(UnicodeHeader)); - - if (hListView != nullptr) { - item.mask = LVIF_TEXT | LVIF_PARAM; - item.iItem = 0; - memset(&fi, 0, sizeof(fi)); - fi.flags = LVFI_PARAM; //let's go search item by lParam number - lfoundi = 0; - } - - POPUPDATAW NewMailPopup = {}; - NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - if (nflags & YAMN_ACC_POPC) { - NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB; - NewMailPopup.colorText = ActualAccount->NewMailN.PopupT; - } - else { - NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime; - - NewMailPopup.PluginWindowProc = NewMailPopupProc; - NewMailPopup.PluginData = nullptr; //it's new mail popup - - for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next, lfoundi++) { - // now we hide mail pointer to item's lParam member. We can later use it to retrieve mail datas - - Extracted = FALSE; FromStr = nullptr; FromStrNew = FALSE; - - if (hListView != nullptr) { - fi.lParam = (LPARAM)msgq; - if (-1 != (foundi = ListView_FindItem(hListView, -1, &fi))) { // if mail is already in window - lfoundi = foundi; - continue; // do not insert any item - } - - item.iItem = lfoundi; // insert after last found item - item.lParam = (LPARAM)msgq; - } - - if (!LoadedMailData(msgq)) { // check if mail is already in memory - Loaded = false; - if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it - continue; - } - else Loaded = true; - - if (((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) || - ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW))) { - - if (!Extracted) ExtractHeader(msgq->MailData->TranslatedHeader, msgq->MailData->CP, &UnicodeHeader); - Extracted = TRUE; - - if ((UnicodeHeader.From != nullptr) && (UnicodeHeader.FromNick != nullptr)) { - size_t size = mir_wstrlen(UnicodeHeader.From) + mir_wstrlen(UnicodeHeader.FromNick) + 4; - FromStr = new wchar_t[size]; - mir_snwprintf(FromStr, size, L"%s <%s>", UnicodeHeader.FromNick, UnicodeHeader.From); - FromStrNew = TRUE; - } - else if (UnicodeHeader.From != nullptr) - FromStr = UnicodeHeader.From; - else if (UnicodeHeader.FromNick != nullptr) - FromStr = UnicodeHeader.FromNick; - else if (UnicodeHeader.ReturnPath != nullptr) - FromStr = UnicodeHeader.ReturnPath; - - if (nullptr == FromStr) { - FromStr = L""; - FromStrNew = FALSE; - } - } - - if ((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) { - item.iSubItem = 0; - item.pszText = FromStr; - item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item); - - item.iSubItem = 1; - item.pszText = (nullptr != UnicodeHeader.Subject ? UnicodeHeader.Subject : (wchar_t *)L""); - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - - item.iSubItem = 2; - mir_snwprintf(SizeStr, L"%d kB", msgq->MailData->Size / 1024); - item.pszText = SizeStr; - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - - item.iSubItem = 3; - item.pszText = L""; - - for (CMimeItem *heads = msgq->MailData->TranslatedHeader; heads != nullptr; heads = heads->Next) { - if (!_stricmp(heads->name, "Date")) { - MimeDateToLocalizedDateTime(heads->value, LocalDateStr, 128); - item.pszText = LocalDateStr; - break; - } - } - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - } - - if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW)) { - mir_wstrncpy(NewMailPopup.lpwzContactName, FromStr, _countof(NewMailPopup.lpwzContactName)); - mir_wstrncpy(NewMailPopup.lpwzText, UnicodeHeader.Subject, _countof(NewMailPopup.lpwzText)); - - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM)); - if (MailParam) { - MailParam->account = ActualAccount; - MailParam->mail = msgq; - MailParam->ThreadRunningEV = nullptr; - NewMailPopup.PluginData = MailParam; - PUAddPopupW(&NewMailPopup); - } - } - - if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN)) - CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, NULL); - - if (FromStrNew) - delete[] FromStr; - - if (Extracted) { - DeleteHeaderContent(&UnicodeHeader); - memset(&UnicodeHeader, 0, sizeof(UnicodeHeader)); - } - - if (!Loaded) { - SaveMailData(msgq); - UnloadMailData(msgq); //do not keep data for mail in memory - } - } - - return TRUE; -} - -void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags) -{ - NOTIFYICONDATA nid = {}; - nid.cbSize = sizeof(nid); - nid.hWnd = hDlg; - - if (MN->Real.EventNC + MN->Virtual.EventNC) - NotifyEventHooks(hNewMailHook, 0, 0); - - if ((nflags & YAMN_ACC_KBN) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) - CallService(MS_KBDNOTIFY_STARTBLINK, (WPARAM)MN->Real.PopupNC + MN->Virtual.PopupNC, NULL); - - if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) { - wchar_t tszMsg[250]; - mir_snwprintf(tszMsg, TranslateT("%s : %d new mail message(s), %d total"), _A2T(ActualAccount->Name).get(), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - - if (!(nflags & YAMN_ACC_CONTNOEVENT)) { - CLISTEVENT evt = {}; - evt.flags = CLEF_UNICODE; - evt.hContact = ActualAccount->hContact; - evt.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - evt.hDbEvent = ActualAccount->hContact; - evt.lParam = ActualAccount->hContact; - evt.pszService = MS_YAMN_CLISTDBLCLICK; - evt.szTooltip.w = tszMsg; - g_clistApi.pfnAddEvent(&evt); - } - db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg); - - if (nflags & YAMN_ACC_CONTNICK) - g_plugin.setWString(ActualAccount->hContact, "Nick", tszMsg); - } - - if ((nflags & YAMN_ACC_POP) && - !(ActualAccount->Flags & YAMN_ACC_POPN) && - (MN->Real.PopupRun + MN->Virtual.PopupRun)) { - POPUPDATAW NewMailPopup; - - NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - if (nflags & YAMN_ACC_POPC) { - NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB; - NewMailPopup.colorText = ActualAccount->NewMailN.PopupT; - } - else { - NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime; - - NewMailPopup.PluginWindowProc = NewMailPopupProc; - NewMailPopup.PluginData = (void *)nullptr; //multiple popups - - mir_wstrncpy(NewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lpwzContactName)); - mir_snwprintf(NewMailPopup.lpwzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - PUAddPopupW(&NewMailPopup); - } - - // destroy tray icon if no new mail - if ((MN->Real.SysTrayUC + MN->Virtual.SysTrayUC == 0) && (hDlg != nullptr)) - Shell_NotifyIcon(NIM_DELETE, &nid); - - // and remove the event - if ((nflags & YAMN_ACC_CONT) && (!(nflags & YAMN_ACC_CONTNOEVENT)) && (MN->Real.UnSeen + MN->Virtual.UnSeen == 0)) - g_clistApi.pfnRemoveEvent(ActualAccount->hContact, ActualAccount->hContact); - - if ((MN->Real.BrowserUC + MN->Virtual.BrowserUC == 0) && (hDlg != nullptr)) { - if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG)) - PostMessage(hDlg, WM_DESTROY, 0, 0); //destroy window if no new mail and window is not visible - if (nnflags & YAMN_ACC_MSG) //if no new mail and msg should be executed - { - SetForegroundWindow(hDlg); - ShowWindow(hDlg, SW_SHOWNORMAL); - } - } - else - if (hDlg != nullptr) //else insert icon and set window if new mails - { - SendDlgItemMessageW(hDlg, IDC_LISTMAILS, LVM_SCROLL, 0, (LPARAM)0x7ffffff); - - if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC + MN->Virtual.SysTrayUC)) { - nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - nid.uCallbackMessage = WM_YAMN_NOTIFYICON; - mir_snwprintf(nid.szTip, L"%S %s", ActualAccount->Name, TranslateT("- new mail message(s)")); - Shell_NotifyIcon(NIM_ADD, &nid); - SetTimer(hDlg, TIMER_FLASHING, 500, nullptr); - } - if (nflags & YAMN_ACC_MSG) //if no new mail and msg should be executed - ShowWindow(hDlg, SW_SHOWNORMAL); - } - - if (MN->Real.AppNC + MN->Virtual.AppNC != 0) { - if (nflags & YAMN_ACC_APP) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - } - } - - if (MN->Real.SoundNC + MN->Virtual.SoundNC != 0) - if (nflags & YAMN_ACC_SND) - Skin_PlaySound(YAMN_NEWMAILSOUND); - - if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) { - POPUPDATAW NoNewMailPopup = {}; - - NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NoNewMailPopup.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP); - if (nflags & YAMN_ACC_POPC) { - NoNewMailPopup.colorBack = ActualAccount->NoNewMailN.PopupB; - NoNewMailPopup.colorText = ActualAccount->NoNewMailN.PopupT; - } - else { - NoNewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NoNewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NoNewMailPopup.iSeconds = ActualAccount->NoNewMailN.PopupTime; - - NoNewMailPopup.PluginWindowProc = NoNewMailPopupProc; - NoNewMailPopup.PluginData = nullptr; //it's not new mail popup - - mir_wstrncpy(NoNewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lpwzContactName)); - if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC) - mir_snwprintf(NoNewMailPopup.lpwzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC); - else - mir_wstrncpy(NoNewMailPopup.lpwzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lpwzText)); - PUAddPopupW(&NoNewMailPopup); - } - - if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) { - if (ActualAccount->hContact != NULL) { - if (MN->Real.PopupTC + MN->Virtual.PopupTC) { - char tmp[255]; - mir_snprintf(tmp, Translate("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - db_set_s(ActualAccount->hContact, "CList", "StatusMsg", tmp); - } - else db_set_s(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message")); - - if (nflags & YAMN_ACC_CONTNICK) - g_plugin.setString(ActualAccount->hContact, "Nick", ActualAccount->Name); - } - } - return; -} - -LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - INT_PTR PluginParam = 0; - switch (msg) { - case WM_COMMAND: - // if clicked and it's new mail popup window - if ((HIWORD(wParam) == STN_CLICKED) && (-1 != (PluginParam = (INT_PTR)PUGetPluginData(hWnd)))) { - MCONTACT hContact = 0; - CAccount *Account; - if (PluginParam) { - PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; - memcpy(MailParam, (PINT_PTR)PluginParam, sizeof(YAMN_MAILSHOWPARAM)); - hContact = MailParam->account->hContact; - Account = MailParam->account; - mir_forkthread(ShowEmailThread, MailParam); - } - else { - DBVARIANT dbv; - - hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - Account = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else Account = (CAccount *)hContact; //???? - - if (WAIT_OBJECT_0 == WaitToReadFcn(Account->AccountAccessSO)) { - switch (msg) { - case WM_COMMAND: - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, Account, - (Account->NewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG, - (Account->NoNewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG}; - - RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - break; - } - ReadDoneFcn(Account->AccountAccessSO); - } - } - if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT)) - g_clistApi.pfnRemoveEvent(hContact, hContact); - } - __fallthrough; - - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - case UM_FREEPLUGINDATA: - { - PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd); - if ((mpd) && (INT_PTR)mpd != -1)free(mpd); - return FALSE; - } - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - WindowList_Add(YAMNVar.MessageWnds, hWnd); - break; - case UM_DESTROYPOPUP: - WindowList_Remove(YAMNVar.MessageWnds, hWnd); - break; - case WM_YAMN_STOPACCOUNT: - { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if ((CAccount *)wParam != ActualAccount) - break; - DestroyWindow(hWnd); - return 0; - } - case WM_NOTIFY: - default: - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_COMMAND: - if ((HIWORD(wParam) == STN_CLICKED) && (msg == WM_COMMAND)) { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - switch (msg) { - case WM_COMMAND: - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr}; - - Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nnflags = Param.nnflags & ~YAMN_ACC_POP; - - Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nflags = Param.nflags & ~YAMN_ACC_POP; - - RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - break; - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - PUDeletePopup(hWnd); - } - break; - - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - - case UM_FREEPLUGINDATA: - //Here we'd free our own data, if we had it. - return FALSE; - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - WindowList_Add(YAMNVar.MessageWnds, hWnd); - break; - case UM_DESTROYPOPUP: - WindowList_Remove(YAMNVar.MessageWnds, hWnd); - break; - case WM_YAMN_STOPACCOUNT: - { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if ((CAccount *)wParam != ActualAccount) - break; - - DestroyWindow(hWnd); - return 0; - } - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -#ifdef __GNUC__ -//number of 100 ns periods between FILETIME 0 (1601/01/01 00:00:00.0000000) and TIMESTAMP 0 (1970/01/01 00:00:00) -#define NUM100NANOSEC 116444736000000000ULL -//The biggest time Get[Date|Time]Format can handle (Fri, 31 Dec 30827 23:59:59.9999999) -#define MAXFILETIME 0x7FFF35F4F06C7FFFULL -#else -#define NUM100NANOSEC 116444736000000000 -#define MAXFILETIME 0x7FFF35F4F06C7FFF -#endif - -ULONGLONG MimeDateToFileTime(char *datein) -{ - char *day = nullptr, *month = nullptr, *year = nullptr, *time = nullptr, *shift = nullptr; - SYSTEMTIME st; - ULONGLONG res = 0; - int wShiftSeconds = TimeZone_ToLocal(0); - GetLocalTime(&st); - //datein = "Xxx, 1 Jan 2060 5:29:1 +0530 XXX"; - //datein = "Xxx, 1 Jan 2060 05:29:10 "; - //datein = " ManySpaces 1.5 Jan 2060 05::"; - //datein = "Xxx, 35 February 20 :29:10 "; - //datein = "01.12.2007 (22:38:17)"; // - if (datein) { - char tmp[64]; - while (datein[0] == ' ') datein++; // eat leading spaces - strncpy(tmp, datein, 63); tmp[63] = 0; - if (atoi(tmp)) { // Parseable integer on DayOfWeek field? Buggy mime date. - day = tmp; - } - else { - int i = 0; - while (tmp[i] == ' ')i++; if (day = strchr(&tmp[i], ' ')) { day[0] = 0; day++; } - } - if (day) { while (day[0] == ' ') day++; if (month = strchr(day, ' ')) { month[0] = 0; month++; } } - if (month) { while (month[0] == ' ')month++; if (year = strchr(month, ' ')) { year[0] = 0; year++; } } - if (year) { while (year[0] == ' ') year++; if (time = strchr(year, ' ')) { time[0] = 0; time++; } } - if (time) { while (time[0] == ' ') time++; if (shift = strchr(time, ' ')) { shift[0] = 0; shift++; shift[5] = 0; } } - - if (year) { - st.wYear = atoi(year); - if (mir_strlen(year) < 4) if (st.wYear < 70)st.wYear += 2000; else st.wYear += 1900; - }; - if (month) for (int i = 0; i < 12; i++) if (strncmp(month, s_MonthNames[i], 3) == 0) { st.wMonth = i + 1; break; } - if (day) st.wDay = atoi(day); - if (time) { - char *h, *m, *s; - h = time; - if (m = strchr(h, ':')) { - m[0] = 0; m++; - if (s = strchr(m, ':')) { s[0] = 0; s++; } - } - else s = nullptr; - st.wHour = atoi(h); - st.wMinute = m ? atoi(m) : 0; - st.wSecond = s ? atoi(s) : 0; - } - else { st.wHour = st.wMinute = st.wSecond = 0; } - - if (shift) { - if (mir_strlen(shift) < 4) { - //has only hour - wShiftSeconds = (atoi(shift)) * 3600; - } - else { - char *smin = shift + mir_strlen(shift) - 2; - int ismin = atoi(smin); - smin[0] = 0; - int ishour = atoi(shift); - wShiftSeconds = (ishour * 60 + (ishour < 0 ? -1 : 1) * ismin) * 60; - } - } - } // if (datein) - FILETIME ft; - if (SystemTimeToFileTime(&st, &ft)) { - res = ((ULONGLONG)ft.dwHighDateTime << 32) | ((ULONGLONG)ft.dwLowDateTime); - LONGLONG w100nano = Int32x32To64((uint32_t)wShiftSeconds, 10000000); - res -= w100nano; - } - else { - res = 0; - } - return res; -} - -void FileTimeToLocalizedDateTime(LONGLONG filetime, wchar_t *dateout, int lendateout) -{ - int localeID = Langpack_GetDefaultLocale(); - //int localeID = MAKELCID(LANG_URDU, SORT_DEFAULT); - if (localeID == CALLSERVICE_NOTFOUND) localeID = LOCALE_USER_DEFAULT; - if (filetime > MAXFILETIME) filetime = MAXFILETIME; - else if (filetime <= 0) { - wcsncpy(dateout, TranslateT("Invalid"), lendateout); - return; - } - SYSTEMTIME st; - uint16_t wTodayYear = 0, wTodayMonth = 0, wTodayDay = 0; - FILETIME ft; - BOOL willShowDate = !(optDateTime & SHOWDATENOTODAY); - if (!willShowDate) { - GetLocalTime(&st); - wTodayYear = st.wYear; - wTodayMonth = st.wMonth; - wTodayDay = st.wDay; - } - ft.dwLowDateTime = (uint32_t)filetime; - ft.dwHighDateTime = (uint32_t)(filetime >> 32); - FILETIME localft; - if (!FileTimeToLocalFileTime(&ft, &localft)) { - // this should never happen - wcsncpy(dateout, L"Incorrect FileTime", lendateout); - } - else { - if (!FileTimeToSystemTime(&localft, &st)) { - // this should never happen - wcsncpy(dateout, L"Incorrect LocalFileTime", lendateout); - } - else { - dateout[lendateout - 1] = 0; - int templen = 0; - if (!willShowDate) willShowDate = (wTodayYear != st.wYear) || (wTodayMonth != st.wMonth) || (wTodayDay != st.wDay); - if (willShowDate) { - templen = GetDateFormatW(localeID, (optDateTime & SHOWDATELONG) ? DATE_LONGDATE : DATE_SHORTDATE, &st, nullptr, dateout, lendateout - 2); - dateout[templen - 1] = ' '; - } - if (templen < (lendateout - 1)) { - GetTimeFormatW(localeID, (optDateTime & SHOWDATENOSECONDS) ? TIME_NOSECONDS : 0, &st, nullptr, &dateout[templen], lendateout - templen - 1); - } - } - } -} - -void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout) -{ - ULONGLONG ft = MimeDateToFileTime(datein); - FileTimeToLocalizedDateTime(ft, dateout, lendateout); -} - -int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - if (lParam1 == NULL || lParam2 == NULL) - return 0; - - int nResult = 0; - char *str1; - char *str2; - HYAMNMAIL email1 = (HYAMNMAIL)lParam1; - HYAMNMAIL email2 = (HYAMNMAIL)lParam2; - struct CShortHeader Header1; - struct CShortHeader Header2; - memset(&Header1, 0, sizeof(Header1)); - memset(&Header2, 0, sizeof(Header2)); - - try { - ExtractShortHeader(email1->MailData->TranslatedHeader, &Header1); - ExtractShortHeader(email2->MailData->TranslatedHeader, &Header2); - - switch ((int)lParamSort) { - case 0: //From - if (Header1.FromNick == nullptr) - str1 = Header1.From; - else str1 = Header1.FromNick; - - if (Header2.FromNick == nullptr) - str2 = Header2.From; - else str2 = Header2.FromNick; - - nResult = mir_strcmp(str1, str2); - - if (bFrom) nResult = -nResult; - break; - case 1: //Subject - if (Header1.Subject == nullptr) - str1 = " "; - else str1 = Header1.Subject; - - if (Header2.Subject == nullptr) - str2 = " "; - else str2 = Header2.Subject; - - nResult = mir_strcmp(str1, str2); - - if (bSub) nResult = -nResult; - break; - case 2: //Size - if (email1->MailData->Size == email2->MailData->Size) nResult = 0; - if (email1->MailData->Size > email2->MailData->Size) nResult = 1; - if (email1->MailData->Size < email2->MailData->Size) nResult = -1; - - if (bSize) nResult = -nResult; - break; - - case 3: //Date - { - ULONGLONG ts1 = 0, ts2 = 0; - ts1 = MimeDateToFileTime(Header1.Date); - ts2 = MimeDateToFileTime(Header2.Date); - if (ts1 > ts2) nResult = 1; - else if (ts1 < ts2) nResult = -1; - else nResult = 0; - } - if (bDate) nResult = -nResult; - break; - - default: - if (Header1.Subject == nullptr) str1 = " "; - else str1 = Header1.Subject; - - if (Header2.Subject == nullptr) str2 = " "; - else str2 = Header2.Subject; - - nResult = mir_strcmp(str1, str2); - break; - } - //MessageBox(NULL,str1,str2,0); - } - catch (...) { - } - - //free mem - DeleteShortHeaderContent(&Header1); - DeleteShortHeaderContent(&Header2); - return nResult; - -} - -HCURSOR hCurSplitNS, hCurSplitWE; -#define DM_SPLITTERMOVED (WM_USER+15) - -static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_NCHITTEST: - return HTCLIENT; - - case WM_SETCURSOR: - SetCursor(hCurSplitNS); - return TRUE; - - case WM_LBUTTONDOWN: - SetCapture(hwnd); - return 0; - - case WM_MOUSEMOVE: - if (GetCapture() == hwnd) { - RECT rc; - GetClientRect(hwnd, &rc); - SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, (short)HIWORD(GetMessagePos()) + rc.bottom / 2, (LPARAM)hwnd); - } - return 0; - - case WM_LBUTTONUP: - ReleaseCapture(); - return 0; - } - return mir_callNextSubclass(hwnd, SplitterSubclassProc, msg, wParam, lParam); -} - -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -INT_PTR CALLBACK DlgProcYAMNShowMessage(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam; - wchar_t *iHeaderW = nullptr; - wchar_t *iValueW = nullptr; - int StrLen; - HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS); - mir_subclassWindow(GetDlgItem(hDlg, IDC_SPLITTER), SplitterSubclassProc); - SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)MailParam); - Window_SetIcon_IcoLib(hDlg, g_plugin.getIconHandle(IDI_NEWMAIL)); - - ListView_SetUnicodeFormat(hListView, TRUE); - ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT); - - StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 0); - iHeaderW = new wchar_t[StrLen + 1]; - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, iHeaderW, StrLen); - - StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, nullptr, 0); - iValueW = new wchar_t[StrLen + 1]; - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, iValueW, StrLen); - - LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 130, iHeaderW, 0, 0}; - LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 400, iValueW, 0, 0}; - SendMessage(hListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0); - SendMessage(hListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1); - if (nullptr != iHeaderW) - delete[] iHeaderW; - if (nullptr != iValueW) - delete[] iValueW; - - SendMessage(hDlg, WM_YAMN_CHANGECONTENT, 0, (LPARAM)MailParam); - MoveWindow(hDlg, HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, 0); - ShowWindow(hDlg, SW_SHOWNORMAL); - } - break; - - case WM_YAMN_CHANGECONTENT: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) - (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER)); - HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS); - HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY); - //do not redraw - SendMessage(hListView, WM_SETREDRAW, 0, 0); - ListView_DeleteAllItems(hListView); - struct CMimeItem *Header; - LVITEMW item; - item.mask = LVIF_TEXT | LVIF_PARAM; - wchar_t *From = nullptr, *Subj = nullptr; - char *contentType = nullptr, *transEncoding = nullptr, *body = nullptr; //should not be delete[]-ed - for (Header = MailParam->mail->MailData->TranslatedHeader; Header != nullptr; Header = Header->Next) { - wchar_t *str1 = nullptr; - wchar_t *str2 = nullptr; - wchar_t str_nul[2] = {0}; - if (!body) if (!_stricmp(Header->name, "Body")) { body = Header->value; continue; } - if (!contentType) if (!_stricmp(Header->name, "Content-Type")) contentType = Header->value; - if (!transEncoding) if (!_stricmp(Header->name, "Content-Transfer-Encoding")) transEncoding = Header->value; - //ConvertCodedStringToUnicode(Header->name,&str1,MailParam->mail->MailData->CP,1); - { - int streamsize = MultiByteToWideChar(20127, 0, Header->name, -1, nullptr, 0); - str1 = (wchar_t *)malloc(sizeof(wchar_t) * (streamsize + 1)); - MultiByteToWideChar(20127, 0, Header->name, -1, str1, streamsize);//US-ASCII - } - ConvertCodedStringToUnicode(Header->value, &str2, MailParam->mail->MailData->CP, 1); - if (!str2) { str2 = (wchar_t *)str_nul; }// the header value may be NULL - if (!From) if (!_stricmp(Header->name, "From")) { - From = new wchar_t[mir_wstrlen(str2) + 1]; - mir_wstrcpy(From, str2); - } - if (!Subj) if (!_stricmp(Header->name, "Subject")) { - Subj = new wchar_t[mir_wstrlen(str2) + 1]; - mir_wstrcpy(Subj, str2); - } - //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true; - int count = 0; wchar_t **split = nullptr; - int ofs = 0; - while (str2[ofs]) { - if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) || - (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D))count++; - ofs++; - } - split = new wchar_t *[count + 1]; - count = 0; ofs = 0; - split[0] = str2; - while (str2[ofs]) { - if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) || - (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D)) { - if (str2[ofs - 1]) { - count++; - } - split[count] = (wchar_t *)(str2 + ofs + 1); - str2[ofs] = 0; - } - ofs++; - }; - - if (!_stricmp(Header->name, "From") || !_stricmp(Header->name, "To") || !_stricmp(Header->name, "Date") || !_stricmp(Header->name, "Subject")) - item.iItem = 0; - else - item.iItem = 999; - for (int i = 0; i <= count; i++) { - item.iSubItem = 0; - if (i == 0) - item.pszText = str1; - else { - item.iItem++; - item.pszText = nullptr; - } - item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item); - item.iSubItem = 1; - item.pszText = str2 ? split[i] : nullptr; - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - } - delete[] split; - - if (str1) - free(str1); - if (str2 != (wchar_t *)str_nul) - free(str2); - } - if (body) { - wchar_t *bodyDecoded = nullptr; - char *localBody = nullptr; - if (contentType) { - if (!_strnicmp(contentType, "text", 4)) { - if (transEncoding) { - if (!_stricmp(transEncoding, "base64")) { - int size = (int)mir_strlen(body) * 3 / 4 + 5; - localBody = new char[size + 1]; - DecodeBase64(body, localBody, size); - } - else if (!_stricmp(transEncoding, "quoted-printable")) { - int size = (int)mir_strlen(body) + 2; - localBody = new char[size + 1]; - DecodeQuotedPrintable(body, localBody, size, FALSE); - } - } - } - else if (!_strnicmp(contentType, "multipart/", 10)) { - char *bondary = nullptr; - if (nullptr != (bondary = ExtractFromContentType(contentType, "boundary="))) { - bodyDecoded = ParseMultipartBody(body, bondary); - delete[] bondary; - } - } - } - if (!bodyDecoded)ConvertStringToUnicode(localBody ? localBody : body, MailParam->mail->MailData->CP, &bodyDecoded); - SetWindowTextW(hEdit, bodyDecoded); - delete[] bodyDecoded; - if (localBody) delete[] localBody; - SetFocus(hEdit); - } - if (!(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)) { - MailParam->mail->Flags |= YAMN_MSG_BODYREQUESTED; - CallService(MS_YAMN_ACCOUNTCHECK, (WPARAM)MailParam->account, 0); - } - else { - if (MailParam->mail->Flags & YAMN_MSG_UNSEEN) { - MailParam->mail->Flags &= ~YAMN_MSG_UNSEEN; //mark the message as seen - HWND hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)MailParam->account); - if (hMailBrowser) { - struct CChangeContent Params = {MailParam->account->NewMailN.Flags | YAMN_ACC_MSGP, MailParam->account->NoNewMailN.Flags | YAMN_ACC_MSGP}; - SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)MailParam->account, (LPARAM)&Params); - } - else UpdateMails(nullptr, MailParam->account, MailParam->account->NewMailN.Flags, MailParam->account->NoNewMailN.Flags); - } - } - ShowWindow(GetDlgItem(hDlg, IDC_SPLITTER), (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE); - ShowWindow(hEdit, (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE); - wchar_t *title = nullptr; - size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4; - title = new wchar_t[size]; - if (From && Subj) - mir_snwprintf(title, size, L"%s (%s)", Subj, From); - else if (From) - wcsncpy_s(title, size, From, _TRUNCATE); - else if (Subj) - wcsncpy_s(title, size, Subj, _TRUNCATE); - else - wcsncpy_s(title, size, L"none", _TRUNCATE); - if (Subj) delete[] Subj; - if (From) delete[] From; - SetWindowTextW(hDlg, title); - delete[] title; - // turn on redrawing - SendMessage(hListView, WM_SETREDRAW, 1, 0); - SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX); - } break; - - case WM_YAMN_STOPACCOUNT: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) - (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER)); - - if (nullptr == MailParam) - break; - if ((CAccount *)wParam != MailParam->account) - break; - - DestroyWindow(hDlg); - } - return 1; - - case WM_CTLCOLORSTATIC: - // here should be check if this is our edittext control. - // but we have only one static control (for now); - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - - case WM_DESTROY: - Window_FreeIcon_IcoLib(hDlg); - { - RECT coord; - if (GetWindowRect(hDlg, &coord)) { - HeadPosX = coord.left; - HeadSizeX = coord.right - coord.left; - HeadPosY = coord.top; - HeadSizeY = coord.bottom - coord.top; - } - - PostQuitMessage(1); - } - break; - - case WM_SYSCOMMAND: - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - break; - } - break; - - case WM_MOVE: - HeadPosX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - HeadPosY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - return 0; - - case DM_SPLITTERMOVED: - if ((HWND)lParam == GetDlgItem(hDlg, IDC_SPLITTER)) { - POINT pt; - pt.x = 0; - pt.y = wParam; - ScreenToClient(hDlg, &pt); - HeadSplitPos = (pt.y * 1000) / HeadSizeY;//+rc.bottom-rc.top; - if (HeadSplitPos >= 1000) HeadSplitPos = 999; - else if (HeadSplitPos <= 0) HeadSplitPos = 1; - else SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX); - } - return 0; - - case WM_SIZE: - if (wParam == SIZE_RESTORED) { - HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS); - HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY); - BOOL isBodyShown = ((PYAMN_MAILSHOWPARAM)(GetWindowLongPtr(hDlg, DWLP_USER)))->mail->Flags & YAMN_MSG_BODYRECEIVED; - HeadSizeX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - HeadSizeY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - int localSplitPos = (HeadSplitPos * HeadSizeY) / 1000; - int localSizeX; - RECT coord; - MoveWindow(GetDlgItem(hDlg, IDC_SPLITTER), 5, localSplitPos, HeadSizeX - 10, 2, TRUE); - MoveWindow(hEdit, 5, localSplitPos + 6, HeadSizeX - 10, HeadSizeY - localSplitPos - 11, TRUE); //where to put text window while resizing - MoveWindow(hList, 5, 5, HeadSizeX - 10, (isBodyShown ? localSplitPos : HeadSizeY) - 10, TRUE); //where to put headers list window while resizing - //if (changeX) { - if (GetClientRect(hList, &coord)) { - localSizeX = coord.right - coord.left; - } - else localSizeX = HeadSizeX; - LONG iNameWidth = ListView_GetColumnWidth(hList, 0); - ListView_SetColumnWidth(hList, 1, (localSizeX <= iNameWidth) ? 0 : (localSizeX - iNameWidth)); - //} - } - return 0; - - case WM_CONTEXTMENU: - if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTHEADERS) { - //MessageBox(0,"LISTHEADERS","Debug",0); - HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS); - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - if (pt.x == -1) pt.x = 0; - if (pt.y == -1) pt.y = 0; - if (int numRows = ListView_GetItemCount(hList)) { - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); - AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr); - DestroyMenu(hMenu); - if (nReturnCmd > 0) { - int courRow = 0; - size_t sizeNeeded = 0; - wchar_t headname[64] = {0}, headvalue[256] = {0}; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, headname, _countof(headname)); - ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue)); - size_t headnamelen = mir_wstrlen(headname); - if (headnamelen) sizeNeeded += 1 + headnamelen; - sizeNeeded += 3 + mir_wstrlen(headvalue); - } - if (sizeNeeded && OpenClipboard(hDlg)) { - EmptyClipboard(); - HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t)); - wchar_t *buff = (wchar_t *)GlobalLock(hData); - int courPos = 0; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, headname, _countof(headname)); - ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue)); - if (mir_wstrlen(headname)) courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s:\t%s\r\n", headname, headvalue); - else courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"\t%s\r\n", headvalue); - } - GlobalUnlock(hData); - - SetClipboardData(CF_UNICODETEXT, hData); - - CloseClipboard(); - } - } - } - } - break; // just in case - } - return 0; -} - -void __cdecl ShowEmailThread(void *Param) -{ - struct MailShowMsgWinParam MyParam = *(struct MailShowMsgWinParam *)Param; - - SCIncFcn(MyParam.account->UsingThreads); - - if (MyParam.mail->MsgWindow) { - //if (!BringWindowToTop(MyParam.mail->MsgWindow)) { - if (!SetForegroundWindow(MyParam.mail->MsgWindow)) { - SendMessage(MyParam.mail->MsgWindow, WM_DESTROY, 0, 0); - MyParam.mail->MsgWindow = nullptr; - goto CREADTEVIEWMESSAGEWINDOW; - } - - if (IsIconic(MyParam.mail->MsgWindow)) - OpenIcon(MyParam.mail->MsgWindow); - } - else { -CREADTEVIEWMESSAGEWINDOW: - MyParam.mail->MsgWindow = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE), nullptr, DlgProcYAMNShowMessage, (LPARAM)&MyParam); - WindowList_Add(YAMNVar.MessageWnds, MyParam.mail->MsgWindow); - MSG msg; - while (GetMessage(&msg, nullptr, 0, 0)) { - if (MyParam.mail->MsgWindow == nullptr || !IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { /* Wine fix. */ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - WindowList_Remove(YAMNVar.MessageWnds, MyParam.mail->MsgWindow); - MyParam.mail->MsgWindow = nullptr; - } - - SCDecFcn(MyParam.account->UsingThreads); - delete (struct MailShowMsgWinParam *)Param; -} - -INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CAccount *ActualAccount; - int Items; - - switch (msg) { - case WM_INITDIALOG: - { - struct MailBrowserWinParam *MyParam = (struct MailBrowserWinParam *)lParam; - - ListView_SetUnicodeFormat(GetDlgItem(hDlg, IDC_LISTMAILS), TRUE); - ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_LISTMAILS), LVS_EX_FULLROWSELECT); - - ActualAccount = MyParam->account; - struct CMailWinUserInfo *mwui = new struct CMailWinUserInfo; - mwui->Account = ActualAccount; - mwui->TrayIconState = 0; - mwui->UpdateMailsMessagesAccess = FALSE; - mwui->Seen = FALSE; - mwui->RunFirstTime = TRUE; - - SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)mwui); - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - DestroyWindow(hDlg); - return FALSE; - } - - SetDlgItemText(hDlg, IDC_BTNAPP, TranslateT("Run application")); - SetDlgItemText(hDlg, IDC_BTNDEL, TranslateT("Delete selected")); - SetDlgItemText(hDlg, IDC_BTNCHECKALL, TranslateT("Select All")); - SetDlgItemText(hDlg, IDC_BTNOK, TranslateT("OK")); - - LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, FromWidth, TranslateT("From"), 0, 0}; - LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SubjectWidth, TranslateT("Subject"), 0, 0}; - LVCOLUMN lvc2 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeWidth, TranslateT("Size"), 0, 0}; - LVCOLUMN lvc3 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeDate, TranslateT("Date"), 0, 0}; - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lvc2); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)3, (LPARAM)&lvc3); - - if ((ActualAccount->NewMailN.App != nullptr) && (mir_wstrlen(ActualAccount->NewMailN.App))) - EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), TRUE); - else - EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), FALSE); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - WindowList_Add(YAMNVar.MessageWnds, hDlg); - WindowList_Add(YAMNVar.NewMailAccountWnd, hDlg, (UINT_PTR)ActualAccount); - - { - wchar_t accstatus[512]; - GetStatusFcn(ActualAccount, accstatus); - SetDlgItemText(hDlg, IDC_STSTATUS, accstatus); - } - SetTimer(hDlg, TIMER_FLASHING, 500, nullptr); - - if (ActualAccount->hContact != NULL) - g_clistApi.pfnRemoveEvent(ActualAccount->hContact, (LPARAM)"yamn new mail message"); - - mir_subclassWindow(GetDlgItem(hDlg, IDC_LISTMAILS), ListViewSubclassProc); - } - break; - - case WM_DESTROY: - { - RECT coord; - LVCOLUMN ColInfo; - HYAMNMAIL Parser; - - Window_FreeIcon_IcoLib(hDlg); - - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - ColInfo.mask = LVCF_WIDTH; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 0, &ColInfo)) - FromWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 1, &ColInfo)) - SubjectWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 2, &ColInfo)) - SizeWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 3, &ColInfo)) - SizeDate = ColInfo.cx; - - if (!YAMNVar.Shutdown && GetWindowRect(hDlg, &coord)) //the YAMNVar.Shutdown testing is because M<iranda strange functionality at shutdown phase, when call to DBWriteContactSetting freezes calling thread - { - PosX = coord.left; - SizeX = coord.right - coord.left; - PosY = coord.top; - SizeY = coord.bottom - coord.top; - g_plugin.setDword(YAMN_DBPOSX, PosX); - g_plugin.setDword(YAMN_DBPOSY, PosY); - g_plugin.setDword(YAMN_DBSIZEX, SizeX); - g_plugin.setDword(YAMN_DBSIZEY, SizeY); - } - KillTimer(hDlg, TIMER_FLASHING); - - WindowList_Remove(YAMNVar.NewMailAccountWnd, hDlg); - WindowList_Remove(YAMNVar.MessageWnds, hDlg); - - if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) - break; - - //delete mails from queue, which are deleted from server (spam level 3 mails e.g.) - for (Parser = (HYAMNMAIL)ActualAccount->Mails; Parser != nullptr; Parser = Parser->Next) { - if ((Parser->Flags & YAMN_MSG_DELETED) && YAMN_MSG_SPAML(Parser->Flags, YAMN_MSG_SPAML3) && mwui->Seen) //if spaml3 was already deleted and user knows about it - { - DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, Parser, 1); - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)Parser); - } - } - - //mark mails as read (remove "new" and "unseen" flags) - if (mwui->Seen) - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY, 0, YAMN_MSG_NEW | YAMN_MSG_UNSEEN, 0); - - WriteDoneFcn(ActualAccount->MessagesAccessSO); - - NOTIFYICONDATA nid; - memset(&nid, 0, sizeof(NOTIFYICONDATA)); - - delete mwui; - SetWindowLongPtr(hDlg, DWLP_USER, NULL); - - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - Shell_NotifyIcon(NIM_DELETE, &nid); - PostQuitMessage(0); - } - break; - - case WM_SHOWWINDOW: - { - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - if (mwui == nullptr) - return 0; - mwui->Seen = TRUE; - } - - case WM_YAMN_CHANGESTATUS: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - if ((CAccount *)wParam != ActualAccount) - break; - - wchar_t accstatus[512]; - GetStatusFcn(ActualAccount, accstatus); - SetDlgItemText(hDlg, IDC_STSTATUS, accstatus); - return 1; - - case WM_YAMN_CHANGECONTENT: - { - struct CUpdateMails UpdateParams; - BOOL ThisThreadWindow = (GetCurrentThreadId() == GetWindowThreadProcessId(hDlg, nullptr)); - - if (nullptr == (UpdateParams.Copied = CreateEvent(nullptr, FALSE, FALSE, nullptr))) { - DestroyWindow(hDlg); - return 0; - } - UpdateParams.Flags = (struct CChangeContent *)lParam; - UpdateParams.Waiting = !ThisThreadWindow; - - if (ThisThreadWindow) { - if (!UpdateMails(hDlg, (CAccount *)wParam, UpdateParams.Flags->nflags, UpdateParams.Flags->nnflags)) - DestroyWindow(hDlg); - } - else if (PostMessage(hDlg, WM_YAMN_UPDATEMAILS, wParam, (LPARAM)&UpdateParams)) //this ensures UpdateMails will execute the thread who created the browser window - { - if (!ThisThreadWindow) - WaitForSingleObject(UpdateParams.Copied, INFINITE); - } - - CloseHandle(UpdateParams.Copied); - } - return 1; - case WM_YAMN_UPDATEMAILS: - { - struct CUpdateMails *um = (struct CUpdateMails *)lParam; - uint32_t nflags, nnflags; - - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - return 0; - if ((CAccount *)wParam != ActualAccount) - return 0; - - nflags = um->Flags->nflags; - nnflags = um->Flags->nnflags; - - if (um->Waiting) - SetEvent(um->Copied); - - if (!UpdateMails(hDlg, ActualAccount, nflags, nnflags)) - DestroyWindow(hDlg); - } - return 1; - case WM_YAMN_STOPACCOUNT: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - if ((CAccount *)wParam != ActualAccount) - break; - PostQuitMessage(0); - return 1; - - case WM_YAMN_NOTIFYICON: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (lParam) { - case WM_LBUTTONDBLCLK: - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - return 0; - } - - if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) { - ShowWindow(hDlg, SW_SHOWNORMAL); - SetForegroundWindow(hDlg); - } - else DestroyWindow(hDlg); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - break; - } - break; - - case WM_YAMN_SHOWSELECTED: - { - int iSelect = SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_GETNEXTITEM, -1, MAKELPARAM((UINT)LVNI_FOCUSED, 0)); // return item selected - if (iSelect != -1) { - LV_ITEMW item; - - item.iItem = iSelect; - item.iSubItem = 0; - item.mask = LVIF_PARAM | LVIF_STATE; - item.stateMask = 0xFFFFFFFF; - ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item); - HYAMNMAIL ActualMail = (HYAMNMAIL)item.lParam; - if (nullptr != ActualMail) { - PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; - MailParam->account = GetWindowAccount(hDlg); - MailParam->mail = ActualMail; - mir_forkthread(ShowEmailThread, MailParam); - } - } - } - break; - - case WM_SYSCOMMAND: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - break; - } - break; - - case WM_COMMAND: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (LOWORD(wParam)) { - case IDC_BTNCHECKALL: - ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, 0, LVIS_SELECTED); // deselect all items - ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, LVIS_SELECTED, LVIS_SELECTED); - Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS)); - ListView_RedrawItems(GetDlgItem(hDlg, IDC_LISTMAILS), 0, Items); - UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS)); - SetFocus(GetDlgItem(hDlg, IDC_LISTMAILS)); - break; - - case IDC_BTNOK: - DestroyWindow(hDlg); - break; - - case IDC_BTNAPP: - { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - - if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000)) - DestroyWindow(hDlg); - } - break; - - case IDC_BTNDEL: - { - HYAMNMAIL ActualMail; - uint32_t Total = 0; - - // we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - break; - - Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS)); - - LVITEM item; - item.stateMask = 0xFFFFFFFF; - - if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - for (int i = 0; i < Items; i++) { - item.iItem = i; - item.iSubItem = 0; - item.mask = LVIF_PARAM | LVIF_STATE; - item.stateMask = 0xFFFFFFFF; - ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item); - ActualMail = (HYAMNMAIL)item.lParam; - if (nullptr == ActualMail) - break; - if (item.state & LVIS_SELECTED) { - ActualMail->Flags |= YAMN_MSG_USERDELETE; //set to mail we are going to delete it - Total++; - } - } - - // Enable write-access to mails - WriteDoneFcn(ActualAccount->MessagesAccessSO); - - if (Total) { - wchar_t DeleteMsg[1024]; - - mir_snwprintf(DeleteMsg, TranslateT("Do you really want to delete %d selected mails?"), Total); - if (IDOK == MessageBox(hDlg, DeleteMsg, TranslateT("Delete confirmation"), MB_OKCANCEL | MB_ICONWARNING)) { - struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, ThreadRunningEV, ActualAccount, nullptr}; - - // Find if there's mail marked to delete, which was deleted before - if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - for (ActualMail = (HYAMNMAIL)ActualAccount->Mails; ActualMail != nullptr; ActualMail = ActualMail->Next) { - if ((ActualMail->Flags & YAMN_MSG_DELETED) && ((ActualMail->Flags & YAMN_MSG_USERDELETE))) //if selected mail was already deleted - { - DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, ActualMail, 1); - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)ActualMail); //delete it from memory - continue; - } - } - // Set flag to marked mails that they can be deleted - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_DELETEOK, 1); - // Create new thread which deletes marked mails. - HANDLE NewThread = mir_forkthread(ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr, &ParamToDeleteMails); - if (NewThread != nullptr) - WaitForSingleObject(ThreadRunningEV, INFINITE); - - // Enable write-access to mails - WriteDoneFcn(ActualAccount->MessagesAccessSO); - } - } - else //else mark messages that they are not to be deleted - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_USERDELETE, 0); - } - } - CloseHandle(ThreadRunningEV); - if (g_plugin.getByte(YAMN_CLOSEDELETE, 0)) - DestroyWindow(hDlg); - } - break; - } - break; - - case WM_SIZE: - if (wParam == SIZE_RESTORED) { - LONG x = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - LONG y = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - MoveWindow(GetDlgItem(hDlg, IDC_BTNDEL), 5, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put DELETE button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNCHECKALL), 10 + (x - 20) / 3, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put CHECK ALL button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNAPP), 15 + (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put RUN APP button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNOK), 20 + 2 * (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put OK button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_LISTMAILS), 5, 5, x - 10, y - 55, TRUE); //where to put list mail window while resizing - MoveWindow(GetDlgItem(hDlg, IDC_STSTATUS), 5, y - 5 - 45, x - 10, 15, TRUE); //where to put account status text while resizing - } - return 0; - - case WM_GETMINMAXINFO: - ((LPMINMAXINFO)lParam)->ptMinTrackSize.x = MAILBROWSER_MINXSIZE; - ((LPMINMAXINFO)lParam)->ptMinTrackSize.y = MAILBROWSER_MINYSIZE; - return 0; - - case WM_TIMER: - { - NOTIFYICONDATA nid; - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - memset(&nid, 0, sizeof(nid)); - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - nid.uFlags = NIF_ICON; - if (mwui->TrayIconState == 0) - nid.hIcon = g_plugin.getIcon(IDI_CHECKMAIL); - else - nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - Shell_NotifyIcon(NIM_MODIFY, &nid); - mwui->TrayIconState = !mwui->TrayIconState; - // UpdateWindow(hDlg); - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->idFrom) { - case IDC_LISTMAILS: - switch (((LPNMHDR)lParam)->code) { - case NM_DBLCLK: - SendMessage(hDlg, WM_YAMN_SHOWSELECTED, 0, 0); - break; - - case LVN_COLUMNCLICK: - if (nullptr != (ActualAccount = GetWindowAccount(hDlg))) { - NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)lParam; - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - switch ((int)pNMListView->iSubItem) { - case 0: - bFrom = !bFrom; - break; - case 1: - bSub = !bSub; - break; - case 2: - bSize = !bSize; - break; - case 3: - bDate = !bDate; - break; - default: - break; - } - ListView_SortItems(pNMListView->hdr.hwndFrom, ListViewCompareProc, pNMListView->iSubItem); - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - break; - - case NM_CUSTOMDRAW: - { - LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam; - LONG_PTR PaintCode; - - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (cd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - PaintCode = CDRF_NOTIFYITEMDRAW; - break; - case CDDS_ITEMPREPAINT: - PaintCode = CDRF_NOTIFYSUBITEMDRAW; - break; - case CDDS_ITEMPREPAINT | CDDS_SUBITEM: - { - BOOL umma; - { - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - umma = mwui->UpdateMailsMessagesAccess; - } - HYAMNMAIL ActualMail = (HYAMNMAIL)cd->nmcd.lItemlParam; - if (!ActualMail) - ActualMail = (HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec); - - if (!umma) - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->MessagesAccessSO)) - return 0; - - switch (ActualMail->Flags & YAMN_MSG_SPAMMASK) { - case YAMN_MSG_SPAML1: - case YAMN_MSG_SPAML2: - cd->clrText = RGB(150, 150, 150); - break; - case YAMN_MSG_SPAML3: - cd->clrText = RGB(200, 200, 200); - cd->clrTextBk = RGB(160, 160, 160); - break; - case 0: - if (cd->nmcd.dwItemSpec & 1) - cd->clrTextBk = RGB(230, 230, 230); - break; - default: - break; - } - if (ActualMail->Flags & YAMN_MSG_UNSEEN) - cd->clrTextBk = RGB(220, 235, 250); - PaintCode = CDRF_DODEFAULT; - - if (!umma) - ReadDoneFcn(ActualAccount->MessagesAccessSO); - break; - } - default: - PaintCode = 0; - } - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PaintCode); - return 1; - } - } - } - break; - - case WM_CONTEXTMENU: - if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTMAILS) { - //MessageBox(0,"LISTHEADERS","Debug",0); - HWND hList = GetDlgItem(hDlg, IDC_LISTMAILS); - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - if (pt.x == -1) pt.x = 0; - if (pt.y == -1) pt.y = 0; - if (int numRows = ListView_GetItemCount(hList)) { - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); - AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr); - DestroyMenu(hMenu); - if (nReturnCmd > 0) { - int courRow = 0; - size_t sizeNeeded = 0; - wchar_t from[128] = {0}, subject[256] = {0}, size[16] = {0}, date[64] = {0}; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, from, _countof(from)); - ListView_GetItemText(hList, courRow, 1, subject, _countof(subject)); - ListView_GetItemText(hList, courRow, 2, size, _countof(size)); - ListView_GetItemText(hList, courRow, 3, date, _countof(date)); - sizeNeeded += 5 + mir_wstrlen(from) + mir_wstrlen(subject) + mir_wstrlen(size) + mir_wstrlen(date); - } - if (sizeNeeded && OpenClipboard(hDlg)) { - EmptyClipboard(); - HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t)); - wchar_t *buff = (wchar_t *)GlobalLock(hData); - int courPos = 0; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, from, _countof(from)); - ListView_GetItemText(hList, courRow, 1, subject, _countof(subject)); - ListView_GetItemText(hList, courRow, 2, size, _countof(size)); - ListView_GetItemText(hList, courRow, 3, date, _countof(date)); - courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s\t%s\t%s\t%s\r\n", from, subject, size, date); - } - GlobalUnlock(hData); - - SetClipboardData(CF_UNICODETEXT, hData); - - CloseClipboard(); - } - } - } - } - break; // just in case - } - return 0; -} - -LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HWND hwndParent = GetParent(hDlg); - - switch (msg) { - case WM_GETDLGCODE: - { - LPMSG lpmsg = (LPMSG)lParam; - if (lpmsg != nullptr) { - if (lpmsg->message == WM_KEYDOWN - && lpmsg->wParam == VK_RETURN) - return DLGC_WANTALLKEYS; - } - } - break; - - case WM_KEYDOWN: - { - BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000; - BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000; - BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; - - switch (wParam) { - case 'A': // ctrl-a - if (!isAlt && !isShift && isCtrl) SendMessage(hwndParent, WM_COMMAND, IDC_BTNCHECKALL, 0); - break; - case VK_RETURN: - case VK_SPACE: - if (!isAlt && !isShift && !isCtrl) SendMessage(hwndParent, WM_YAMN_SHOWSELECTED, 0, 0); - break; - case VK_DELETE: - SendMessage(hwndParent, WM_COMMAND, IDC_BTNDEL, 0); - break; - } - } - break; - } - return mir_callNextSubclass(hDlg, ListViewSubclassProc, msg, wParam, lParam); -} - -void __cdecl MailBrowser(void *Param) -{ - MSG msg; - - HWND hMailBrowser; - BOOL WndFound = FALSE; - - struct MailBrowserWinParam MyParam = *(struct MailBrowserWinParam *)Param; - CAccount *ActualAccount = MyParam.account; - SCIncFcn(ActualAccount->UsingThreads); - - // we will not use params in stack anymore - SetEvent(MyParam.ThreadRunningEV); - - __try { - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - return; - - if (!(ActualAccount->AbilityFlags & YAMN_ACC_BROWSE)) { - MyParam.nflags = MyParam.nflags & ~YAMN_ACC_MSG; - MyParam.nnflags = MyParam.nnflags & ~YAMN_ACC_MSG; - } - - if (!(ActualAccount->AbilityFlags & YAMN_ACC_POPUP)) - MyParam.nflags = MyParam.nflags & ~YAMN_ACC_POP; - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - if (nullptr != (hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)ActualAccount))) - WndFound = TRUE; - - if ((hMailBrowser == nullptr) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) { - hMailBrowser = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES), nullptr, DlgProcYAMNMailBrowser, (LPARAM)&MyParam); - Window_SetIcon_IcoLib(hMailBrowser, g_plugin.getIconHandle(IDI_NEWMAIL)); - MoveWindow(hMailBrowser, PosX, PosY, SizeX, SizeY, TRUE); - } - - if (hMailBrowser != nullptr) { - struct CChangeContent Params = {MyParam.nflags, MyParam.nnflags}; //if this thread created window, just post message to update mails - - SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)ActualAccount, (LPARAM)&Params); //we ensure this will do the thread who created the browser window - } - else - UpdateMails(nullptr, ActualAccount, MyParam.nflags, MyParam.nnflags); //update mails without displaying or refreshing any window - - if ((hMailBrowser != nullptr) && !WndFound) { //we process message loop only for thread that created window - while (GetMessage(&msg, nullptr, 0, 0)) { - if (hMailBrowser == nullptr || !IsDialogMessage(hMailBrowser, &msg)) { /* Wine fix. */ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - - if ((!WndFound) && (ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork) - ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); - } - __finally { - SCDecFcn(ActualAccount->UsingThreads); - } -} - -INT_PTR RunMailBrowserSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_MAILBROWSERPARAM Param = (PYAMN_MAILBROWSERPARAM)wParam; - - if ((uint32_t)lParam != YAMN_MAILBROWSERVERSION) - return 0; - - //an event for successfull copy parameters to which point a pointer in stack for new thread - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - Param->ThreadRunningEV = ThreadRunningEV; - - HANDLE NewThread = mir_forkthread(MailBrowser, Param); - if (NewThread != nullptr) - WaitForSingleObject(ThreadRunningEV, INFINITE); - - CloseHandle(ThreadRunningEV); - return 1; -} +/*
+ * This code implements window handling (new mail)
+ *
+ * (c) majvan 2002-2004
+ */
+ /* There can be problems when compiling this file, because in this file
+ * we are using both unicode and no-unicode functions and compiler does not
+ * like it in one file
+ * When you got errors, try to comment the #define <stdio.h> and compile, then
+ * put it back to uncommented and compile again :)
+ */
+
+#include "../stdafx.h"
+
+#define TIMER_FLASHING 0x09061979
+#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window
+#define MAILBROWSER_MINYSIZE 130
+
+#define MAILBROWSERTITLE LPGEN("%s - %d new mail messages, %d total")
+
+void __cdecl ShowEmailThread(void *Param);
+
+//--------------------------------------------------------------------------------------------------
+char *s_MonthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+bool bDate = false, bSub = false, bSize = false, bFrom = false;
+int PosX = 0, PosY = 0, SizeX = 460, SizeY = 100;
+int HeadSizeX = 0x2b2, HeadSizeY = 0x0b5, HeadPosX = 100, HeadPosY = 100;
+int HeadSplitPos = 250; // per-mils of the size
+static int FromWidth = 250, SubjectWidth = 280, SizeWidth = 50, SizeDate = 205;
+unsigned char optDateTime = (SHOWDATELONG | SHOWDATENOTODAY);
+
+struct CMailNumbersSub
+{
+ int Total; //any mail
+ int New; //uses YAMN_MSG_NEW flag
+ int UnSeen; //uses YAMN_MSG_UNSEEN flag
+ // int Browser; //uses YAMN_MSG_BROWSER flag
+ int BrowserUC; //uses YAMN_MSG_BROWSER flag and YAMN_MSG_UNSEEN flag
+ int Display; //uses YAMN_MSG_DISPLAY flag
+ int DisplayTC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag
+ int DisplayUC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag and YAMN_MSG_UNSEEN flag
+ int Popup; //uses YAMN_MSG_POPUP flag
+ int PopupTC; //uses YAMN_MSG_POPUPC flag
+ int PopupNC; //uses YAMN_MSG_POPUPC flag and YAMN_MSG_NEW flag
+ int PopupRun; //uses YAMN_MSG_POPUP flag and YAMN_MSG_NEW flag
+ int PopupSL2NC; //uses YAMN_MSG_SPAML2 flag and YAMN_MSG_NEW flag
+ int PopupSL3NC; //uses YAMN_MSG_SPAML3 flag and YAMN_MSG_NEW flag
+ // int SysTray; //uses YAMN_MSG_SYSTRAY flag
+ int SysTrayUC; //uses YAMN_MSG_SYSTRAY flag and YAMN_MSG_UNSEEN flag
+ // int Sound; //uses YAMN_MSG_SOUND flag
+ int SoundNC; //uses YAMN_MSG_SOUND flag and YAMN_MSG_NEW flag
+ // int App; //uses YAMN_MSG_APP flag
+ int AppNC; //uses YAMN_MSG_APP flag and YAMN_MSG_NEW flag
+ int EventNC; //uses YAMN_MSG_NEVENT flag and YAMN_MSG_NEW flag
+};
+
+struct CMailNumbers
+{
+ struct CMailNumbersSub Real;
+ struct CMailNumbersSub Virtual;
+};
+
+struct CMailWinUserInfo
+{
+ CAccount *Account;
+ int TrayIconState;
+ BOOL UpdateMailsMessagesAccess;
+ BOOL Seen;
+ BOOL RunFirstTime;
+};
+
+struct CChangeContent
+{
+ uint32_t nflags;
+ uint32_t nnflags;
+};
+
+struct CUpdateMails
+{
+ struct CChangeContent *Flags;
+ BOOL Waiting;
+ HANDLE Copied;
+};
+
+struct CSortList
+{
+ HWND hDlg;
+ int iSubItem;
+};
+
+// Retrieves CAccount *, whose mails are displayed in ListMails
+// hLM- handle of dialog window
+// returns handle of account
+inline CAccount *GetWindowAccount(HWND hDialog);
+
+// Looks to mail flags and increment mail counter (e.g. if mail is new, increments the new mail counter
+// msgq- mail, which increments the counters
+// MN- counnters structure
+void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN);
+
+enum
+{
+ UPDATE_FAIL = 0, //function failed
+ UPDATE_NONE, //none update has been performed
+ UPDATE_OK, //some changes occured, update performed
+};
+
+// Just looks for mail changes in account and update the mail browser window
+// hDlg- dialog handle
+// ActualAccount- account handle
+// nflags- flags what to do when new mail arrives
+// nnflags- flags what to do when no new mail arrives
+// returns one of UPDATE_XXX value(not implemented yet)
+int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags);
+
+// When new mail occurs, shows window, plays sound, runs application...
+// hDlg- dialog handle. Dialog of mailbrowser is already created and actions are performed over this window
+// ActualAccount- handle of account, whose mails are to be notified
+// MN- statistics of mails in account
+// nflags- what to do or not to do (e.g. to show mailbrowser window or prohibit to show)
+// nflags- flags what to do when new mail arrives
+// nnflags- flags what to do when no new mail arrives
+void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags);
+
+// Looks for items in mailbrowser and if they were deleted, delete them from browser window
+// hListView- handle of listview window
+// ActualAccount- handle of account, whose mails are show
+// MailNumbers- pointer to structure, in which function stores numbers of mails with some property
+// returns one of UPDATE_XXX value (not implemented yet)
+int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount);
+
+// Adds new mails to ListView and if any new, shows multi popup (every new message is new popup window created by popup plugin)
+// hListView- handle of listview window
+// ActualAccount- handle of account, whose mails are show
+// NewMailPopup- pointer to prepared structure for popup plugin, can be NULL if no popup show
+// MailNumbers- pointer to structure, in which function stores numbers of mails with some property
+// nflags- flags what to do when new mail arrives
+// returns one of UPDATE_XXX value (not implemented yet)
+int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags);
+
+// Window callback procedure for popup window (created by popup plugin)
+LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Window callback procedure for popup window (created by popup plugin)
+LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Dialog callback procedure for mail browser
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// MailBrowser thread function creates window if needed, tray icon and plays sound
+void __cdecl MailBrowser(void *Param);
+
+LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Runs mail browser in new thread
+INT_PTR RunMailBrowserSvc(WPARAM, LPARAM);
+
+#define YAMN_BROWSER_SHOWPOPUP 0x01
+
+// list view items' order criteria
+#define LVORDER_NOORDER -1
+#define LVORDER_STRING 0
+#define LVORDER_NUMERIC 1
+#define LVORDER_DATETIME 2
+
+// list view order direction
+#define LVORDER_ASCENDING 1
+#define LVORDER_NONE 0
+#define LVORDER_DESCENDING -1
+
+// list view sort type
+#define LVSORTPRIORITY_NONE -1
+
+// List view column info.
+typedef struct _SAMPLELISTVIEWCOLUMN
+{
+ UINT uCXCol; // index
+ int nSortType; // sorting type (STRING = 0, NUMERIC, DATE, DATETIME)
+ int nSortOrder; // sorting order (ASCENDING = -1, NONE, DESCENDING)
+ int nPriority; // sort priority (-1 for none, 0, 1, ..., nColumns - 1 maximum)
+ wchar_t lpszName[128]; // column name
+} SAMPLELISTVIEWCOLUMN;
+
+// Compare priority
+typedef struct _LVCOMPAREINFO
+{
+ int iIdx; // Index
+ int iPriority; // Priority
+} LVCOMPAREINFO, *LPLVCOMPAREINFO;
+
+//--------------------------------------------------------------------------------------------------
+
+LPARAM readItemLParam(HWND hwnd, uint32_t iItem)
+{
+ LVITEM item;
+ item.mask = LVIF_PARAM;
+ item.iItem = iItem;
+ item.iSubItem = 0;
+ SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
+ return item.lParam;
+}
+
+inline CAccount *GetWindowAccount(HWND hDlg)
+{
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ return (mwui == nullptr) ? nullptr : mwui->Account;
+}
+
+void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN)
+{
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Total++;
+ else
+ MN->Real.Total++;
+
+ if (msgq->Flags & YAMN_MSG_NEW)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.New++;
+ else
+ MN->Real.New++;
+ if (msgq->Flags & YAMN_MSG_UNSEEN)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.UnSeen++;
+ else
+ MN->Real.UnSeen++;
+ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) == (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.BrowserUC++;
+ else
+ MN->Real.BrowserUC++;
+ if (msgq->Flags & YAMN_MSG_DISPLAY)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Display++;
+ else
+ MN->Real.Display++;
+ if ((msgq->Flags & (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.DisplayTC++;
+ else
+ MN->Real.DisplayTC++;
+ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.DisplayUC++;
+ else
+ MN->Real.DisplayUC++;
+ if (msgq->Flags & YAMN_MSG_POPUP)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Popup++;
+ else
+ MN->Real.Popup++;
+ if ((msgq->Flags & YAMN_MSG_POPUPC) == YAMN_MSG_POPUPC)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupTC++;
+ else
+ MN->Real.PopupTC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) == (YAMN_MSG_NEW | YAMN_MSG_POPUPC))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupNC++;
+ else
+ MN->Real.PopupNC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUP)) == (YAMN_MSG_NEW | YAMN_MSG_POPUP))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupRun++;
+ else
+ MN->Real.PopupRun++;
+ if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML2))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupSL2NC++;
+ else
+ MN->Real.PopupSL2NC++;
+ if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML3))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupSL3NC++;
+ else
+ MN->Real.PopupSL3NC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_SYSTRAY)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SysTray++;
+ else
+ MN->Real.SysTray++;
+ */ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SysTrayUC++;
+ else
+ MN->Real.SysTrayUC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_SOUND)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Sound++;
+ else
+ MN->Real.Sound++;
+ */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_SOUND)) == (YAMN_MSG_NEW | YAMN_MSG_SOUND))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SoundNC++;
+ else
+ MN->Real.SoundNC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_APP)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.App++;
+ else
+ MN->Real.App++;
+ */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_APP)) == (YAMN_MSG_NEW | YAMN_MSG_APP))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.AppNC++;
+ else
+ MN->Real.AppNC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) == (YAMN_MSG_NEW | YAMN_MSG_NEVENT))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.EventNC++;
+ else
+ MN->Real.EventNC++;
+}
+
+int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags)
+{
+ struct CMailNumbers MN;
+
+ BOOL Loaded;
+ BOOL RunMailBrowser, RunPopups;
+
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ //now we ensure read access for account and write access for its mails
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ PostMessage(hDlg, WM_DESTROY, 0, 0);
+ return UPDATE_FAIL;
+ }
+
+ if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ PostMessage(hDlg, WM_DESTROY, 0, 0);
+ return UPDATE_FAIL;
+ }
+
+ memset(&MN, 0, sizeof(MN));
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next) {
+ if (!LoadedMailData(msgq)) //check if mail is already in memory
+ {
+ Loaded = false;
+ if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it
+ continue;
+ }
+ else
+ Loaded = true;
+
+ IncrementMailCounters(msgq, &MN);
+
+ if (!Loaded)
+ UnloadMailData(msgq); //do not keep data for mail in memory
+ }
+
+ if (mwui != nullptr)
+ mwui->UpdateMailsMessagesAccess = TRUE;
+
+ //Now we are going to check if extracting data from mail headers are needed.
+ //If popups will be displayed or mailbrowser window
+ if ((((mwui != nullptr) && !(mwui->RunFirstTime)) &&
+ (
+ ((nnflags & YAMN_ACC_MSGP) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) ||
+ ((nflags & YAMN_ACC_MSGP) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC))
+ )
+ ) || //if mail window was displayed before and flag YAMN_ACC_MSGP is set
+ ((nnflags & YAMN_ACC_MSG) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if needed to run mailbrowser when no unseen and no unseen mail found
+ ((nflags & YAMN_ACC_MSG) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if unseen mails found, we sure run mailbrowser
+ ((nflags & YAMN_ACC_ICO) && (MN.Real.SysTrayUC + MN.Virtual.SysTrayUC))
+ ) //if needed to run systray
+ RunMailBrowser = TRUE;
+ else
+ RunMailBrowser = FALSE;
+
+ // if some popups with mails are needed to show
+ if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (MN.Real.PopupNC + MN.Virtual.PopupNC))
+ RunPopups = TRUE;
+ else RunPopups = FALSE;
+
+ if (RunMailBrowser)
+ ChangeExistingMailStatus(GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount);
+ if (RunMailBrowser || RunPopups)
+ AddNewMailsToListView(hDlg == nullptr ? nullptr : GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount, nflags);
+
+ if (RunMailBrowser) {
+ size_t len = mir_strlen(ActualAccount->Name) + mir_strlen(Translate(MAILBROWSERTITLE)) + 10; //+10 chars for numbers
+ char *TitleStrA = new char[len];
+ wchar_t *TitleStrW = new wchar_t[len];
+
+ mir_snprintf(TitleStrA, len, Translate(MAILBROWSERTITLE), ActualAccount->Name, MN.Real.DisplayUC + MN.Virtual.DisplayUC, MN.Real.Display + MN.Virtual.Display);
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, TitleStrA, -1, TitleStrW, (int)mir_strlen(TitleStrA) + 1);
+ SetWindowTextW(hDlg, TitleStrW);
+ delete[] TitleStrA;
+ delete[] TitleStrW;
+ }
+
+ DoMailActions(hDlg, ActualAccount, &MN, nflags, nnflags);
+
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_NEW, 0, YAMN_MSG_NEW, YAMN_FLAG_REMOVE); //rempve the new flag
+ if (!RunMailBrowser)
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_UNSEEN, YAMN_MSG_STAYUNSEEN, YAMN_MSG_UNSEEN, YAMN_FLAG_REMOVE); //remove the unseen flag when it was not displayed and it has not "stay unseen" flag set
+
+ if (mwui != nullptr) {
+ mwui->UpdateMailsMessagesAccess = FALSE;
+ mwui->RunFirstTime = FALSE;
+ }
+
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ if (RunMailBrowser)
+ UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS));
+ else if (hDlg != nullptr)
+ DestroyWindow(hDlg);
+
+ return 1;
+}
+
+int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount)
+{
+ LVITEM item;
+ HYAMNMAIL mail, msgq;
+
+ int in = ListView_GetItemCount(hListView);
+ item.mask = LVIF_PARAM;
+
+ for (int i = 0; i < in; i++) {
+ item.iItem = i;
+ item.iSubItem = 0;
+ if (TRUE == ListView_GetItem(hListView, &item))
+ mail = (HYAMNMAIL)item.lParam;
+ else
+ continue;
+ for (msgq = (HYAMNMAIL)ActualAccount->Mails; (msgq != nullptr) && (msgq != mail); msgq = msgq->Next); //found the same mail in account queue
+ if (msgq == nullptr) //if mail was not found
+ if (TRUE == ListView_DeleteItem(hListView, i)) {
+ in--; i--;
+ continue;
+ }
+ }
+
+ return TRUE;
+}
+
+void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout);
+int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags)
+{
+ wchar_t *FromStr;
+ wchar_t SizeStr[20];
+ wchar_t LocalDateStr[128];
+
+ LVITEMW item;
+ LVFINDINFO fi;
+
+ int foundi = 0, lfoundi = 0;
+ struct CHeader UnicodeHeader;
+ BOOL Loaded, Extracted, FromStrNew = FALSE;
+
+ memset(&item, 0, sizeof(item));
+ memset(&UnicodeHeader, 0, sizeof(UnicodeHeader));
+
+ if (hListView != nullptr) {
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ item.iItem = 0;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = LVFI_PARAM; //let's go search item by lParam number
+ lfoundi = 0;
+ }
+
+ POPUPDATAW NewMailPopup = {};
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = nullptr; //it's new mail popup
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next, lfoundi++) {
+ // now we hide mail pointer to item's lParam member. We can later use it to retrieve mail datas
+
+ Extracted = FALSE; FromStr = nullptr; FromStrNew = FALSE;
+
+ if (hListView != nullptr) {
+ fi.lParam = (LPARAM)msgq;
+ if (-1 != (foundi = ListView_FindItem(hListView, -1, &fi))) { // if mail is already in window
+ lfoundi = foundi;
+ continue; // do not insert any item
+ }
+
+ item.iItem = lfoundi; // insert after last found item
+ item.lParam = (LPARAM)msgq;
+ }
+
+ if (!LoadedMailData(msgq)) { // check if mail is already in memory
+ Loaded = false;
+ if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it
+ continue;
+ }
+ else Loaded = true;
+
+ if (((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) ||
+ ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW))) {
+
+ if (!Extracted) ExtractHeader(msgq->MailData->TranslatedHeader, msgq->MailData->CP, &UnicodeHeader);
+ Extracted = TRUE;
+
+ if ((UnicodeHeader.From != nullptr) && (UnicodeHeader.FromNick != nullptr)) {
+ size_t size = mir_wstrlen(UnicodeHeader.From) + mir_wstrlen(UnicodeHeader.FromNick) + 4;
+ FromStr = new wchar_t[size];
+ mir_snwprintf(FromStr, size, L"%s <%s>", UnicodeHeader.FromNick, UnicodeHeader.From);
+ FromStrNew = TRUE;
+ }
+ else if (UnicodeHeader.From != nullptr)
+ FromStr = UnicodeHeader.From;
+ else if (UnicodeHeader.FromNick != nullptr)
+ FromStr = UnicodeHeader.FromNick;
+ else if (UnicodeHeader.ReturnPath != nullptr)
+ FromStr = UnicodeHeader.ReturnPath;
+
+ if (nullptr == FromStr) {
+ FromStr = L"";
+ FromStrNew = FALSE;
+ }
+ }
+
+ if ((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) {
+ item.iSubItem = 0;
+ item.pszText = FromStr;
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+
+ item.iSubItem = 1;
+ item.pszText = (nullptr != UnicodeHeader.Subject ? UnicodeHeader.Subject : (wchar_t *)L"");
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 2;
+ mir_snwprintf(SizeStr, L"%d kB", msgq->MailData->Size / 1024);
+ item.pszText = SizeStr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 3;
+ item.pszText = L"";
+
+ for (CMimeItem *heads = msgq->MailData->TranslatedHeader; heads != nullptr; heads = heads->Next) {
+ if (!_stricmp(heads->name, "Date")) {
+ MimeDateToLocalizedDateTime(heads->value, LocalDateStr, 128);
+ item.pszText = LocalDateStr;
+ break;
+ }
+ }
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+ }
+
+ if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW)) {
+ mir_wstrncpy(NewMailPopup.lpwzContactName, FromStr, _countof(NewMailPopup.lpwzContactName));
+ mir_wstrncpy(NewMailPopup.lpwzText, UnicodeHeader.Subject, _countof(NewMailPopup.lpwzText));
+
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM));
+ if (MailParam) {
+ MailParam->account = ActualAccount;
+ MailParam->mail = msgq;
+ MailParam->ThreadRunningEV = nullptr;
+ NewMailPopup.PluginData = MailParam;
+ PUAddPopupW(&NewMailPopup);
+ }
+ }
+
+ if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN))
+ CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, NULL);
+
+ if (FromStrNew)
+ delete[] FromStr;
+
+ if (Extracted) {
+ DeleteHeaderContent(&UnicodeHeader);
+ memset(&UnicodeHeader, 0, sizeof(UnicodeHeader));
+ }
+
+ if (!Loaded) {
+ SaveMailData(msgq);
+ UnloadMailData(msgq); //do not keep data for mail in memory
+ }
+ }
+
+ return TRUE;
+}
+
+void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags)
+{
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hDlg;
+
+ if (MN->Real.EventNC + MN->Virtual.EventNC)
+ NotifyEventHooks(hNewMailHook, 0, 0);
+
+ if ((nflags & YAMN_ACC_KBN) && (MN->Real.PopupRun + MN->Virtual.PopupRun))
+ CallService(MS_KBDNOTIFY_STARTBLINK, (WPARAM)MN->Real.PopupNC + MN->Virtual.PopupNC, NULL);
+
+ if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) {
+ wchar_t tszMsg[250];
+ mir_snwprintf(tszMsg, TranslateT("%s : %d new mail message(s), %d total"), _A2T(ActualAccount->Name).get(), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+
+ if (!(nflags & YAMN_ACC_CONTNOEVENT)) {
+ CLISTEVENT evt = {};
+ evt.flags = CLEF_UNICODE;
+ evt.hContact = ActualAccount->hContact;
+ evt.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ evt.hDbEvent = ActualAccount->hContact;
+ evt.lParam = ActualAccount->hContact;
+ evt.pszService = MS_YAMN_CLISTDBLCLICK;
+ evt.szTooltip.w = tszMsg;
+ g_clistApi.pfnAddEvent(&evt);
+ }
+ db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg);
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setWString(ActualAccount->hContact, "Nick", tszMsg);
+ }
+
+ if ((nflags & YAMN_ACC_POP) &&
+ !(ActualAccount->Flags & YAMN_ACC_POPN) &&
+ (MN->Real.PopupRun + MN->Virtual.PopupRun)) {
+ POPUPDATAW NewMailPopup;
+
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = (void *)nullptr; //multiple popups
+
+ mir_wstrncpy(NewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lpwzContactName));
+ mir_snwprintf(NewMailPopup.lpwzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ PUAddPopupW(&NewMailPopup);
+ }
+
+ // destroy tray icon if no new mail
+ if ((MN->Real.SysTrayUC + MN->Virtual.SysTrayUC == 0) && (hDlg != nullptr))
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+
+ // and remove the event
+ if ((nflags & YAMN_ACC_CONT) && (!(nflags & YAMN_ACC_CONTNOEVENT)) && (MN->Real.UnSeen + MN->Virtual.UnSeen == 0))
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, ActualAccount->hContact);
+
+ if ((MN->Real.BrowserUC + MN->Virtual.BrowserUC == 0) && (hDlg != nullptr)) {
+ if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG))
+ PostMessage(hDlg, WM_DESTROY, 0, 0); //destroy window if no new mail and window is not visible
+ if (nnflags & YAMN_ACC_MSG) //if no new mail and msg should be executed
+ {
+ SetForegroundWindow(hDlg);
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+ }
+ else
+ if (hDlg != nullptr) //else insert icon and set window if new mails
+ {
+ SendDlgItemMessageW(hDlg, IDC_LISTMAILS, LVM_SCROLL, 0, (LPARAM)0x7ffffff);
+
+ if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC + MN->Virtual.SysTrayUC)) {
+ nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S %s", ActualAccount->Name, TranslateT("- new mail message(s)"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+ }
+ if (nflags & YAMN_ACC_MSG) //if no new mail and msg should be executed
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+
+ if (MN->Real.AppNC + MN->Virtual.AppNC != 0) {
+ if (nflags & YAMN_ACC_APP) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+ }
+ }
+
+ if (MN->Real.SoundNC + MN->Virtual.SoundNC != 0)
+ if (nflags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_NEWMAILSOUND);
+
+ if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) {
+ POPUPDATAW NoNewMailPopup = {};
+
+ NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NoNewMailPopup.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP);
+ if (nflags & YAMN_ACC_POPC) {
+ NoNewMailPopup.colorBack = ActualAccount->NoNewMailN.PopupB;
+ NoNewMailPopup.colorText = ActualAccount->NoNewMailN.PopupT;
+ }
+ else {
+ NoNewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NoNewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NoNewMailPopup.iSeconds = ActualAccount->NoNewMailN.PopupTime;
+
+ NoNewMailPopup.PluginWindowProc = NoNewMailPopupProc;
+ NoNewMailPopup.PluginData = nullptr; //it's not new mail popup
+
+ mir_wstrncpy(NoNewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lpwzContactName));
+ if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC)
+ mir_snwprintf(NoNewMailPopup.lpwzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC);
+ else
+ mir_wstrncpy(NoNewMailPopup.lpwzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lpwzText));
+ PUAddPopupW(&NoNewMailPopup);
+ }
+
+ if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) {
+ if (ActualAccount->hContact != NULL) {
+ if (MN->Real.PopupTC + MN->Virtual.PopupTC) {
+ char tmp[255];
+ mir_snprintf(tmp, Translate("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ db_set_s(ActualAccount->hContact, "CList", "StatusMsg", tmp);
+ }
+ else db_set_s(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setString(ActualAccount->hContact, "Nick", ActualAccount->Name);
+ }
+ }
+ return;
+}
+
+LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR PluginParam = 0;
+ switch (msg) {
+ case WM_COMMAND:
+ // if clicked and it's new mail popup window
+ if ((HIWORD(wParam) == STN_CLICKED) && (-1 != (PluginParam = (INT_PTR)PUGetPluginData(hWnd)))) {
+ MCONTACT hContact = 0;
+ CAccount *Account;
+ if (PluginParam) {
+ PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM;
+ memcpy(MailParam, (PINT_PTR)PluginParam, sizeof(YAMN_MAILSHOWPARAM));
+ hContact = MailParam->account->hContact;
+ Account = MailParam->account;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ else {
+ DBVARIANT dbv;
+
+ hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ Account = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else Account = (CAccount *)hContact; //????
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(Account->AccountAccessSO)) {
+ switch (msg) {
+ case WM_COMMAND:
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, Account,
+ (Account->NewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG,
+ (Account->NoNewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG};
+
+ RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ break;
+ }
+ ReadDoneFcn(Account->AccountAccessSO);
+ }
+ }
+ if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT))
+ g_clistApi.pfnRemoveEvent(hContact, hContact);
+ }
+ __fallthrough;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+ case UM_FREEPLUGINDATA:
+ {
+ PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd);
+ if ((mpd) && (INT_PTR)mpd != -1)free(mpd);
+ return FALSE;
+ }
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ WindowList_Add(YAMNVar.MessageWnds, hWnd);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+ DestroyWindow(hWnd);
+ return 0;
+ }
+ case WM_NOTIFY:
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ if ((HIWORD(wParam) == STN_CLICKED) && (msg == WM_COMMAND)) {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ switch (msg) {
+ case WM_COMMAND:
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr};
+
+ Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nnflags = Param.nnflags & ~YAMN_ACC_POP;
+
+ Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nflags = Param.nflags & ~YAMN_ACC_POP;
+
+ RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ break;
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ PUDeletePopup(hWnd);
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ //Here we'd free our own data, if we had it.
+ return FALSE;
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ WindowList_Add(YAMNVar.MessageWnds, hWnd);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+
+ DestroyWindow(hWnd);
+ return 0;
+ }
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+#ifdef __GNUC__
+//number of 100 ns periods between FILETIME 0 (1601/01/01 00:00:00.0000000) and TIMESTAMP 0 (1970/01/01 00:00:00)
+#define NUM100NANOSEC 116444736000000000ULL
+//The biggest time Get[Date|Time]Format can handle (Fri, 31 Dec 30827 23:59:59.9999999)
+#define MAXFILETIME 0x7FFF35F4F06C7FFFULL
+#else
+#define NUM100NANOSEC 116444736000000000
+#define MAXFILETIME 0x7FFF35F4F06C7FFF
+#endif
+
+ULONGLONG MimeDateToFileTime(char *datein)
+{
+ char *day = nullptr, *month = nullptr, *year = nullptr, *time = nullptr, *shift = nullptr;
+ SYSTEMTIME st;
+ ULONGLONG res = 0;
+ int wShiftSeconds = TimeZone_ToLocal(0);
+ GetLocalTime(&st);
+ //datein = "Xxx, 1 Jan 2060 5:29:1 +0530 XXX";
+ //datein = "Xxx, 1 Jan 2060 05:29:10 ";
+ //datein = " ManySpaces 1.5 Jan 2060 05::";
+ //datein = "Xxx, 35 February 20 :29:10 ";
+ //datein = "01.12.2007 (22:38:17)"; //
+ if (datein) {
+ char tmp[64];
+ while (datein[0] == ' ') datein++; // eat leading spaces
+ strncpy(tmp, datein, 63); tmp[63] = 0;
+ if (atoi(tmp)) { // Parseable integer on DayOfWeek field? Buggy mime date.
+ day = tmp;
+ }
+ else {
+ int i = 0;
+ while (tmp[i] == ' ')i++; if (day = strchr(&tmp[i], ' ')) { day[0] = 0; day++; }
+ }
+ if (day) { while (day[0] == ' ') day++; if (month = strchr(day, ' ')) { month[0] = 0; month++; } }
+ if (month) { while (month[0] == ' ')month++; if (year = strchr(month, ' ')) { year[0] = 0; year++; } }
+ if (year) { while (year[0] == ' ') year++; if (time = strchr(year, ' ')) { time[0] = 0; time++; } }
+ if (time) { while (time[0] == ' ') time++; if (shift = strchr(time, ' ')) { shift[0] = 0; shift++; shift[5] = 0; } }
+
+ if (year) {
+ st.wYear = atoi(year);
+ if (mir_strlen(year) < 4) if (st.wYear < 70)st.wYear += 2000; else st.wYear += 1900;
+ };
+ if (month) for (int i = 0; i < 12; i++) if (strncmp(month, s_MonthNames[i], 3) == 0) { st.wMonth = i + 1; break; }
+ if (day) st.wDay = atoi(day);
+ if (time) {
+ char *h, *m, *s;
+ h = time;
+ if (m = strchr(h, ':')) {
+ m[0] = 0; m++;
+ if (s = strchr(m, ':')) { s[0] = 0; s++; }
+ }
+ else s = nullptr;
+ st.wHour = atoi(h);
+ st.wMinute = m ? atoi(m) : 0;
+ st.wSecond = s ? atoi(s) : 0;
+ }
+ else { st.wHour = st.wMinute = st.wSecond = 0; }
+
+ if (shift) {
+ if (mir_strlen(shift) < 4) {
+ //has only hour
+ wShiftSeconds = (atoi(shift)) * 3600;
+ }
+ else {
+ char *smin = shift + mir_strlen(shift) - 2;
+ int ismin = atoi(smin);
+ smin[0] = 0;
+ int ishour = atoi(shift);
+ wShiftSeconds = (ishour * 60 + (ishour < 0 ? -1 : 1) * ismin) * 60;
+ }
+ }
+ } // if (datein)
+ FILETIME ft;
+ if (SystemTimeToFileTime(&st, &ft)) {
+ res = ((ULONGLONG)ft.dwHighDateTime << 32) | ((ULONGLONG)ft.dwLowDateTime);
+ LONGLONG w100nano = Int32x32To64((uint32_t)wShiftSeconds, 10000000);
+ res -= w100nano;
+ }
+ else {
+ res = 0;
+ }
+ return res;
+}
+
+void FileTimeToLocalizedDateTime(LONGLONG filetime, wchar_t *dateout, int lendateout)
+{
+ int localeID = Langpack_GetDefaultLocale();
+ //int localeID = MAKELCID(LANG_URDU, SORT_DEFAULT);
+ if (localeID == CALLSERVICE_NOTFOUND) localeID = LOCALE_USER_DEFAULT;
+ if (filetime > MAXFILETIME) filetime = MAXFILETIME;
+ else if (filetime <= 0) {
+ wcsncpy(dateout, TranslateT("Invalid"), lendateout);
+ return;
+ }
+ SYSTEMTIME st;
+ uint16_t wTodayYear = 0, wTodayMonth = 0, wTodayDay = 0;
+ FILETIME ft;
+ BOOL willShowDate = !(optDateTime & SHOWDATENOTODAY);
+ if (!willShowDate) {
+ GetLocalTime(&st);
+ wTodayYear = st.wYear;
+ wTodayMonth = st.wMonth;
+ wTodayDay = st.wDay;
+ }
+ ft.dwLowDateTime = (uint32_t)filetime;
+ ft.dwHighDateTime = (uint32_t)(filetime >> 32);
+ FILETIME localft;
+ if (!FileTimeToLocalFileTime(&ft, &localft)) {
+ // this should never happen
+ wcsncpy(dateout, L"Incorrect FileTime", lendateout);
+ }
+ else {
+ if (!FileTimeToSystemTime(&localft, &st)) {
+ // this should never happen
+ wcsncpy(dateout, L"Incorrect LocalFileTime", lendateout);
+ }
+ else {
+ dateout[lendateout - 1] = 0;
+ int templen = 0;
+ if (!willShowDate) willShowDate = (wTodayYear != st.wYear) || (wTodayMonth != st.wMonth) || (wTodayDay != st.wDay);
+ if (willShowDate) {
+ templen = GetDateFormatW(localeID, (optDateTime & SHOWDATELONG) ? DATE_LONGDATE : DATE_SHORTDATE, &st, nullptr, dateout, lendateout - 2);
+ dateout[templen - 1] = ' ';
+ }
+ if (templen < (lendateout - 1)) {
+ GetTimeFormatW(localeID, (optDateTime & SHOWDATENOSECONDS) ? TIME_NOSECONDS : 0, &st, nullptr, &dateout[templen], lendateout - templen - 1);
+ }
+ }
+ }
+}
+
+void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout)
+{
+ ULONGLONG ft = MimeDateToFileTime(datein);
+ FileTimeToLocalizedDateTime(ft, dateout, lendateout);
+}
+
+int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ if (lParam1 == NULL || lParam2 == NULL)
+ return 0;
+
+ int nResult = 0;
+ char *str1;
+ char *str2;
+ HYAMNMAIL email1 = (HYAMNMAIL)lParam1;
+ HYAMNMAIL email2 = (HYAMNMAIL)lParam2;
+ struct CShortHeader Header1;
+ struct CShortHeader Header2;
+ memset(&Header1, 0, sizeof(Header1));
+ memset(&Header2, 0, sizeof(Header2));
+
+ try {
+ ExtractShortHeader(email1->MailData->TranslatedHeader, &Header1);
+ ExtractShortHeader(email2->MailData->TranslatedHeader, &Header2);
+
+ switch ((int)lParamSort) {
+ case 0: //From
+ if (Header1.FromNick == nullptr)
+ str1 = Header1.From;
+ else str1 = Header1.FromNick;
+
+ if (Header2.FromNick == nullptr)
+ str2 = Header2.From;
+ else str2 = Header2.FromNick;
+
+ nResult = mir_strcmp(str1, str2);
+
+ if (bFrom) nResult = -nResult;
+ break;
+ case 1: //Subject
+ if (Header1.Subject == nullptr)
+ str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr)
+ str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_strcmp(str1, str2);
+
+ if (bSub) nResult = -nResult;
+ break;
+ case 2: //Size
+ if (email1->MailData->Size == email2->MailData->Size) nResult = 0;
+ if (email1->MailData->Size > email2->MailData->Size) nResult = 1;
+ if (email1->MailData->Size < email2->MailData->Size) nResult = -1;
+
+ if (bSize) nResult = -nResult;
+ break;
+
+ case 3: //Date
+ {
+ ULONGLONG ts1 = 0, ts2 = 0;
+ ts1 = MimeDateToFileTime(Header1.Date);
+ ts2 = MimeDateToFileTime(Header2.Date);
+ if (ts1 > ts2) nResult = 1;
+ else if (ts1 < ts2) nResult = -1;
+ else nResult = 0;
+ }
+ if (bDate) nResult = -nResult;
+ break;
+
+ default:
+ if (Header1.Subject == nullptr) str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr) str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_strcmp(str1, str2);
+ break;
+ }
+ //MessageBox(NULL,str1,str2,0);
+ }
+ catch (...) {
+ }
+
+ //free mem
+ DeleteShortHeaderContent(&Header1);
+ DeleteShortHeaderContent(&Header2);
+ return nResult;
+
+}
+
+HCURSOR hCurSplitNS, hCurSplitWE;
+#define DM_SPLITTERMOVED (WM_USER+15)
+
+static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_NCHITTEST:
+ return HTCLIENT;
+
+ case WM_SETCURSOR:
+ SetCursor(hCurSplitNS);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ SetCapture(hwnd);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ if (GetCapture() == hwnd) {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, (short)HIWORD(GetMessagePos()) + rc.bottom / 2, (LPARAM)hwnd);
+ }
+ return 0;
+
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ return 0;
+ }
+ return mir_callNextSubclass(hwnd, SplitterSubclassProc, msg, wParam, lParam);
+}
+
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+INT_PTR CALLBACK DlgProcYAMNShowMessage(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam;
+ wchar_t *iHeaderW = nullptr;
+ wchar_t *iValueW = nullptr;
+ int StrLen;
+ HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_SPLITTER), SplitterSubclassProc);
+ SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)MailParam);
+ Window_SetIcon_IcoLib(hDlg, g_plugin.getIconHandle(IDI_NEWMAIL));
+
+ ListView_SetUnicodeFormat(hListView, TRUE);
+ ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT);
+
+ StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 0);
+ iHeaderW = new wchar_t[StrLen + 1];
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, iHeaderW, StrLen);
+
+ StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, nullptr, 0);
+ iValueW = new wchar_t[StrLen + 1];
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, iValueW, StrLen);
+
+ LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 130, iHeaderW, 0, 0};
+ LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 400, iValueW, 0, 0};
+ SendMessage(hListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendMessage(hListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ if (nullptr != iHeaderW)
+ delete[] iHeaderW;
+ if (nullptr != iValueW)
+ delete[] iValueW;
+
+ SendMessage(hDlg, WM_YAMN_CHANGECONTENT, 0, (LPARAM)MailParam);
+ MoveWindow(hDlg, HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, 0);
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+ break;
+
+ case WM_YAMN_CHANGECONTENT:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)
+ (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER));
+ HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY);
+ //do not redraw
+ SendMessage(hListView, WM_SETREDRAW, 0, 0);
+ ListView_DeleteAllItems(hListView);
+ struct CMimeItem *Header;
+ LVITEMW item;
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ wchar_t *From = nullptr, *Subj = nullptr;
+ char *contentType = nullptr, *transEncoding = nullptr, *body = nullptr; //should not be delete[]-ed
+ for (Header = MailParam->mail->MailData->TranslatedHeader; Header != nullptr; Header = Header->Next) {
+ wchar_t *str1 = nullptr;
+ wchar_t *str2 = nullptr;
+ wchar_t str_nul[2] = {0};
+ if (!body) if (!_stricmp(Header->name, "Body")) { body = Header->value; continue; }
+ if (!contentType) if (!_stricmp(Header->name, "Content-Type")) contentType = Header->value;
+ if (!transEncoding) if (!_stricmp(Header->name, "Content-Transfer-Encoding")) transEncoding = Header->value;
+ //ConvertCodedStringToUnicode(Header->name,&str1,MailParam->mail->MailData->CP,1);
+ {
+ int streamsize = MultiByteToWideChar(20127, 0, Header->name, -1, nullptr, 0);
+ str1 = (wchar_t *)malloc(sizeof(wchar_t) * (streamsize + 1));
+ MultiByteToWideChar(20127, 0, Header->name, -1, str1, streamsize);//US-ASCII
+ }
+ ConvertCodedStringToUnicode(Header->value, &str2, MailParam->mail->MailData->CP, 1);
+ if (!str2) { str2 = (wchar_t *)str_nul; }// the header value may be NULL
+ if (!From) if (!_stricmp(Header->name, "From")) {
+ From = new wchar_t[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(From, str2);
+ }
+ if (!Subj) if (!_stricmp(Header->name, "Subject")) {
+ Subj = new wchar_t[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(Subj, str2);
+ }
+ //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true;
+ int count = 0; wchar_t **split = nullptr;
+ int ofs = 0;
+ while (str2[ofs]) {
+ if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) ||
+ (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D))count++;
+ ofs++;
+ }
+ split = new wchar_t *[count + 1];
+ count = 0; ofs = 0;
+ split[0] = str2;
+ while (str2[ofs]) {
+ if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) ||
+ (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D)) {
+ if (str2[ofs - 1]) {
+ count++;
+ }
+ split[count] = (wchar_t *)(str2 + ofs + 1);
+ str2[ofs] = 0;
+ }
+ ofs++;
+ };
+
+ if (!_stricmp(Header->name, "From") || !_stricmp(Header->name, "To") || !_stricmp(Header->name, "Date") || !_stricmp(Header->name, "Subject"))
+ item.iItem = 0;
+ else
+ item.iItem = 999;
+ for (int i = 0; i <= count; i++) {
+ item.iSubItem = 0;
+ if (i == 0)
+ item.pszText = str1;
+ else {
+ item.iItem++;
+ item.pszText = nullptr;
+ }
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+ item.iSubItem = 1;
+ item.pszText = str2 ? split[i] : nullptr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+ }
+ delete[] split;
+
+ if (str1)
+ free(str1);
+ if (str2 != (wchar_t *)str_nul)
+ free(str2);
+ }
+ if (body) {
+ wchar_t *bodyDecoded = nullptr;
+ char *localBody = nullptr;
+ if (contentType) {
+ if (!_strnicmp(contentType, "text", 4)) {
+ if (transEncoding) {
+ if (!_stricmp(transEncoding, "base64")) {
+ int size = (int)mir_strlen(body) * 3 / 4 + 5;
+ localBody = new char[size + 1];
+ DecodeBase64(body, localBody, size);
+ }
+ else if (!_stricmp(transEncoding, "quoted-printable")) {
+ int size = (int)mir_strlen(body) + 2;
+ localBody = new char[size + 1];
+ DecodeQuotedPrintable(body, localBody, size, FALSE);
+ }
+ }
+ }
+ else if (!_strnicmp(contentType, "multipart/", 10)) {
+ char *bondary = nullptr;
+ if (nullptr != (bondary = ExtractFromContentType(contentType, "boundary="))) {
+ bodyDecoded = ParseMultipartBody(body, bondary);
+ delete[] bondary;
+ }
+ }
+ }
+ if (!bodyDecoded)ConvertStringToUnicode(localBody ? localBody : body, MailParam->mail->MailData->CP, &bodyDecoded);
+ SetWindowTextW(hEdit, bodyDecoded);
+ delete[] bodyDecoded;
+ if (localBody) delete[] localBody;
+ SetFocus(hEdit);
+ }
+ if (!(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)) {
+ MailParam->mail->Flags |= YAMN_MSG_BODYREQUESTED;
+ CallService(MS_YAMN_ACCOUNTCHECK, (WPARAM)MailParam->account, 0);
+ }
+ else {
+ if (MailParam->mail->Flags & YAMN_MSG_UNSEEN) {
+ MailParam->mail->Flags &= ~YAMN_MSG_UNSEEN; //mark the message as seen
+ HWND hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)MailParam->account);
+ if (hMailBrowser) {
+ struct CChangeContent Params = {MailParam->account->NewMailN.Flags | YAMN_ACC_MSGP, MailParam->account->NoNewMailN.Flags | YAMN_ACC_MSGP};
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)MailParam->account, (LPARAM)&Params);
+ }
+ else UpdateMails(nullptr, MailParam->account, MailParam->account->NewMailN.Flags, MailParam->account->NoNewMailN.Flags);
+ }
+ }
+ ShowWindow(GetDlgItem(hDlg, IDC_SPLITTER), (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE);
+ ShowWindow(hEdit, (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE);
+ wchar_t *title = nullptr;
+ size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4;
+ title = new wchar_t[size];
+ if (From && Subj)
+ mir_snwprintf(title, size, L"%s (%s)", Subj, From);
+ else if (From)
+ wcsncpy_s(title, size, From, _TRUNCATE);
+ else if (Subj)
+ wcsncpy_s(title, size, Subj, _TRUNCATE);
+ else
+ wcsncpy_s(title, size, L"none", _TRUNCATE);
+ if (Subj) delete[] Subj;
+ if (From) delete[] From;
+ SetWindowTextW(hDlg, title);
+ delete[] title;
+ // turn on redrawing
+ SendMessage(hListView, WM_SETREDRAW, 1, 0);
+ SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX);
+ } break;
+
+ case WM_YAMN_STOPACCOUNT:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)
+ (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER));
+
+ if (nullptr == MailParam)
+ break;
+ if ((CAccount *)wParam != MailParam->account)
+ break;
+
+ DestroyWindow(hDlg);
+ }
+ return 1;
+
+ case WM_CTLCOLORSTATIC:
+ // here should be check if this is our edittext control.
+ // but we have only one static control (for now);
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hDlg);
+ {
+ RECT coord;
+ if (GetWindowRect(hDlg, &coord)) {
+ HeadPosX = coord.left;
+ HeadSizeX = coord.right - coord.left;
+ HeadPosY = coord.top;
+ HeadSizeY = coord.bottom - coord.top;
+ }
+
+ PostQuitMessage(1);
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+
+ case WM_MOVE:
+ HeadPosX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ HeadPosY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ return 0;
+
+ case DM_SPLITTERMOVED:
+ if ((HWND)lParam == GetDlgItem(hDlg, IDC_SPLITTER)) {
+ POINT pt;
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hDlg, &pt);
+ HeadSplitPos = (pt.y * 1000) / HeadSizeY;//+rc.bottom-rc.top;
+ if (HeadSplitPos >= 1000) HeadSplitPos = 999;
+ else if (HeadSplitPos <= 0) HeadSplitPos = 1;
+ else SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX);
+ }
+ return 0;
+
+ case WM_SIZE:
+ if (wParam == SIZE_RESTORED) {
+ HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY);
+ BOOL isBodyShown = ((PYAMN_MAILSHOWPARAM)(GetWindowLongPtr(hDlg, DWLP_USER)))->mail->Flags & YAMN_MSG_BODYRECEIVED;
+ HeadSizeX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ HeadSizeY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ int localSplitPos = (HeadSplitPos * HeadSizeY) / 1000;
+ int localSizeX;
+ RECT coord;
+ MoveWindow(GetDlgItem(hDlg, IDC_SPLITTER), 5, localSplitPos, HeadSizeX - 10, 2, TRUE);
+ MoveWindow(hEdit, 5, localSplitPos + 6, HeadSizeX - 10, HeadSizeY - localSplitPos - 11, TRUE); //where to put text window while resizing
+ MoveWindow(hList, 5, 5, HeadSizeX - 10, (isBodyShown ? localSplitPos : HeadSizeY) - 10, TRUE); //where to put headers list window while resizing
+ //if (changeX) {
+ if (GetClientRect(hList, &coord)) {
+ localSizeX = coord.right - coord.left;
+ }
+ else localSizeX = HeadSizeX;
+ LONG iNameWidth = ListView_GetColumnWidth(hList, 0);
+ ListView_SetColumnWidth(hList, 1, (localSizeX <= iNameWidth) ? 0 : (localSizeX - iNameWidth));
+ //}
+ }
+ return 0;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTHEADERS) {
+ //MessageBox(0,"LISTHEADERS","Debug",0);
+ HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ if (pt.x == -1) pt.x = 0;
+ if (pt.y == -1) pt.y = 0;
+ if (int numRows = ListView_GetItemCount(hList)) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected"));
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t headname[64] = {0}, headvalue[256] = {0};
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, headname, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ size_t headnamelen = mir_wstrlen(headname);
+ if (headnamelen) sizeNeeded += 1 + headnamelen;
+ sizeNeeded += 3 + mir_wstrlen(headvalue);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t *)GlobalLock(hData);
+ int courPos = 0;
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, headname, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ if (mir_wstrlen(headname)) courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s:\t%s\r\n", headname, headvalue);
+ else courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"\t%s\r\n", headvalue);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+void __cdecl ShowEmailThread(void *Param)
+{
+ struct MailShowMsgWinParam MyParam = *(struct MailShowMsgWinParam *)Param;
+
+ SCIncFcn(MyParam.account->UsingThreads);
+
+ if (MyParam.mail->MsgWindow) {
+ //if (!BringWindowToTop(MyParam.mail->MsgWindow)) {
+ if (!SetForegroundWindow(MyParam.mail->MsgWindow)) {
+ SendMessage(MyParam.mail->MsgWindow, WM_DESTROY, 0, 0);
+ MyParam.mail->MsgWindow = nullptr;
+ goto CREADTEVIEWMESSAGEWINDOW;
+ }
+
+ if (IsIconic(MyParam.mail->MsgWindow))
+ OpenIcon(MyParam.mail->MsgWindow);
+ }
+ else {
+CREADTEVIEWMESSAGEWINDOW:
+ MyParam.mail->MsgWindow = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE), nullptr, DlgProcYAMNShowMessage, (LPARAM)&MyParam);
+ WindowList_Add(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (MyParam.mail->MsgWindow == nullptr || !IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ WindowList_Remove(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MyParam.mail->MsgWindow = nullptr;
+ }
+
+ SCDecFcn(MyParam.account->UsingThreads);
+ delete (struct MailShowMsgWinParam *)Param;
+}
+
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAccount *ActualAccount;
+ int Items;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct MailBrowserWinParam *MyParam = (struct MailBrowserWinParam *)lParam;
+
+ ListView_SetUnicodeFormat(GetDlgItem(hDlg, IDC_LISTMAILS), TRUE);
+ ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_LISTMAILS), LVS_EX_FULLROWSELECT);
+
+ ActualAccount = MyParam->account;
+ struct CMailWinUserInfo *mwui = new struct CMailWinUserInfo;
+ mwui->Account = ActualAccount;
+ mwui->TrayIconState = 0;
+ mwui->UpdateMailsMessagesAccess = FALSE;
+ mwui->Seen = FALSE;
+ mwui->RunFirstTime = TRUE;
+
+ SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)mwui);
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ DestroyWindow(hDlg);
+ return FALSE;
+ }
+
+ SetDlgItemText(hDlg, IDC_BTNAPP, TranslateT("Run application"));
+ SetDlgItemText(hDlg, IDC_BTNDEL, TranslateT("Delete selected"));
+ SetDlgItemText(hDlg, IDC_BTNCHECKALL, TranslateT("Select All"));
+ SetDlgItemText(hDlg, IDC_BTNOK, TranslateT("OK"));
+
+ LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, FromWidth, TranslateT("From"), 0, 0};
+ LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SubjectWidth, TranslateT("Subject"), 0, 0};
+ LVCOLUMN lvc2 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeWidth, TranslateT("Size"), 0, 0};
+ LVCOLUMN lvc3 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeDate, TranslateT("Date"), 0, 0};
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lvc2);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)3, (LPARAM)&lvc3);
+
+ if ((ActualAccount->NewMailN.App != nullptr) && (mir_wstrlen(ActualAccount->NewMailN.App)))
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), TRUE);
+ else
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), FALSE);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ WindowList_Add(YAMNVar.MessageWnds, hDlg);
+ WindowList_Add(YAMNVar.NewMailAccountWnd, hDlg, (UINT_PTR)ActualAccount);
+
+ {
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ }
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+
+ if (ActualAccount->hContact != NULL)
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, (LPARAM)"yamn new mail message");
+
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_LISTMAILS), ListViewSubclassProc);
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ RECT coord;
+ LVCOLUMN ColInfo;
+ HYAMNMAIL Parser;
+
+ Window_FreeIcon_IcoLib(hDlg);
+
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ ColInfo.mask = LVCF_WIDTH;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 0, &ColInfo))
+ FromWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 1, &ColInfo))
+ SubjectWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 2, &ColInfo))
+ SizeWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 3, &ColInfo))
+ SizeDate = ColInfo.cx;
+
+ if (!YAMNVar.Shutdown && GetWindowRect(hDlg, &coord)) //the YAMNVar.Shutdown testing is because M<iranda strange functionality at shutdown phase, when call to DBWriteContactSetting freezes calling thread
+ {
+ PosX = coord.left;
+ SizeX = coord.right - coord.left;
+ PosY = coord.top;
+ SizeY = coord.bottom - coord.top;
+ g_plugin.setDword(YAMN_DBPOSX, PosX);
+ g_plugin.setDword(YAMN_DBPOSY, PosY);
+ g_plugin.setDword(YAMN_DBSIZEX, SizeX);
+ g_plugin.setDword(YAMN_DBSIZEY, SizeY);
+ }
+ KillTimer(hDlg, TIMER_FLASHING);
+
+ WindowList_Remove(YAMNVar.NewMailAccountWnd, hDlg);
+ WindowList_Remove(YAMNVar.MessageWnds, hDlg);
+
+ if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO))
+ break;
+
+ //delete mails from queue, which are deleted from server (spam level 3 mails e.g.)
+ for (Parser = (HYAMNMAIL)ActualAccount->Mails; Parser != nullptr; Parser = Parser->Next) {
+ if ((Parser->Flags & YAMN_MSG_DELETED) && YAMN_MSG_SPAML(Parser->Flags, YAMN_MSG_SPAML3) && mwui->Seen) //if spaml3 was already deleted and user knows about it
+ {
+ DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, Parser, 1);
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)Parser);
+ }
+ }
+
+ //mark mails as read (remove "new" and "unseen" flags)
+ if (mwui->Seen)
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY, 0, YAMN_MSG_NEW | YAMN_MSG_UNSEEN, 0);
+
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+
+ NOTIFYICONDATA nid;
+ memset(&nid, 0, sizeof(NOTIFYICONDATA));
+
+ delete mwui;
+ SetWindowLongPtr(hDlg, DWLP_USER, NULL);
+
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ PostQuitMessage(0);
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ {
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ if (mwui == nullptr)
+ return 0;
+ mwui->Seen = TRUE;
+ }
+
+ case WM_YAMN_CHANGESTATUS:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ return 1;
+
+ case WM_YAMN_CHANGECONTENT:
+ {
+ struct CUpdateMails UpdateParams;
+ BOOL ThisThreadWindow = (GetCurrentThreadId() == GetWindowThreadProcessId(hDlg, nullptr));
+
+ if (nullptr == (UpdateParams.Copied = CreateEvent(nullptr, FALSE, FALSE, nullptr))) {
+ DestroyWindow(hDlg);
+ return 0;
+ }
+ UpdateParams.Flags = (struct CChangeContent *)lParam;
+ UpdateParams.Waiting = !ThisThreadWindow;
+
+ if (ThisThreadWindow) {
+ if (!UpdateMails(hDlg, (CAccount *)wParam, UpdateParams.Flags->nflags, UpdateParams.Flags->nnflags))
+ DestroyWindow(hDlg);
+ }
+ else if (PostMessage(hDlg, WM_YAMN_UPDATEMAILS, wParam, (LPARAM)&UpdateParams)) //this ensures UpdateMails will execute the thread who created the browser window
+ {
+ if (!ThisThreadWindow)
+ WaitForSingleObject(UpdateParams.Copied, INFINITE);
+ }
+
+ CloseHandle(UpdateParams.Copied);
+ }
+ return 1;
+ case WM_YAMN_UPDATEMAILS:
+ {
+ struct CUpdateMails *um = (struct CUpdateMails *)lParam;
+ uint32_t nflags, nnflags;
+
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ return 0;
+ if ((CAccount *)wParam != ActualAccount)
+ return 0;
+
+ nflags = um->Flags->nflags;
+ nnflags = um->Flags->nnflags;
+
+ if (um->Waiting)
+ SetEvent(um->Copied);
+
+ if (!UpdateMails(hDlg, ActualAccount, nflags, nnflags))
+ DestroyWindow(hDlg);
+ }
+ return 1;
+ case WM_YAMN_STOPACCOUNT:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+ PostQuitMessage(0);
+ return 1;
+
+ case WM_YAMN_NOTIFYICON:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ return 0;
+ }
+
+ if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) {
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ SetForegroundWindow(hDlg);
+ }
+ else DestroyWindow(hDlg);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ break;
+ }
+ break;
+
+ case WM_YAMN_SHOWSELECTED:
+ {
+ int iSelect = SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_GETNEXTITEM, -1, MAKELPARAM((UINT)LVNI_FOCUSED, 0)); // return item selected
+ if (iSelect != -1) {
+ LV_ITEMW item;
+
+ item.iItem = iSelect;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ item.stateMask = 0xFFFFFFFF;
+ ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item);
+ HYAMNMAIL ActualMail = (HYAMNMAIL)item.lParam;
+ if (nullptr != ActualMail) {
+ PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM;
+ MailParam->account = GetWindowAccount(hDlg);
+ MailParam->mail = ActualMail;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (LOWORD(wParam)) {
+ case IDC_BTNCHECKALL:
+ ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, 0, LVIS_SELECTED); // deselect all items
+ ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, LVIS_SELECTED, LVIS_SELECTED);
+ Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS));
+ ListView_RedrawItems(GetDlgItem(hDlg, IDC_LISTMAILS), 0, Items);
+ UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS));
+ SetFocus(GetDlgItem(hDlg, IDC_LISTMAILS));
+ break;
+
+ case IDC_BTNOK:
+ DestroyWindow(hDlg);
+ break;
+
+ case IDC_BTNAPP:
+ {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+
+ if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000))
+ DestroyWindow(hDlg);
+ }
+ break;
+
+ case IDC_BTNDEL:
+ {
+ HYAMNMAIL ActualMail;
+ uint32_t Total = 0;
+
+ // we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ break;
+
+ Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS));
+
+ LVITEM item;
+ item.stateMask = 0xFFFFFFFF;
+
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ for (int i = 0; i < Items; i++) {
+ item.iItem = i;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ item.stateMask = 0xFFFFFFFF;
+ ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item);
+ ActualMail = (HYAMNMAIL)item.lParam;
+ if (nullptr == ActualMail)
+ break;
+ if (item.state & LVIS_SELECTED) {
+ ActualMail->Flags |= YAMN_MSG_USERDELETE; //set to mail we are going to delete it
+ Total++;
+ }
+ }
+
+ // Enable write-access to mails
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+
+ if (Total) {
+ wchar_t DeleteMsg[1024];
+
+ mir_snwprintf(DeleteMsg, TranslateT("Do you really want to delete %d selected mails?"), Total);
+ if (IDOK == MessageBox(hDlg, DeleteMsg, TranslateT("Delete confirmation"), MB_OKCANCEL | MB_ICONWARNING)) {
+ struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, ThreadRunningEV, ActualAccount, nullptr};
+
+ // Find if there's mail marked to delete, which was deleted before
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ for (ActualMail = (HYAMNMAIL)ActualAccount->Mails; ActualMail != nullptr; ActualMail = ActualMail->Next) {
+ if ((ActualMail->Flags & YAMN_MSG_DELETED) && ((ActualMail->Flags & YAMN_MSG_USERDELETE))) //if selected mail was already deleted
+ {
+ DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, ActualMail, 1);
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)ActualMail); //delete it from memory
+ continue;
+ }
+ }
+ // Set flag to marked mails that they can be deleted
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_DELETEOK, 1);
+ // Create new thread which deletes marked mails.
+ HANDLE NewThread = mir_forkthread(ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr, &ParamToDeleteMails);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ // Enable write-access to mails
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+ }
+ }
+ else //else mark messages that they are not to be deleted
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_USERDELETE, 0);
+ }
+ }
+ CloseHandle(ThreadRunningEV);
+ if (g_plugin.getByte(YAMN_CLOSEDELETE, 0))
+ DestroyWindow(hDlg);
+ }
+ break;
+ }
+ break;
+
+ case WM_SIZE:
+ if (wParam == SIZE_RESTORED) {
+ LONG x = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ LONG y = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNDEL), 5, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put DELETE button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNCHECKALL), 10 + (x - 20) / 3, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put CHECK ALL button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNAPP), 15 + (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put RUN APP button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNOK), 20 + 2 * (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put OK button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_LISTMAILS), 5, 5, x - 10, y - 55, TRUE); //where to put list mail window while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_STSTATUS), 5, y - 5 - 45, x - 10, 15, TRUE); //where to put account status text while resizing
+ }
+ return 0;
+
+ case WM_GETMINMAXINFO:
+ ((LPMINMAXINFO)lParam)->ptMinTrackSize.x = MAILBROWSER_MINXSIZE;
+ ((LPMINMAXINFO)lParam)->ptMinTrackSize.y = MAILBROWSER_MINYSIZE;
+ return 0;
+
+ case WM_TIMER:
+ {
+ NOTIFYICONDATA nid;
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ nid.uFlags = NIF_ICON;
+ if (mwui->TrayIconState == 0)
+ nid.hIcon = g_plugin.getIcon(IDI_CHECKMAIL);
+ else
+ nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+ mwui->TrayIconState = !mwui->TrayIconState;
+ // UpdateWindow(hDlg);
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case IDC_LISTMAILS:
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_DBLCLK:
+ SendMessage(hDlg, WM_YAMN_SHOWSELECTED, 0, 0);
+ break;
+
+ case LVN_COLUMNCLICK:
+ if (nullptr != (ActualAccount = GetWindowAccount(hDlg))) {
+ NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)lParam;
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ switch ((int)pNMListView->iSubItem) {
+ case 0:
+ bFrom = !bFrom;
+ break;
+ case 1:
+ bSub = !bSub;
+ break;
+ case 2:
+ bSize = !bSize;
+ break;
+ case 3:
+ bDate = !bDate;
+ break;
+ default:
+ break;
+ }
+ ListView_SortItems(pNMListView->hdr.hwndFrom, ListViewCompareProc, pNMListView->iSubItem);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ break;
+
+ case NM_CUSTOMDRAW:
+ {
+ LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam;
+ LONG_PTR PaintCode;
+
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (cd->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ PaintCode = CDRF_NOTIFYITEMDRAW;
+ break;
+ case CDDS_ITEMPREPAINT:
+ PaintCode = CDRF_NOTIFYSUBITEMDRAW;
+ break;
+ case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
+ {
+ BOOL umma;
+ {
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ umma = mwui->UpdateMailsMessagesAccess;
+ }
+ HYAMNMAIL ActualMail = (HYAMNMAIL)cd->nmcd.lItemlParam;
+ if (!ActualMail)
+ ActualMail = (HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec);
+
+ if (!umma)
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->MessagesAccessSO))
+ return 0;
+
+ switch (ActualMail->Flags & YAMN_MSG_SPAMMASK) {
+ case YAMN_MSG_SPAML1:
+ case YAMN_MSG_SPAML2:
+ cd->clrText = RGB(150, 150, 150);
+ break;
+ case YAMN_MSG_SPAML3:
+ cd->clrText = RGB(200, 200, 200);
+ cd->clrTextBk = RGB(160, 160, 160);
+ break;
+ case 0:
+ if (cd->nmcd.dwItemSpec & 1)
+ cd->clrTextBk = RGB(230, 230, 230);
+ break;
+ default:
+ break;
+ }
+ if (ActualMail->Flags & YAMN_MSG_UNSEEN)
+ cd->clrTextBk = RGB(220, 235, 250);
+ PaintCode = CDRF_DODEFAULT;
+
+ if (!umma)
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+ break;
+ }
+ default:
+ PaintCode = 0;
+ }
+ SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PaintCode);
+ return 1;
+ }
+ }
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTMAILS) {
+ //MessageBox(0,"LISTHEADERS","Debug",0);
+ HWND hList = GetDlgItem(hDlg, IDC_LISTMAILS);
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ if (pt.x == -1) pt.x = 0;
+ if (pt.y == -1) pt.y = 0;
+ if (int numRows = ListView_GetItemCount(hList)) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected"));
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t from[128] = {0}, subject[256] = {0}, size[16] = {0}, date[64] = {0};
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, from, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ sizeNeeded += 5 + mir_wstrlen(from) + mir_wstrlen(subject) + mir_wstrlen(size) + mir_wstrlen(date);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t *)GlobalLock(hData);
+ int courPos = 0;
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, from, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s\t%s\t%s\t%s\r\n", from, subject, size, date);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hDlg);
+
+ switch (msg) {
+ case WM_GETDLGCODE:
+ {
+ LPMSG lpmsg = (LPMSG)lParam;
+ if (lpmsg != nullptr) {
+ if (lpmsg->message == WM_KEYDOWN
+ && lpmsg->wParam == VK_RETURN)
+ return DLGC_WANTALLKEYS;
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ {
+ BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000;
+ BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000;
+ BOOL isAlt = GetKeyState(VK_MENU) & 0x8000;
+
+ switch (wParam) {
+ case 'A': // ctrl-a
+ if (!isAlt && !isShift && isCtrl) SendMessage(hwndParent, WM_COMMAND, IDC_BTNCHECKALL, 0);
+ break;
+ case VK_RETURN:
+ case VK_SPACE:
+ if (!isAlt && !isShift && !isCtrl) SendMessage(hwndParent, WM_YAMN_SHOWSELECTED, 0, 0);
+ break;
+ case VK_DELETE:
+ SendMessage(hwndParent, WM_COMMAND, IDC_BTNDEL, 0);
+ break;
+ }
+ }
+ break;
+ }
+ return mir_callNextSubclass(hDlg, ListViewSubclassProc, msg, wParam, lParam);
+}
+
+void __cdecl MailBrowser(void *Param)
+{
+ MSG msg;
+
+ HWND hMailBrowser;
+ BOOL WndFound = FALSE;
+
+ struct MailBrowserWinParam MyParam = *(struct MailBrowserWinParam *)Param;
+ CAccount *ActualAccount = MyParam.account;
+ SCIncFcn(ActualAccount->UsingThreads);
+
+ // we will not use params in stack anymore
+ SetEvent(MyParam.ThreadRunningEV);
+
+ __try {
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ return;
+
+ if (!(ActualAccount->AbilityFlags & YAMN_ACC_BROWSE)) {
+ MyParam.nflags = MyParam.nflags & ~YAMN_ACC_MSG;
+ MyParam.nnflags = MyParam.nnflags & ~YAMN_ACC_MSG;
+ }
+
+ if (!(ActualAccount->AbilityFlags & YAMN_ACC_POPUP))
+ MyParam.nflags = MyParam.nflags & ~YAMN_ACC_POP;
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ if (nullptr != (hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)ActualAccount)))
+ WndFound = TRUE;
+
+ if ((hMailBrowser == nullptr) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) {
+ hMailBrowser = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES), nullptr, DlgProcYAMNMailBrowser, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hMailBrowser, g_plugin.getIconHandle(IDI_NEWMAIL));
+ MoveWindow(hMailBrowser, PosX, PosY, SizeX, SizeY, TRUE);
+ }
+
+ if (hMailBrowser != nullptr) {
+ struct CChangeContent Params = {MyParam.nflags, MyParam.nnflags}; //if this thread created window, just post message to update mails
+
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)ActualAccount, (LPARAM)&Params); //we ensure this will do the thread who created the browser window
+ }
+ else
+ UpdateMails(nullptr, ActualAccount, MyParam.nflags, MyParam.nnflags); //update mails without displaying or refreshing any window
+
+ if ((hMailBrowser != nullptr) && !WndFound) { //we process message loop only for thread that created window
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (hMailBrowser == nullptr || !IsDialogMessage(hMailBrowser, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ if ((!WndFound) && (ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork)
+ ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr();
+ }
+ __finally {
+ SCDecFcn(ActualAccount->UsingThreads);
+ }
+}
+
+INT_PTR RunMailBrowserSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_MAILBROWSERPARAM Param = (PYAMN_MAILBROWSERPARAM)wParam;
+
+ if ((uint32_t)lParam != YAMN_MAILBROWSERVERSION)
+ return 0;
+
+ //an event for successfull copy parameters to which point a pointer in stack for new thread
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ Param->ThreadRunningEV = ThreadRunningEV;
+
+ HANDLE NewThread = mir_forkthread(MailBrowser, Param);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ CloseHandle(ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/debug.cpp b/protocols/YAMN/src/debug.cpp index 1fc41adc19..65322366ab 100644 --- a/protocols/YAMN/src/debug.cpp +++ b/protocols/YAMN/src/debug.cpp @@ -1,111 +1,111 @@ -/* - * YAMN plugin main file - * Miranda homepage: http://miranda-icq.sourceforge.net/ - * - * Debug functions used in DEBUG release (you need to global #define DEBUG to get debug version) - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - -#ifdef _DEBUG - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -wchar_t DebugUserDirectory[MAX_PATH] = L"."; -CRITICAL_SECTION FileAccessCS; - -#ifdef DEBUG_COMM -wchar_t DebugCommFileName2[]=L"%s\\yamn-debug.comm.log"; -HANDLE CommFile; -#endif - -#ifdef DEBUG_DECODE -wchar_t DebugDecodeFileName2[]=L"%s\\yamn-debug.decode.log"; -HANDLE DecodeFile; -#endif - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void InitDebug() -{ -#if defined (DEBUG_COMM) || defined (DEBUG_DECODE) - wchar_t DebugFileName[MAX_PATH]; -#endif - InitializeCriticalSection(&FileAccessCS); - -#ifdef DEBUG_COMM - mir_snwprintf(DebugFileName, DebugCommFileName2, DebugUserDirectory); - - CommFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); - DebugLog(CommFile,"Communication debug file created by %s\n",YAMN_VER); -#endif - -#ifdef DEBUG_DECODE - mir_snwprintf(DebugFileName, DebugDecodeFileName2, DebugUserDirectory); - - DecodeFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); - DebugLog(DecodeFile,"Decoding kernel debug file created by %s\n",YAMN_VER); -#endif -} - -void UnInitDebug() -{ - DeleteCriticalSection(&FileAccessCS); -#ifdef DEBUG_COMM - DebugLog(CommFile,"File is being closed normally."); - CloseHandle(CommFile); -#endif -#ifdef DEBUG_DECODE - DebugLog(DecodeFile,"File is being closed normally."); - CloseHandle(DecodeFile); -#endif -} - - -void DebugLog(HANDLE File,const char *fmt,...) -{ - char *str; - char tids[32]; - va_list vararg; - int strsize; - DWORD Written; - - va_start(vararg,fmt); - str=(char *)malloc(strsize=65536); - mir_snprintf(tids, "[%x]",GetCurrentThreadId()); - while(mir_vsnprintf(str, strsize, fmt, vararg)==-1) - str=(char *)realloc(str,strsize+=65536); - va_end(vararg); - EnterCriticalSection(&FileAccessCS); - WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr); - WriteFile(File,str,(uint32_t)mir_strlen(str),&Written,nullptr); - LeaveCriticalSection(&FileAccessCS); - free(str); -} - -void DebugLogW(HANDLE File,const wchar_t *fmt,...) -{ - wchar_t *str; - char tids[32]; - va_list vararg; - int strsize; - DWORD Written; - - va_start(vararg,fmt); - str=(wchar_t *)malloc((strsize=65536)*sizeof(wchar_t)); - mir_snprintf(tids, "[%x]",GetCurrentThreadId()); - while(mir_vsnwprintf(str, strsize, fmt, vararg)==-1) - str=(wchar_t *)realloc(str,(strsize+=65536)*sizeof(wchar_t)); - va_end(vararg); - EnterCriticalSection(&FileAccessCS); - WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr); - WriteFile(File,str,(uint32_t)mir_wstrlen(str)*sizeof(wchar_t),&Written,nullptr); - LeaveCriticalSection(&FileAccessCS); - free(str); -} - +/*
+ * YAMN plugin main file
+ * Miranda homepage: http://miranda-icq.sourceforge.net/
+ *
+ * Debug functions used in DEBUG release (you need to global #define DEBUG to get debug version)
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+#ifdef _DEBUG
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+wchar_t DebugUserDirectory[MAX_PATH] = L".";
+CRITICAL_SECTION FileAccessCS;
+
+#ifdef DEBUG_COMM
+wchar_t DebugCommFileName2[]=L"%s\\yamn-debug.comm.log";
+HANDLE CommFile;
+#endif
+
+#ifdef DEBUG_DECODE
+wchar_t DebugDecodeFileName2[]=L"%s\\yamn-debug.decode.log";
+HANDLE DecodeFile;
+#endif
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void InitDebug()
+{
+#if defined (DEBUG_COMM) || defined (DEBUG_DECODE)
+ wchar_t DebugFileName[MAX_PATH];
+#endif
+ InitializeCriticalSection(&FileAccessCS);
+
+#ifdef DEBUG_COMM
+ mir_snwprintf(DebugFileName, DebugCommFileName2, DebugUserDirectory);
+
+ CommFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
+ DebugLog(CommFile,"Communication debug file created by %s\n",YAMN_VER);
+#endif
+
+#ifdef DEBUG_DECODE
+ mir_snwprintf(DebugFileName, DebugDecodeFileName2, DebugUserDirectory);
+
+ DecodeFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
+ DebugLog(DecodeFile,"Decoding kernel debug file created by %s\n",YAMN_VER);
+#endif
+}
+
+void UnInitDebug()
+{
+ DeleteCriticalSection(&FileAccessCS);
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"File is being closed normally.");
+ CloseHandle(CommFile);
+#endif
+#ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"File is being closed normally.");
+ CloseHandle(DecodeFile);
+#endif
+}
+
+
+void DebugLog(HANDLE File,const char *fmt,...)
+{
+ char *str;
+ char tids[32];
+ va_list vararg;
+ int strsize;
+ DWORD Written;
+
+ va_start(vararg,fmt);
+ str=(char *)malloc(strsize=65536);
+ mir_snprintf(tids, "[%x]",GetCurrentThreadId());
+ while(mir_vsnprintf(str, strsize, fmt, vararg)==-1)
+ str=(char *)realloc(str,strsize+=65536);
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(uint32_t)mir_strlen(str),&Written,nullptr);
+ LeaveCriticalSection(&FileAccessCS);
+ free(str);
+}
+
+void DebugLogW(HANDLE File,const wchar_t *fmt,...)
+{
+ wchar_t *str;
+ char tids[32];
+ va_list vararg;
+ int strsize;
+ DWORD Written;
+
+ va_start(vararg,fmt);
+ str=(wchar_t *)malloc((strsize=65536)*sizeof(wchar_t));
+ mir_snprintf(tids, "[%x]",GetCurrentThreadId());
+ while(mir_vsnwprintf(str, strsize, fmt, vararg)==-1)
+ str=(wchar_t *)realloc(str,(strsize+=65536)*sizeof(wchar_t));
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(uint32_t)mir_wstrlen(str)*sizeof(wchar_t),&Written,nullptr);
+ LeaveCriticalSection(&FileAccessCS);
+ free(str);
+}
+
#endif //ifdef DEBUG
\ No newline at end of file diff --git a/protocols/YAMN/src/debug.h b/protocols/YAMN/src/debug.h index a13ac952b0..e2e8e3e506 100644 --- a/protocols/YAMN/src/debug.h +++ b/protocols/YAMN/src/debug.h @@ -1,50 +1,50 @@ -#ifndef __DEBUG_H -#define __DEBUG_H - -#ifdef _DEBUG - -//#define DEBUG_COMM //debug communiation to a file -//#define DEBUG_DECODE //debug header decoding to a file -//#define DEBUG_DECODECODEPAGE //add info about codepage used in conversion -//#define DEBUG_DECODEBASE64 //add info about base64 result -//#define DEBUG_DECODEQUOTED //add info about quoted printable result -//#define DEBUG_FILEREAD //debug file reading to message boxes -//#define DEBUG_FILEREADMESSAGES //debug file reading messages to message boxes - -void DebugLog(HANDLE,const char *fmt,...); -void DebugLogW(HANDLE File,const wchar_t *fmt,...); - -#ifdef DEBUG_SYNCHRO -// Used for synchronization debug -extern HANDLE SynchroFile; -#endif - -#ifdef DEBUG_COMM -// Used for communication debug -extern HANDLE CommFile; -#endif - -#ifdef DEBUG_DECODE -// Used for decoding debug -extern HANDLE DecodeFile; -#endif - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); - -uint32_t ReadStringFromMemoryW(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString); - -#else -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo); - -uint32_t ReadStringFromMemoryW(wchar_t **Parser,wchar_t *End,wchar_t **StoreTo); - -#endif - -//#ifdef DEBUG_ACCOUNTS -//int GetAccounts(); -//void WriteAccounts(); -//#endif - -#endif //YAMN_DEBUG -#endif //_DEBUG_H +#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#ifdef _DEBUG
+
+//#define DEBUG_COMM //debug communiation to a file
+//#define DEBUG_DECODE //debug header decoding to a file
+//#define DEBUG_DECODECODEPAGE //add info about codepage used in conversion
+//#define DEBUG_DECODEBASE64 //add info about base64 result
+//#define DEBUG_DECODEQUOTED //add info about quoted printable result
+//#define DEBUG_FILEREAD //debug file reading to message boxes
+//#define DEBUG_FILEREADMESSAGES //debug file reading messages to message boxes
+
+void DebugLog(HANDLE,const char *fmt,...);
+void DebugLogW(HANDLE File,const wchar_t *fmt,...);
+
+#ifdef DEBUG_SYNCHRO
+// Used for synchronization debug
+extern HANDLE SynchroFile;
+#endif
+
+#ifdef DEBUG_COMM
+// Used for communication debug
+extern HANDLE CommFile;
+#endif
+
+#ifdef DEBUG_DECODE
+// Used for decoding debug
+extern HANDLE DecodeFile;
+#endif
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString);
+
+uint32_t ReadStringFromMemoryW(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString);
+
+#else
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo);
+
+uint32_t ReadStringFromMemoryW(wchar_t **Parser,wchar_t *End,wchar_t **StoreTo);
+
+#endif
+
+//#ifdef DEBUG_ACCOUNTS
+//int GetAccounts();
+//void WriteAccounts();
+//#endif
+
+#endif //YAMN_DEBUG
+#endif //_DEBUG_H
diff --git a/protocols/YAMN/src/filterplugin.cpp b/protocols/YAMN/src/filterplugin.cpp index 1d55f3a9c1..451ea155aa 100644 --- a/protocols/YAMN/src/filterplugin.cpp +++ b/protocols/YAMN/src/filterplugin.cpp @@ -1,169 +1,169 @@ -/* - * YAMN plugin export functions for filtering - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------------------------- - -PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin = nullptr; - -INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM); - -//Removes plugin from queue and deletes its structures -INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin); - -INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM lParam); - -//Removes all filter plugins -INT_PTR UnregisterFilterPlugins(); - -INT_PTR FilterMailSvc(WPARAM, LPARAM); - -//Sets imported functions for an plugin and therefore it starts plugin to be registered and running -// Plugin- plugin, which wants to set its functions -// Importance- importance of plugin (see m_filterplugin.h) -// YAMNFilterFcn- pointer to imported functions -// YAMNfilterFcnVer- version of YAMN_FILTERIMPORTFCN, use YAMN_FILTERIMPORTFCNVERSION -// returns nonzero if success -int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer); - -struct CExportedFunctions FilterPluginExportedFcn[] = -{ - {YAMN_SETFILTERPLUGINFCNIMPORTID, (void *)SetFilterPluginFcnImportFcn}, -}; - -struct CExportedServices FilterPluginExportedSvc[] = -{ - {MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc}, - {MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR RegisterFilterPluginSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_FILTERREGISTRATION Registration = (PYAMN_FILTERREGISTRATION)wParam; - HYAMNFILTERPLUGIN Plugin; - - if (lParam != YAMN_FILTERREGISTRATIONVERSION) - return 0; - if ((Registration->Name == nullptr) || (Registration->Ver == nullptr)) - return NULL; - if (nullptr == (Plugin = new YAMN_FILTERPLUGIN)) - return NULL; - - Plugin->PluginInfo = Registration; - Plugin->FilterFcn = nullptr; - return (INT_PTR)Plugin; -} - -INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin) -{ - PYAMN_FILTERPLUGINQUEUE Parser, Found; - - if (FirstFilterPlugin->Plugin == Plugin) { - Found = FirstFilterPlugin; - FirstFilterPlugin = FirstFilterPlugin->Next; - } - else { - for (Parser = FirstFilterPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next); - if (Parser->Next != nullptr) { - Found = Parser->Next; - Parser->Next = Parser->Next->Next; - } - else - Found = nullptr; - } - if (Found != nullptr) { - if (Plugin->FilterFcn->UnLoadFcn != nullptr) - Plugin->FilterFcn->UnLoadFcn((void *)nullptr); - - delete Found->Plugin; - delete Found; - return 1; - } - - return 0; -} - -INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM) -{ - HYAMNFILTERPLUGIN Plugin = (HYAMNFILTERPLUGIN)wParam; - - mir_cslock lck(PluginRegCS); - UnregisterFilterPlugin(Plugin); - return 1; -} - -INT_PTR UnregisterFilterPlugins() -{ - mir_cslock lck(PluginRegCS); - - // We remove protocols from the protocol list - while (FirstFilterPlugin != nullptr) - UnregisterFilterPlugin(FirstFilterPlugin->Plugin); - return 1; -} - -int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer) -{ - PYAMN_FILTERPLUGINQUEUE Parser, Previous; - - if (YAMNFilterFcnVer != YAMN_FILTERIMPORTFCNVERSION) - return 0; - if (YAMNFilterFcn == nullptr) - return 0; - - Plugin->Importance = Importance; - Plugin->FilterFcn = YAMNFilterFcn; - - mir_cslock lck(PluginRegCS); - - // We add protocol to the protocol list - for (Previous = nullptr, Parser = FirstFilterPlugin; Parser != nullptr && Parser->Next != nullptr && Parser->Plugin->Importance <= Importance; Previous = Parser, Parser = Parser->Next); - - if (Previous == nullptr) { //insert to the beginnig of queue - FirstFilterPlugin = new YAMN_FILTERPLUGINQUEUE; - FirstFilterPlugin->Plugin = Plugin; - FirstFilterPlugin->Next = Parser; - } - else { - Previous->Next = new YAMN_FILTERPLUGINQUEUE; - Previous = Previous->Next; //leave previous, go to actual plugin - Previous->Plugin = Plugin; - Previous->Next = Parser; //and in actual plugin set, that next plugin is the one we insert in front of - } - return 1; -} - -INT_PTR FilterMailSvc(WPARAM wParam, LPARAM lParam) -{ - CAccount *Account = (CAccount *)wParam; - HYAMNMAIL Mail = (HYAMNMAIL)lParam; - PYAMN_FILTERPLUGINQUEUE ActualPlugin; - - mir_cslock lck(PluginRegCS); - WaitToWriteFcn(Account->MessagesAccessSO); - - for (ActualPlugin = FirstFilterPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) - if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr != nullptr) - ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr(Account, YAMN_ACCOUNTVERSION, Mail, YAMN_MAILVERSION); - - Mail->Flags |= YAMN_MSG_FILTERED; - - //Set mail flags according to spamlevel settings - if ((Mail->Flags & YAMN_MSG_SPAMMASK) > YAMN_MSG_SPAML1) - Mail->Flags = Mail->Flags & ~(YAMN_MSG_BROWSER | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT); - if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3) || YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML4)) - Mail->Flags = Mail->Flags | (YAMN_MSG_AUTODELETE | YAMN_MSG_DELETEOK); //set message to delete - if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3)) - Mail->Flags = Mail->Flags & ~(YAMN_MSG_MEMDELETE); //set message not to delete it immidiatelly from memory - - WriteDoneFcn(Account->MessagesAccessSO); - return 1; -} +/*
+ * YAMN plugin export functions for filtering
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+ //--------------------------------------------------------------------------------------------------
+
+PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin = nullptr;
+
+INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM);
+
+//Removes plugin from queue and deletes its structures
+INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin);
+
+INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM lParam);
+
+//Removes all filter plugins
+INT_PTR UnregisterFilterPlugins();
+
+INT_PTR FilterMailSvc(WPARAM, LPARAM);
+
+//Sets imported functions for an plugin and therefore it starts plugin to be registered and running
+// Plugin- plugin, which wants to set its functions
+// Importance- importance of plugin (see m_filterplugin.h)
+// YAMNFilterFcn- pointer to imported functions
+// YAMNfilterFcnVer- version of YAMN_FILTERIMPORTFCN, use YAMN_FILTERIMPORTFCNVERSION
+// returns nonzero if success
+int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer);
+
+struct CExportedFunctions FilterPluginExportedFcn[] =
+{
+ {YAMN_SETFILTERPLUGINFCNIMPORTID, (void *)SetFilterPluginFcnImportFcn},
+};
+
+struct CExportedServices FilterPluginExportedSvc[] =
+{
+ {MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc},
+ {MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR RegisterFilterPluginSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_FILTERREGISTRATION Registration = (PYAMN_FILTERREGISTRATION)wParam;
+ HYAMNFILTERPLUGIN Plugin;
+
+ if (lParam != YAMN_FILTERREGISTRATIONVERSION)
+ return 0;
+ if ((Registration->Name == nullptr) || (Registration->Ver == nullptr))
+ return NULL;
+ if (nullptr == (Plugin = new YAMN_FILTERPLUGIN))
+ return NULL;
+
+ Plugin->PluginInfo = Registration;
+ Plugin->FilterFcn = nullptr;
+ return (INT_PTR)Plugin;
+}
+
+INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin)
+{
+ PYAMN_FILTERPLUGINQUEUE Parser, Found;
+
+ if (FirstFilterPlugin->Plugin == Plugin) {
+ Found = FirstFilterPlugin;
+ FirstFilterPlugin = FirstFilterPlugin->Next;
+ }
+ else {
+ for (Parser = FirstFilterPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next);
+ if (Parser->Next != nullptr) {
+ Found = Parser->Next;
+ Parser->Next = Parser->Next->Next;
+ }
+ else
+ Found = nullptr;
+ }
+ if (Found != nullptr) {
+ if (Plugin->FilterFcn->UnLoadFcn != nullptr)
+ Plugin->FilterFcn->UnLoadFcn((void *)nullptr);
+
+ delete Found->Plugin;
+ delete Found;
+ return 1;
+ }
+
+ return 0;
+}
+
+INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM)
+{
+ HYAMNFILTERPLUGIN Plugin = (HYAMNFILTERPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterFilterPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterFilterPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+
+ // We remove protocols from the protocol list
+ while (FirstFilterPlugin != nullptr)
+ UnregisterFilterPlugin(FirstFilterPlugin->Plugin);
+ return 1;
+}
+
+int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer)
+{
+ PYAMN_FILTERPLUGINQUEUE Parser, Previous;
+
+ if (YAMNFilterFcnVer != YAMN_FILTERIMPORTFCNVERSION)
+ return 0;
+ if (YAMNFilterFcn == nullptr)
+ return 0;
+
+ Plugin->Importance = Importance;
+ Plugin->FilterFcn = YAMNFilterFcn;
+
+ mir_cslock lck(PluginRegCS);
+
+ // We add protocol to the protocol list
+ for (Previous = nullptr, Parser = FirstFilterPlugin; Parser != nullptr && Parser->Next != nullptr && Parser->Plugin->Importance <= Importance; Previous = Parser, Parser = Parser->Next);
+
+ if (Previous == nullptr) { //insert to the beginnig of queue
+ FirstFilterPlugin = new YAMN_FILTERPLUGINQUEUE;
+ FirstFilterPlugin->Plugin = Plugin;
+ FirstFilterPlugin->Next = Parser;
+ }
+ else {
+ Previous->Next = new YAMN_FILTERPLUGINQUEUE;
+ Previous = Previous->Next; //leave previous, go to actual plugin
+ Previous->Plugin = Plugin;
+ Previous->Next = Parser; //and in actual plugin set, that next plugin is the one we insert in front of
+ }
+ return 1;
+}
+
+INT_PTR FilterMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ CAccount *Account = (CAccount *)wParam;
+ HYAMNMAIL Mail = (HYAMNMAIL)lParam;
+ PYAMN_FILTERPLUGINQUEUE ActualPlugin;
+
+ mir_cslock lck(PluginRegCS);
+ WaitToWriteFcn(Account->MessagesAccessSO);
+
+ for (ActualPlugin = FirstFilterPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next)
+ if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr != nullptr)
+ ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr(Account, YAMN_ACCOUNTVERSION, Mail, YAMN_MAILVERSION);
+
+ Mail->Flags |= YAMN_MSG_FILTERED;
+
+ //Set mail flags according to spamlevel settings
+ if ((Mail->Flags & YAMN_MSG_SPAMMASK) > YAMN_MSG_SPAML1)
+ Mail->Flags = Mail->Flags & ~(YAMN_MSG_BROWSER | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT);
+ if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3) || YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML4))
+ Mail->Flags = Mail->Flags | (YAMN_MSG_AUTODELETE | YAMN_MSG_DELETEOK); //set message to delete
+ if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3))
+ Mail->Flags = Mail->Flags & ~(YAMN_MSG_MEMDELETE); //set message not to delete it immidiatelly from memory
+
+ WriteDoneFcn(Account->MessagesAccessSO);
+ return 1;
+}
diff --git a/protocols/YAMN/src/mails/decode.cpp b/protocols/YAMN/src/mails/decode.cpp index 414edfce60..7306376c2e 100644 --- a/protocols/YAMN/src/mails/decode.cpp +++ b/protocols/YAMN/src/mails/decode.cpp @@ -1,534 +1,534 @@ -/* - * This code implements decoding encoded MIME header in style - * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?= - * - * (c) majvan 2002-2004 - */ -#include "../stdafx.h" -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -struct _tcptable CodePageNamesAll[]= -{ - { "ANSI", "",TRUE,CP_ACP}, - { "WINDOWS-1", "250",0,1250}, - { "WINDOWS-1", "251",0,1251}, - { "WINDOWS-1", "252",0,1252}, - { "WINDOWS-1", "253",0,1253}, - { "WINDOWS-1", "254",0,1254}, - { "WINDOWS-1", "255",0,1255}, - { "WINDOWS-1", "256",0,1256}, - { "WINDOWS-1", "257",0,1257}, - { "WINDOWS-1", "258",0,1258}, - { "CP1", "250",0,1250}, - { "CP1", "251",0,1251}, - { "CP1", "252",0,1252}, - { "CP1", "253",0,1253}, - { "CP1", "254",0,1254}, - { "CP1", "255",0,1255}, - { "CP1", "256",0,1256}, - { "CP1", "257",0,1257}, - { "CP1", "258",0,1258}, - { "ANSI-1", "250",0,1250}, - { "ANSI-1", "251",0,1251}, - { "ANSI-1", "252",0,1252}, - { "ANSI-1", "253",0,1253}, - { "ANSI-1", "254",0,1254}, - { "ANSI-1", "255",0,1255}, - { "ANSI-1", "256",0,1256}, - { "ANSI-1", "257",0,1257}, - { "ANSI-1", "258",0,1258}, - { "KOI8", "-R",0,20866}, - { "KOI8", "",0,20866}, - { "KOI8", "-U",0,21866}, - { "KOI8", "-RU",0,21866}, - { "US-", "ASCII",0,20127}, - { "CP", "367",0,20127}, - { "ASCII", "",0,20127}, - { "ASCII", "7",0,20127}, - { "ISO-8859", "-1",0,28591}, - { "ISO-8859", "-2",0,28592}, - { "ISO-8859", "-3",0,28593}, - { "ISO-8859", "-4",0,28594}, - { "ISO-8859", "-5",0,28595}, - { "ISO-8859", "-6",0,28596}, - { "ISO-8859", "-7",0,28597}, - { "ISO-8859", "-8",0,28598}, - { "ISO-8859", "-9",0,28599}, - { "ISO-8859", "-15",0,28605}, - { "ISO_8859", "-1",0,28591}, - { "ISO_8859", "-2",0,28592}, - { "ISO_8859", "-3",0,28593}, - { "ISO_8859", "-4",0,28594}, - { "ISO_8859", "-5",0,28595}, - { "ISO_8859", "-6",0,28596}, - { "ISO_8859", "-7",0,28597}, - { "ISO_8859", "-8",0,28598}, - { "ISO_8859", "-9",0,28599}, - { "ISO_8859", "-15",0,28605}, - { "ISO-", "10646-USC2",0,1200}, - { "ISO-2022", "/2-JP",0,50220}, - { "ISO-2022", "-JP",0,50221}, - { "ISO-2022", "/JIS-JP",0,50222}, - { "ISO-2022", "-KR",0,50225}, - { "ISO-2022", "-CH(SP)",0,50227}, - { "ISO-2022", "-CH(TR)",0,50229}, - { "UTF-", "7",0,65000}, - { "UTF-", "8",0,65001}, - { "ARAB-", "TRANSPARENT",0,710}, - { "ASMO-", "TRANSPARENT",0,720}, - { "ASMO-", "449",0,709}, - { "ASMO-", "708",0,708}, - { "BIG5", "",0,950}, - { "EUC-", "CH(SP)",0,51936}, - { "EUC-", "CH(TR)",0,51950}, - { "EUC-", "JP",0,51932}, - { "EUC-", "KR",0,51949}, - { "GB-", "2312",0,20936}, - { "GB", "2312",0,20936}, - { "HZGB-", "2312",0,52936}, - { "IBM-", "037",0,37}, - { "IBM-", "290",0,290}, - { "IBM-", "437",0,437}, - { "IBM-", "500",0,500}, - { "IBM-", "775",0,775}, - { "IBM-", "850",0,850}, - { "IBM-", "852",0,852}, - { "IBM-", "855",0,855}, - { "IBM-", "857",0,857}, - { "IBM-", "860",0,860}, - { "IBM-", "861",0,861}, - { "IBM-", "862",0,862}, - { "IBM-", "863",0,863}, - { "IBM-", "864",0,864}, - { "IBM-", "865",0,865}, - { "IBM-", "866",0,866}, - { "IBM-", "869",0,869}, - { "IBM-", "870",0,870}, - { "IBM-", "875",0,875}, - { "IBM-", "1026",0,1026}, - { "IBM-", "273",0,20273}, - { "IBM-", "277",0,20277}, - { "IBM-", "278",0,20278}, - { "IBM-", "280",0,20280}, - { "IBM-", "284",0,20284}, - { "IBM-", "285",0,20285}, - { "IBM-", "290",0,20290}, - { "IBM-", "297",0,20297}, - { "IBM-", "420",0,20420}, - { "IBM-", "423",0,20423}, - { "IBM-", "871",0,20871}, - { "IBM-", "880",0,20880}, - { "IBM-", "905",0,20905}, - { "IBM-", "THAI",0,20838}, - { "ISCII-", "DEVANAGARI",0,57002}, - { "ISCII-", "BENGALI",0,57003}, - { "ISCII-", "TAMIL",0,57004}, - { "ISCII-", "TELUGU",0,57005}, - { "ISCII-", "ASSAMESE",0,57006}, - { "ISCII-", "ORIYA",0,57007}, - { "ISCII-", "KANNADA",0,57008}, - { "ISCII-", "MALAYALAM",0,57009}, - { "ISCII-", "GUJARATI",0,57010}, - { "ISCII-", "PUNJABI",0,57011}, - { "KOR-", "JOHAB",0,1361}, - { "KSC-", "5601",0,1361}, - { "MAC-", "ROMAN",0,10000}, - { "MAC-", "JP",0,10001}, - { "MAC-", "CH(SP)(BIG5)",0,10002}, - { "MAC-", "KR",0,10003}, - { "MAC-", "AR",0,10004}, - { "MAC-", "HW",0,10005}, - { "MAC-", "GR",0,10006}, - { "MAC-", "CY",0,10007}, - { "MAC-", "CH(SP)(GB2312)",0,10008}, - { "MAC-", "ROMANIA",0,10010}, - { "MAC-", "UA",0,10017}, - { "MAC-", "TH",0,10021}, - { "MAC-", "LAT2",0,10029}, - { "MAC-", "ICE",0,10079}, - { "MAC-", "TR",0,10081}, - { "MAC-", "CR",0,10082} -}; - -int CPLENALL = _countof(CodePageNamesAll); -struct _tcptable *CodePageNamesSupp; -int CPLENSUPP = 1; - -//Gets codepage ID from string representing charset such as "iso-8859-1" -// input- the string -// size- max length of input string -int GetCharsetFromString(char *input, size_t size); - -//HexValue to DecValue ('a' to 10) -// HexValue- hexa value ('a') -// DecValue- poiner where to store dec value -// returns 0 if not success -int FromHexa(char HexValue, char *DecValue); - -//Decodes a char from Base64 -// Base64Value- input char in Base64 -// DecValue- pointer where to store the result -// returns 0 if not success -int FromBase64(char Base64Value, char *DecValue); - -//Decodes string in quoted printable -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// isQ- if is "Q-encoding" modification. should be TRUE in headers -// always returns 1 -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); - -//Decodes string in base64 -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// returns 0 if string was not properly decoded -int DecodeBase64(char *Src, char *Dst, int DstLen); - -//Converts string to unicode from string with specified codepage -// stream- input string -// cp- codepage of input string -// out- pointer to new allocated memory that contains unicode string -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -//Converts string from MIME header to unicode -// stream- input string -// cp- codepage of input string -// storeto- pointer to memory that contains unicode string -// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string) -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -int GetCharsetFromString(char *input, size_t size) -//"ISO-8859-1" to ID from table -{ - char *pin = input; - char *pout, *parser; - - if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr) - return -1; - while ((*pin != 0) && (pin - input < (INT_PTR)size)) { - if ((*pin >= 'a') && (*pin <= 'z')) - *parser++ = *(pin++) - ('a' - 'A'); // make it capital - //else if (*pin=='\"') // this is already done in ExtractFromContentType - // *pin++; //skip the quotes if any - else - *parser++ = *pin++; - } - - *parser = 0; - - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "<CodePage>%s</CodePage>", pout); - #endif - for (int i = 0; i < CPLENALL; i++) { - size_t len = mir_strlen(CodePageNamesAll[i].NameBase); - if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) { - if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) { - delete[] pout; - return CodePageNamesAll[i].CP; - } - } - } - delete[] pout; - return -1; //not found -} - -int FromHexa(char HexValue, char *DecValue) -{ - if (HexValue >= '0' && HexValue <= '9') { - *DecValue = HexValue - '0'; - return 1; - } - if (HexValue >= 'A' && HexValue <= 'F') { - *DecValue = HexValue - 'A' + 10; - return 1; - } - if (HexValue >= 'a' && HexValue <= 'f') { - *DecValue = HexValue - 'a' + 10; - return 1; - } - return 0; -} - -int FromBase64(char Base64Value, char *DecValue) -{ - if (Base64Value >= 'A' && Base64Value <= 'Z') { - *DecValue = Base64Value - 'A'; - return 1; - } - if (Base64Value >= 'a' && Base64Value <= 'z') { - *DecValue = Base64Value - 'a' + 26; - return 1; - } - if (Base64Value >= '0' && Base64Value <= '9') { - *DecValue = Base64Value - '0' + 52; - return 1; - } - if (Base64Value == '+') { - *DecValue = Base64Value - '+' + 62; - return 1; - } - if (Base64Value == '/') { - *DecValue = Base64Value - '/' + 63; - return 1; - } - if (Base64Value == '=') { - *DecValue = 0; - return 1; - } - return 0; -} - -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ) -{ - #ifdef DEBUG_DECODEQUOTED - char *DstTemp = Dst; - DebugLog(DecodeFile, "<Decode Quoted><Input>%s</Input>", Src); - #endif - for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++) - if (*Src == '=') { - if (!isQ) { - if (Src[1] == 0x0D) { - Src++; Src++; - if (Src[0] == 0x0A) Src++; - goto CopyCharQuotedPrintable; - } - if (Src[1] == 0x0A) { - Src++; Src++; - goto CopyCharQuotedPrintable; - } - } - char First, Second; - if (!FromHexa(*(++Src), &First)) { - *Dst++ = '='; Src--; - continue; - } - if (!FromHexa(*(++Src), &Second)) { - *Dst++ = '='; Src--; Src--; - continue; - } - *Dst = (char)(First) << 4; - *Dst += Second; - } - else if (isQ && *Src == '_') - *Dst = ' '; - else - CopyCharQuotedPrintable: // Yeah. Bad programming stile. - *Dst = *Src; - *Dst = 0; - #ifdef DEBUG_DECODEQUOTED - DebugLog(DecodeFile, "<Output>%s</Output></Decode Quoted>", DstTemp); - #endif - return 1; -} - -int DecodeBase64(char *Src, char *Dst, int DstLen) -{ - int Result = 0; - char Locator = 0, MiniResult[4]; - char *End = Dst + DstLen; - - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; - - #ifdef DEBUG_DECODEBASE64 - char *DstTemp = Dst; - DebugLog(DecodeFile, "<Decode Base64><Input>\n%s\n</Input>\n", Src); - #endif - while (*Src != 0 && DstLen && Dst != End) { - if ((*Src == 0x0D) || (*Src == 0x0A)) { - Src++; - continue; - } - if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes - { - Locator = 0; //next write to the first byte - *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4)); - if (Dst == End) goto end; //DstLen exceeded? - *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2)); - if (Dst == End) goto end; //someones don't like goto, but not me - *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]); - if (!Result && (*Src == 0)) goto end; //end of string? - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop - } - if (!Result) return 0; //unrecognised character occured - Src++; - } -end: - *Dst = 0; - #ifdef DEBUG_DECODEBASE64 - DebugLog(DecodeFile, "<Output>\n%s\n</Output></Decode Base64>", DstTemp); - #endif - return 1; -} - - - -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out) -{ - CPINFO CPInfo; - wchar_t *temp, *src = *out, *dest; - size_t outlen; - int streamlen, Index; - - //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar - uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001}; - - if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo)) - cp = CP_ACP; - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "<CodePage #>%d</CodePage #>", cp); - #endif - - for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++) - if (CodePagesZeroFlags[Index] == cp) { - Index = -1; - break; - } - if (Index == -1) - streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0); - else - streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0); - - if (*out != nullptr) - outlen = mir_wstrlen(*out); - else - outlen = 0; - temp = new wchar_t[streamlen + outlen + 1]; - - if (*out != nullptr) { - for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp - *dest = *src; - // *dest++=L' '; //add space? - delete[] * out; - } - else - dest = temp; - *out = temp; - - if (Index == -1) { - if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen)) - return 0; - } - else { - if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen)) - return 0; - } - return 1; -} - -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode) -{ - char *start = stream, *finder, *finderend; - char Encoding = 0; - - if (stream == nullptr) - return; - - while (WS(start)) start++; - wchar_t *tempstore = nullptr; - if (!ConvertStringToUnicode(stream, cp, &tempstore))return; - - size_t tempstoreLength = mir_wstrlen(tempstore); - - size_t outind = 0; - while (*start != 0) { - if (CODES(start)) { - finder = start + 2; finderend = finder; - while (!CODED(finderend) && !EOS(finderend)) finderend++; - start = finderend; - if (CODED(finderend)) { - Encoding = *(finderend + 1); - switch (Encoding) { - case 'b': - case 'B': - case 'q': - case 'Q': - break; - default: - goto NotEncoded; - } - if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder))) - cp = CP_ACP; - if (Encoding != 0) { - int size = 0, codeend; - char *pcodeend = nullptr; - - finder = finderend + 2; - if (CODED(finder)) - finder++; - while (WS(finder)) finder++; - finderend = finder; - while (!CODEE(finderend) && !EOS(finderend)) finderend++; - if (codeend = CODEE(finderend)) - pcodeend = finderend; - while (WS(finderend - 1)) finderend--; - if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) { - finder++; - finderend--; - } - char *oneWordEncoded = new char[finderend - finder + 1]; - strncpy(oneWordEncoded, finder, finderend - finder); - oneWordEncoded[finderend - finder] = 0; - switch (Encoding) { - case 'b': - case 'B': - size = (finderend - finder) * 3 / 4 + 3 + 1 + 1; - break; - case 'q': - case 'Q': - size = finderend - finder + 1 + 1; - break; - } - - char *DecodedResult = new char[size + 1]; - switch (Encoding) { - case 'q': - case 'Q': - DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE); - break; - case 'b': - case 'B': - DecodeBase64(oneWordEncoded, DecodedResult, size); - break; - } - delete[] oneWordEncoded; - if (codeend) - finderend = pcodeend + 2; - if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted - { - size_t len = mir_strlen(DecodedResult); - DecodedResult[len] = ' '; - DecodedResult[len + 1] = 0; - finderend++; - } - wchar_t *oneWord = nullptr; - if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) { - size_t len = mir_wstrlen(oneWord); - memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t)); - outind += len; - } - delete oneWord; - oneWord = nullptr; - delete[] DecodedResult; - start = finderend; - } - else if (!EOS(start)) start++; - } - else if (!EOS(start)) start++; - } - else { -NotEncoded: - tempstore[outind] = tempstore[start - stream]; - outind++; - if (outind > tempstoreLength) break; - start++; - } - } - tempstore[outind] = 0; - *storeto = tempstore; -} +/*
+ * This code implements decoding encoded MIME header in style
+ * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?=
+ *
+ * (c) majvan 2002-2004
+ */
+#include "../stdafx.h"
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+struct _tcptable CodePageNamesAll[]=
+{
+ { "ANSI", "",TRUE,CP_ACP},
+ { "WINDOWS-1", "250",0,1250},
+ { "WINDOWS-1", "251",0,1251},
+ { "WINDOWS-1", "252",0,1252},
+ { "WINDOWS-1", "253",0,1253},
+ { "WINDOWS-1", "254",0,1254},
+ { "WINDOWS-1", "255",0,1255},
+ { "WINDOWS-1", "256",0,1256},
+ { "WINDOWS-1", "257",0,1257},
+ { "WINDOWS-1", "258",0,1258},
+ { "CP1", "250",0,1250},
+ { "CP1", "251",0,1251},
+ { "CP1", "252",0,1252},
+ { "CP1", "253",0,1253},
+ { "CP1", "254",0,1254},
+ { "CP1", "255",0,1255},
+ { "CP1", "256",0,1256},
+ { "CP1", "257",0,1257},
+ { "CP1", "258",0,1258},
+ { "ANSI-1", "250",0,1250},
+ { "ANSI-1", "251",0,1251},
+ { "ANSI-1", "252",0,1252},
+ { "ANSI-1", "253",0,1253},
+ { "ANSI-1", "254",0,1254},
+ { "ANSI-1", "255",0,1255},
+ { "ANSI-1", "256",0,1256},
+ { "ANSI-1", "257",0,1257},
+ { "ANSI-1", "258",0,1258},
+ { "KOI8", "-R",0,20866},
+ { "KOI8", "",0,20866},
+ { "KOI8", "-U",0,21866},
+ { "KOI8", "-RU",0,21866},
+ { "US-", "ASCII",0,20127},
+ { "CP", "367",0,20127},
+ { "ASCII", "",0,20127},
+ { "ASCII", "7",0,20127},
+ { "ISO-8859", "-1",0,28591},
+ { "ISO-8859", "-2",0,28592},
+ { "ISO-8859", "-3",0,28593},
+ { "ISO-8859", "-4",0,28594},
+ { "ISO-8859", "-5",0,28595},
+ { "ISO-8859", "-6",0,28596},
+ { "ISO-8859", "-7",0,28597},
+ { "ISO-8859", "-8",0,28598},
+ { "ISO-8859", "-9",0,28599},
+ { "ISO-8859", "-15",0,28605},
+ { "ISO_8859", "-1",0,28591},
+ { "ISO_8859", "-2",0,28592},
+ { "ISO_8859", "-3",0,28593},
+ { "ISO_8859", "-4",0,28594},
+ { "ISO_8859", "-5",0,28595},
+ { "ISO_8859", "-6",0,28596},
+ { "ISO_8859", "-7",0,28597},
+ { "ISO_8859", "-8",0,28598},
+ { "ISO_8859", "-9",0,28599},
+ { "ISO_8859", "-15",0,28605},
+ { "ISO-", "10646-USC2",0,1200},
+ { "ISO-2022", "/2-JP",0,50220},
+ { "ISO-2022", "-JP",0,50221},
+ { "ISO-2022", "/JIS-JP",0,50222},
+ { "ISO-2022", "-KR",0,50225},
+ { "ISO-2022", "-CH(SP)",0,50227},
+ { "ISO-2022", "-CH(TR)",0,50229},
+ { "UTF-", "7",0,65000},
+ { "UTF-", "8",0,65001},
+ { "ARAB-", "TRANSPARENT",0,710},
+ { "ASMO-", "TRANSPARENT",0,720},
+ { "ASMO-", "449",0,709},
+ { "ASMO-", "708",0,708},
+ { "BIG5", "",0,950},
+ { "EUC-", "CH(SP)",0,51936},
+ { "EUC-", "CH(TR)",0,51950},
+ { "EUC-", "JP",0,51932},
+ { "EUC-", "KR",0,51949},
+ { "GB-", "2312",0,20936},
+ { "GB", "2312",0,20936},
+ { "HZGB-", "2312",0,52936},
+ { "IBM-", "037",0,37},
+ { "IBM-", "290",0,290},
+ { "IBM-", "437",0,437},
+ { "IBM-", "500",0,500},
+ { "IBM-", "775",0,775},
+ { "IBM-", "850",0,850},
+ { "IBM-", "852",0,852},
+ { "IBM-", "855",0,855},
+ { "IBM-", "857",0,857},
+ { "IBM-", "860",0,860},
+ { "IBM-", "861",0,861},
+ { "IBM-", "862",0,862},
+ { "IBM-", "863",0,863},
+ { "IBM-", "864",0,864},
+ { "IBM-", "865",0,865},
+ { "IBM-", "866",0,866},
+ { "IBM-", "869",0,869},
+ { "IBM-", "870",0,870},
+ { "IBM-", "875",0,875},
+ { "IBM-", "1026",0,1026},
+ { "IBM-", "273",0,20273},
+ { "IBM-", "277",0,20277},
+ { "IBM-", "278",0,20278},
+ { "IBM-", "280",0,20280},
+ { "IBM-", "284",0,20284},
+ { "IBM-", "285",0,20285},
+ { "IBM-", "290",0,20290},
+ { "IBM-", "297",0,20297},
+ { "IBM-", "420",0,20420},
+ { "IBM-", "423",0,20423},
+ { "IBM-", "871",0,20871},
+ { "IBM-", "880",0,20880},
+ { "IBM-", "905",0,20905},
+ { "IBM-", "THAI",0,20838},
+ { "ISCII-", "DEVANAGARI",0,57002},
+ { "ISCII-", "BENGALI",0,57003},
+ { "ISCII-", "TAMIL",0,57004},
+ { "ISCII-", "TELUGU",0,57005},
+ { "ISCII-", "ASSAMESE",0,57006},
+ { "ISCII-", "ORIYA",0,57007},
+ { "ISCII-", "KANNADA",0,57008},
+ { "ISCII-", "MALAYALAM",0,57009},
+ { "ISCII-", "GUJARATI",0,57010},
+ { "ISCII-", "PUNJABI",0,57011},
+ { "KOR-", "JOHAB",0,1361},
+ { "KSC-", "5601",0,1361},
+ { "MAC-", "ROMAN",0,10000},
+ { "MAC-", "JP",0,10001},
+ { "MAC-", "CH(SP)(BIG5)",0,10002},
+ { "MAC-", "KR",0,10003},
+ { "MAC-", "AR",0,10004},
+ { "MAC-", "HW",0,10005},
+ { "MAC-", "GR",0,10006},
+ { "MAC-", "CY",0,10007},
+ { "MAC-", "CH(SP)(GB2312)",0,10008},
+ { "MAC-", "ROMANIA",0,10010},
+ { "MAC-", "UA",0,10017},
+ { "MAC-", "TH",0,10021},
+ { "MAC-", "LAT2",0,10029},
+ { "MAC-", "ICE",0,10079},
+ { "MAC-", "TR",0,10081},
+ { "MAC-", "CR",0,10082}
+};
+
+int CPLENALL = _countof(CodePageNamesAll);
+struct _tcptable *CodePageNamesSupp;
+int CPLENSUPP = 1;
+
+//Gets codepage ID from string representing charset such as "iso-8859-1"
+// input- the string
+// size- max length of input string
+int GetCharsetFromString(char *input, size_t size);
+
+//HexValue to DecValue ('a' to 10)
+// HexValue- hexa value ('a')
+// DecValue- poiner where to store dec value
+// returns 0 if not success
+int FromHexa(char HexValue, char *DecValue);
+
+//Decodes a char from Base64
+// Base64Value- input char in Base64
+// DecValue- pointer where to store the result
+// returns 0 if not success
+int FromBase64(char Base64Value, char *DecValue);
+
+//Decodes string in quoted printable
+// Src- input string
+// Dst- where to store output string
+// DstLen- how max long should be output string
+// isQ- if is "Q-encoding" modification. should be TRUE in headers
+// always returns 1
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+
+//Decodes string in base64
+// Src- input string
+// Dst- where to store output string
+// DstLen- how max long should be output string
+// returns 0 if string was not properly decoded
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+
+//Converts string to unicode from string with specified codepage
+// stream- input string
+// cp- codepage of input string
+// out- pointer to new allocated memory that contains unicode string
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+//Converts string from MIME header to unicode
+// stream- input string
+// cp- codepage of input string
+// storeto- pointer to memory that contains unicode string
+// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string)
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+int GetCharsetFromString(char *input, size_t size)
+//"ISO-8859-1" to ID from table
+{
+ char *pin = input;
+ char *pout, *parser;
+
+ if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr)
+ return -1;
+ while ((*pin != 0) && (pin - input < (INT_PTR)size)) {
+ if ((*pin >= 'a') && (*pin <= 'z'))
+ *parser++ = *(pin++) - ('a' - 'A'); // make it capital
+ //else if (*pin=='\"') // this is already done in ExtractFromContentType
+ // *pin++; //skip the quotes if any
+ else
+ *parser++ = *pin++;
+ }
+
+ *parser = 0;
+
+ #ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile, "<CodePage>%s</CodePage>", pout);
+ #endif
+ for (int i = 0; i < CPLENALL; i++) {
+ size_t len = mir_strlen(CodePageNamesAll[i].NameBase);
+ if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) {
+ if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) {
+ delete[] pout;
+ return CodePageNamesAll[i].CP;
+ }
+ }
+ }
+ delete[] pout;
+ return -1; //not found
+}
+
+int FromHexa(char HexValue, char *DecValue)
+{
+ if (HexValue >= '0' && HexValue <= '9') {
+ *DecValue = HexValue - '0';
+ return 1;
+ }
+ if (HexValue >= 'A' && HexValue <= 'F') {
+ *DecValue = HexValue - 'A' + 10;
+ return 1;
+ }
+ if (HexValue >= 'a' && HexValue <= 'f') {
+ *DecValue = HexValue - 'a' + 10;
+ return 1;
+ }
+ return 0;
+}
+
+int FromBase64(char Base64Value, char *DecValue)
+{
+ if (Base64Value >= 'A' && Base64Value <= 'Z') {
+ *DecValue = Base64Value - 'A';
+ return 1;
+ }
+ if (Base64Value >= 'a' && Base64Value <= 'z') {
+ *DecValue = Base64Value - 'a' + 26;
+ return 1;
+ }
+ if (Base64Value >= '0' && Base64Value <= '9') {
+ *DecValue = Base64Value - '0' + 52;
+ return 1;
+ }
+ if (Base64Value == '+') {
+ *DecValue = Base64Value - '+' + 62;
+ return 1;
+ }
+ if (Base64Value == '/') {
+ *DecValue = Base64Value - '/' + 63;
+ return 1;
+ }
+ if (Base64Value == '=') {
+ *DecValue = 0;
+ return 1;
+ }
+ return 0;
+}
+
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ)
+{
+ #ifdef DEBUG_DECODEQUOTED
+ char *DstTemp = Dst;
+ DebugLog(DecodeFile, "<Decode Quoted><Input>%s</Input>", Src);
+ #endif
+ for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++)
+ if (*Src == '=') {
+ if (!isQ) {
+ if (Src[1] == 0x0D) {
+ Src++; Src++;
+ if (Src[0] == 0x0A) Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ if (Src[1] == 0x0A) {
+ Src++; Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ }
+ char First, Second;
+ if (!FromHexa(*(++Src), &First)) {
+ *Dst++ = '='; Src--;
+ continue;
+ }
+ if (!FromHexa(*(++Src), &Second)) {
+ *Dst++ = '='; Src--; Src--;
+ continue;
+ }
+ *Dst = (char)(First) << 4;
+ *Dst += Second;
+ }
+ else if (isQ && *Src == '_')
+ *Dst = ' ';
+ else
+ CopyCharQuotedPrintable: // Yeah. Bad programming stile.
+ *Dst = *Src;
+ *Dst = 0;
+ #ifdef DEBUG_DECODEQUOTED
+ DebugLog(DecodeFile, "<Output>%s</Output></Decode Quoted>", DstTemp);
+ #endif
+ return 1;
+}
+
+int DecodeBase64(char *Src, char *Dst, int DstLen)
+{
+ int Result = 0;
+ char Locator = 0, MiniResult[4];
+ char *End = Dst + DstLen;
+
+ MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0;
+
+ #ifdef DEBUG_DECODEBASE64
+ char *DstTemp = Dst;
+ DebugLog(DecodeFile, "<Decode Base64><Input>\n%s\n</Input>\n", Src);
+ #endif
+ while (*Src != 0 && DstLen && Dst != End) {
+ if ((*Src == 0x0D) || (*Src == 0x0A)) {
+ Src++;
+ continue;
+ }
+ if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes
+ {
+ Locator = 0; //next write to the first byte
+ *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4));
+ if (Dst == End) goto end; //DstLen exceeded?
+ *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2));
+ if (Dst == End) goto end; //someones don't like goto, but not me
+ *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]);
+ if (!Result && (*Src == 0)) goto end; //end of string?
+ MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop
+ }
+ if (!Result) return 0; //unrecognised character occured
+ Src++;
+ }
+end:
+ *Dst = 0;
+ #ifdef DEBUG_DECODEBASE64
+ DebugLog(DecodeFile, "<Output>\n%s\n</Output></Decode Base64>", DstTemp);
+ #endif
+ return 1;
+}
+
+
+
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out)
+{
+ CPINFO CPInfo;
+ wchar_t *temp, *src = *out, *dest;
+ size_t outlen;
+ int streamlen, Index;
+
+ //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar
+ uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001};
+
+ if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo))
+ cp = CP_ACP;
+ #ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile, "<CodePage #>%d</CodePage #>", cp);
+ #endif
+
+ for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++)
+ if (CodePagesZeroFlags[Index] == cp) {
+ Index = -1;
+ break;
+ }
+ if (Index == -1)
+ streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0);
+ else
+ streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0);
+
+ if (*out != nullptr)
+ outlen = mir_wstrlen(*out);
+ else
+ outlen = 0;
+ temp = new wchar_t[streamlen + outlen + 1];
+
+ if (*out != nullptr) {
+ for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp
+ *dest = *src;
+ // *dest++=L' '; //add space?
+ delete[] * out;
+ }
+ else
+ dest = temp;
+ *out = temp;
+
+ if (Index == -1) {
+ if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen))
+ return 0;
+ }
+ else {
+ if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen))
+ return 0;
+ }
+ return 1;
+}
+
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode)
+{
+ char *start = stream, *finder, *finderend;
+ char Encoding = 0;
+
+ if (stream == nullptr)
+ return;
+
+ while (WS(start)) start++;
+ wchar_t *tempstore = nullptr;
+ if (!ConvertStringToUnicode(stream, cp, &tempstore))return;
+
+ size_t tempstoreLength = mir_wstrlen(tempstore);
+
+ size_t outind = 0;
+ while (*start != 0) {
+ if (CODES(start)) {
+ finder = start + 2; finderend = finder;
+ while (!CODED(finderend) && !EOS(finderend)) finderend++;
+ start = finderend;
+ if (CODED(finderend)) {
+ Encoding = *(finderend + 1);
+ switch (Encoding) {
+ case 'b':
+ case 'B':
+ case 'q':
+ case 'Q':
+ break;
+ default:
+ goto NotEncoded;
+ }
+ if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder)))
+ cp = CP_ACP;
+ if (Encoding != 0) {
+ int size = 0, codeend;
+ char *pcodeend = nullptr;
+
+ finder = finderend + 2;
+ if (CODED(finder))
+ finder++;
+ while (WS(finder)) finder++;
+ finderend = finder;
+ while (!CODEE(finderend) && !EOS(finderend)) finderend++;
+ if (codeend = CODEE(finderend))
+ pcodeend = finderend;
+ while (WS(finderend - 1)) finderend--;
+ if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) {
+ finder++;
+ finderend--;
+ }
+ char *oneWordEncoded = new char[finderend - finder + 1];
+ strncpy(oneWordEncoded, finder, finderend - finder);
+ oneWordEncoded[finderend - finder] = 0;
+ switch (Encoding) {
+ case 'b':
+ case 'B':
+ size = (finderend - finder) * 3 / 4 + 3 + 1 + 1;
+ break;
+ case 'q':
+ case 'Q':
+ size = finderend - finder + 1 + 1;
+ break;
+ }
+
+ char *DecodedResult = new char[size + 1];
+ switch (Encoding) {
+ case 'q':
+ case 'Q':
+ DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE);
+ break;
+ case 'b':
+ case 'B':
+ DecodeBase64(oneWordEncoded, DecodedResult, size);
+ break;
+ }
+ delete[] oneWordEncoded;
+ if (codeend)
+ finderend = pcodeend + 2;
+ if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted
+ {
+ size_t len = mir_strlen(DecodedResult);
+ DecodedResult[len] = ' ';
+ DecodedResult[len + 1] = 0;
+ finderend++;
+ }
+ wchar_t *oneWord = nullptr;
+ if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) {
+ size_t len = mir_wstrlen(oneWord);
+ memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t));
+ outind += len;
+ }
+ delete oneWord;
+ oneWord = nullptr;
+ delete[] DecodedResult;
+ start = finderend;
+ }
+ else if (!EOS(start)) start++;
+ }
+ else if (!EOS(start)) start++;
+ }
+ else {
+NotEncoded:
+ tempstore[outind] = tempstore[start - stream];
+ outind++;
+ if (outind > tempstoreLength) break;
+ start++;
+ }
+ }
+ tempstore[outind] = 0;
+ *storeto = tempstore;
+}
diff --git a/protocols/YAMN/src/mails/mails.cpp b/protocols/YAMN/src/mails/mails.cpp index 168c6c9397..1385cb649d 100644 --- a/protocols/YAMN/src/mails/mails.cpp +++ b/protocols/YAMN/src/mails/mails.cpp @@ -1,473 +1,473 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------------------------- - - // SMALL INTRO - // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure - // member called Mails. - // Mail queue is ended with NULL- pointered mail (NULL handle) - - //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN) -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN) -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Loads mail data from standard storage to memory -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail data from memory -INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); - -//Saves mail data from memory to standard storage -INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Appends second MIME mail queue to the first one -//Only finds the end of first queue and its Next memember repoints to second one -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second); - -//Synchronizes two accounts -//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue -//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue -//After this, OldQueue is pointer to mails that are on mailbox, but not new mails -//and NewQueue contains new mails in account -//New accounts can be then appended to account mails queue, but they have set the New flag -// -//Two mails equals if they have the same ID -// -// hPlugin- handle of plugin going to delete mails -// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones -// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue -// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails -// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue -//So function works like: -//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue -//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew); - -//Deletes messages from mail From to the end -// Account- account who owns mails -// From- first mail in queue, which is going to delete -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); - -//Removes message from queue, does not delete from memory -// From- queue pointer -// Which- mail to delete -// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); - -//Finds message in queue that has the same ID number -// From- message queue -// ID- pointer to ID -// returns pointer to found message, NULL if not found -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID); - -//Translate header from text to queue of CMimeItem structures -//This means that new queue will contain all info about headers -// stream- pointer to text containing header (can be ended with zero) -// len- length of stream -// head- function fills this pointer to first header item in queue -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head); - -//Creates new mail queue, copying only these mails, that have set flag for deleting -// From- message queue, whose mail with given flag are duplicated -// returns new mail queue (or NULL when no mail with flag is in From queue) -//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so -//you can use this fcn only if you have your ID as pointer to char string ended with zero character -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From); - -//Sets/removes flags from specific mails -// From- pointer to first message -// FlagsSet- mail must have set these flags... -// FlagsNotSet- ...and must not have set these flags... -// FlagsToSetRemove- ...to set/remove these flags (see mode) -// mode- nonzero to set, else remove -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode); - -struct CExportedFunctions MailExportedFcn[] = -{ - {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn}, - {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn}, - {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn}, - {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn}, - {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn}, - {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn}, - {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn}, - {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn}, -}; - -struct CExportedServices MailExportedSvc[] = -{ - {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc}, - {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc}, - {MS_YAMN_LOADMAILDATA, LoadMailDataSvc}, - {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc}, - {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc}, -}; - - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - CAccount *Account = (CAccount *)wParam; - uint32_t MailVersion = (uint32_t)lParam; - HYAMNMAIL NewMail; - - //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) - if (MailVersion != YAMN_MAILVERSION) - return NULL; - - if (Account->Plugin != nullptr) { - if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) { - //Let plugin create its own structure, which can be derived from CAccount structure - if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION))) - return NULL; - } - else { - //We suggest plugin uses standard CAccount structure, so we create it - if (nullptr == (NewMail = new YAMNMAIL)) - //If not created successfully - return NULL; - NewMail->MailData = nullptr; - } - //Init every members of structure, used by YAMN - return (INT_PTR)NewMail; - } - return NULL; -} - -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - HYAMNMAIL OldMail = (HYAMNMAIL)lParam; - struct CMimeItem *TH; - - if (Plugin->MailFcn != nullptr) { - if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) { - //Let plugin delete its own CMimeMsgQueue derived structure - Plugin->MailFcn->DeleteMailFcnPtr(OldMail); - return 1; - } - } - if (OldMail->MailData != nullptr) { - if (OldMail->MailData->Body != nullptr) - delete[] OldMail->MailData->Body; - if ((TH = OldMail->MailData->TranslatedHeader) != nullptr) - for (; OldMail->MailData->TranslatedHeader != nullptr;) { - TH = TH->Next; - if (OldMail->MailData->TranslatedHeader->name != nullptr) - delete[] OldMail->MailData->TranslatedHeader->name; - if (OldMail->MailData->TranslatedHeader->value != nullptr) - delete[] OldMail->MailData->TranslatedHeader->value; - delete OldMail->MailData->TranslatedHeader; - OldMail->MailData->TranslatedHeader = TH; - } - delete OldMail->MailData; - } - if (OldMail->ID != nullptr) - delete[] OldMail->ID; - - delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor - return 1; -} - - -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second) -{ - HYAMNMAIL Finder = first; - while (Finder->Next != nullptr) Finder = Finder->Next; - Finder->Next = second; -} - -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNMAIL Mail = (HYAMNMAIL)wParam; - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return NULL; - - // now we have all data to memory persisting, so no loading is needed - return (INT_PTR)Mail->MailData; -} - -INT_PTR UnloadMailDataSvc(WPARAM, LPARAM) -{ - return 1; -} - -INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam) -{ - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return (INT_PTR)-1; - - // now we have all data to memory persisting, so no saving is needed - return (INT_PTR)0; -} - -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew) -//deletes messages from new queue, if they are old -//it also deletes messages from old queue, if they are not in mailbox anymore -//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue) -//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue) -{ - HYAMNMAIL Finder, FinderPrev; - HYAMNMAIL Parser, ParserPrev; - HYAMNMAIL RemovedOldParser = nullptr; - HYAMNMAIL RemovedNewParser = nullptr; - if (RemovedOld != nullptr) *RemovedOld = nullptr; - if (RemovedNew != nullptr) *RemovedNew = nullptr; - - for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) { - if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail - { - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - continue; - } - for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) { - if (Parser->Flags & YAMN_MSG_DELETED) - continue; - - if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID - continue; - - if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue - break; - } - if (Parser != nullptr) //found equal message in new queue - { - if (Parser == *NewQueue) - *NewQueue = (*NewQueue)->Next; - else - ParserPrev->Next = Parser->Next; - Finder->Number = Parser->Number; //rewrite the number of current message in old queue - - if (RemovedNew == nullptr) //delete from new queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser); - else //or move to RemovedNew - { - if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue - *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue - else - RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue - RemovedNewParser = Parser; //follow RemovedNew queue - RemovedNewParser->Next = nullptr; - } - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - } - else //a message was already deleted from mailbox - { - if (Finder == *OldQueue) //if we are at the first item in OldQueue - { - *OldQueue = (*OldQueue)->Next; //set OldQueue to next item - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = *OldQueue; - } - else { - FinderPrev->Next = Finder->Next; - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = FinderPrev->Next; - } - } - } -} - -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From) -{ - HYAMNMAIL Temp; - while (From != nullptr) { - Temp = From; - From = From->Next; - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp); - } -} - -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - uint32_t Number = Which->Number; - HYAMNMAIL Parser; - - if (*From == Which) { - Parser = Which->Next; - *From = Parser; - } - else { - for (Parser = *From; Which != Parser->Next; Parser = Parser->Next) - if (mode && (Parser->Number > Number)) Parser->Number--; - if (mode && (Parser->Number > Number)) Parser->Number--; - Parser->Next = Parser->Next->Next; - Parser = Which->Next; - } - if (mode) - for (; Parser != nullptr; Parser = Parser->Next) - if (Parser->Number > Number) Parser->Number--; -} - -void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - HYAMNMAIL Parser; - - for (Parser = Which; Parser != nullptr; Parser = Parser->Next) - DeleteMessageFromQueueFcn(From, Parser, mode); -} - -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID) -{ - HYAMNMAIL Browser; - - for (Browser = From; Browser != nullptr; Browser = Browser->Next) - if (0 == mir_strcmp(Browser->ID, ID)) - break; - return Browser; -} - -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head) -{ - try { - char *finder = stream; - char *prev1, *prev2, *prev3; - struct CMimeItem *Item = nullptr; - - while (finder <= (stream + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (DOTLINE(finder + 1)) //at the end of stream - break; - - prev1 = finder; - - while (*finder != ':' && !EOS(finder)) finder++; - if (!EOS(finder)) - prev2 = finder++; - else - break; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (Item != nullptr) { - if (nullptr == (Item->Next = new struct CMimeItem)) - break; - Item = Item->Next; - } - else { - Item = new CMimeItem; - *head = Item; - } - - Item->Next = nullptr; - Item->name = new char[prev2 - prev1 + 1]; - mir_strncpy(Item->name, prev1, prev2 - prev1 + 1); - Item->value = new char[finder - prev3 + 1]; - mir_strncpy(Item->value, prev3, finder - prev3 + 1); - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!DOTLINE(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?! - Item = Item->Next; - Item->Next = nullptr;//just in case; - Item->name = new char[5]; strncpy(Item->name, "Body", 5); - Item->value = new char[prev2 - prev1]; - mir_strncpy(Item->value, prev1, prev2 - prev1 - 1); - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBoxA(nullptr, "Translate header error", "", 0); - } -} - -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From) -{ - HYAMNMAIL FirstMail, Browser = nullptr; - - for (FirstMail = nullptr; From != nullptr; From = From->Next) { - if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) { - if (FirstMail == nullptr) { - FirstMail = Browser = new YAMNMAIL; - if (FirstMail == nullptr) - break; - } - else { - Browser->Next = new YAMNMAIL; - Browser = Browser->Next; - } - Browser->ID = new char[mir_strlen(From->ID) + 1]; - mir_strcpy(Browser->ID, From->ID); - Browser->Number = From->Number; - Browser->Flags = From->Flags; - } - } - return FirstMail; -} - -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode) -{ - HYAMNMAIL msgq; - - for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) { - if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) { - if (mode) - msgq->Flags = msgq->Flags | FlagsToSetRemove; - else - msgq->Flags = msgq->Flags & ~FlagsToSetRemove; - } - } -} +/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+ //--------------------------------------------------------------------------------------------------
+
+ // SMALL INTRO
+ // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure
+ // member called Mails.
+ // Mail queue is ended with NULL- pointered mail (NULL handle)
+
+ //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN)
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam);
+
+//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN)
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam);
+
+//Loads mail data from standard storage to memory
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//Deletes mail data from memory
+INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM);
+
+//Saves mail data from memory to standard storage
+INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//Appends second MIME mail queue to the first one
+//Only finds the end of first queue and its Next memember repoints to second one
+void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second);
+
+//Synchronizes two accounts
+//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue
+//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue
+//After this, OldQueue is pointer to mails that are on mailbox, but not new mails
+//and NewQueue contains new mails in account
+//New accounts can be then appended to account mails queue, but they have set the New flag
+//
+//Two mails equals if they have the same ID
+//
+// hPlugin- handle of plugin going to delete mails
+// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones
+// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue
+// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails
+// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue
+//So function works like:
+//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue
+//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue
+void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew);
+
+//Deletes messages from mail From to the end
+// Account- account who owns mails
+// From- first mail in queue, which is going to delete
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From);
+
+//Removes message from queue, does not delete from memory
+// From- queue pointer
+// Which- mail to delete
+// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode);
+
+//Finds message in queue that has the same ID number
+// From- message queue
+// ID- pointer to ID
+// returns pointer to found message, NULL if not found
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID);
+
+//Translate header from text to queue of CMimeItem structures
+//This means that new queue will contain all info about headers
+// stream- pointer to text containing header (can be ended with zero)
+// len- length of stream
+// head- function fills this pointer to first header item in queue
+void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head);
+
+//Creates new mail queue, copying only these mails, that have set flag for deleting
+// From- message queue, whose mail with given flag are duplicated
+// returns new mail queue (or NULL when no mail with flag is in From queue)
+//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so
+//you can use this fcn only if you have your ID as pointer to char string ended with zero character
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From);
+
+//Sets/removes flags from specific mails
+// From- pointer to first message
+// FlagsSet- mail must have set these flags...
+// FlagsNotSet- ...and must not have set these flags...
+// FlagsToSetRemove- ...to set/remove these flags (see mode)
+// mode- nonzero to set, else remove
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode);
+
+struct CExportedFunctions MailExportedFcn[] =
+{
+ {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn},
+ {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn},
+ {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn},
+ {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn},
+ {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn},
+ {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn},
+ {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn},
+ {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn},
+};
+
+struct CExportedServices MailExportedSvc[] =
+{
+ {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc},
+ {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc},
+ {MS_YAMN_LOADMAILDATA, LoadMailDataSvc},
+ {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc},
+ {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc},
+};
+
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ CAccount *Account = (CAccount *)wParam;
+ uint32_t MailVersion = (uint32_t)lParam;
+ HYAMNMAIL NewMail;
+
+ //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match)
+ if (MailVersion != YAMN_MAILVERSION)
+ return NULL;
+
+ if (Account->Plugin != nullptr) {
+ if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) {
+ //Let plugin create its own structure, which can be derived from CAccount structure
+ if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION)))
+ return NULL;
+ }
+ else {
+ //We suggest plugin uses standard CAccount structure, so we create it
+ if (nullptr == (NewMail = new YAMNMAIL))
+ //If not created successfully
+ return NULL;
+ NewMail->MailData = nullptr;
+ }
+ //Init every members of structure, used by YAMN
+ return (INT_PTR)NewMail;
+ }
+ return NULL;
+}
+
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ HYAMNMAIL OldMail = (HYAMNMAIL)lParam;
+ struct CMimeItem *TH;
+
+ if (Plugin->MailFcn != nullptr) {
+ if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) {
+ //Let plugin delete its own CMimeMsgQueue derived structure
+ Plugin->MailFcn->DeleteMailFcnPtr(OldMail);
+ return 1;
+ }
+ }
+ if (OldMail->MailData != nullptr) {
+ if (OldMail->MailData->Body != nullptr)
+ delete[] OldMail->MailData->Body;
+ if ((TH = OldMail->MailData->TranslatedHeader) != nullptr)
+ for (; OldMail->MailData->TranslatedHeader != nullptr;) {
+ TH = TH->Next;
+ if (OldMail->MailData->TranslatedHeader->name != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->name;
+ if (OldMail->MailData->TranslatedHeader->value != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->value;
+ delete OldMail->MailData->TranslatedHeader;
+ OldMail->MailData->TranslatedHeader = TH;
+ }
+ delete OldMail->MailData;
+ }
+ if (OldMail->ID != nullptr)
+ delete[] OldMail->ID;
+
+ delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor
+ return 1;
+}
+
+
+void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second)
+{
+ HYAMNMAIL Finder = first;
+ while (Finder->Next != nullptr) Finder = Finder->Next;
+ Finder->Next = second;
+}
+
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNMAIL Mail = (HYAMNMAIL)wParam;
+ uint32_t MailVersion = (uint32_t)lParam;
+
+ if (MailVersion != YAMN_MAILDATAVERSION)
+ return NULL;
+
+ // now we have all data to memory persisting, so no loading is needed
+ return (INT_PTR)Mail->MailData;
+}
+
+INT_PTR UnloadMailDataSvc(WPARAM, LPARAM)
+{
+ return 1;
+}
+
+INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam)
+{
+ uint32_t MailVersion = (uint32_t)lParam;
+
+ if (MailVersion != YAMN_MAILDATAVERSION)
+ return (INT_PTR)-1;
+
+ // now we have all data to memory persisting, so no saving is needed
+ return (INT_PTR)0;
+}
+
+void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew)
+//deletes messages from new queue, if they are old
+//it also deletes messages from old queue, if they are not in mailbox anymore
+//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue)
+//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue)
+{
+ HYAMNMAIL Finder, FinderPrev;
+ HYAMNMAIL Parser, ParserPrev;
+ HYAMNMAIL RemovedOldParser = nullptr;
+ HYAMNMAIL RemovedNewParser = nullptr;
+ if (RemovedOld != nullptr) *RemovedOld = nullptr;
+ if (RemovedNew != nullptr) *RemovedNew = nullptr;
+
+ for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) {
+ if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail
+ {
+ FinderPrev = Finder;
+ Finder = Finder->Next; //get next message in old queue for testing
+ continue;
+ }
+ for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) {
+ if (Parser->Flags & YAMN_MSG_DELETED)
+ continue;
+
+ if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID
+ continue;
+
+ if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue
+ break;
+ }
+ if (Parser != nullptr) //found equal message in new queue
+ {
+ if (Parser == *NewQueue)
+ *NewQueue = (*NewQueue)->Next;
+ else
+ ParserPrev->Next = Parser->Next;
+ Finder->Number = Parser->Number; //rewrite the number of current message in old queue
+
+ if (RemovedNew == nullptr) //delete from new queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser);
+ else //or move to RemovedNew
+ {
+ if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue
+ *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue
+ else
+ RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue
+ RemovedNewParser = Parser; //follow RemovedNew queue
+ RemovedNewParser->Next = nullptr;
+ }
+ FinderPrev = Finder;
+ Finder = Finder->Next; //get next message in old queue for testing
+ }
+ else //a message was already deleted from mailbox
+ {
+ if (Finder == *OldQueue) //if we are at the first item in OldQueue
+ {
+ *OldQueue = (*OldQueue)->Next; //set OldQueue to next item
+ if (RemovedOld == nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue
+ *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue
+ else
+ RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue
+ RemovedOldParser = Finder; //follow RemovedOld queue
+ RemovedOldParser->Next = nullptr;
+ }
+ Finder = *OldQueue;
+ }
+ else {
+ FinderPrev->Next = Finder->Next;
+ if (RemovedOld == nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue
+ *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue
+ else
+ RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue
+ RemovedOldParser = Finder; //follow RemovedOld queue
+ RemovedOldParser->Next = nullptr;
+ }
+ Finder = FinderPrev->Next;
+ }
+ }
+ }
+}
+
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From)
+{
+ HYAMNMAIL Temp;
+ while (From != nullptr) {
+ Temp = From;
+ From = From->Next;
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp);
+ }
+}
+
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0)
+{
+ uint32_t Number = Which->Number;
+ HYAMNMAIL Parser;
+
+ if (*From == Which) {
+ Parser = Which->Next;
+ *From = Parser;
+ }
+ else {
+ for (Parser = *From; Which != Parser->Next; Parser = Parser->Next)
+ if (mode && (Parser->Number > Number)) Parser->Number--;
+ if (mode && (Parser->Number > Number)) Parser->Number--;
+ Parser->Next = Parser->Next->Next;
+ Parser = Which->Next;
+ }
+ if (mode)
+ for (; Parser != nullptr; Parser = Parser->Next)
+ if (Parser->Number > Number) Parser->Number--;
+}
+
+void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0)
+{
+ HYAMNMAIL Parser;
+
+ for (Parser = Which; Parser != nullptr; Parser = Parser->Next)
+ DeleteMessageFromQueueFcn(From, Parser, mode);
+}
+
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID)
+{
+ HYAMNMAIL Browser;
+
+ for (Browser = From; Browser != nullptr; Browser = Browser->Next)
+ if (0 == mir_strcmp(Browser->ID, ID))
+ break;
+ return Browser;
+}
+
+void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head)
+{
+ try {
+ char *finder = stream;
+ char *prev1, *prev2, *prev3;
+ struct CMimeItem *Item = nullptr;
+
+ while (finder <= (stream + len)) {
+ while (ENDLINEWS(finder)) finder++;
+
+ //at the start of line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+
+ prev1 = finder;
+
+ while (*finder != ':' && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev2 = finder++;
+ else
+ break;
+
+ while (WS(finder) && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev3 = finder;
+ else
+ break;
+
+ do {
+ if (ENDLINEWS(finder)) finder += 2; //after endline information continues
+ while (!ENDLINE(finder) && !EOS(finder)) finder++;
+ } while (ENDLINEWS(finder));
+
+ if (Item != nullptr) {
+ if (nullptr == (Item->Next = new struct CMimeItem))
+ break;
+ Item = Item->Next;
+ }
+ else {
+ Item = new CMimeItem;
+ *head = Item;
+ }
+
+ Item->Next = nullptr;
+ Item->name = new char[prev2 - prev1 + 1];
+ mir_strncpy(Item->name, prev1, prev2 - prev1 + 1);
+ Item->value = new char[finder - prev3 + 1];
+ mir_strncpy(Item->value, prev3, finder - prev3 + 1);
+
+ if (EOS(finder))
+ break;
+ finder++;
+ if (ENDLINE(finder)) {
+ finder++;
+ if (ENDLINE(finder)) {
+ // end of headers. message body begins
+ finder++;
+ if (ENDLINE(finder))finder++;
+ prev1 = finder;
+ while (!DOTLINE(finder + 1))finder++;
+ if (ENDLINE(finder))finder--;
+ prev2 = finder;
+ if (prev2 > prev1) { // yes, we have body
+ if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?!
+ Item = Item->Next;
+ Item->Next = nullptr;//just in case;
+ Item->name = new char[5]; strncpy(Item->name, "Body", 5);
+ Item->value = new char[prev2 - prev1];
+ mir_strncpy(Item->value, prev1, prev2 - prev1 - 1);
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch (...) {
+ MessageBoxA(nullptr, "Translate header error", "", 0);
+ }
+}
+
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From)
+{
+ HYAMNMAIL FirstMail, Browser = nullptr;
+
+ for (FirstMail = nullptr; From != nullptr; From = From->Next) {
+ if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) {
+ if (FirstMail == nullptr) {
+ FirstMail = Browser = new YAMNMAIL;
+ if (FirstMail == nullptr)
+ break;
+ }
+ else {
+ Browser->Next = new YAMNMAIL;
+ Browser = Browser->Next;
+ }
+ Browser->ID = new char[mir_strlen(From->ID) + 1];
+ mir_strcpy(Browser->ID, From->ID);
+ Browser->Number = From->Number;
+ Browser->Flags = From->Flags;
+ }
+ }
+ return FirstMail;
+}
+
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode)
+{
+ HYAMNMAIL msgq;
+
+ for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) {
+ if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) {
+ if (mode)
+ msgq->Flags = msgq->Flags | FlagsToSetRemove;
+ else
+ msgq->Flags = msgq->Flags & ~FlagsToSetRemove;
+ }
+ }
+}
diff --git a/protocols/YAMN/src/mails/mime.cpp b/protocols/YAMN/src/mails/mime.cpp index 69099af808..2a2e7b4665 100644 --- a/protocols/YAMN/src/mails/mime.cpp +++ b/protocols/YAMN/src/mails/mime.cpp @@ -1,695 +1,695 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - - //Copies one string to another - // srcstart- source string - // srcend- address to the end of source string - // dest- pointer that stores new allocated string that contains copy of source string - // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode); - -//Extracts email address (finds nick name and mail and then stores them to strings) -// finder- source string -// storeto- pointer that receives address of mail string -// storetonick- pointer that receives address of nickname -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick); - -//Extracts simple text from string -// finder- source string -// storeto- pointer that receives address of string -void ExtractStringFromLine(char *finder, char **storeto); - -//Extracts some item from content-type string -//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" -// ContetType- content-type string -// value- string item -// returns extracted string (or NULL when not found) -char *ExtractFromContentType(char *ContentType, char *value); - -//Extracts info from header text into header members -//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract -//(e.g. the X-Priority and Importance and so on) -// items- translated header (see TranslateHeaderFcn) -// head- header to be filled with values extracted from items -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); - -//Extracts header to mail using ExtractShortHeader fcn. -// items- translated header (see TranslateHeaderFcn) -// CP- codepage used when no default found -// head- header to be filled with values extracted from items, in unicode (wide char) -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); - -//Deletes items in CShortHeader structure -// head- structure whose items are deleted -void DeleteShortHeaderContent(struct CShortHeader *head); - -//Deletes list of YAMN_MIMENAMES structures -// Names- pointer to first item of list -void DeleteNames(CMimeNames *Names); - -//Deletes list of YAMN_MIMESHORTNAMES structures -// Names- pointer to first item of list -void DeleteShortNames(CShortNames *Names); - -//Makes a string lowercase -// string- string to be lowercased -void inline ToLower(char *string); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode) -{ - char *dst; - - if (dest == nullptr) - return; - if (srcstart >= srcend) - return; - - if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) { - srcstart++; - srcend--; - } - - if (srcstart >= srcend) - return; - - if (nullptr != *dest) - delete[] * dest; - if (nullptr == (*dest = new char[srcend - srcstart + 1])) - return; - - dst = *dest; - - for (; srcstart < srcend; dst++, srcstart++) { - if (ENDLINE(srcstart)) { - while (ENDLINE(srcstart) || WS(srcstart)) srcstart++; - *dst = ' '; - srcstart--; //because at the end of "for loop" we increment srcstart - } - else - *dst = *srcstart; - } - *dst = 0; -} - -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick) -{ - if (finder == nullptr) { - *storeto = *storetonick = nullptr; - return; - } - while (WS(finder)) finder++; - if ((*finder) != '<') { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace - if (*finderend != '>') //not '>' at the end of line - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); - else //at the end of line, there's '>' - { - char *finder2 = finderend; - while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start - CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL); - if (*finder2 == '<') //if we found '<', the rest copy as from nick - { - finder2--; - while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace - CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname - } - } - } - else { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy - finder = finderend + 1; - while (WS(finder)) finder++; //parse whitespace - if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick - { - finderend = finder + 1; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL); - } - } -} - -void ExtractStringFromLine(char *finder, char **storeto) -{ - if (finder == nullptr) { - *storeto = nullptr; - return; - } - while (WS(finder)) finder++; - char *finderend = finder; - - do { - if (ENDLINEWS(finderend)) finderend++; //after endline information continues - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN); -} - -char *ExtractFromContentType(char *ContentType, char *value) -{ - char *lowered = _strdup(ContentType); - ToLower(lowered); - char *finder = strstr(lowered, value); - if (finder == nullptr) { - free(lowered); - return nullptr; - } - finder = finder - lowered + ContentType; - free(lowered); - - char *temp, *copier; - char *CopiedString; - - temp = finder - 1; - while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" - if (*temp != ';' && !ENDLINE(temp) && temp != ContentType) - return nullptr; - finder = finder + mir_strlen(value); //jump over value string - - while (WS(finder)) finder++; //jump over whitespaces - temp = finder; - while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;) - temp--; - while (WS(temp)) temp--; //remove whitespaces from the end - if (*finder == '\"') { //remove heading and tailing quotes - finder++; - if (*temp == '\"') temp--; - } - if (nullptr == (CopiedString = new char[++temp - finder + 1])) - return nullptr; - for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string - *copier = 0; //and end it with zero character - - return CopiedString; -} - -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head) -{ - for (; items != nullptr; items = items->Next) { - //at the start of line - //MessageBox(NULL,items->value,items->name,0); - if (0 == _strnicmp(items->name, "From", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting from>"); - #endif - ExtractAddressFromLine(items->value, &head->From, &head->FromNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Return-Path", 11)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting return-path>"); - #endif - ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Subject", 7)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting subject>"); - #endif - ExtractStringFromLine(items->value, &head->Subject); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Body", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting body>"); - #endif - ExtractStringFromLine(items->value, &head->Body); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Date", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting date>"); - #endif - ExtractStringFromLine(items->value, &head->Date); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Content-Type", 12)) { - if (items->value == nullptr) - continue; - - char *ContentType = nullptr, *CharSetStr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting Content-Type>"); - #endif - ExtractStringFromLine(items->value, &ContentType); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - ToLower(ContentType); - if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) { - head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - delete[] ContentType; - } - else if (0 == _strnicmp(items->name, "Importance", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting importance>"); - #endif - if (head->Priority != -1) { - if (0 == strncmp(items->value, "low", 3)) - head->Priority = 5; - else if (0 == strncmp(items->value, "normal", 6)) - head->Priority = 3; - else if (0 == strncmp(items->value, "high", 4)) - head->Priority = 1; - } - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "X-Priority", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<X-Priority>"); - #endif - if ((*items->value >= '1') && (*items->value <= '5')) - head->Priority = *items->value - '0'; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - - } -} - -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head) -{ - struct CShortHeader ShortHeader; - - memset(&ShortHeader, 0, sizeof(struct CShortHeader)); - ShortHeader.Priority = ShortHeader.CP = -1; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting header>\n"); - #endif - ExtractShortHeader(items, &ShortHeader); - - head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority; - CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP; - #ifdef DEBUG_DECODE - if (NULL != ShortHeader.From) - DebugLog(DecodeFile, "<Decoded from>%s</Decoded)\n", ShortHeader.From); - if (NULL != ShortHeader.FromNick) - DebugLog(DecodeFile, "<Decoded from-nick>%s</Decoded)\n", ShortHeader.FromNick); - if (NULL != ShortHeader.ReturnPath) - DebugLog(DecodeFile, "<Decoded return-path>%s</Decoded)\n", ShortHeader.ReturnPath); - if (NULL != ShortHeader.ReturnPathNick) - DebugLog(DecodeFile, "<Decoded return-path nick>%s</Decoded)\n", ShortHeader.ReturnPathNick); - if (NULL != ShortHeader.Subject) - DebugLog(DecodeFile, "<Decoded subject>%s</Decoded)\n", ShortHeader.Subject); - if (NULL != ShortHeader.Date) - DebugLog(DecodeFile, "<Decoded date>%s</Decoded)\n", ShortHeader.Date); - DebugLog(DecodeFile, "</Extracting header>\n"); - DebugLog(DecodeFile, "<Convert>\n"); - #endif - - ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN); - - #ifdef DEBUG_DECODE - if (NULL != head->From) - DebugLogW(DecodeFile, L"<Converted from>%s</Converted>\n", head->From); - #endif - ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->FromNick) - DebugLogW(DecodeFile, L"<Converted from-nick>%s</Converted>\n", head->FromNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPath) - DebugLogW(DecodeFile, L"<Converted return-path>%s</Converted>\n", head->ReturnPath); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPathNick) - DebugLogW(DecodeFile, L"<Converted return-path nick>%s</Converted>\n", head->ReturnPathNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Subject) - DebugLogW(DecodeFile, L"<Converted subject>%s</Converted>\n", head->Subject); - #endif - ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Date) - DebugLogW(DecodeFile, L"<Converted date>%s</Converted>\n", head->Date); - #endif - - ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Body) - DebugLogW(DecodeFile, L"<Converted Body>%s</Converted>\n", head->Body); - #endif - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Convert>\n"); - #endif - - DeleteShortHeaderContent(&ShortHeader); - - // head->From=L"Frommmm"; - // head->Subject=L"Subject"; - return; -} - -void DeleteShortHeaderContent(struct CShortHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->To != nullptr) DeleteShortNames(head->To); - if (head->Cc != nullptr) DeleteShortNames(head->Cc); - if (head->Bcc != nullptr) DeleteShortNames(head->Bcc); - if (head->Body != nullptr) delete[] head->Body; -} - -void DeleteHeaderContent(struct CHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->Body != nullptr) delete[] head->Body; - if (head->To != nullptr) DeleteNames(head->To); - if (head->Cc != nullptr) DeleteNames(head->Cc); - if (head->Bcc != nullptr) DeleteNames(head->Bcc); -} - -void DeleteNames(CMimeNames *Names) -{ - CMimeNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CMimeNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - -void DeleteShortNames(CShortNames *Names) -{ - CShortNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CShortNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - - -void inline ToLower(char *string) -{ - for (; *string != 0; string++) - if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a'; -} - -#define TE_UNKNOWN -#define TE_QUOTEDPRINTABLE 1 -#define TE_BASE64 2 -struct APartDataType -{ - char *Src;//Input - char *ContType; - int CodePage; - char *TransEnc; - uint8_t TransEncType; //TE_something - char *body; - int bodyLen; - wchar_t *wBody; -}; - - -void ParseAPart(APartDataType *data) -{ - size_t len = mir_strlen(data->Src); - try { - char *finder = data->Src; - char *prev1, *prev2, *prev3; - - while (finder <= (data->Src + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - prev1 = finder; - - while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++; - if (ENDLINE(finder) || EOS(finder)) { - // no ":" in the line? here the body begins; - data->body = prev1; - break; - } - prev2 = finder++; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) { - data->ContType = prev3; - } - else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) { - data->TransEnc = prev3; - } - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!EOS(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - data->body = prev1; - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBox(nullptr, TranslateT("Translate header error"), L"", 0); - } - if (data->body) data->bodyLen = (int)mir_strlen(data->body); -} - -//from decode.cpp -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); -int DecodeBase64(char *Src, char *Dst, int DstLen); -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -wchar_t *ParseMultipartBody(char *src, char *bond) -{ - char *srcback = _strdup(src); - size_t sizebond = mir_strlen(bond); - int numparts = 1; - int i; - char *courbond = srcback; - wchar_t *dest; - for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond); - APartDataType *partData = new APartDataType[numparts]; - memset(partData, 0, sizeof(APartDataType) * numparts); - partData[0].Src = courbond = srcback; - for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) { - *(courbond - 2) = 0; - partData[i].Src = courbond + sizebond; - while (ENDLINE(partData[i].Src)) partData[i].Src++; - } - size_t resultSize = 0; - for (i = 0; i < numparts; i++) { - ParseAPart(&partData[i]); - if (partData[i].body) { - if (partData[i].TransEnc) { - if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64; - else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE; - } - if (partData[i].ContType) { - char *CharSetStr; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - } - if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) { - char *localBody = nullptr; - switch (partData[i].TransEncType) { - case TE_BASE64: - { - int size = partData[i].bodyLen * 3 / 4 + 5; - localBody = new char[size + 1]; - DecodeBase64(partData[i].body, localBody, size); - }break; - case TE_QUOTEDPRINTABLE: - { - int size = partData[i].bodyLen + 2; - localBody = new char[size + 1]; - DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE); - }break; - } - ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody); - if (localBody) delete[] localBody; - } - else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) { - //Multipart in mulitipart recursive? should be SPAM. Ah well - char *bondary = nullptr; - if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) { - partData[i].wBody = ParseMultipartBody(partData[i].body, bondary); - delete[] bondary; - } - else goto FailBackRaw; //multipart with no boundary? badly formatted messages. - } - else { -FailBackRaw: - ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody); - } - resultSize += mir_wstrlen(partData[i].wBody); - }// if (partData[i].body) - resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet - } - dest = new wchar_t[resultSize + 1]; - size_t destpos = 0; - for (i = 0; i < numparts; i++) { - if (i) { // part before first boudary should not have headers - char infoline[1024]; size_t linesize = 0; - mir_snprintf(infoline, "%s %d", Translate("Part"), i); - linesize = mir_strlen(infoline); - if (partData[i].TransEnc) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc); - linesize = mir_strlen(infoline); - } - if (partData[i].ContType) { - char *CharSetStr = strchr(partData[i].ContType, ';'); - if (CharSetStr) { - CharSetStr[0] = 0; - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - partData[i].ContType = CharSetStr + 1; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - } - else { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - } - } - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n"); - { - wchar_t *temp = nullptr; - dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet; - destpos += 3; - ConvertStringToUnicode(infoline, CP_ACP, &temp); - size_t wsize = mir_wstrlen(temp); - mir_wstrcpy(&dest[destpos], temp); - destpos += wsize; - delete[] temp; - } - } // if (i) - - if (partData[i].wBody) { - size_t wsize = mir_wstrlen(partData[i].wBody); - mir_wstrcpy(&dest[destpos], partData[i].wBody); - destpos += wsize; - delete[] partData[i].wBody; - } - } - - free(srcback); - delete[] partData; - dest[resultSize] = 0;//just in case - return dest; -} +/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+ //Copies one string to another
+ // srcstart- source string
+ // srcend- address to the end of source string
+ // dest- pointer that stores new allocated string that contains copy of source string
+ // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string
+void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode);
+
+//Extracts email address (finds nick name and mail and then stores them to strings)
+// finder- source string
+// storeto- pointer that receives address of mail string
+// storetonick- pointer that receives address of nickname
+void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick);
+
+//Extracts simple text from string
+// finder- source string
+// storeto- pointer that receives address of string
+void ExtractStringFromLine(char *finder, char **storeto);
+
+//Extracts some item from content-type string
+//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII"
+// ContetType- content-type string
+// value- string item
+// returns extracted string (or NULL when not found)
+char *ExtractFromContentType(char *ContentType, char *value);
+
+//Extracts info from header text into header members
+//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract
+//(e.g. the X-Priority and Importance and so on)
+// items- translated header (see TranslateHeaderFcn)
+// head- header to be filled with values extracted from items
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head);
+
+//Extracts header to mail using ExtractShortHeader fcn.
+// items- translated header (see TranslateHeaderFcn)
+// CP- codepage used when no default found
+// head- header to be filled with values extracted from items, in unicode (wide char)
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head);
+
+//Deletes items in CShortHeader structure
+// head- structure whose items are deleted
+void DeleteShortHeaderContent(struct CShortHeader *head);
+
+//Deletes list of YAMN_MIMENAMES structures
+// Names- pointer to first item of list
+void DeleteNames(CMimeNames *Names);
+
+//Deletes list of YAMN_MIMESHORTNAMES structures
+// Names- pointer to first item of list
+void DeleteShortNames(CShortNames *Names);
+
+//Makes a string lowercase
+// string- string to be lowercased
+void inline ToLower(char *string);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode)
+{
+ char *dst;
+
+ if (dest == nullptr)
+ return;
+ if (srcstart >= srcend)
+ return;
+
+ if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) {
+ srcstart++;
+ srcend--;
+ }
+
+ if (srcstart >= srcend)
+ return;
+
+ if (nullptr != *dest)
+ delete[] * dest;
+ if (nullptr == (*dest = new char[srcend - srcstart + 1]))
+ return;
+
+ dst = *dest;
+
+ for (; srcstart < srcend; dst++, srcstart++) {
+ if (ENDLINE(srcstart)) {
+ while (ENDLINE(srcstart) || WS(srcstart)) srcstart++;
+ *dst = ' ';
+ srcstart--; //because at the end of "for loop" we increment srcstart
+ }
+ else
+ *dst = *srcstart;
+ }
+ *dst = 0;
+}
+
+void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick)
+{
+ if (finder == nullptr) {
+ *storeto = *storetonick = nullptr;
+ return;
+ }
+ while (WS(finder)) finder++;
+ if ((*finder) != '<') {
+ char *finderend = finder + 1;
+ do {
+ if (ENDLINEWS(finderend)) //after endline information continues
+ finderend += 2;
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string
+ } while (ENDLINEWS(finderend));
+ finderend--;
+ while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace
+ if (*finderend != '>') //not '>' at the end of line
+ CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL);
+ else //at the end of line, there's '>'
+ {
+ char *finder2 = finderend;
+ while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start
+ CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL);
+ if (*finder2 == '<') //if we found '<', the rest copy as from nick
+ {
+ finder2--;
+ while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace
+ CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname
+ }
+ }
+ }
+ else {
+ char *finderend = finder + 1;
+ do {
+ if (ENDLINEWS(finderend)) //after endline information continues
+ finderend += 2;
+ while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string
+ } while (ENDLINEWS(finderend));
+ CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy
+ finder = finderend + 1;
+ while (WS(finder)) finder++; //parse whitespace
+ if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick
+ {
+ finderend = finder + 1;
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string
+ finderend--;
+ while (WS(finderend)) finderend--; //find the end of line, no whitespace
+ CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL);
+ }
+ }
+}
+
+void ExtractStringFromLine(char *finder, char **storeto)
+{
+ if (finder == nullptr) {
+ *storeto = nullptr;
+ return;
+ }
+ while (WS(finder)) finder++;
+ char *finderend = finder;
+
+ do {
+ if (ENDLINEWS(finderend)) finderend++; //after endline information continues
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++;
+ } while (ENDLINEWS(finderend));
+ finderend--;
+ while (WS(finderend)) finderend--; //find the end of line, no whitespace
+ CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN);
+}
+
+char *ExtractFromContentType(char *ContentType, char *value)
+{
+ char *lowered = _strdup(ContentType);
+ ToLower(lowered);
+ char *finder = strstr(lowered, value);
+ if (finder == nullptr) {
+ free(lowered);
+ return nullptr;
+ }
+ finder = finder - lowered + ContentType;
+ free(lowered);
+
+ char *temp, *copier;
+ char *CopiedString;
+
+ temp = finder - 1;
+ while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset="
+ if (*temp != ';' && !ENDLINE(temp) && temp != ContentType)
+ return nullptr;
+ finder = finder + mir_strlen(value); //jump over value string
+
+ while (WS(finder)) finder++; //jump over whitespaces
+ temp = finder;
+ while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;)
+ temp--;
+ while (WS(temp)) temp--; //remove whitespaces from the end
+ if (*finder == '\"') { //remove heading and tailing quotes
+ finder++;
+ if (*temp == '\"') temp--;
+ }
+ if (nullptr == (CopiedString = new char[++temp - finder + 1]))
+ return nullptr;
+ for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string
+ *copier = 0; //and end it with zero character
+
+ return CopiedString;
+}
+
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head)
+{
+ for (; items != nullptr; items = items->Next) {
+ //at the start of line
+ //MessageBox(NULL,items->value,items->name,0);
+ if (0 == _strnicmp(items->name, "From", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting from>");
+ #endif
+ ExtractAddressFromLine(items->value, &head->From, &head->FromNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Return-Path", 11)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting return-path>");
+ #endif
+ ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Subject", 7)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting subject>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Subject);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Body", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting body>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Body);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Date", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting date>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Date);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Content-Type", 12)) {
+ if (items->value == nullptr)
+ continue;
+
+ char *ContentType = nullptr, *CharSetStr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting Content-Type>");
+ #endif
+ ExtractStringFromLine(items->value, &ContentType);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ ToLower(ContentType);
+ if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) {
+ head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ delete[] ContentType;
+ }
+ else if (0 == _strnicmp(items->name, "Importance", 10)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting importance>");
+ #endif
+ if (head->Priority != -1) {
+ if (0 == strncmp(items->value, "low", 3))
+ head->Priority = 5;
+ else if (0 == strncmp(items->value, "normal", 6))
+ head->Priority = 3;
+ else if (0 == strncmp(items->value, "high", 4))
+ head->Priority = 1;
+ }
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "X-Priority", 10)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<X-Priority>");
+ #endif
+ if ((*items->value >= '1') && (*items->value <= '5'))
+ head->Priority = *items->value - '0';
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+
+ }
+}
+
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head)
+{
+ struct CShortHeader ShortHeader;
+
+ memset(&ShortHeader, 0, sizeof(struct CShortHeader));
+ ShortHeader.Priority = ShortHeader.CP = -1;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting header>\n");
+ #endif
+ ExtractShortHeader(items, &ShortHeader);
+
+ head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority;
+ CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP;
+ #ifdef DEBUG_DECODE
+ if (NULL != ShortHeader.From)
+ DebugLog(DecodeFile, "<Decoded from>%s</Decoded)\n", ShortHeader.From);
+ if (NULL != ShortHeader.FromNick)
+ DebugLog(DecodeFile, "<Decoded from-nick>%s</Decoded)\n", ShortHeader.FromNick);
+ if (NULL != ShortHeader.ReturnPath)
+ DebugLog(DecodeFile, "<Decoded return-path>%s</Decoded)\n", ShortHeader.ReturnPath);
+ if (NULL != ShortHeader.ReturnPathNick)
+ DebugLog(DecodeFile, "<Decoded return-path nick>%s</Decoded)\n", ShortHeader.ReturnPathNick);
+ if (NULL != ShortHeader.Subject)
+ DebugLog(DecodeFile, "<Decoded subject>%s</Decoded)\n", ShortHeader.Subject);
+ if (NULL != ShortHeader.Date)
+ DebugLog(DecodeFile, "<Decoded date>%s</Decoded)\n", ShortHeader.Date);
+ DebugLog(DecodeFile, "</Extracting header>\n");
+ DebugLog(DecodeFile, "<Convert>\n");
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN);
+
+ #ifdef DEBUG_DECODE
+ if (NULL != head->From)
+ DebugLogW(DecodeFile, L"<Converted from>%s</Converted>\n", head->From);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->FromNick)
+ DebugLogW(DecodeFile, L"<Converted from-nick>%s</Converted>\n", head->FromNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->ReturnPath)
+ DebugLogW(DecodeFile, L"<Converted return-path>%s</Converted>\n", head->ReturnPath);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->ReturnPathNick)
+ DebugLogW(DecodeFile, L"<Converted return-path nick>%s</Converted>\n", head->ReturnPathNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Subject)
+ DebugLogW(DecodeFile, L"<Converted subject>%s</Converted>\n", head->Subject);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Date)
+ DebugLogW(DecodeFile, L"<Converted date>%s</Converted>\n", head->Date);
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Body)
+ DebugLogW(DecodeFile, L"<Converted Body>%s</Converted>\n", head->Body);
+ #endif
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Convert>\n");
+ #endif
+
+ DeleteShortHeaderContent(&ShortHeader);
+
+ // head->From=L"Frommmm";
+ // head->Subject=L"Subject";
+ return;
+}
+
+void DeleteShortHeaderContent(struct CShortHeader *head)
+{
+ if (head->From != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->To != nullptr) DeleteShortNames(head->To);
+ if (head->Cc != nullptr) DeleteShortNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteShortNames(head->Bcc);
+ if (head->Body != nullptr) delete[] head->Body;
+}
+
+void DeleteHeaderContent(struct CHeader *head)
+{
+ if (head->From != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->Body != nullptr) delete[] head->Body;
+ if (head->To != nullptr) DeleteNames(head->To);
+ if (head->Cc != nullptr) DeleteNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteNames(head->Bcc);
+}
+
+void DeleteNames(CMimeNames *Names)
+{
+ CMimeNames *Parser = Names;
+ for (; Parser != nullptr; Parser = Parser->Next) {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ delete[] Parser->ValueNick;
+
+ CMimeNames *Old = Parser;
+ Parser = Parser->Next;
+ delete Old;
+ }
+}
+
+void DeleteShortNames(CShortNames *Names)
+{
+ CShortNames *Parser = Names;
+ for (; Parser != nullptr; Parser = Parser->Next) {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ delete[] Parser->ValueNick;
+
+ CShortNames *Old = Parser;
+ Parser = Parser->Next;
+ delete Old;
+ }
+}
+
+
+void inline ToLower(char *string)
+{
+ for (; *string != 0; string++)
+ if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a';
+}
+
+#define TE_UNKNOWN
+#define TE_QUOTEDPRINTABLE 1
+#define TE_BASE64 2
+struct APartDataType
+{
+ char *Src;//Input
+ char *ContType;
+ int CodePage;
+ char *TransEnc;
+ uint8_t TransEncType; //TE_something
+ char *body;
+ int bodyLen;
+ wchar_t *wBody;
+};
+
+
+void ParseAPart(APartDataType *data)
+{
+ size_t len = mir_strlen(data->Src);
+ try {
+ char *finder = data->Src;
+ char *prev1, *prev2, *prev3;
+
+ while (finder <= (data->Src + len)) {
+ while (ENDLINEWS(finder)) finder++;
+
+ //at the start of line
+ if (finder > data->Src) {
+ if (*(finder - 2) == '\r' || *(finder - 2) == '\n')
+ *(finder - 2) = 0;
+ if (*(finder - 1) == '\r' || *(finder - 1) == '\n')
+ *(finder - 1) = 0;
+ }
+ prev1 = finder;
+
+ while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++;
+ if (ENDLINE(finder) || EOS(finder)) {
+ // no ":" in the line? here the body begins;
+ data->body = prev1;
+ break;
+ }
+ prev2 = finder++;
+
+ while (WS(finder) && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev3 = finder;
+ else
+ break;
+
+ do {
+ if (ENDLINEWS(finder)) finder += 2; //after endline information continues
+ while (!ENDLINE(finder) && !EOS(finder)) finder++;
+ } while (ENDLINEWS(finder));
+
+ if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) {
+ data->ContType = prev3;
+ }
+ else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) {
+ data->TransEnc = prev3;
+ }
+
+ if (EOS(finder))
+ break;
+ finder++;
+ if (ENDLINE(finder)) {
+ finder++;
+ if (ENDLINE(finder)) {
+ // end of headers. message body begins
+ if (finder > data->Src) {
+ if (*(finder - 2) == '\r' || *(finder - 2) == '\n')
+ *(finder - 2) = 0;
+ if (*(finder - 1) == '\r' || *(finder - 1) == '\n')
+ *(finder - 1) = 0;
+ }
+ finder++;
+ if (ENDLINE(finder))finder++;
+ prev1 = finder;
+ while (!EOS(finder + 1))finder++;
+ if (ENDLINE(finder))finder--;
+ prev2 = finder;
+ if (prev2 > prev1) { // yes, we have body
+ data->body = prev1;
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch (...) {
+ MessageBox(nullptr, TranslateT("Translate header error"), L"", 0);
+ }
+ if (data->body) data->bodyLen = (int)mir_strlen(data->body);
+}
+
+//from decode.cpp
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+wchar_t *ParseMultipartBody(char *src, char *bond)
+{
+ char *srcback = _strdup(src);
+ size_t sizebond = mir_strlen(bond);
+ int numparts = 1;
+ int i;
+ char *courbond = srcback;
+ wchar_t *dest;
+ for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond);
+ APartDataType *partData = new APartDataType[numparts];
+ memset(partData, 0, sizeof(APartDataType) * numparts);
+ partData[0].Src = courbond = srcback;
+ for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) {
+ *(courbond - 2) = 0;
+ partData[i].Src = courbond + sizebond;
+ while (ENDLINE(partData[i].Src)) partData[i].Src++;
+ }
+ size_t resultSize = 0;
+ for (i = 0; i < numparts; i++) {
+ ParseAPart(&partData[i]);
+ if (partData[i].body) {
+ if (partData[i].TransEnc) {
+ if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64;
+ else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE;
+ }
+ if (partData[i].ContType) {
+ char *CharSetStr;
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) {
+ partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ }
+ if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) {
+ char *localBody = nullptr;
+ switch (partData[i].TransEncType) {
+ case TE_BASE64:
+ {
+ int size = partData[i].bodyLen * 3 / 4 + 5;
+ localBody = new char[size + 1];
+ DecodeBase64(partData[i].body, localBody, size);
+ }break;
+ case TE_QUOTEDPRINTABLE:
+ {
+ int size = partData[i].bodyLen + 2;
+ localBody = new char[size + 1];
+ DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE);
+ }break;
+ }
+ ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody);
+ if (localBody) delete[] localBody;
+ }
+ else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) {
+ //Multipart in mulitipart recursive? should be SPAM. Ah well
+ char *bondary = nullptr;
+ if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) {
+ partData[i].wBody = ParseMultipartBody(partData[i].body, bondary);
+ delete[] bondary;
+ }
+ else goto FailBackRaw; //multipart with no boundary? badly formatted messages.
+ }
+ else {
+FailBackRaw:
+ ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody);
+ }
+ resultSize += mir_wstrlen(partData[i].wBody);
+ }// if (partData[i].body)
+ resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet
+ }
+ dest = new wchar_t[resultSize + 1];
+ size_t destpos = 0;
+ for (i = 0; i < numparts; i++) {
+ if (i) { // part before first boudary should not have headers
+ char infoline[1024]; size_t linesize = 0;
+ mir_snprintf(infoline, "%s %d", Translate("Part"), i);
+ linesize = mir_strlen(infoline);
+ if (partData[i].TransEnc) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc);
+ linesize = mir_strlen(infoline);
+ }
+ if (partData[i].ContType) {
+ char *CharSetStr = strchr(partData[i].ContType, ';');
+ if (CharSetStr) {
+ CharSetStr[0] = 0;
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ partData[i].ContType = CharSetStr + 1;
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ }
+ else {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ }
+ }
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n");
+ {
+ wchar_t *temp = nullptr;
+ dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet;
+ destpos += 3;
+ ConvertStringToUnicode(infoline, CP_ACP, &temp);
+ size_t wsize = mir_wstrlen(temp);
+ mir_wstrcpy(&dest[destpos], temp);
+ destpos += wsize;
+ delete[] temp;
+ }
+ } // if (i)
+
+ if (partData[i].wBody) {
+ size_t wsize = mir_wstrlen(partData[i].wBody);
+ mir_wstrcpy(&dest[destpos], partData[i].wBody);
+ destpos += wsize;
+ delete[] partData[i].wBody;
+ }
+ }
+
+ free(srcback);
+ delete[] partData;
+ dest[resultSize] = 0;//just in case
+ return dest;
+}
diff --git a/protocols/YAMN/src/main.cpp b/protocols/YAMN/src/main.cpp index 72b831f765..c4979af1fb 100644 --- a/protocols/YAMN/src/main.cpp +++ b/protocols/YAMN/src/main.cpp @@ -1,324 +1,324 @@ -/* - * YAMN plugin main file - * Miranda homepage: http://miranda-icq.sourceforge.net/ - * YAMN homepage: http://www.majvan.host.sk/Projekty/YAMN - * - * initializes all variables for further work - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -wchar_t ProfileName[MAX_PATH]; -wchar_t UserDirectory[MAX_PATH]; - -wchar_t szMirandaDir[MAX_PATH]; -wchar_t szProfileDir[MAX_PATH]; - -BOOL UninstallPlugins; - -HANDLE hAccountFolder; - -HINSTANCE *hDllPlugins; -static int iDllPlugins = 0; - -YAMN_VARIABLES YAMNVar; - -CMPlugin g_plugin; - -HANDLE hNewMailHook; -HANDLE NoWriterEV; -HANDLE hTTButton; - -UINT SecTimer; - -#define FIXED_TAB_SIZE 100 // default value for fixed width tabs - -static void GetProfileDirectory(wchar_t *szPath, int cbPath) -//This is copied from Miranda's sources. In 0.2.1.0 it is needed, in newer vesions of Miranda use MS_DB_GETPROFILEPATH service -{ - wchar_t tszOldPath[MAX_PATH]; - Profile_GetPathW(_countof(tszOldPath), tszOldPath); - mir_wstrcat(tszOldPath, L"\\*.book"); - - VARSW ptszNewPath(L"%miranda_userdata%"); - - SHFILEOPSTRUCT file_op = { - nullptr, - FO_MOVE, - tszOldPath, - ptszNewPath, - FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT, - false, - nullptr, - L""}; - SHFileOperation(&file_op); - - wcsncpy(szPath, ptszNewPath, cbPath); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - -///////////////////////////////////////////////////////////////////////////////////////// - -PLUGININFOEX pluginInfoEx = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {B047A7E5-027A-4CFC-8B18-EDA8345D2790} - {0xb047a7e5, 0x27a, 0x4cfc, {0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90}} -}; - -CMPlugin::CMPlugin() : - PLUGIN<CMPlugin>(YAMN_DBMODULE, pluginInfoEx) -{ - RegisterProtocol(PROTOTYPE_VIRTUAL); - SetUniqueId("Id"); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// The callback function - -BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr) -{ - // Convert code page string to number - UINT cp = _wtoi(cpStr); - if (!IsValidCodePage(cp)) - return TRUE; - - // Get Code Page name - CPINFOEX info; - if (GetCPInfoEx(cp, 0, &info)) { - for (int i = 1; i < CPLENALL; i++) if (CodePageNamesAll[i].CP == cp) { - CodePageNamesAll[i].isValid = TRUE; - CPLENSUPP++; - break; - } - } - return TRUE; -} - -int SystemModulesLoaded(WPARAM, LPARAM) -{ - //Insert "Check mail (YAMN)" item to Miranda's menu - CMenuItem mi(&g_plugin); - - SET_UID(mi, 0xa01ff3d9, 0x53cb, 0x4406, 0x85, 0xd9, 0xf1, 0x90, 0x3a, 0x94, 0xed, 0xf4); - mi.position = 0xb0000000; - mi.hIcolibItem = g_plugin.getIconHandle(IDI_CHECKMAIL); - mi.name.a = LPGEN("Check &mail (All Account)"); - mi.pszService = MS_YAMN_FORCECHECK; - Menu_AddMainMenuItem(&mi); - - SET_UID(mi, 0xfe22191f, 0x40c8, 0x479f, 0x93, 0x5d, 0xa5, 0x17, 0x1f, 0x57, 0x2f, 0xcb); - mi.name.a = LPGEN("Check &mail (This Account)"); - mi.pszService = MS_YAMN_CLISTCONTEXT; - Menu_AddContactMenuItem(&mi, YAMN_DBMODULE); - - SET_UID(mi, 0x147c7800, 0x12d0, 0x4209, 0xab, 0xcc, 0xfa, 0x64, 0xc6, 0xb0, 0xa6, 0xeb); - mi.hIcolibItem = g_plugin.getIconHandle(IDI_LAUNCHAPP); - mi.name.a = LPGEN("Launch application"); - mi.pszService = MS_YAMN_CLISTCONTEXTAPP; - Menu_AddContactMenuItem(&mi, YAMN_DBMODULE); - - if (hAccountFolder = FoldersRegisterCustomPathW(LPGEN("YAMN"), LPGEN("YAMN Account Folder"), UserDirectory)) - FoldersGetCustomPathW(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory); - - RegisterPOP3Plugin(0, 0); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static IconItem iconList[] = -{ - {LPGEN("Check mail"), "YAMN_Check", IDI_CHECKMAIL}, - {LPGEN("Launch application"), "YAMN_Launch", IDI_LAUNCHAPP}, - {LPGEN("New Mail"), "YAMN_NewMail", IDI_NEWMAIL}, - {LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_BADCONNECT}, -}; - -void LoadIcons() -{ - g_plugin.registerIcon("YAMN", iconList); -} - -static void LoadPlugins() -{ - wchar_t szSearchPath[MAX_PATH]; - mir_snwprintf(szSearchPath, L"%s\\Plugins\\YAMN\\*.dll", szMirandaDir); - - hDllPlugins = nullptr; - - WIN32_FIND_DATA fd; - HANDLE hFind = FindFirstFile(szSearchPath, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too - wchar_t *dot = wcsrchr(fd.cFileName, '.'); - if (dot == nullptr) - continue; - - // we have a dot - int len = (int)mir_wstrlen(fd.cFileName); // find the length of the string - wchar_t *end = fd.cFileName + len; // get a pointer to the NULL - int safe = (end - dot) - 1; // figure out how many chars after the dot are "safe", not including NULL - - if ((safe != 3) || (mir_wstrcmpi(dot + 1, L"dll") != 0)) //not bound, however the "dll" string should mean only 3 chars are compared - continue; - - wchar_t szPluginPath[MAX_PATH]; - mir_snwprintf(szPluginPath, L"%s\\Plugins\\YAMN\\%s", szMirandaDir, fd.cFileName); - HINSTANCE hDll = LoadLibrary(szPluginPath); - if (hDll == nullptr) - continue; - - LOADFILTERFCN LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter"); - if (nullptr == LoadFilter) { - FreeLibrary(hDll); - hDll = nullptr; - continue; - } - - if (!LoadFilter(GetFcnPtrSvc)) { - FreeLibrary(hDll); - hDll = nullptr; - } - - if (hDll != nullptr) { - hDllPlugins = (HINSTANCE *)realloc(hDllPlugins, (iDllPlugins + 1) * sizeof(HINSTANCE)); - hDllPlugins[iDllPlugins++] = hDll; - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } -} - -int CMPlugin::Load() -{ - // we get the Miranda Root Path - PathToAbsoluteW(L".", szMirandaDir); - - // retrieve the current profile name - Profile_GetNameW(_countof(ProfileName), ProfileName); - wchar_t *fc = wcsrchr(ProfileName, '.'); - if (fc != nullptr) *fc = 0; - - // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file - GetProfileDirectory(UserDirectory, _countof(UserDirectory)); - - // Enumerate all the code pages available for the System Locale - EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED); - CodePageNamesSupp = new _tcptable[CPLENSUPP]; - for (int i = 0, k = 0; i < CPLENALL; i++) - if (CodePageNamesAll[i].isValid) { - CodePageNamesSupp[k] = CodePageNamesAll[i]; - k++; - } - - if (nullptr == (NoWriterEV = CreateEvent(nullptr, TRUE, TRUE, nullptr))) - return 1; - if (nullptr == (WriteToFileEV = CreateEvent(nullptr, FALSE, FALSE, nullptr))) - return 1; - if (nullptr == (ExitEV = CreateEvent(nullptr, TRUE, FALSE, nullptr))) - return 1; - - PosX = g_plugin.getDword(YAMN_DBPOSX, 0); - PosY = g_plugin.getDword(YAMN_DBPOSY, 0); - SizeX = g_plugin.getDword(YAMN_DBSIZEX, 800); - SizeY = g_plugin.getDword(YAMN_DBSIZEY, 200); - - HeadPosX = g_plugin.getDword(YAMN_DBMSGPOSX, 0); - HeadPosY = g_plugin.getDword(YAMN_DBMSGPOSY, 0); - HeadSizeX = g_plugin.getDword(YAMN_DBMSGSIZEX, 690); - HeadSizeY = g_plugin.getDword(YAMN_DBMSGSIZEY, 300); - HeadSplitPos = g_plugin.getWord(YAMN_DBMSGPOSSPLIT, 250); - - optDateTime = g_plugin.getByte(YAMN_DBTIMEOPTIONS, optDateTime); - - // Create new window queues for broadcast messages - YAMNVar.MessageWnds = WindowList_Create(); - YAMNVar.NewMailAccountWnd = WindowList_Create(); - YAMNVar.Shutdown = FALSE; - - hCurSplitNS = LoadCursor(nullptr, IDC_SIZENS); - hCurSplitWE = LoadCursor(nullptr, IDC_SIZEWE); - - #ifdef _DEBUG - InitDebug(); - #endif - - CreateServiceFunctions(); - - g_plugin.addSound(YAMN_NEWMAILSOUND, L"YAMN", YAMN_NEWMAILSNDDESC); - g_plugin.addSound(YAMN_CONNECTFAILSOUND, L"YAMN", YAMN_CONNECTFAILSNDDESC); - - HookEvents(); - - LoadIcons(); - LoadPlugins(); - - HOTKEYDESC hkd = {}; - hkd.pszName = "YAMN_hotkey"; - hkd.pszService = MS_YAMN_FORCECHECK; - hkd.szSection.a = YAMN_DBMODULE; - hkd.szDescription.a = LPGEN("Check mail"); - hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11); - g_plugin.addHotkey(&hkd); - - //Create thread that will be executed every second - if (!(SecTimer = SetTimer(nullptr, 0, 1000, TimerProc))) - return 1; - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void UnloadPlugins() -{ - if (hDllPlugins == nullptr) - return; - - for (int i = iDllPlugins - 1; i >= 0; i--) { - if (FreeLibrary(hDllPlugins[i])) { - hDllPlugins[i] = nullptr; //for safety - iDllPlugins--; - } - } - free((void *)hDllPlugins); - hDllPlugins = nullptr; -} - -int CMPlugin::Unload() -{ - #ifdef _DEBUG - UnInitDebug(); - #endif - - WindowList_Destroy(YAMNVar.MessageWnds); - WindowList_Destroy(YAMNVar.NewMailAccountWnd); - - DestroyCursor(hCurSplitNS); - DestroyCursor(hCurSplitWE); - - CloseHandle(NoWriterEV); - CloseHandle(WriteToFileEV); - CloseHandle(ExitEV); - - UnloadPlugins(); - - delete[] CodePageNamesSupp; - return 0; -} +/*
+ * YAMN plugin main file
+ * Miranda homepage: http://miranda-icq.sourceforge.net/
+ * YAMN homepage: http://www.majvan.host.sk/Projekty/YAMN
+ *
+ * initializes all variables for further work
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+wchar_t ProfileName[MAX_PATH];
+wchar_t UserDirectory[MAX_PATH];
+
+wchar_t szMirandaDir[MAX_PATH];
+wchar_t szProfileDir[MAX_PATH];
+
+BOOL UninstallPlugins;
+
+HANDLE hAccountFolder;
+
+HINSTANCE *hDllPlugins;
+static int iDllPlugins = 0;
+
+YAMN_VARIABLES YAMNVar;
+
+CMPlugin g_plugin;
+
+HANDLE hNewMailHook;
+HANDLE NoWriterEV;
+HANDLE hTTButton;
+
+UINT SecTimer;
+
+#define FIXED_TAB_SIZE 100 // default value for fixed width tabs
+
+static void GetProfileDirectory(wchar_t *szPath, int cbPath)
+//This is copied from Miranda's sources. In 0.2.1.0 it is needed, in newer vesions of Miranda use MS_DB_GETPROFILEPATH service
+{
+ wchar_t tszOldPath[MAX_PATH];
+ Profile_GetPathW(_countof(tszOldPath), tszOldPath);
+ mir_wstrcat(tszOldPath, L"\\*.book");
+
+ VARSW ptszNewPath(L"%miranda_userdata%");
+
+ SHFILEOPSTRUCT file_op = {
+ nullptr,
+ FO_MOVE,
+ tszOldPath,
+ ptszNewPath,
+ FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT,
+ false,
+ nullptr,
+ L""};
+ SHFileOperation(&file_op);
+
+ wcsncpy(szPath, ptszNewPath, cbPath);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {B047A7E5-027A-4CFC-8B18-EDA8345D2790}
+ {0xb047a7e5, 0x27a, 0x4cfc, {0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(YAMN_DBMODULE, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId("Id");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// The callback function
+
+BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr)
+{
+ // Convert code page string to number
+ UINT cp = _wtoi(cpStr);
+ if (!IsValidCodePage(cp))
+ return TRUE;
+
+ // Get Code Page name
+ CPINFOEX info;
+ if (GetCPInfoEx(cp, 0, &info)) {
+ for (int i = 1; i < CPLENALL; i++) if (CodePageNamesAll[i].CP == cp) {
+ CodePageNamesAll[i].isValid = TRUE;
+ CPLENSUPP++;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM)
+{
+ //Insert "Check mail (YAMN)" item to Miranda's menu
+ CMenuItem mi(&g_plugin);
+
+ SET_UID(mi, 0xa01ff3d9, 0x53cb, 0x4406, 0x85, 0xd9, 0xf1, 0x90, 0x3a, 0x94, 0xed, 0xf4);
+ mi.position = 0xb0000000;
+ mi.hIcolibItem = g_plugin.getIconHandle(IDI_CHECKMAIL);
+ mi.name.a = LPGEN("Check &mail (All Account)");
+ mi.pszService = MS_YAMN_FORCECHECK;
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xfe22191f, 0x40c8, 0x479f, 0x93, 0x5d, 0xa5, 0x17, 0x1f, 0x57, 0x2f, 0xcb);
+ mi.name.a = LPGEN("Check &mail (This Account)");
+ mi.pszService = MS_YAMN_CLISTCONTEXT;
+ Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ SET_UID(mi, 0x147c7800, 0x12d0, 0x4209, 0xab, 0xcc, 0xfa, 0x64, 0xc6, 0xb0, 0xa6, 0xeb);
+ mi.hIcolibItem = g_plugin.getIconHandle(IDI_LAUNCHAPP);
+ mi.name.a = LPGEN("Launch application");
+ mi.pszService = MS_YAMN_CLISTCONTEXTAPP;
+ Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ if (hAccountFolder = FoldersRegisterCustomPathW(LPGEN("YAMN"), LPGEN("YAMN Account Folder"), UserDirectory))
+ FoldersGetCustomPathW(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory);
+
+ RegisterPOP3Plugin(0, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static IconItem iconList[] =
+{
+ {LPGEN("Check mail"), "YAMN_Check", IDI_CHECKMAIL},
+ {LPGEN("Launch application"), "YAMN_Launch", IDI_LAUNCHAPP},
+ {LPGEN("New Mail"), "YAMN_NewMail", IDI_NEWMAIL},
+ {LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_BADCONNECT},
+};
+
+void LoadIcons()
+{
+ g_plugin.registerIcon("YAMN", iconList);
+}
+
+static void LoadPlugins()
+{
+ wchar_t szSearchPath[MAX_PATH];
+ mir_snwprintf(szSearchPath, L"%s\\Plugins\\YAMN\\*.dll", szMirandaDir);
+
+ hDllPlugins = nullptr;
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearchPath, &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too
+ wchar_t *dot = wcsrchr(fd.cFileName, '.');
+ if (dot == nullptr)
+ continue;
+
+ // we have a dot
+ int len = (int)mir_wstrlen(fd.cFileName); // find the length of the string
+ wchar_t *end = fd.cFileName + len; // get a pointer to the NULL
+ int safe = (end - dot) - 1; // figure out how many chars after the dot are "safe", not including NULL
+
+ if ((safe != 3) || (mir_wstrcmpi(dot + 1, L"dll") != 0)) //not bound, however the "dll" string should mean only 3 chars are compared
+ continue;
+
+ wchar_t szPluginPath[MAX_PATH];
+ mir_snwprintf(szPluginPath, L"%s\\Plugins\\YAMN\\%s", szMirandaDir, fd.cFileName);
+ HINSTANCE hDll = LoadLibrary(szPluginPath);
+ if (hDll == nullptr)
+ continue;
+
+ LOADFILTERFCN LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter");
+ if (nullptr == LoadFilter) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ continue;
+ }
+
+ if (!LoadFilter(GetFcnPtrSvc)) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ }
+
+ if (hDll != nullptr) {
+ hDllPlugins = (HINSTANCE *)realloc(hDllPlugins, (iDllPlugins + 1) * sizeof(HINSTANCE));
+ hDllPlugins[iDllPlugins++] = hDll;
+ }
+ } while (FindNextFile(hFind, &fd));
+
+ FindClose(hFind);
+ }
+}
+
+int CMPlugin::Load()
+{
+ // we get the Miranda Root Path
+ PathToAbsoluteW(L".", szMirandaDir);
+
+ // retrieve the current profile name
+ Profile_GetNameW(_countof(ProfileName), ProfileName);
+ wchar_t *fc = wcsrchr(ProfileName, '.');
+ if (fc != nullptr) *fc = 0;
+
+ // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file
+ GetProfileDirectory(UserDirectory, _countof(UserDirectory));
+
+ // Enumerate all the code pages available for the System Locale
+ EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED);
+ CodePageNamesSupp = new _tcptable[CPLENSUPP];
+ for (int i = 0, k = 0; i < CPLENALL; i++)
+ if (CodePageNamesAll[i].isValid) {
+ CodePageNamesSupp[k] = CodePageNamesAll[i];
+ k++;
+ }
+
+ if (nullptr == (NoWriterEV = CreateEvent(nullptr, TRUE, TRUE, nullptr)))
+ return 1;
+ if (nullptr == (WriteToFileEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ return 1;
+ if (nullptr == (ExitEV = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
+ return 1;
+
+ PosX = g_plugin.getDword(YAMN_DBPOSX, 0);
+ PosY = g_plugin.getDword(YAMN_DBPOSY, 0);
+ SizeX = g_plugin.getDword(YAMN_DBSIZEX, 800);
+ SizeY = g_plugin.getDword(YAMN_DBSIZEY, 200);
+
+ HeadPosX = g_plugin.getDword(YAMN_DBMSGPOSX, 0);
+ HeadPosY = g_plugin.getDword(YAMN_DBMSGPOSY, 0);
+ HeadSizeX = g_plugin.getDword(YAMN_DBMSGSIZEX, 690);
+ HeadSizeY = g_plugin.getDword(YAMN_DBMSGSIZEY, 300);
+ HeadSplitPos = g_plugin.getWord(YAMN_DBMSGPOSSPLIT, 250);
+
+ optDateTime = g_plugin.getByte(YAMN_DBTIMEOPTIONS, optDateTime);
+
+ // Create new window queues for broadcast messages
+ YAMNVar.MessageWnds = WindowList_Create();
+ YAMNVar.NewMailAccountWnd = WindowList_Create();
+ YAMNVar.Shutdown = FALSE;
+
+ hCurSplitNS = LoadCursor(nullptr, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(nullptr, IDC_SIZEWE);
+
+ #ifdef _DEBUG
+ InitDebug();
+ #endif
+
+ CreateServiceFunctions();
+
+ g_plugin.addSound(YAMN_NEWMAILSOUND, L"YAMN", YAMN_NEWMAILSNDDESC);
+ g_plugin.addSound(YAMN_CONNECTFAILSOUND, L"YAMN", YAMN_CONNECTFAILSNDDESC);
+
+ HookEvents();
+
+ LoadIcons();
+ LoadPlugins();
+
+ HOTKEYDESC hkd = {};
+ hkd.pszName = "YAMN_hotkey";
+ hkd.pszService = MS_YAMN_FORCECHECK;
+ hkd.szSection.a = YAMN_DBMODULE;
+ hkd.szDescription.a = LPGEN("Check mail");
+ hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11);
+ g_plugin.addHotkey(&hkd);
+
+ //Create thread that will be executed every second
+ if (!(SecTimer = SetTimer(nullptr, 0, 1000, TimerProc)))
+ return 1;
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void UnloadPlugins()
+{
+ if (hDllPlugins == nullptr)
+ return;
+
+ for (int i = iDllPlugins - 1; i >= 0; i--) {
+ if (FreeLibrary(hDllPlugins[i])) {
+ hDllPlugins[i] = nullptr; //for safety
+ iDllPlugins--;
+ }
+ }
+ free((void *)hDllPlugins);
+ hDllPlugins = nullptr;
+}
+
+int CMPlugin::Unload()
+{
+ #ifdef _DEBUG
+ UnInitDebug();
+ #endif
+
+ WindowList_Destroy(YAMNVar.MessageWnds);
+ WindowList_Destroy(YAMNVar.NewMailAccountWnd);
+
+ DestroyCursor(hCurSplitNS);
+ DestroyCursor(hCurSplitWE);
+
+ CloseHandle(NoWriterEV);
+ CloseHandle(WriteToFileEV);
+ CloseHandle(ExitEV);
+
+ UnloadPlugins();
+
+ delete[] CodePageNamesSupp;
+ return 0;
+}
diff --git a/protocols/YAMN/src/main.h b/protocols/YAMN/src/main.h index cdcf5c285c..971ba43c9f 100644 --- a/protocols/YAMN/src/main.h +++ b/protocols/YAMN/src/main.h @@ -1,37 +1,37 @@ -#ifndef __MAIN_H -#define __MAIN_H - -#define YAMN_NEWMAILSNDDESC LPGENW("New mail message") -#define YAMN_CONNECTFAILSNDDESC LPGENW("Connect failed") -#define YAMN_CONNECTFAILSOUND "YAMN/Sound/ConnectFail" -#define YAMN_NEWMAILSOUND "YAMN/Sound/NewMail" - -#define YAMN_DBMODULE "YAMN" -#define YAMN_DBPOSX "MailBrowserWinX" -#define YAMN_DBPOSY "MailBrowserWinY" -#define YAMN_DBSIZEX "MailBrowserWinW" -#define YAMN_DBSIZEY "MailBrowserWinH" -#define YAMN_DBMSGPOSX "MailMessageWinX" -#define YAMN_DBMSGPOSY "MailMessageWinY" -#define YAMN_DBMSGSIZEX "MailMessageWinW" -#define YAMN_DBMSGSIZEY "MailMessageWinH" -#define YAMN_DBMSGPOSSPLIT "MailMessageSplitY" -#define YAMN_TTBFCHECK "ForceCheckTTB" -#define YAMN_CLOSEDELETE "CloseOnDelete" -#define YAMN_DBTIMEOPTIONS "MailBrowserTimeOpts" - -#define YAMN_DEFAULTHK MAKEWORD(VK_F11,MOD_CONTROL) - -#define SHOWDATELONG 0x01 -#define SHOWDATENOTODAY 0x02 -#define SHOWDATENOSECONDS 0x04 - -extern unsigned char optDateTime; - -// Loading Icon and checking for icolib -void LoadIcons(); - -typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn); - -#endif - +#ifndef __MAIN_H
+#define __MAIN_H
+
+#define YAMN_NEWMAILSNDDESC LPGENW("New mail message")
+#define YAMN_CONNECTFAILSNDDESC LPGENW("Connect failed")
+#define YAMN_CONNECTFAILSOUND "YAMN/Sound/ConnectFail"
+#define YAMN_NEWMAILSOUND "YAMN/Sound/NewMail"
+
+#define YAMN_DBMODULE "YAMN"
+#define YAMN_DBPOSX "MailBrowserWinX"
+#define YAMN_DBPOSY "MailBrowserWinY"
+#define YAMN_DBSIZEX "MailBrowserWinW"
+#define YAMN_DBSIZEY "MailBrowserWinH"
+#define YAMN_DBMSGPOSX "MailMessageWinX"
+#define YAMN_DBMSGPOSY "MailMessageWinY"
+#define YAMN_DBMSGSIZEX "MailMessageWinW"
+#define YAMN_DBMSGSIZEY "MailMessageWinH"
+#define YAMN_DBMSGPOSSPLIT "MailMessageSplitY"
+#define YAMN_TTBFCHECK "ForceCheckTTB"
+#define YAMN_CLOSEDELETE "CloseOnDelete"
+#define YAMN_DBTIMEOPTIONS "MailBrowserTimeOpts"
+
+#define YAMN_DEFAULTHK MAKEWORD(VK_F11,MOD_CONTROL)
+
+#define SHOWDATELONG 0x01
+#define SHOWDATENOTODAY 0x02
+#define SHOWDATENOSECONDS 0x04
+
+extern unsigned char optDateTime;
+
+// Loading Icon and checking for icolib
+void LoadIcons();
+
+typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn);
+
+#endif
+
diff --git a/protocols/YAMN/src/proto/netlib.cpp b/protocols/YAMN/src/proto/netlib.cpp index cf477e8219..726860e459 100644 --- a/protocols/YAMN/src/proto/netlib.cpp +++ b/protocols/YAMN/src/proto/netlib.cpp @@ -1,232 +1,232 @@ -/* - * This code implements communication based on Miranda netlib library - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -BOOL SSLLoaded = FALSE; -HNETLIBUSER hNetlibUser = nullptr; - -void __stdcall SSL_DebugLog(const char *fmt, ...) -{ - char str[4096]; - va_list vararg; - - va_start(vararg, fmt); - int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg); - if (tBytes == 0) - return; - - if (tBytes > 0) - str[tBytes] = 0; - else - str[sizeof(str) - 1] = 0; - - Netlib_Log(hNetlibUser, str); - va_end(vararg); -} - -HANDLE RegisterNLClient(char *name) -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<Register PROXY support>"); - #endif - - NETLIBUSER nlu = {}; - nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS; - nlu.szDescriptiveName.a = name; - nlu.szSettingsModule = (char *)name; - hNetlibUser = Netlib_RegisterUser(&nlu); - - #ifdef DEBUG_COMM - if (NULL == hNetlibUser) - DebugLog(CommFile, "<error></Register PROXY support>\n"); - else - DebugLog(CommFile, "</Register PROXY support>\n"); - #endif - return hNetlibUser; -} - -//Move connection to SSL -void CNLClient::SSLify() throw(DWORD) -{ - #ifdef DEBUG_COMM - SSL_DebugLog("Staring SSL..."); - #endif - int socket = Netlib_GetSocket(hConnection); - if (socket != INVALID_SOCKET) { - #ifdef DEBUG_COMM - SSL_DebugLog("Staring netlib core SSL"); - #endif - if (Netlib_StartSsl(hConnection, nullptr)) { - #ifdef DEBUG_COMM - SSL_DebugLog("Netlib core SSL started"); - #endif - isTLSed = true; - SSLLoaded = TRUE; - return; - } - } - - //ssl could not be created - throw NetworkError = (uint32_t)ESSL_CREATESSL; -} - -//Connects to the server through the sock -//if not success, exception is throwed -void CNLClient::Connect(const char *servername, const int port) throw(DWORD) -{ - NetworkError = SystemError = 0; - isTLSed = false; - - #ifdef DEBUG_COMM - DebugLog(CommFile, "<connect>\n"); - #endif - try { - if (nullptr == (hConnection = Netlib_OpenConnection(hNetlibUser, servername, port))) { - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_CONNECT; - } - #ifdef DEBUG_COMM - DebugLog(CommFile, "</connect>\n"); - #endif - return; - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></connect>\n"); - #endif - throw; - } -} - -//Performs a simple query -// query- command to send -int CNLClient::LocalNetlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags) -{ - return Netlib_Send(hConn, buf, len, flags); -} - -void CNLClient::Send(const char *query) throw(DWORD) -{ - unsigned int Sent; - - if (nullptr == query) - return; - if (hConnection == nullptr) - return; - #ifdef DEBUG_COMM - DebugLog(CommFile, "<send>%s", query); - #endif - try { - if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_strlen(query)) { - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_SEND; - } - #ifdef DEBUG_COMM - DebugLog(CommFile, "</send>\n"); - #endif - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></send>\n"); - #endif - throw; - } -} - -//Reads data from socket -// buf- buffer where to store max. buflen of received characters -// if buf is NULL, creates buffer of buflen size -// buf is NULL by default -//You need free() returned buffer, which can be allocated in this function -//if not success, exception is throwed - -int CNLClient::LocalNetlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags) -{ - int iReturn = Netlib_Recv(hConn, buf, len, flags); - if (isTLSed) { - #ifdef DEBUG_COMM - SSL_DebugLog("SSL recv: %s", buf); - #endif - } - - return iReturn; -} - -char *CNLClient::Recv(char *buf, int buflen) throw(DWORD) -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<reading>"); - #endif - try { - if (buf == nullptr) - buf = (char *)malloc(sizeof(char) * (buflen + 1)); - if (buf == nullptr) - throw NetworkError = (uint32_t)ENL_RECVALLOC; - - if (!isTLSed) { - NETLIBSELECT nls = {}; - nls.dwTimeout = 60000; - nls.hReadConns[0] = hConnection; - switch (Netlib_Select(&nls)) { - case SOCKET_ERROR: - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - case 0: // time out! - free(buf); - throw NetworkError = (uint32_t)ENL_TIMEOUT; - } - } - - memset(buf, 0, buflen); - if (SOCKET_ERROR == (Rcv = LocalNetlib_Recv(hConnection, buf, buflen, MSG_DUMPASTEXT))) { - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - } - if (!Rcv) { - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - } - #ifdef DEBUG_COMM - *(buf + Rcv) = 0; //end the buffer to write it to file - DebugLog(CommFile, "%s", buf); - DebugLog(CommFile, "</reading>\n"); - #endif - return(buf); - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></reading>\n"); - #endif - throw; - } -} - -//Closes netlib connection -void CNLClient::Disconnect() -{ - Netlib_CloseHandle(hConnection); - hConnection = nullptr; -} - -//Uninitializes netlib library -void UnregisterNLClient() -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<Unregister PROXY support>"); - #endif - - Netlib_CloseHandle(hNetlibUser); - hNetlibUser = nullptr; - #ifdef DEBUG_COMM - DebugLog(CommFile, "</Unregister PROXY support>\n"); - #endif -} +/*
+ * This code implements communication based on Miranda netlib library
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+BOOL SSLLoaded = FALSE;
+HNETLIBUSER hNetlibUser = nullptr;
+
+void __stdcall SSL_DebugLog(const char *fmt, ...)
+{
+ char str[4096];
+ va_list vararg;
+
+ va_start(vararg, fmt);
+ int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg);
+ if (tBytes == 0)
+ return;
+
+ if (tBytes > 0)
+ str[tBytes] = 0;
+ else
+ str[sizeof(str) - 1] = 0;
+
+ Netlib_Log(hNetlibUser, str);
+ va_end(vararg);
+}
+
+HANDLE RegisterNLClient(char *name)
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Register PROXY support>");
+ #endif
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szDescriptiveName.a = name;
+ nlu.szSettingsModule = (char *)name;
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ #ifdef DEBUG_COMM
+ if (NULL == hNetlibUser)
+ DebugLog(CommFile, "<error></Register PROXY support>\n");
+ else
+ DebugLog(CommFile, "</Register PROXY support>\n");
+ #endif
+ return hNetlibUser;
+}
+
+//Move connection to SSL
+void CNLClient::SSLify() throw(DWORD)
+{
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Staring SSL...");
+ #endif
+ int socket = Netlib_GetSocket(hConnection);
+ if (socket != INVALID_SOCKET) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Staring netlib core SSL");
+ #endif
+ if (Netlib_StartSsl(hConnection, nullptr)) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Netlib core SSL started");
+ #endif
+ isTLSed = true;
+ SSLLoaded = TRUE;
+ return;
+ }
+ }
+
+ //ssl could not be created
+ throw NetworkError = (uint32_t)ESSL_CREATESSL;
+}
+
+//Connects to the server through the sock
+//if not success, exception is throwed
+void CNLClient::Connect(const char *servername, const int port) throw(DWORD)
+{
+ NetworkError = SystemError = 0;
+ isTLSed = false;
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<connect>\n");
+ #endif
+ try {
+ if (nullptr == (hConnection = Netlib_OpenConnection(hNetlibUser, servername, port))) {
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_CONNECT;
+ }
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</connect>\n");
+ #endif
+ return;
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></connect>\n");
+ #endif
+ throw;
+ }
+}
+
+//Performs a simple query
+// query- command to send
+int CNLClient::LocalNetlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags)
+{
+ return Netlib_Send(hConn, buf, len, flags);
+}
+
+void CNLClient::Send(const char *query) throw(DWORD)
+{
+ unsigned int Sent;
+
+ if (nullptr == query)
+ return;
+ if (hConnection == nullptr)
+ return;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<send>%s", query);
+ #endif
+ try {
+ if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_strlen(query)) {
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_SEND;
+ }
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</send>\n");
+ #endif
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></send>\n");
+ #endif
+ throw;
+ }
+}
+
+//Reads data from socket
+// buf- buffer where to store max. buflen of received characters
+// if buf is NULL, creates buffer of buflen size
+// buf is NULL by default
+//You need free() returned buffer, which can be allocated in this function
+//if not success, exception is throwed
+
+int CNLClient::LocalNetlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags)
+{
+ int iReturn = Netlib_Recv(hConn, buf, len, flags);
+ if (isTLSed) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("SSL recv: %s", buf);
+ #endif
+ }
+
+ return iReturn;
+}
+
+char *CNLClient::Recv(char *buf, int buflen) throw(DWORD)
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<reading>");
+ #endif
+ try {
+ if (buf == nullptr)
+ buf = (char *)malloc(sizeof(char) * (buflen + 1));
+ if (buf == nullptr)
+ throw NetworkError = (uint32_t)ENL_RECVALLOC;
+
+ if (!isTLSed) {
+ NETLIBSELECT nls = {};
+ nls.dwTimeout = 60000;
+ nls.hReadConns[0] = hConnection;
+ switch (Netlib_Select(&nls)) {
+ case SOCKET_ERROR:
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ case 0: // time out!
+ free(buf);
+ throw NetworkError = (uint32_t)ENL_TIMEOUT;
+ }
+ }
+
+ memset(buf, 0, buflen);
+ if (SOCKET_ERROR == (Rcv = LocalNetlib_Recv(hConnection, buf, buflen, MSG_DUMPASTEXT))) {
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ }
+ if (!Rcv) {
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ }
+ #ifdef DEBUG_COMM
+ *(buf + Rcv) = 0; //end the buffer to write it to file
+ DebugLog(CommFile, "%s", buf);
+ DebugLog(CommFile, "</reading>\n");
+ #endif
+ return(buf);
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></reading>\n");
+ #endif
+ throw;
+ }
+}
+
+//Closes netlib connection
+void CNLClient::Disconnect()
+{
+ Netlib_CloseHandle(hConnection);
+ hConnection = nullptr;
+}
+
+//Uninitializes netlib library
+void UnregisterNLClient()
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Unregister PROXY support>");
+ #endif
+
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</Unregister PROXY support>\n");
+ #endif
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3.cpp b/protocols/YAMN/src/proto/pop3/pop3.cpp index d8f704dbd6..8d24a5218c 100644 --- a/protocols/YAMN/src/proto/pop3/pop3.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3.cpp @@ -1,344 +1,344 @@ -/* - * This code implements basics of POP3 protocol - * - * (c) majvan 2002-2004 - */ -/* This was made from the libspopc project - * copyright c 2002 Benoit Rouits <brouits@free.fr> - * released under the terms of GNU LGPL - * (GNU Lesser General Public Licence). - * libspopc offers simple API for a pop3 client (MTA). - * See RFC 1725 for pop3 specifications. - * more information on http://brouits.free.fr/libspopc/ - */ -/* - * This file is not original and is changed by majvan <om3tn@psg.sk> - * for mail checker purpose. Please see original web page to - * obtain the original. I rewrote it in C++, but good ideas were, - * I think, unchanged. - * - * Note that this file was not designed to work under Unix. It's - * needed to add Unix-specific features. I was interested only in - * Windows for my project. majvan - * - */ - -#include "../../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - - //Connects to the server through the netlib - //if not success, exception is throwed - //returns welcome string returned by server - //sets AckFlag -char *CPop3Client::Connect(const char *servername, const int port, BOOL UseSSL, BOOL NoTLS) -{ - if (Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - delete NetClient; - SSL = UseSSL; - NetClient = new CNLClient; - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "Connect:servername: %s port:%d\n", servername, port); - #endif - POP3Error = EPOP3_CONNECT; - NetClient->Connect(servername, port); - POP3Error = 0; - - if (SSL) { - try { - NetClient->SSLify(); - } - catch (...) { - NetClient->Disconnect(); - return nullptr; - } - } - - char *temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - extern BOOL SSLLoaded; - if (!NoTLS & !(SSL)) { - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - NetClient->Send("STLS\r\n"); - free(temp); - temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FOK) { // Ok, we are going to tls - try { - NetClient->SSLify(); - } - catch (...) { - NetClient->Disconnect(); - return nullptr; - } - } - } - return temp; -} - -//Receives data to the end of packet -// prev- previous data read (appends to this string next received data) -// mode- mode of packet. -// Packet can end with ack state (+OK or -ERR): set mode to POP3_SEARCHACK -// If packet ends with '.' (end of string), set mode to POP3_SEARCHDOT -// size- received data are stored to memory, but if length of data is more than allocated memory, function allocates -// new memory. New allocated memory has allocated size more bytes -// This value can be selectable: if you think it is better to reallocate by 1kB size, select size to 1024, -// default is 128. You do not need to use this parameter - -char *CPop3Client::RecvRest(char *prev, int mode, int size) -{ - int SizeRead = 0; - int SizeLeft = size - NetClient->Rcv; - int RcvAll = NetClient->Rcv; - char *LastString, *PrevString = prev; - - AckFlag = 0; - - while (((mode == POP3_SEARCHDOT) && !SearchFromEnd(PrevString + RcvAll - 1, RcvAll - 3, POP3_SEARCHDOT) && !SearchFromStart(PrevString, 2, POP3_SEARCHERR)) || //we are looking for dot or -err phrase - ((mode == POP3_SEARCHACK) && (!SearchFromStart(PrevString, RcvAll - 3, mode) || !((RcvAll > 3) && SearchFromEnd(PrevString + RcvAll - 1, 1, POP3_SEARCHNL))))) //we are looking for +ok or -err phrase ended with newline - { //if not found - if (NetClient->Stopped) //check if we can work with this POP3 client session - { - if (PrevString != nullptr) - free(PrevString); - throw POP3Error = (uint32_t)EPOP3_STOPPED; - } - if (SizeLeft == 0) //if block is full - { - SizeRead += size; - SizeLeft = size; - LastString = NetClient->Recv(nullptr, SizeLeft); - PrevString = (char *)realloc(PrevString, sizeof(char) * (SizeRead + size)); - if (PrevString == nullptr) - throw POP3Error = (uint32_t)EPOP3_RESTALLOC; - memcpy(PrevString + SizeRead, LastString, size); - free(LastString); - } - else - NetClient->Recv(PrevString + RcvAll, SizeLeft); //to Rcv stores received bytes - SizeLeft = SizeLeft - NetClient->Rcv; - RcvAll += NetClient->Rcv; - } - NetClient->Rcv = RcvAll; //at the end, store the number of all bytes, no the number of last received bytes - return PrevString; -} - -// CPop3Client::SearchFromEnd -// returns 1 if substring DOTLINE or ENDLINE found from end in bs bytes -// if you need to add condition for mode, insert it into switch statement -BOOL CPop3Client::SearchFromEnd(char *end, int bs, int mode) -{ - while (bs >= 0) { - switch (mode) { - case POP3_SEARCHDOT: - if (DOTLINE(end)) - return 1; - break; - - case POP3_SEARCHNL: - if (ENDLINE(end)) - return 1; - break; - } - end--; - bs--; - } - return 0; -} - -//Finds for a occurence of some pattern in string -// returns 1 if substring OKLINE, ERRLINE or any of them found from start in bs bytes -//call only this function to retrieve ack status (+OK or -ERR), because it sets flag AckFlag -//if you need to add condition for mode, insert it into switch statement -BOOL CPop3Client::SearchFromStart(char *start, int bs, int mode) -{ - while (bs >= 0) { - switch (mode) { - case POP3_SEARCHOK: - if (OKLINE(start)) { - AckFlag = POP3_FOK; - return 1; - } - break; - case POP3_SEARCHERR: - if (ERRLINE(start)) { - AckFlag = POP3_FERR; - return 1; - } - break; - case POP3_SEARCHACK: - if (ACKLINE(start)) { - OKLINE(start) ? AckFlag = POP3_FOK : AckFlag = POP3_FERR; - return 1; - } - break; - } - start++; - bs--; - } - return 0; -} - -//Performs "USER" pop query and returns server response -//sets AckFlag -char *CPop3Client::User(char *name) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - char *Result; - - mir_snprintf(query, "USER %s\r\n", name); - NetClient->Send(query); - Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADUSER; - POP3Error = 0; - return Result; -} - -//Performs "PASS" pop query and returns server response -//sets AckFlag -char *CPop3Client::Pass(char *pw) -{ - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - mir_snprintf(query, "PASS %s\r\n", pw); - NetClient->Send(query); - - char *Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADPASS; - return Result; -} - -//Performs "APOP" pop query and returns server response -//sets AckFlag -char *CPop3Client::APOP(char *name, char *pw, char *timestamp) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[512]; - char *Result; - unsigned char digest[16]; - - if (timestamp == nullptr) - throw POP3Error = (uint32_t)EPOP3_APOP; - mir_md5_state_s ctx; - mir_md5_init(&ctx); - mir_md5_append(&ctx, (const unsigned char *)timestamp, (unsigned int)mir_strlen(timestamp)); - mir_md5_append(&ctx, (const unsigned char *)pw, (unsigned int)mir_strlen(pw)); - mir_md5_finish(&ctx, digest); - - char hexdigest[40]; - mir_snprintf(query, "APOP %s %s\r\n", name, bin2hex(digest, sizeof(digest), hexdigest)); - - NetClient->Send(query); - Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADUSER; - return Result; -} - -//Performs "QUIT" pop query and returns server response -//sets AckFlag -char *CPop3Client::Quit() -{ - char query[] = "QUIT\r\n"; - - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "STAT" pop query and returns server response -//sets AckFlag -char *CPop3Client::Stat() -{ - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[] = "STAT\r\n"; - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "LIST" pop query and returns server response -//sets AckFlag -char *CPop3Client::List() -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[] = "LIST\r\n"; - - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "TOP" pop query and returns server response -//sets AckFlag -char *CPop3Client::Top(int nr, int lines) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - - mir_snprintf(query, "TOP %d %d\r\n", nr, lines); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "UIDL" pop query and returns server response -//sets AckFlag -char *CPop3Client::Uidl(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - if (nr) { - mir_snprintf(query, "UIDL %d\r\n", nr); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); - } - mir_snprintf(query, "UIDL\r\n"); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "DELE" pop query and returns server response -//sets AckFlag -char *CPop3Client::Dele(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - - mir_snprintf(query, "DELE %d\r\n", nr); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "RETR" pop query and returns server response -//sets AckFlag -char *CPop3Client::Retr(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - mir_snprintf(query, "RETR %d\r\n", nr); - NetClient->Send(query); - - RecvRest(NetClient->Recv(), POP3_SEARCHACK); - return NetClient->Recv(); -} +/*
+ * This code implements basics of POP3 protocol
+ *
+ * (c) majvan 2002-2004
+ */
+/* This was made from the libspopc project
+ * copyright c 2002 Benoit Rouits <brouits@free.fr>
+ * released under the terms of GNU LGPL
+ * (GNU Lesser General Public Licence).
+ * libspopc offers simple API for a pop3 client (MTA).
+ * See RFC 1725 for pop3 specifications.
+ * more information on http://brouits.free.fr/libspopc/
+ */
+/*
+ * This file is not original and is changed by majvan <om3tn@psg.sk>
+ * for mail checker purpose. Please see original web page to
+ * obtain the original. I rewrote it in C++, but good ideas were,
+ * I think, unchanged.
+ *
+ * Note that this file was not designed to work under Unix. It's
+ * needed to add Unix-specific features. I was interested only in
+ * Windows for my project. majvan
+ *
+ */
+
+#include "../../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+ //Connects to the server through the netlib
+ //if not success, exception is throwed
+ //returns welcome string returned by server
+ //sets AckFlag
+char *CPop3Client::Connect(const char *servername, const int port, BOOL UseSSL, BOOL NoTLS)
+{
+ if (Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ delete NetClient;
+ SSL = UseSSL;
+ NetClient = new CNLClient;
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "Connect:servername: %s port:%d\n", servername, port);
+ #endif
+ POP3Error = EPOP3_CONNECT;
+ NetClient->Connect(servername, port);
+ POP3Error = 0;
+
+ if (SSL) {
+ try {
+ NetClient->SSLify();
+ }
+ catch (...) {
+ NetClient->Disconnect();
+ return nullptr;
+ }
+ }
+
+ char *temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ extern BOOL SSLLoaded;
+ if (!NoTLS & !(SSL)) {
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+ NetClient->Send("STLS\r\n");
+ free(temp);
+ temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FOK) { // Ok, we are going to tls
+ try {
+ NetClient->SSLify();
+ }
+ catch (...) {
+ NetClient->Disconnect();
+ return nullptr;
+ }
+ }
+ }
+ return temp;
+}
+
+//Receives data to the end of packet
+// prev- previous data read (appends to this string next received data)
+// mode- mode of packet.
+// Packet can end with ack state (+OK or -ERR): set mode to POP3_SEARCHACK
+// If packet ends with '.' (end of string), set mode to POP3_SEARCHDOT
+// size- received data are stored to memory, but if length of data is more than allocated memory, function allocates
+// new memory. New allocated memory has allocated size more bytes
+// This value can be selectable: if you think it is better to reallocate by 1kB size, select size to 1024,
+// default is 128. You do not need to use this parameter
+
+char *CPop3Client::RecvRest(char *prev, int mode, int size)
+{
+ int SizeRead = 0;
+ int SizeLeft = size - NetClient->Rcv;
+ int RcvAll = NetClient->Rcv;
+ char *LastString, *PrevString = prev;
+
+ AckFlag = 0;
+
+ while (((mode == POP3_SEARCHDOT) && !SearchFromEnd(PrevString + RcvAll - 1, RcvAll - 3, POP3_SEARCHDOT) && !SearchFromStart(PrevString, 2, POP3_SEARCHERR)) || //we are looking for dot or -err phrase
+ ((mode == POP3_SEARCHACK) && (!SearchFromStart(PrevString, RcvAll - 3, mode) || !((RcvAll > 3) && SearchFromEnd(PrevString + RcvAll - 1, 1, POP3_SEARCHNL))))) //we are looking for +ok or -err phrase ended with newline
+ { //if not found
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ {
+ if (PrevString != nullptr)
+ free(PrevString);
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+ }
+ if (SizeLeft == 0) //if block is full
+ {
+ SizeRead += size;
+ SizeLeft = size;
+ LastString = NetClient->Recv(nullptr, SizeLeft);
+ PrevString = (char *)realloc(PrevString, sizeof(char) * (SizeRead + size));
+ if (PrevString == nullptr)
+ throw POP3Error = (uint32_t)EPOP3_RESTALLOC;
+ memcpy(PrevString + SizeRead, LastString, size);
+ free(LastString);
+ }
+ else
+ NetClient->Recv(PrevString + RcvAll, SizeLeft); //to Rcv stores received bytes
+ SizeLeft = SizeLeft - NetClient->Rcv;
+ RcvAll += NetClient->Rcv;
+ }
+ NetClient->Rcv = RcvAll; //at the end, store the number of all bytes, no the number of last received bytes
+ return PrevString;
+}
+
+// CPop3Client::SearchFromEnd
+// returns 1 if substring DOTLINE or ENDLINE found from end in bs bytes
+// if you need to add condition for mode, insert it into switch statement
+BOOL CPop3Client::SearchFromEnd(char *end, int bs, int mode)
+{
+ while (bs >= 0) {
+ switch (mode) {
+ case POP3_SEARCHDOT:
+ if (DOTLINE(end))
+ return 1;
+ break;
+
+ case POP3_SEARCHNL:
+ if (ENDLINE(end))
+ return 1;
+ break;
+ }
+ end--;
+ bs--;
+ }
+ return 0;
+}
+
+//Finds for a occurence of some pattern in string
+// returns 1 if substring OKLINE, ERRLINE or any of them found from start in bs bytes
+//call only this function to retrieve ack status (+OK or -ERR), because it sets flag AckFlag
+//if you need to add condition for mode, insert it into switch statement
+BOOL CPop3Client::SearchFromStart(char *start, int bs, int mode)
+{
+ while (bs >= 0) {
+ switch (mode) {
+ case POP3_SEARCHOK:
+ if (OKLINE(start)) {
+ AckFlag = POP3_FOK;
+ return 1;
+ }
+ break;
+ case POP3_SEARCHERR:
+ if (ERRLINE(start)) {
+ AckFlag = POP3_FERR;
+ return 1;
+ }
+ break;
+ case POP3_SEARCHACK:
+ if (ACKLINE(start)) {
+ OKLINE(start) ? AckFlag = POP3_FOK : AckFlag = POP3_FERR;
+ return 1;
+ }
+ break;
+ }
+ start++;
+ bs--;
+ }
+ return 0;
+}
+
+//Performs "USER" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::User(char *name)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ char *Result;
+
+ mir_snprintf(query, "USER %s\r\n", name);
+ NetClient->Send(query);
+ Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADUSER;
+ POP3Error = 0;
+ return Result;
+}
+
+//Performs "PASS" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Pass(char *pw)
+{
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ mir_snprintf(query, "PASS %s\r\n", pw);
+ NetClient->Send(query);
+
+ char *Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADPASS;
+ return Result;
+}
+
+//Performs "APOP" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::APOP(char *name, char *pw, char *timestamp)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[512];
+ char *Result;
+ unsigned char digest[16];
+
+ if (timestamp == nullptr)
+ throw POP3Error = (uint32_t)EPOP3_APOP;
+ mir_md5_state_s ctx;
+ mir_md5_init(&ctx);
+ mir_md5_append(&ctx, (const unsigned char *)timestamp, (unsigned int)mir_strlen(timestamp));
+ mir_md5_append(&ctx, (const unsigned char *)pw, (unsigned int)mir_strlen(pw));
+ mir_md5_finish(&ctx, digest);
+
+ char hexdigest[40];
+ mir_snprintf(query, "APOP %s %s\r\n", name, bin2hex(digest, sizeof(digest), hexdigest));
+
+ NetClient->Send(query);
+ Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADUSER;
+ return Result;
+}
+
+//Performs "QUIT" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Quit()
+{
+ char query[] = "QUIT\r\n";
+
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "STAT" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Stat()
+{
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[] = "STAT\r\n";
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "LIST" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::List()
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[] = "LIST\r\n";
+
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "TOP" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Top(int nr, int lines)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+
+ mir_snprintf(query, "TOP %d %d\r\n", nr, lines);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "UIDL" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Uidl(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ if (nr) {
+ mir_snprintf(query, "UIDL %d\r\n", nr);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ }
+ mir_snprintf(query, "UIDL\r\n");
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "DELE" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Dele(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+
+ mir_snprintf(query, "DELE %d\r\n", nr);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "RETR" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Retr(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ mir_snprintf(query, "RETR %d\r\n", nr);
+ NetClient->Send(query);
+
+ RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ return NetClient->Recv();
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3comm.cpp b/protocols/YAMN/src/proto/pop3/pop3comm.cpp index 946b93ea54..fc0f5819bb 100644 --- a/protocols/YAMN/src/proto/pop3/pop3comm.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3comm.cpp @@ -1,1329 +1,1329 @@ -/* - * This code implements POP3 server checking for new mail and so on. - * There's function SynchroPOP3 in this file- for checking and synchronising POP3 account - * and DeleteMailsPOP3- for deleting mails from POP3 server - * - * Note this file acts as main file for internal plugin. - * - * (c) majvan 2002-2004 - * 18/08 - */ - - -#include "../../stdafx.h" - -#define ERRORSTR_MAXLEN 1024 //in wide-chars - - //-------------------------------------------------------------------------------------------------- - -HANDLE hNetLib = nullptr; -PSCOUNTER CPOP3Account::AccountWriterSO = nullptr; - -//Creates new CPOP3Account structure -CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin, DWORD CAccountVersion); - -//Deletes CPOP3Account structure -void WINAPI DeletePOP3Account(CAccount *Which); - -//Sets stop flag to account -void WINAPI StopPOP3Account(CAccount *Which); - -//Function registers standard functions for YAMN -int RegisterPOP3Plugin(WPARAM, LPARAM); - -//Unloads all variables created on heap (delete[]) -DWORD WINAPI UnLoadPOP3(void *); - -//Function writes POP3 accounts using YAMN exported functions -DWORD WINAPI WritePOP3Accounts(); - -//Function stores plugin's data for account to file -DWORD WINAPI WritePOP3Options(HANDLE, CAccount *); - -//Function reads plugin's data for account from file -DWORD WINAPI ReadPOP3Options(CAccount *, char **, char *); - -//Creates new mail for an account -HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD CMimeMailVersion); - -//Function does all needed work when connection failed or any error occured -//Creates structure containing error code, closes internet session, runs "bad connect" function -static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnect, uint32_t POP3PluginParam, BOOL UseSSL); - -//Checks POP3 account and stores all info to account. It deletes old mails=> synchro -// WhichTemp- pointer to strucure containing needed information -DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp); - -//Deletes mails from POP3 server -// WhichTemp- structure containing needed information (queued messages to delete) -//Function deletes from memory queue in WhichTemp structure -void __cdecl DeleteMailsPOP3(void *param); - -//Function makes readable message about error. It sends it back to YAMN, so YAMN then -//can show it to the message window -wchar_t *WINAPI GetErrorString(DWORD Code); - -//Function deletes string allocated in GetErrorString -void WINAPI DeleteErrorString(LPVOID String); - -//Extracts info from result of POP3's STAT command -// stream- source string -// len- length of source string -// mboxsize- adreess to integer, that receives size of mailbox -// mails- adreess to integer, that receives number of mails -void ExtractStat(char *stream, int *mboxsize, int *mails); - -//Extracts mail ID on mailbox -// stream- source string -// len- length of source string -// queue- address of first message, where first ID will be stored -void ExtractUIDL(char *stream, int len, HYAMNMAIL queue); - -//Extracts mail size on mailbox -// stream- source string -// len- length of source string -// queue- address of first message, where size of message #1 will be stored -void ExtractList(char *stream, int len, HYAMNMAIL queue); - -void ExtractMail(char *stream, int len, HYAMNMAIL queue); - -YAMNExportedFcns *pYAMNFcn = nullptr; -MailExportedFcns *pYAMNMailFcn = nullptr; - -YAMN_PROTOIMPORTFCN POP3ProtocolFunctions = -{ - CreatePOP3Account, - DeletePOP3Account, - StopPOP3Account, - WritePOP3Options, - ReadPOP3Options, - SynchroPOP3, - SynchroPOP3, - SynchroPOP3, - DeleteMailsPOP3, - GetErrorString, - nullptr, - DeleteErrorString, - WritePOP3Accounts, - nullptr, - UnLoadPOP3, -}; - -YAMN_MAILIMPORTFCN POP3MailFunctions = -{ - CreatePOP3Mail, - nullptr, - nullptr, - nullptr, -}; - -PYAMN_VARIABLES pYAMNVar = nullptr; -HYAMNPROTOPLUGIN POP3Plugin = nullptr; - -YAMN_PROTOREGISTRATION POP3ProtocolRegistration = -{ - "POP3 protocol (internal)", - __VERSION_STRING_DOTS, - __COPYRIGHT, - __DESCRIPTION, - __AUTHORWEB, -}; - -static wchar_t *FileName = nullptr; - -HANDLE RegisterNLClient(char *name); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -CPOP3Account::CPOP3Account() -{ - //NOTE! This constructor constructs CAccount structure. If your plugin is not internal, - //you will need these constructors. All you need is in Account.cpp. Just copy to your source code - //constructor and destructor of CAccount. - UseInternetFree = CreateEvent(nullptr, FALSE, TRUE, nullptr); - InternetQueries = new SCOUNTER; - AbilityFlags = YAMN_ACC_BROWSE | YAMN_ACC_POPUP; - - SetAccountStatus((CAccount *)this, TranslateT("Disconnected")); -} - -CPOP3Account::~CPOP3Account() -{ - CloseHandle(UseInternetFree); - if (InternetQueries != nullptr) - delete InternetQueries; -} - -CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN, DWORD) -{ - //First, we should check whether CAccountVersion matches. - //But this is internal plugin, so YAMN's CAccount structure and our CAccount structure are - //the same, so we do not need to test version. Otherwise, if CAccount version does not match - //in your plugin, you should return NULL, like this: - // if (CAccountVersion != YAMN_ACCOUNTVERSION) return NULL; - - //Now it is needed to construct our POP3 account and return its handle - return (CAccount *)new struct CPOP3Account(); -} - -void WINAPI DeletePOP3Account(CAccount *Which) -{ - delete (HPOP3ACCOUNT)Which; -} - -void WINAPI StopPOP3Account(CAccount *Which) -{ - ((HPOP3ACCOUNT)Which)->Client.Stopped = TRUE; - if (((HPOP3ACCOUNT)Which)->Client.NetClient != nullptr) //we should inform also network client. Usefull only when network client implements this feature - ((HPOP3ACCOUNT)Which)->Client.NetClient->Stopped = TRUE; -} - -//This function is like main function for POP3 internal protocol -int RegisterPOP3Plugin(WPARAM, LPARAM) -{ - // Get YAMN variables we can use - if (nullptr == (pYAMNVar = (PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES, YAMN_VARIABLESVERSION, 0))) - return 0; - - // We have to get pointers to YAMN exported functions: allocate structure and fill it - if (nullptr == (pYAMNFcn = new struct YAMNExportedFcns)) { -LBL_Error: - UnLoadPOP3(nullptr); - return 0; - } - - // Register new pop3 user in netlib - if (nullptr == (hNetLib = RegisterNLClient("YAMN (POP3)"))) - goto LBL_Error; - - pYAMNFcn->SetProtocolPluginFcnImportFcn = (YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID, 0); - pYAMNFcn->WaitToWriteFcn = (YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOWRITEID, 0); - pYAMNFcn->WriteDoneFcn = (YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WRITEDONEID, 0); - pYAMNFcn->WaitToReadFcn = (YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOREADID, 0); - pYAMNFcn->ReadDoneFcn = (YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_READDONEID, 0); - pYAMNFcn->SCGetNumberFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCGETNUMBERID, 0); - pYAMNFcn->SCIncFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCINCID, 0); - pYAMNFcn->SCDecFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCDECID, 0); - pYAMNFcn->SetStatusFcn = (YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETSTATUSID, 0); - pYAMNFcn->GetStatusFcn = (YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_GETSTATUSID, 0); - - if (nullptr == (pYAMNMailFcn = new struct MailExportedFcns)) - goto LBL_Error; - - pYAMNMailFcn->SynchroMessagesFcn = (YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SYNCHROMIMEMSGSID, 0); - pYAMNMailFcn->TranslateHeaderFcn = (YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_TRANSLATEHEADERID, 0); - pYAMNMailFcn->AppendQueueFcn = (YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_APPENDQUEUEID, 0); - pYAMNMailFcn->DeleteMessagesToEndFcn = (YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEQUEUEID, 0); - pYAMNMailFcn->DeleteMessageFromQueueFcn = (YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEMESSAGEID, 0); - pYAMNMailFcn->FindMessageByIDFcn = (YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_FINDMIMEMESSAGEID, 0); - pYAMNMailFcn->CreateNewDeleteQueueFcn = (YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_CREATENEWDELETEQUEUEID, 0); - - //set static variable - if (CPOP3Account::AccountWriterSO == nullptr) - if (nullptr == (CPOP3Account::AccountWriterSO = new SCOUNTER)) - goto LBL_Error; - - //First, we register this plugin - //it is quite impossible this function returns zero (failure) as YAMN and internal plugin structre versions are the same - POP3ProtocolRegistration.Name = Translate("POP3 protocol (internal)"); - POP3ProtocolRegistration.Description = Translate(__DESCRIPTION); - if (nullptr == (POP3Plugin = (HYAMNPROTOPLUGIN)CallService(MS_YAMN_REGISTERPROTOPLUGIN, (WPARAM)&POP3ProtocolRegistration, (LPARAM)YAMN_PROTOREGISTRATIONVERSION))) - return 0; - - //Next we set our imported functions for YAMN - if (!SetProtocolPluginFcnImport(POP3Plugin, &POP3ProtocolFunctions, YAMN_PROTOIMPORTFCNVERSION, &POP3MailFunctions, YAMN_MAILIMPORTFCNVERSION)) - return 0; - - //Then, we read all mails for accounts. - //You must first register account, before using this function as YAMN must use CreatePOP3Account function to add new accounts - //But if CreatePOP3Account is not implemented (equals to NULL), YAMN creates account as YAMN's standard CAccount * - if (FileName) CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); //shoud not happen (only for secure) - FileName = (wchar_t *)CallService(MS_YAMN_GETFILENAME, (WPARAM)L"pop3", 0); - - switch (CallService(MS_YAMN_READACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName)) { - case EACC_FILEVERSION: - MessageBox(nullptr, TranslateT("Found new version of account book, not compatible with this version of YAMN."), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_FILECOMPATIBILITY: - MessageBox(nullptr, TranslateT("Error reading account file. Account file corrupted."), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_ALLOC: - MessageBox(nullptr, TranslateT("Memory allocation error while data reading"), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_SYSTEM: - if (ERROR_FILE_NOT_FOUND != GetLastError()) { - wchar_t temp[1024] = {0}; - mir_snwprintf(temp, L"%s\n%s", TranslateT("Reading file error. File already in use?"), FileName); - MessageBox(nullptr, temp, TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - } - break; - } - - for (CAccount *Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - Finder->hContact = NULL; - for (auto &hContact : Contacts(YAMN_DBMODULE)) { - DBVARIANT dbv; - if (!g_plugin.getString(hContact, "Id", &dbv)) { - if (mir_strcmp(dbv.pszVal, Finder->Name) == 0) { - Finder->hContact = hContact; - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE); - db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); - if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) - Contact::Hide(Finder->hContact, false); - - if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT)) - Contact::Hide(Finder->hContact); - } - db_free(&dbv); - } - } - - if (!Finder->hContact && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { - // No account contact found, have to create one - Finder->hContact = db_add_contact(); - Proto_AddToContact(Finder->hContact, YAMN_DBMODULE); - g_plugin.setString(Finder->hContact, "Id", Finder->Name); - g_plugin.setString(Finder->hContact, "Nick", Finder->Name); - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_OFFLINE); - } - } - - return 0; -} - -DWORD WINAPI UnLoadPOP3(void *) -{ - //pYAMNVar is only a pointr, no need delete or free - if (hNetLib) { - Netlib_CloseHandle(hNetLib); hNetLib = nullptr; - } - if (CPOP3Account::AccountWriterSO) { - delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = nullptr; - } - if (pYAMNMailFcn) { - delete pYAMNMailFcn; pYAMNMailFcn = nullptr; - } - if (pYAMNFcn) { - delete pYAMNFcn; pYAMNFcn = nullptr; - } - if (FileName) { - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); FileName = nullptr; - } - - return 1; -} - -DWORD WINAPI WritePOP3Accounts() -{ - uint32_t ReturnValue = CallService(MS_YAMN_WRITEACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName); - if (ReturnValue == EACC_SYSTEM) { - wchar_t temp[1024] = {0}; - mir_snwprintf(temp, L"%s\n%s", TranslateT("Error while copying data to disk occurred. Is file in use?"), FileName); - MessageBox(nullptr, temp, TranslateT("POP3 plugin - write file error"), MB_OK); - } - - return ReturnValue; -} - -DWORD WINAPI WritePOP3Options(HANDLE File, CAccount *Which) -{ - DWORD WrittenBytes; - uint32_t Ver = POP3_FILEVERSION; - - if ((!WriteFile(File, (char *)&Ver, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&((HPOP3ACCOUNT)Which)->CP, sizeof(uint16_t), &WrittenBytes, nullptr))) - return EACC_SYSTEM; - return 0; -} - -DWORD WINAPI ReadPOP3Options(CAccount *Which, char **Parser, char *End) -{ - uint32_t Ver; - #ifdef DEBUG_FILEREAD - wchar_t Debug[256]; - #endif - Ver = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - if (Ver != POP3_FILEVERSION) - return EACC_FILECOMPATIBILITY; - - ((HPOP3ACCOUNT)Which)->CP = *(uint16_t *)(*Parser); - (*Parser) += sizeof(uint16_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"CodePage: %d, remaining %d chars", ((HPOP3ACCOUNT)Which)->CP, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - return 0; -} - -HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD) -{ - HYAMNMAIL NewMail; - //First, we should check whether MAILDATA matches. - //But this is internal plugin, so YAMN's MAILDATA structure and our MAILDATA structure are - //the same, so we do not need to test version. Otherwise, if MAILDATA version does not match - //in your plugin, you should return NULL, like this: - // if (MailDataVersion != YAMN_MAILDATAVERSION) return NULL; - - //Now it is needed to construct our POP3 account and return its handle - if (nullptr == (NewMail = new YAMNMAIL)) - return nullptr; - - if (nullptr == (NewMail->MailData = new CMailData())) { - delete NewMail; - return nullptr; - } - NewMail->MailData->CP = ((HPOP3ACCOUNT)Account)->CP; - return (HYAMNMAIL)NewMail; -} - -static void SetContactStatus(CAccount *account, int status) -{ - if ((account->hContact) && (account->NewMailN.Flags & YAMN_ACC_CONT)) - g_plugin.setWord(account->hContact, "Status", status); -} - -static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnection, uint32_t POP3PluginParam, BOOL UseSSL) -{ - char *DataRX; - - //We create new structure, that we pass to bad connection dialog procedure. This procedure next calls YAMN imported fuction - //from POP3 protocol to determine the description of error. We can describe error from our error code structure, because later, - //when YAMN calls our function, it passes us our error code. This is pointer to structure for POP3 protocol in fact. - PPOP3_ERRORCODE ErrorCode; - - //We store status before we do Quit(), because quit can destroy our errorcode status - if (nullptr != (ErrorCode = new POP3_ERRORCODE)) { - ErrorCode->SSL = UseSSL; - ErrorCode->AppError = ActualAccount->SystemError; - ErrorCode->POP3Error = ActualAccount->Client.POP3Error; - ErrorCode->NetError = ActualAccount->Client.NetClient->NetworkError; - ErrorCode->SystemError = ActualAccount->Client.NetClient->SystemError; - } - - if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call (force check or so on) - { - try { - DataRX = ActualAccount->Client.Quit(); - if (DataRX != nullptr) - free(DataRX); - } - catch (...) { - } - //We always close connection if error occured - try { - ActualAccount->Client.NetClient->Disconnect(); - } - catch (...) { - } - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - - //If we cannot allocate memory, do nothing - if (ErrorCode == nullptr) { - SetEvent(ActualAccount->UseInternetFree); - return; - } - } - else // else it was called from POP3 plugin, probably error when deleting old mail (POP3 synchro calls POP3 delete) - if (ErrorCode == nullptr) - return; - - if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP)) - RunBadConnection(ActualAccount, (UINT_PTR)ErrorCode, ParamToBadConnection); - - if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call - SetEvent(ActualAccount->UseInternetFree); -} - -//Checks POP3 account and synchronizes it -DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp) -{ - HPOP3ACCOUNT ActualAccount; - CPop3Client *MyClient; - HYAMNMAIL NewMails = nullptr, MsgQueuePtr = nullptr; - char *DataRX = nullptr, *Temp; - int mboxsize, msgs, i; - SYSTEMTIME now; - LPVOID YAMNParam; - uint32_t CheckFlags; - BOOL UsingInternet = FALSE; - struct - { - char *ServerName; - uint32_t ServerPort; - char *ServerLogin; - char *ServerPasswd; - uint32_t Flags; - uint32_t NFlags; - uint32_t NNFlags; - } ActualCopied; - - //First, we should compare our version of CheckParam structure, but here it is not needed, because YAMN and internal plugin - //have the same version. But your plugin should do that in this way: - // if (((struct CheckParam *)WhichTemp)->Ver != YAMN_CHECKVERSION) - // { - // SetEvent(((struct CheckParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN - // return (uint32_t)-1; //ok, but we should return value. - // //When our plugin returns e.g. 0xFFFFFFFF (=-1, this is only our plugin value, YAMN does nothing with return value, - // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn. We know problem occured in YAMN incompatibility - // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". - // } - - ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread - YAMNParam = WhichTemp->BrowserParam; - CheckFlags = WhichTemp->Flags; - - SCInc(ActualAccount->UsingThreads); - //Unblock YAMN, signal that we have copied all parameters from YAMN thread stack - if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV) - SetEvent(WhichTemp->ThreadRunningEV); - - if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) { - SCDec(ActualAccount->UsingThreads); - return 0; - } - - MyClient = &ActualAccount->Client; - //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. - ActualCopied.ServerName = _strdup(ActualAccount->Server->Name); - ActualCopied.ServerPort = ActualAccount->Server->Port; - ActualCopied.Flags = ActualAccount->Flags; - ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login); - ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd); - ActualCopied.NFlags = ActualAccount->NewMailN.Flags; - ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags; - - ReadDone(ActualAccount); - SCInc(ActualAccount->InternetQueries); //increment counter, that there is one more thread waiting for connection - - WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); //wait until we can use connection - SCDec(ActualAccount->InternetQueries); - - //OK, we enter the "use internet" section. But after we start communication, we can test if we did not enter the "use internet" section only for the reason, - //that previous thread release the internet section because this account has stop signal (we stop account and there are 2 threads: one communicating, - //the second one waiting for network access- the first one ends because we want to stop account, this one is released, but should be stopped as well). - if (!ActualAccount->AbleToWork) { - SetEvent(ActualAccount->UseInternetFree); - SCDec(ActualAccount->UsingThreads); - return 0; - } - UsingInternet = TRUE; - - GetLocalTime(&now); - ActualAccount->SystemError = 0; //now we can use internet for this socket. First, clear errorcode. - try { - SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED); - - // if we are already connected, we have open session (another thread left us open session), so we don't need to login - // note that connected state without logging cannot occur, because if we close session, we always close socket too (we must close socket is the right word :)) - if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) { - SetAccountStatus(ActualAccount, TranslateT("Connecting to server")); - - DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS); - char *timestamp = nullptr; - - if (DataRX != nullptr) { - if (ActualCopied.Flags & YAMN_ACC_APOP) { - char *lpos = strchr(DataRX, '<'); - char *rpos = strchr(DataRX, '>'); - if (lpos && rpos && rpos > lpos) { - int sz = (int)(rpos - lpos + 2); - timestamp = new char[sz]; - memcpy(timestamp, lpos, sz - 1); - timestamp[sz - 1] = '\0'; - } - } - free(DataRX); - DataRX = nullptr; - } - - SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account")); - - if (ActualCopied.Flags & YAMN_ACC_APOP) { - DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - delete[] timestamp; - } - else { - DataRX = MyClient->User(ActualCopied.ServerLogin); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - DataRX = MyClient->Pass(ActualCopied.ServerPasswd); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - } - SetAccountStatus(ActualAccount, TranslateT("Searching for new mail message")); - - DataRX = MyClient->Stat(); - - ExtractStat(DataRX, &mboxsize, &msgs); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - for (i = 0; i < msgs; i++) { - if (!i) - MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - else { - MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - MsgQueuePtr = MsgQueuePtr->Next; - } - if (MsgQueuePtr == nullptr) { - ActualAccount->SystemError = EPOP3_QUEUEALLOC; - throw (uint32_t)ActualAccount->SystemError; - } - } - - if (msgs) { - DataRX = MyClient->List(); - ExtractList(DataRX, MyClient->NetClient->Rcv, NewMails); - if (DataRX != nullptr) - free(DataRX); - - DataRX = MyClient->Uidl(); - ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)(ActualAccount->SystemError = EACC_STOPPED); - - ActualAccount->LastChecked = now; - for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) { - if (MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) { - HYAMNMAIL NewMsgsPtr = nullptr; - for (NewMsgsPtr = (HYAMNMAIL)NewMails; NewMsgsPtr != nullptr; NewMsgsPtr = NewMsgsPtr->Next) { - if (!mir_strcmp(MsgQueuePtr->ID, NewMsgsPtr->ID)) { - wchar_t accstatus[512]; - mir_snwprintf(accstatus, TranslateT("Reading body %s"), NewMsgsPtr->ID); - SetAccountStatus(ActualAccount, accstatus); - DataRX = MyClient->Top(MsgQueuePtr->Number, 100); - if (DataRX != nullptr) { - Temp = DataRX; - while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; - - if (OKLINE(DataRX)) - for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++); - while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++; - } - else - continue; - //delete all the headers of the old mail MsgQueuePtr->MailData->TranslatedHeader - struct CMimeItem *TH = MsgQueuePtr->MailData->TranslatedHeader; - if (TH) for (; MsgQueuePtr->MailData->TranslatedHeader != nullptr;) { - TH = TH->Next; - if (MsgQueuePtr->MailData->TranslatedHeader->name != nullptr) - delete[] MsgQueuePtr->MailData->TranslatedHeader->name; - if (MsgQueuePtr->MailData->TranslatedHeader->value != nullptr) - delete[] MsgQueuePtr->MailData->TranslatedHeader->value; - delete MsgQueuePtr->MailData->TranslatedHeader; - MsgQueuePtr->MailData->TranslatedHeader = TH; - } - - TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader); - - MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED; - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - break; - } - } - } - } - - SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); //we get only new mails on server! - - MsgsWriteDone(ActualAccount); - for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) { - if ((MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) && (MsgQueuePtr->Flags & YAMN_MSG_BODYRECEIVED)) { - MsgQueuePtr->Flags &= ~YAMN_MSG_BODYREQUESTED; - if (MsgQueuePtr->MsgWindow) - SendMessage(MsgQueuePtr->MsgWindow, WM_YAMN_CHANGECONTENT, 0, 0); - } - } - - for (msgs = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next, msgs++); //get number of new mails - - try { - wchar_t accstatus[512]; - - for (i = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; i++) { - BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY) != 0; - DataRX = MyClient->Top(MsgQueuePtr->Number, autoretr ? 100 : 0); - mir_snwprintf(accstatus, TranslateT("Reading new mail messages (%d%% done)"), 100 * i / msgs); - SetAccountStatus(ActualAccount, accstatus); - - if (DataRX != nullptr) { - Temp = DataRX; - while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; - - if (OKLINE(DataRX)) - for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++); - while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++; - } - else - continue; - - TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader); - - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</New mail>\n"); - #endif - MsgQueuePtr->Flags |= YAMN_MSG_NORMALNEW; - if (autoretr) MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED; - - //We are going to filter mail. Warning!- we must not be in read access neither write access to mails when calling this service - //This is done, because the "NewMails" queue is not synchronised. It is because it is new queue. Only this thread uses new queue yet, it is not - //connected to account mail queue. - // CallService(MS_YAMN_FILTERMAIL,(WPARAM)ActualAccount,(LPARAM)MsgQueuePtr); - FilterMailSvc((WPARAM)ActualAccount, (LPARAM)MsgQueuePtr); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - - //MsgQueuePtr->MailData->Body=MyClient->Retr(MsgQueuePtr->Number); - - MsgQueuePtr = MsgQueuePtr->Next; - - } - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)ActualAccount->SystemError == EACC_STOPPED; - - if (ActualAccount->Mails == nullptr) - ActualAccount->Mails = NewMails; - else { - ActualAccount->LastMail = ActualAccount->LastChecked; - AppendQueue((HYAMNMAIL)ActualAccount->Mails, NewMails); - } - - MsgsWriteDone(ActualAccount); - - // we are going to delete mails having SPAM flag level3 and 4 (see m_mails.h) set - { - struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, INVALID_HANDLE_VALUE, ActualAccount, YAMNParam, (void *)POP3_DELETEFROMCHECK}; - - // Delete mails from server. Here we should not be in write access for account's mails - DeleteMailsPOP3(&ParamToDeleteMails); - } - - // if there is no waiting thread for internet connection close it - // else leave connection open - if (0 == SCGetNumber(ActualAccount->InternetQueries)) { - DataRX = MyClient->Quit(); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - MyClient->NetClient->Disconnect(); - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - } - - UsingInternet = FALSE; - SetEvent(ActualAccount->UseInternetFree); - - ActualAccount->LastSChecked = ActualAccount->LastChecked; - ActualAccount->LastSynchronised = ActualAccount->LastChecked; - } - catch (...) { - throw; //go to the main exception handling - } - - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, ActualCopied.NNFlags, YAMNParam}; - - if (CheckFlags & YAMN_FORCECHECK) - Param.nnflags |= YAMN_ACC_POP; //if force check, show popup anyway and if mailbrowser was opened, do not close - Param.nnflags |= YAMN_ACC_MSGP; //do not close browser if already open - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - } - #ifdef DEBUG_COMM - catch (uint32_t ErrorCode) - #else - catch (uint32_t) - #endif - { - if (ActualAccount->Client.POP3Error == EPOP3_STOPPED) - ActualAccount->SystemError = EACC_STOPPED; - #ifdef DEBUG_COMM - DebugLog(CommFile, "ERROR: %x\n", ErrorCode); - #endif - if (WAIT_OBJECT_0 == MsgsWaitToWrite(ActualAccount)) { - ActualAccount->LastChecked = now; - MsgsWriteDone(ActualAccount); - } - - DeleteMIMEQueue(ActualAccount, NewMails); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - switch (ActualAccount->SystemError) { - case EACC_QUEUEALLOC: - case EACC_STOPPED: - ActualAccount->Client.NetClient->Disconnect(); - break; - default: - PostErrorProc(ActualAccount, YAMNParam, (uint32_t)NULL, MyClient->SSL); //it closes internet connection too - } - - if (UsingInternet) //if our thread still uses internet - SetEvent(ActualAccount->UseInternetFree); - - SetContactStatus(ActualAccount, ID_STATUS_NA); - } - free(ActualCopied.ServerName); - free(ActualCopied.ServerLogin); - free(ActualCopied.ServerPasswd); - #ifdef DEBUG_COMM - DebugLog(CommFile, "</--------Communication-------->\n"); - #endif - - // WriteAccounts(); - SCDec(ActualAccount->UsingThreads); - return 0; -} - -void __cdecl DeleteMailsPOP3(void *param) -{ - DeleteParam *WhichTemp = (DeleteParam *)param; - - CPop3Client *MyClient; - HYAMNMAIL DeleteMails, NewMails = nullptr, MsgQueuePtr = nullptr; - char *DataRX = nullptr; - int mboxsize = 0, msgs = 0, i; - BOOL UsingInternet = FALSE; - struct - { - char *ServerName; - uint32_t ServerPort; - char *ServerLogin; - char *ServerPasswd; - uint32_t Flags; - uint32_t NFlags; - uint32_t NNFlags; - } ActualCopied; - - //First, we should compare our version of DeleteParam structure, but here it is not needed, because YAMN and internal plugin - //have the same version. But your plugin should do that in this way: - // if (((struct DeleteParam *)WhichTemp)->Ver != YAMN_DELETEVERSION) - // { - // SetEvent(((struct DeleteParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN - // return (uint32_t)-1; //ok, but we should return value. - // //When our plugin returns e.g. 0xFFFFFFFF (this is only our plugin value, YAMN does nothing with return value, - // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn), we know problem occured in YAMN incompatibility - // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". - // } - - HPOP3ACCOUNT ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread - LPVOID YAMNParam = WhichTemp->BrowserParam; - UINT_PTR POP3PluginParam = (UINT_PTR)((struct DeleteParam *)WhichTemp)->CustomParam; - - SCInc(ActualAccount->UsingThreads); - if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV) - SetEvent(WhichTemp->ThreadRunningEV); - - if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) { - SCDec(ActualAccount->UsingThreads); - return; - } - - if (nullptr == (DeleteMails = (HYAMNMAIL)CreateNewDeleteQueue((HYAMNMAIL)ActualAccount->Mails))) //if there's no mail for deleting, return - { - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, YAMN_ACC_MSGP, YAMN_ACC_MSGP, YAMNParam}; //Just update the window - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - - SCDec(ActualAccount->UsingThreads); - return; - } - - MyClient = &(ActualAccount->Client); - - //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. - ActualCopied.ServerName = _strdup(ActualAccount->Server->Name); - ActualCopied.ServerPort = ActualAccount->Server->Port; - ActualCopied.Flags = ActualAccount->Flags; - ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login); - ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd); - ActualCopied.NFlags = ActualAccount->NewMailN.Flags; - ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags; - - ReadDone(ActualAccount); - - SCInc(ActualAccount->InternetQueries); //This is POP3-internal SCOUNTER, we set another thread wait for this account to be connected to inet - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked - WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); - - SCDec(ActualAccount->InternetQueries); - UsingInternet = TRUE; - - try { - SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED); - #ifdef DEBUG_COMM - DebugLog(CommFile, "<--------Communication-------->\n"); - #endif - if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) { - SetAccountStatus(ActualAccount, TranslateT("Connecting to server")); - - DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS); - - char *timestamp = nullptr; - if (DataRX != nullptr) { - if (ActualAccount->Flags & YAMN_ACC_APOP) { - char *lpos = strchr(DataRX, '<'); - char *rpos = strchr(DataRX, '>'); - if (lpos && rpos && rpos > lpos) { - int sz = (int)(rpos - lpos + 2); - timestamp = new char[sz]; - memcpy(timestamp, lpos, sz - 1); - timestamp[sz - 1] = '\0'; - } - } - free(DataRX); - DataRX = nullptr; - } - SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account")); - - if (ActualAccount->Flags & YAMN_ACC_APOP) { - DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - delete[] timestamp; - } - else { - DataRX = MyClient->User(ActualCopied.ServerLogin); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - DataRX = MyClient->Pass(ActualCopied.ServerPasswd); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - } - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<--------Deleting requested mails-------->\n"); - #endif - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not need to get mails on server as we have already it from check function - { - SetAccountStatus(ActualAccount, TranslateT("Deleting requested mails")); - - DataRX = MyClient->Stat(); - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting stat>\n"); - #endif - ExtractStat(DataRX, &mboxsize, &msgs); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<MailBoxSize>%d</MailBoxSize>\n", mboxsize); - DebugLog(DecodeFile, "<Msgs>%d</Msgs>\n", msgs); - DebugLog(DecodeFile, "</Extracting stat>\n"); - #endif - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - for (i = 0; i < msgs; i++) { - if (!i) - MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - else { - MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - MsgQueuePtr = MsgQueuePtr->Next; - } - if (MsgQueuePtr == nullptr) { - ActualAccount->SystemError = EPOP3_QUEUEALLOC; - throw (uint32_t)ActualAccount->SystemError; - } - } - - if (msgs) { - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting UIDL>\n"); - #endif - DataRX = MyClient->Uidl(); - ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting UIDL>\n"); - #endif - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - // we get "new mails" on server (NewMails will contain all mails on server not found in DeleteMails) - // but also in DeleteMails we get only those, which are still on server with their responsable numbers - SynchroMessages(ActualAccount, (HYAMNMAIL *)&DeleteMails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); - } - } - else SetAccountStatus(ActualAccount, TranslateT("Deleting spam")); - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)EACC_STOPPED; - - if (msgs || POP3_DELETEFROMCHECK == POP3PluginParam) { - try { - HYAMNMAIL Temp; - - for (i = 0, MsgQueuePtr = DeleteMails; MsgQueuePtr != nullptr; i++) { - if (!(MsgQueuePtr->Flags & YAMN_MSG_VIRTUAL)) //of course we can only delete real mails, not virtual - { - DataRX = MyClient->Dele(MsgQueuePtr->Number); - Temp = MsgQueuePtr->Next; - if (POP3_FOK == MyClient->AckFlag) //if server answers that mail was deleted - { - DeleteMIMEMessage((HYAMNMAIL *)&DeleteMails, MsgQueuePtr); - HYAMNMAIL DeletedMail = FindMIMEMessageByID((HYAMNMAIL)ActualAccount->Mails, MsgQueuePtr->ID); - if ((MsgQueuePtr->Flags & YAMN_MSG_MEMDELETE)) //if mail should be deleted from memory (or disk) - { - DeleteMIMEMessage((HYAMNMAIL *)&ActualAccount->Mails, DeletedMail); //remove from queue - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)POP3Plugin, (LPARAM)DeletedMail); - } - else //else mark it only as "deleted mail" - { - DeletedMail->Flags |= (YAMN_MSG_VIRTUAL | YAMN_MSG_DELETED); - DeletedMail->Flags &= ~(YAMN_MSG_NEW | YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE); //clear "new mail" - } - delete MsgQueuePtr->MailData; - delete[] MsgQueuePtr->ID; - delete MsgQueuePtr; - } - MsgQueuePtr = Temp; - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - else - MsgQueuePtr = MsgQueuePtr->Next; - } - } - catch (...) //if any exception in the code where we have write-access to account occured, don't forget to leave write-access - { - MsgsWriteDone(ActualAccount); - throw; //and go to the main exception handling - } - - if (NewMails != nullptr) - // in ActualAccount->Mails we have all mails stored before calling this function - // in NewMails we have all mails not found in DeleteMails (in other words: we performed new ID checking and we - // stored all mails found on server, then we deleted the ones we wanted to delete in this function - // and NewMails queue now contains actual state of mails on server). But we will not use NewMails as actual state, because NewMails does not contain header data (subject, from...) - // We perform deleting from ActualAccount->Mails: we remove from original queue (ActualAccount->Mails) all deleted mails - SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); - // Now ActualAccount->Mails contains all mails when calling this function except the ones, we wanted to delete (these are in DeleteMails) - // And in NewMails we have new mails (if any) - else if (POP3_DELETEFROMCHECK != POP3PluginParam) { - DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails); - ActualAccount->Mails = nullptr; - } - } - else { - DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails); - ActualAccount->Mails = nullptr; - } - - MsgsWriteDone(ActualAccount); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</--------Deleting requested mails-------->\n"); - #endif - - // TODO: now, we have in NewMails new mails. If NewMails is not NULL, we found some new mails, so Checking for new mail should be performed - // now, we do not call CheckPOP3 - - // if there is no waiting thread for internet connection close it - // else leave connection open - // if this functin was called from SynchroPOP3, then do not try to disconnect - if (POP3_DELETEFROMCHECK != POP3PluginParam) { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, YAMN_ACC_MSGP, YAMNParam}; - - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - - if (0 == SCGetNumber(ActualAccount->InternetQueries)) { - DataRX = MyClient->Quit(); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - MyClient->NetClient->Disconnect(); - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - } - - UsingInternet = FALSE; - SetEvent(ActualAccount->UseInternetFree); - } - SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - } - #ifdef DEBUG_COMM - catch (uint32_t ErrorCode) - #else - catch (uint32_t) - #endif - { - if (ActualAccount->Client.POP3Error == EPOP3_STOPPED) - ActualAccount->SystemError = EACC_STOPPED; - #ifdef DEBUG_COMM - DebugLog(CommFile, "ERROR %x\n", ErrorCode); - #endif - if (DataRX != nullptr) - free(DataRX); - switch (ActualAccount->SystemError) { - case EACC_QUEUEALLOC: - case EACC_STOPPED: - ActualAccount->Client.NetClient->Disconnect(); - break; - default: - PostErrorProc(ActualAccount, YAMNParam, POP3PluginParam, MyClient->SSL); //it closes internet connection too - } - - if (UsingInternet && (POP3_DELETEFROMCHECK != POP3PluginParam)) //if our thread still uses internet and it is needed to release internet - SetEvent(ActualAccount->UseInternetFree); - } - - free(ActualCopied.ServerName); - free(ActualCopied.ServerLogin); - free(ActualCopied.ServerPasswd); - - DeleteMIMEQueue(ActualAccount, NewMails); - DeleteMIMEQueue(ActualAccount, DeleteMails); - - #ifdef DEBUG_COMM - DebugLog(CommFile, "</--------Communication-------->\n"); - #endif - - // WriteAccounts(); - SCDec(ActualAccount->UsingThreads); - return; -} - -void ExtractStat(char *stream, int *mboxsize, int *mails) -{ - char *finder = stream; - while (WS(finder) || ENDLINE(finder)) finder++; - if (ACKLINE(finder)) { - while (!WS(finder)) finder++; - while (WS(finder)) finder++; - } - if (1 != sscanf(finder, "%d", mails)) - throw (uint32_t)EPOP3_STAT; - while (!WS(finder)) finder++; - while (WS(finder)) finder++; - if (1 != sscanf(finder, "%d", mboxsize)) - throw (uint32_t)EPOP3_STAT; -} -void ExtractMail(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr = queue; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n"); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) - throw (uint32_t)EPOP3_UIDL; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++); - // if (i != msgnr) - // throw (uint32_t)EPOP3_UIDL; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - while (!WS(finderend) && !ENDLINE(finderend)) finderend++; - queueptr->ID = new char[finderend - finder + 1]; - for (i = 0; finder != finderend; finder++, i++) - queueptr->MailData->Body[i] = *finder; - queueptr->MailData->Body[i] = 0; //ends string - queueptr->Number = msgnr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->MailData->Body); - DebugLog(DecodeFile, "</Message>\n"); - #endif - queueptr = queueptr->Next; - while (!ENDLINE(finder)) finder++; - } -} - -void ExtractUIDL(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr = queue; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n"); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) - throw (uint32_t)EPOP3_UIDL; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++); - // if (i != msgnr) - // throw (uint32_t)EPOP3_UIDL; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - while (!WS(finderend) && !ENDLINE(finderend)) finderend++; - queueptr->ID = new char[finderend - finder + 1]; - for (i = 0; finder != finderend; finder++, i++) - queueptr->ID[i] = *finder; - queueptr->ID[i] = 0; //ends string - queueptr->Number = msgnr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->ID); - DebugLog(DecodeFile, "</Message>\n"); - #endif - queueptr = queueptr->Next; - while (!ENDLINE(finder)) finder++; - } -} - -void ExtractList(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n", NULL, 0); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) //message nr. - throw (uint32_t)EPOP3_LIST; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - - for (i = 1, queueptr = queue; (queueptr->Next != nullptr) && (i < msgnr); queueptr = queueptr->Next, i++); - if (i != msgnr) - throw (uint32_t)EPOP3_LIST; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - if (1 != sscanf(finder, "%u", &queueptr->MailData->Size)) - throw (uint32_t)EPOP3_LIST; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", queueptr->MailData->Size); - #endif - while (!ENDLINE(finder)) finder++; - } -} - -wchar_t *WINAPI GetErrorString(DWORD Code) -{ - static wchar_t *POP3Errors[] = - { - LPGENW("Memory allocation error."), //memory allocation - LPGENW("Account is about to be stopped."), //stop account - LPGENW("Cannot connect to POP3 server."), - LPGENW("Cannot allocate memory for received data."), - LPGENW("Cannot login to POP3 server."), - LPGENW("Bad user or password."), - LPGENW("Server does not support APOP authorization."), - LPGENW("Error while executing POP3 command."), - LPGENW("Error while executing POP3 command."), - LPGENW("Error while executing POP3 command."), - }; - - static wchar_t *NetlibErrors[] = - { - LPGENW("Cannot connect to server with NetLib."), - LPGENW("Cannot send data."), - LPGENW("Cannot receive data."), - LPGENW("Cannot allocate memory for received data."), - }; - - static wchar_t *SSLErrors[] = - { - LPGENW("OpenSSL not loaded."), - LPGENW("Windows socket 2.0 init failed."), - LPGENW("DNS lookup error."), - LPGENW("Error while creating base socket."), - LPGENW("Error connecting to server with socket."), - LPGENW("Error while creating SSL structure."), - LPGENW("Error connecting socket with SSL."), - LPGENW("Server rejected connection with SSL."), - LPGENW("Cannot write SSL data."), - LPGENW("Cannot read SSL data."), - LPGENW("Cannot allocate memory for received data."), - }; - - wchar_t *ErrorString = new wchar_t[ERRORSTR_MAXLEN]; - POP3_ERRORCODE *ErrorCode = (POP3_ERRORCODE *)(UINT_PTR)Code; - - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"), ErrorCode->AppError, ErrorCode->POP3Error, ErrorCode->NetError, ErrorCode->SystemError); - if (ErrorCode->POP3Error) - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(POP3Errors[ErrorCode->POP3Error - 1])); - if (ErrorCode->NetError) { - if (ErrorCode->SSL) - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(SSLErrors[ErrorCode->NetError - 1])); - else - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(NetlibErrors[ErrorCode->NetError - 4])); - } - - return ErrorString; -} - -void WINAPI DeleteErrorString(LPVOID String) -{ - delete (char *)String; -} +/*
+ * This code implements POP3 server checking for new mail and so on.
+ * There's function SynchroPOP3 in this file- for checking and synchronising POP3 account
+ * and DeleteMailsPOP3- for deleting mails from POP3 server
+ *
+ * Note this file acts as main file for internal plugin.
+ *
+ * (c) majvan 2002-2004
+ * 18/08
+ */
+
+
+#include "../../stdafx.h"
+
+#define ERRORSTR_MAXLEN 1024 //in wide-chars
+
+ //--------------------------------------------------------------------------------------------------
+
+HANDLE hNetLib = nullptr;
+PSCOUNTER CPOP3Account::AccountWriterSO = nullptr;
+
+//Creates new CPOP3Account structure
+CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin, DWORD CAccountVersion);
+
+//Deletes CPOP3Account structure
+void WINAPI DeletePOP3Account(CAccount *Which);
+
+//Sets stop flag to account
+void WINAPI StopPOP3Account(CAccount *Which);
+
+//Function registers standard functions for YAMN
+int RegisterPOP3Plugin(WPARAM, LPARAM);
+
+//Unloads all variables created on heap (delete[])
+DWORD WINAPI UnLoadPOP3(void *);
+
+//Function writes POP3 accounts using YAMN exported functions
+DWORD WINAPI WritePOP3Accounts();
+
+//Function stores plugin's data for account to file
+DWORD WINAPI WritePOP3Options(HANDLE, CAccount *);
+
+//Function reads plugin's data for account from file
+DWORD WINAPI ReadPOP3Options(CAccount *, char **, char *);
+
+//Creates new mail for an account
+HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD CMimeMailVersion);
+
+//Function does all needed work when connection failed or any error occured
+//Creates structure containing error code, closes internet session, runs "bad connect" function
+static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnect, uint32_t POP3PluginParam, BOOL UseSSL);
+
+//Checks POP3 account and stores all info to account. It deletes old mails=> synchro
+// WhichTemp- pointer to strucure containing needed information
+DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp);
+
+//Deletes mails from POP3 server
+// WhichTemp- structure containing needed information (queued messages to delete)
+//Function deletes from memory queue in WhichTemp structure
+void __cdecl DeleteMailsPOP3(void *param);
+
+//Function makes readable message about error. It sends it back to YAMN, so YAMN then
+//can show it to the message window
+wchar_t *WINAPI GetErrorString(DWORD Code);
+
+//Function deletes string allocated in GetErrorString
+void WINAPI DeleteErrorString(LPVOID String);
+
+//Extracts info from result of POP3's STAT command
+// stream- source string
+// len- length of source string
+// mboxsize- adreess to integer, that receives size of mailbox
+// mails- adreess to integer, that receives number of mails
+void ExtractStat(char *stream, int *mboxsize, int *mails);
+
+//Extracts mail ID on mailbox
+// stream- source string
+// len- length of source string
+// queue- address of first message, where first ID will be stored
+void ExtractUIDL(char *stream, int len, HYAMNMAIL queue);
+
+//Extracts mail size on mailbox
+// stream- source string
+// len- length of source string
+// queue- address of first message, where size of message #1 will be stored
+void ExtractList(char *stream, int len, HYAMNMAIL queue);
+
+void ExtractMail(char *stream, int len, HYAMNMAIL queue);
+
+YAMNExportedFcns *pYAMNFcn = nullptr;
+MailExportedFcns *pYAMNMailFcn = nullptr;
+
+YAMN_PROTOIMPORTFCN POP3ProtocolFunctions =
+{
+ CreatePOP3Account,
+ DeletePOP3Account,
+ StopPOP3Account,
+ WritePOP3Options,
+ ReadPOP3Options,
+ SynchroPOP3,
+ SynchroPOP3,
+ SynchroPOP3,
+ DeleteMailsPOP3,
+ GetErrorString,
+ nullptr,
+ DeleteErrorString,
+ WritePOP3Accounts,
+ nullptr,
+ UnLoadPOP3,
+};
+
+YAMN_MAILIMPORTFCN POP3MailFunctions =
+{
+ CreatePOP3Mail,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+PYAMN_VARIABLES pYAMNVar = nullptr;
+HYAMNPROTOPLUGIN POP3Plugin = nullptr;
+
+YAMN_PROTOREGISTRATION POP3ProtocolRegistration =
+{
+ "POP3 protocol (internal)",
+ __VERSION_STRING_DOTS,
+ __COPYRIGHT,
+ __DESCRIPTION,
+ __AUTHORWEB,
+};
+
+static wchar_t *FileName = nullptr;
+
+HANDLE RegisterNLClient(char *name);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+CPOP3Account::CPOP3Account()
+{
+ //NOTE! This constructor constructs CAccount structure. If your plugin is not internal,
+ //you will need these constructors. All you need is in Account.cpp. Just copy to your source code
+ //constructor and destructor of CAccount.
+ UseInternetFree = CreateEvent(nullptr, FALSE, TRUE, nullptr);
+ InternetQueries = new SCOUNTER;
+ AbilityFlags = YAMN_ACC_BROWSE | YAMN_ACC_POPUP;
+
+ SetAccountStatus((CAccount *)this, TranslateT("Disconnected"));
+}
+
+CPOP3Account::~CPOP3Account()
+{
+ CloseHandle(UseInternetFree);
+ if (InternetQueries != nullptr)
+ delete InternetQueries;
+}
+
+CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN, DWORD)
+{
+ //First, we should check whether CAccountVersion matches.
+ //But this is internal plugin, so YAMN's CAccount structure and our CAccount structure are
+ //the same, so we do not need to test version. Otherwise, if CAccount version does not match
+ //in your plugin, you should return NULL, like this:
+ // if (CAccountVersion != YAMN_ACCOUNTVERSION) return NULL;
+
+ //Now it is needed to construct our POP3 account and return its handle
+ return (CAccount *)new struct CPOP3Account();
+}
+
+void WINAPI DeletePOP3Account(CAccount *Which)
+{
+ delete (HPOP3ACCOUNT)Which;
+}
+
+void WINAPI StopPOP3Account(CAccount *Which)
+{
+ ((HPOP3ACCOUNT)Which)->Client.Stopped = TRUE;
+ if (((HPOP3ACCOUNT)Which)->Client.NetClient != nullptr) //we should inform also network client. Usefull only when network client implements this feature
+ ((HPOP3ACCOUNT)Which)->Client.NetClient->Stopped = TRUE;
+}
+
+//This function is like main function for POP3 internal protocol
+int RegisterPOP3Plugin(WPARAM, LPARAM)
+{
+ // Get YAMN variables we can use
+ if (nullptr == (pYAMNVar = (PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES, YAMN_VARIABLESVERSION, 0)))
+ return 0;
+
+ // We have to get pointers to YAMN exported functions: allocate structure and fill it
+ if (nullptr == (pYAMNFcn = new struct YAMNExportedFcns)) {
+LBL_Error:
+ UnLoadPOP3(nullptr);
+ return 0;
+ }
+
+ // Register new pop3 user in netlib
+ if (nullptr == (hNetLib = RegisterNLClient("YAMN (POP3)")))
+ goto LBL_Error;
+
+ pYAMNFcn->SetProtocolPluginFcnImportFcn = (YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID, 0);
+ pYAMNFcn->WaitToWriteFcn = (YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOWRITEID, 0);
+ pYAMNFcn->WriteDoneFcn = (YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WRITEDONEID, 0);
+ pYAMNFcn->WaitToReadFcn = (YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOREADID, 0);
+ pYAMNFcn->ReadDoneFcn = (YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_READDONEID, 0);
+ pYAMNFcn->SCGetNumberFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCGETNUMBERID, 0);
+ pYAMNFcn->SCIncFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCINCID, 0);
+ pYAMNFcn->SCDecFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCDECID, 0);
+ pYAMNFcn->SetStatusFcn = (YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETSTATUSID, 0);
+ pYAMNFcn->GetStatusFcn = (YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_GETSTATUSID, 0);
+
+ if (nullptr == (pYAMNMailFcn = new struct MailExportedFcns))
+ goto LBL_Error;
+
+ pYAMNMailFcn->SynchroMessagesFcn = (YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SYNCHROMIMEMSGSID, 0);
+ pYAMNMailFcn->TranslateHeaderFcn = (YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_TRANSLATEHEADERID, 0);
+ pYAMNMailFcn->AppendQueueFcn = (YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_APPENDQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessagesToEndFcn = (YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessageFromQueueFcn = (YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEMESSAGEID, 0);
+ pYAMNMailFcn->FindMessageByIDFcn = (YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_FINDMIMEMESSAGEID, 0);
+ pYAMNMailFcn->CreateNewDeleteQueueFcn = (YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_CREATENEWDELETEQUEUEID, 0);
+
+ //set static variable
+ if (CPOP3Account::AccountWriterSO == nullptr)
+ if (nullptr == (CPOP3Account::AccountWriterSO = new SCOUNTER))
+ goto LBL_Error;
+
+ //First, we register this plugin
+ //it is quite impossible this function returns zero (failure) as YAMN and internal plugin structre versions are the same
+ POP3ProtocolRegistration.Name = Translate("POP3 protocol (internal)");
+ POP3ProtocolRegistration.Description = Translate(__DESCRIPTION);
+ if (nullptr == (POP3Plugin = (HYAMNPROTOPLUGIN)CallService(MS_YAMN_REGISTERPROTOPLUGIN, (WPARAM)&POP3ProtocolRegistration, (LPARAM)YAMN_PROTOREGISTRATIONVERSION)))
+ return 0;
+
+ //Next we set our imported functions for YAMN
+ if (!SetProtocolPluginFcnImport(POP3Plugin, &POP3ProtocolFunctions, YAMN_PROTOIMPORTFCNVERSION, &POP3MailFunctions, YAMN_MAILIMPORTFCNVERSION))
+ return 0;
+
+ //Then, we read all mails for accounts.
+ //You must first register account, before using this function as YAMN must use CreatePOP3Account function to add new accounts
+ //But if CreatePOP3Account is not implemented (equals to NULL), YAMN creates account as YAMN's standard CAccount *
+ if (FileName) CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); //shoud not happen (only for secure)
+ FileName = (wchar_t *)CallService(MS_YAMN_GETFILENAME, (WPARAM)L"pop3", 0);
+
+ switch (CallService(MS_YAMN_READACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName)) {
+ case EACC_FILEVERSION:
+ MessageBox(nullptr, TranslateT("Found new version of account book, not compatible with this version of YAMN."), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_FILECOMPATIBILITY:
+ MessageBox(nullptr, TranslateT("Error reading account file. Account file corrupted."), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_ALLOC:
+ MessageBox(nullptr, TranslateT("Memory allocation error while data reading"), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_SYSTEM:
+ if (ERROR_FILE_NOT_FOUND != GetLastError()) {
+ wchar_t temp[1024] = {0};
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Reading file error. File already in use?"), FileName);
+ MessageBox(nullptr, temp, TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ }
+ break;
+ }
+
+ for (CAccount *Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ Finder->hContact = NULL;
+ for (auto &hContact : Contacts(YAMN_DBMODULE)) {
+ DBVARIANT dbv;
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ if (mir_strcmp(dbv.pszVal, Finder->Name) == 0) {
+ Finder->hContact = hContact;
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ Contact::Hide(Finder->hContact, false);
+
+ if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ Contact::Hide(Finder->hContact);
+ }
+ db_free(&dbv);
+ }
+ }
+
+ if (!Finder->hContact && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ // No account contact found, have to create one
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_OFFLINE);
+ }
+ }
+
+ return 0;
+}
+
+DWORD WINAPI UnLoadPOP3(void *)
+{
+ //pYAMNVar is only a pointr, no need delete or free
+ if (hNetLib) {
+ Netlib_CloseHandle(hNetLib); hNetLib = nullptr;
+ }
+ if (CPOP3Account::AccountWriterSO) {
+ delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = nullptr;
+ }
+ if (pYAMNMailFcn) {
+ delete pYAMNMailFcn; pYAMNMailFcn = nullptr;
+ }
+ if (pYAMNFcn) {
+ delete pYAMNFcn; pYAMNFcn = nullptr;
+ }
+ if (FileName) {
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); FileName = nullptr;
+ }
+
+ return 1;
+}
+
+DWORD WINAPI WritePOP3Accounts()
+{
+ uint32_t ReturnValue = CallService(MS_YAMN_WRITEACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName);
+ if (ReturnValue == EACC_SYSTEM) {
+ wchar_t temp[1024] = {0};
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Error while copying data to disk occurred. Is file in use?"), FileName);
+ MessageBox(nullptr, temp, TranslateT("POP3 plugin - write file error"), MB_OK);
+ }
+
+ return ReturnValue;
+}
+
+DWORD WINAPI WritePOP3Options(HANDLE File, CAccount *Which)
+{
+ DWORD WrittenBytes;
+ uint32_t Ver = POP3_FILEVERSION;
+
+ if ((!WriteFile(File, (char *)&Ver, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&((HPOP3ACCOUNT)Which)->CP, sizeof(uint16_t), &WrittenBytes, nullptr)))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WINAPI ReadPOP3Options(CAccount *Which, char **Parser, char *End)
+{
+ uint32_t Ver;
+ #ifdef DEBUG_FILEREAD
+ wchar_t Debug[256];
+ #endif
+ Ver = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Ver != POP3_FILEVERSION)
+ return EACC_FILECOMPATIBILITY;
+
+ ((HPOP3ACCOUNT)Which)->CP = *(uint16_t *)(*Parser);
+ (*Parser) += sizeof(uint16_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"CodePage: %d, remaining %d chars", ((HPOP3ACCOUNT)Which)->CP, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ return 0;
+}
+
+HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD)
+{
+ HYAMNMAIL NewMail;
+ //First, we should check whether MAILDATA matches.
+ //But this is internal plugin, so YAMN's MAILDATA structure and our MAILDATA structure are
+ //the same, so we do not need to test version. Otherwise, if MAILDATA version does not match
+ //in your plugin, you should return NULL, like this:
+ // if (MailDataVersion != YAMN_MAILDATAVERSION) return NULL;
+
+ //Now it is needed to construct our POP3 account and return its handle
+ if (nullptr == (NewMail = new YAMNMAIL))
+ return nullptr;
+
+ if (nullptr == (NewMail->MailData = new CMailData())) {
+ delete NewMail;
+ return nullptr;
+ }
+ NewMail->MailData->CP = ((HPOP3ACCOUNT)Account)->CP;
+ return (HYAMNMAIL)NewMail;
+}
+
+static void SetContactStatus(CAccount *account, int status)
+{
+ if ((account->hContact) && (account->NewMailN.Flags & YAMN_ACC_CONT))
+ g_plugin.setWord(account->hContact, "Status", status);
+}
+
+static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnection, uint32_t POP3PluginParam, BOOL UseSSL)
+{
+ char *DataRX;
+
+ //We create new structure, that we pass to bad connection dialog procedure. This procedure next calls YAMN imported fuction
+ //from POP3 protocol to determine the description of error. We can describe error from our error code structure, because later,
+ //when YAMN calls our function, it passes us our error code. This is pointer to structure for POP3 protocol in fact.
+ PPOP3_ERRORCODE ErrorCode;
+
+ //We store status before we do Quit(), because quit can destroy our errorcode status
+ if (nullptr != (ErrorCode = new POP3_ERRORCODE)) {
+ ErrorCode->SSL = UseSSL;
+ ErrorCode->AppError = ActualAccount->SystemError;
+ ErrorCode->POP3Error = ActualAccount->Client.POP3Error;
+ ErrorCode->NetError = ActualAccount->Client.NetClient->NetworkError;
+ ErrorCode->SystemError = ActualAccount->Client.NetClient->SystemError;
+ }
+
+ if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call (force check or so on)
+ {
+ try {
+ DataRX = ActualAccount->Client.Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ }
+ catch (...) {
+ }
+ //We always close connection if error occured
+ try {
+ ActualAccount->Client.NetClient->Disconnect();
+ }
+ catch (...) {
+ }
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+
+ //If we cannot allocate memory, do nothing
+ if (ErrorCode == nullptr) {
+ SetEvent(ActualAccount->UseInternetFree);
+ return;
+ }
+ }
+ else // else it was called from POP3 plugin, probably error when deleting old mail (POP3 synchro calls POP3 delete)
+ if (ErrorCode == nullptr)
+ return;
+
+ if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP))
+ RunBadConnection(ActualAccount, (UINT_PTR)ErrorCode, ParamToBadConnection);
+
+ if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call
+ SetEvent(ActualAccount->UseInternetFree);
+}
+
+//Checks POP3 account and synchronizes it
+DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp)
+{
+ HPOP3ACCOUNT ActualAccount;
+ CPop3Client *MyClient;
+ HYAMNMAIL NewMails = nullptr, MsgQueuePtr = nullptr;
+ char *DataRX = nullptr, *Temp;
+ int mboxsize, msgs, i;
+ SYSTEMTIME now;
+ LPVOID YAMNParam;
+ uint32_t CheckFlags;
+ BOOL UsingInternet = FALSE;
+ struct
+ {
+ char *ServerName;
+ uint32_t ServerPort;
+ char *ServerLogin;
+ char *ServerPasswd;
+ uint32_t Flags;
+ uint32_t NFlags;
+ uint32_t NNFlags;
+ } ActualCopied;
+
+ //First, we should compare our version of CheckParam structure, but here it is not needed, because YAMN and internal plugin
+ //have the same version. But your plugin should do that in this way:
+ // if (((struct CheckParam *)WhichTemp)->Ver != YAMN_CHECKVERSION)
+ // {
+ // SetEvent(((struct CheckParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN
+ // return (uint32_t)-1; //ok, but we should return value.
+ // //When our plugin returns e.g. 0xFFFFFFFF (=-1, this is only our plugin value, YAMN does nothing with return value,
+ // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn. We know problem occured in YAMN incompatibility
+ // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN".
+ // }
+
+ ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread
+ YAMNParam = WhichTemp->BrowserParam;
+ CheckFlags = WhichTemp->Flags;
+
+ SCInc(ActualAccount->UsingThreads);
+ //Unblock YAMN, signal that we have copied all parameters from YAMN thread stack
+ if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV)
+ SetEvent(WhichTemp->ThreadRunningEV);
+
+ if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) {
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+ }
+
+ MyClient = &ActualAccount->Client;
+ //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes.
+ ActualCopied.ServerName = _strdup(ActualAccount->Server->Name);
+ ActualCopied.ServerPort = ActualAccount->Server->Port;
+ ActualCopied.Flags = ActualAccount->Flags;
+ ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login);
+ ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd);
+ ActualCopied.NFlags = ActualAccount->NewMailN.Flags;
+ ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags;
+
+ ReadDone(ActualAccount);
+ SCInc(ActualAccount->InternetQueries); //increment counter, that there is one more thread waiting for connection
+
+ WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); //wait until we can use connection
+ SCDec(ActualAccount->InternetQueries);
+
+ //OK, we enter the "use internet" section. But after we start communication, we can test if we did not enter the "use internet" section only for the reason,
+ //that previous thread release the internet section because this account has stop signal (we stop account and there are 2 threads: one communicating,
+ //the second one waiting for network access- the first one ends because we want to stop account, this one is released, but should be stopped as well).
+ if (!ActualAccount->AbleToWork) {
+ SetEvent(ActualAccount->UseInternetFree);
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+ }
+ UsingInternet = TRUE;
+
+ GetLocalTime(&now);
+ ActualAccount->SystemError = 0; //now we can use internet for this socket. First, clear errorcode.
+ try {
+ SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED);
+
+ // if we are already connected, we have open session (another thread left us open session), so we don't need to login
+ // note that connected state without logging cannot occur, because if we close session, we always close socket too (we must close socket is the right word :))
+ if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) {
+ SetAccountStatus(ActualAccount, TranslateT("Connecting to server"));
+
+ DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS);
+ char *timestamp = nullptr;
+
+ if (DataRX != nullptr) {
+ if (ActualCopied.Flags & YAMN_ACC_APOP) {
+ char *lpos = strchr(DataRX, '<');
+ char *rpos = strchr(DataRX, '>');
+ if (lpos && rpos && rpos > lpos) {
+ int sz = (int)(rpos - lpos + 2);
+ timestamp = new char[sz];
+ memcpy(timestamp, lpos, sz - 1);
+ timestamp[sz - 1] = '\0';
+ }
+ }
+ free(DataRX);
+ DataRX = nullptr;
+ }
+
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualCopied.Flags & YAMN_ACC_APOP) {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+ SetAccountStatus(ActualAccount, TranslateT("Searching for new mail message"));
+
+ DataRX = MyClient->Stat();
+
+ ExtractStat(DataRX, &mboxsize, &msgs);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ for (i = 0; i < msgs; i++) {
+ if (!i)
+ MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ else {
+ MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ if (MsgQueuePtr == nullptr) {
+ ActualAccount->SystemError = EPOP3_QUEUEALLOC;
+ throw (uint32_t)ActualAccount->SystemError;
+ }
+ }
+
+ if (msgs) {
+ DataRX = MyClient->List();
+ ExtractList(DataRX, MyClient->NetClient->Rcv, NewMails);
+ if (DataRX != nullptr)
+ free(DataRX);
+
+ DataRX = MyClient->Uidl();
+ ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)(ActualAccount->SystemError = EACC_STOPPED);
+
+ ActualAccount->LastChecked = now;
+ for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) {
+ if (MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) {
+ HYAMNMAIL NewMsgsPtr = nullptr;
+ for (NewMsgsPtr = (HYAMNMAIL)NewMails; NewMsgsPtr != nullptr; NewMsgsPtr = NewMsgsPtr->Next) {
+ if (!mir_strcmp(MsgQueuePtr->ID, NewMsgsPtr->ID)) {
+ wchar_t accstatus[512];
+ mir_snwprintf(accstatus, TranslateT("Reading body %s"), NewMsgsPtr->ID);
+ SetAccountStatus(ActualAccount, accstatus);
+ DataRX = MyClient->Top(MsgQueuePtr->Number, 100);
+ if (DataRX != nullptr) {
+ Temp = DataRX;
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++);
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++;
+ }
+ else
+ continue;
+ //delete all the headers of the old mail MsgQueuePtr->MailData->TranslatedHeader
+ struct CMimeItem *TH = MsgQueuePtr->MailData->TranslatedHeader;
+ if (TH) for (; MsgQueuePtr->MailData->TranslatedHeader != nullptr;) {
+ TH = TH->Next;
+ if (MsgQueuePtr->MailData->TranslatedHeader->name != nullptr)
+ delete[] MsgQueuePtr->MailData->TranslatedHeader->name;
+ if (MsgQueuePtr->MailData->TranslatedHeader->value != nullptr)
+ delete[] MsgQueuePtr->MailData->TranslatedHeader->value;
+ delete MsgQueuePtr->MailData->TranslatedHeader;
+ MsgQueuePtr->MailData->TranslatedHeader = TH;
+ }
+
+ TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader);
+
+ MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED;
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ break;
+ }
+ }
+ }
+ }
+
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); //we get only new mails on server!
+
+ MsgsWriteDone(ActualAccount);
+ for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) {
+ if ((MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) && (MsgQueuePtr->Flags & YAMN_MSG_BODYRECEIVED)) {
+ MsgQueuePtr->Flags &= ~YAMN_MSG_BODYREQUESTED;
+ if (MsgQueuePtr->MsgWindow)
+ SendMessage(MsgQueuePtr->MsgWindow, WM_YAMN_CHANGECONTENT, 0, 0);
+ }
+ }
+
+ for (msgs = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next, msgs++); //get number of new mails
+
+ try {
+ wchar_t accstatus[512];
+
+ for (i = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; i++) {
+ BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY) != 0;
+ DataRX = MyClient->Top(MsgQueuePtr->Number, autoretr ? 100 : 0);
+ mir_snwprintf(accstatus, TranslateT("Reading new mail messages (%d%% done)"), 100 * i / msgs);
+ SetAccountStatus(ActualAccount, accstatus);
+
+ if (DataRX != nullptr) {
+ Temp = DataRX;
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++);
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++;
+ }
+ else
+ continue;
+
+ TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader);
+
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</New mail>\n");
+ #endif
+ MsgQueuePtr->Flags |= YAMN_MSG_NORMALNEW;
+ if (autoretr) MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED;
+
+ //We are going to filter mail. Warning!- we must not be in read access neither write access to mails when calling this service
+ //This is done, because the "NewMails" queue is not synchronised. It is because it is new queue. Only this thread uses new queue yet, it is not
+ //connected to account mail queue.
+ // CallService(MS_YAMN_FILTERMAIL,(WPARAM)ActualAccount,(LPARAM)MsgQueuePtr);
+ FilterMailSvc((WPARAM)ActualAccount, (LPARAM)MsgQueuePtr);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+
+ //MsgQueuePtr->MailData->Body=MyClient->Retr(MsgQueuePtr->Number);
+
+ MsgQueuePtr = MsgQueuePtr->Next;
+
+ }
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)ActualAccount->SystemError == EACC_STOPPED;
+
+ if (ActualAccount->Mails == nullptr)
+ ActualAccount->Mails = NewMails;
+ else {
+ ActualAccount->LastMail = ActualAccount->LastChecked;
+ AppendQueue((HYAMNMAIL)ActualAccount->Mails, NewMails);
+ }
+
+ MsgsWriteDone(ActualAccount);
+
+ // we are going to delete mails having SPAM flag level3 and 4 (see m_mails.h) set
+ {
+ struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, INVALID_HANDLE_VALUE, ActualAccount, YAMNParam, (void *)POP3_DELETEFROMCHECK};
+
+ // Delete mails from server. Here we should not be in write access for account's mails
+ DeleteMailsPOP3(&ParamToDeleteMails);
+ }
+
+ // if there is no waiting thread for internet connection close it
+ // else leave connection open
+ if (0 == SCGetNumber(ActualAccount->InternetQueries)) {
+ DataRX = MyClient->Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ MyClient->NetClient->Disconnect();
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+ }
+
+ UsingInternet = FALSE;
+ SetEvent(ActualAccount->UseInternetFree);
+
+ ActualAccount->LastSChecked = ActualAccount->LastChecked;
+ ActualAccount->LastSynchronised = ActualAccount->LastChecked;
+ }
+ catch (...) {
+ throw; //go to the main exception handling
+ }
+
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, ActualCopied.NNFlags, YAMNParam};
+
+ if (CheckFlags & YAMN_FORCECHECK)
+ Param.nnflags |= YAMN_ACC_POP; //if force check, show popup anyway and if mailbrowser was opened, do not close
+ Param.nnflags |= YAMN_ACC_MSGP; //do not close browser if already open
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ }
+ #ifdef DEBUG_COMM
+ catch (uint32_t ErrorCode)
+ #else
+ catch (uint32_t)
+ #endif
+ {
+ if (ActualAccount->Client.POP3Error == EPOP3_STOPPED)
+ ActualAccount->SystemError = EACC_STOPPED;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "ERROR: %x\n", ErrorCode);
+ #endif
+ if (WAIT_OBJECT_0 == MsgsWaitToWrite(ActualAccount)) {
+ ActualAccount->LastChecked = now;
+ MsgsWriteDone(ActualAccount);
+ }
+
+ DeleteMIMEQueue(ActualAccount, NewMails);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ switch (ActualAccount->SystemError) {
+ case EACC_QUEUEALLOC:
+ case EACC_STOPPED:
+ ActualAccount->Client.NetClient->Disconnect();
+ break;
+ default:
+ PostErrorProc(ActualAccount, YAMNParam, (uint32_t)NULL, MyClient->SSL); //it closes internet connection too
+ }
+
+ if (UsingInternet) //if our thread still uses internet
+ SetEvent(ActualAccount->UseInternetFree);
+
+ SetContactStatus(ActualAccount, ID_STATUS_NA);
+ }
+ free(ActualCopied.ServerName);
+ free(ActualCopied.ServerLogin);
+ free(ActualCopied.ServerPasswd);
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</--------Communication-------->\n");
+ #endif
+
+ // WriteAccounts();
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+}
+
+void __cdecl DeleteMailsPOP3(void *param)
+{
+ DeleteParam *WhichTemp = (DeleteParam *)param;
+
+ CPop3Client *MyClient;
+ HYAMNMAIL DeleteMails, NewMails = nullptr, MsgQueuePtr = nullptr;
+ char *DataRX = nullptr;
+ int mboxsize = 0, msgs = 0, i;
+ BOOL UsingInternet = FALSE;
+ struct
+ {
+ char *ServerName;
+ uint32_t ServerPort;
+ char *ServerLogin;
+ char *ServerPasswd;
+ uint32_t Flags;
+ uint32_t NFlags;
+ uint32_t NNFlags;
+ } ActualCopied;
+
+ //First, we should compare our version of DeleteParam structure, but here it is not needed, because YAMN and internal plugin
+ //have the same version. But your plugin should do that in this way:
+ // if (((struct DeleteParam *)WhichTemp)->Ver != YAMN_DELETEVERSION)
+ // {
+ // SetEvent(((struct DeleteParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN
+ // return (uint32_t)-1; //ok, but we should return value.
+ // //When our plugin returns e.g. 0xFFFFFFFF (this is only our plugin value, YAMN does nothing with return value,
+ // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn), we know problem occured in YAMN incompatibility
+ // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN".
+ // }
+
+ HPOP3ACCOUNT ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread
+ LPVOID YAMNParam = WhichTemp->BrowserParam;
+ UINT_PTR POP3PluginParam = (UINT_PTR)((struct DeleteParam *)WhichTemp)->CustomParam;
+
+ SCInc(ActualAccount->UsingThreads);
+ if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV)
+ SetEvent(WhichTemp->ThreadRunningEV);
+
+ if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) {
+ SCDec(ActualAccount->UsingThreads);
+ return;
+ }
+
+ if (nullptr == (DeleteMails = (HYAMNMAIL)CreateNewDeleteQueue((HYAMNMAIL)ActualAccount->Mails))) //if there's no mail for deleting, return
+ {
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, YAMN_ACC_MSGP, YAMN_ACC_MSGP, YAMNParam}; //Just update the window
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+
+ SCDec(ActualAccount->UsingThreads);
+ return;
+ }
+
+ MyClient = &(ActualAccount->Client);
+
+ //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes.
+ ActualCopied.ServerName = _strdup(ActualAccount->Server->Name);
+ ActualCopied.ServerPort = ActualAccount->Server->Port;
+ ActualCopied.Flags = ActualAccount->Flags;
+ ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login);
+ ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd);
+ ActualCopied.NFlags = ActualAccount->NewMailN.Flags;
+ ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags;
+
+ ReadDone(ActualAccount);
+
+ SCInc(ActualAccount->InternetQueries); //This is POP3-internal SCOUNTER, we set another thread wait for this account to be connected to inet
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked
+ WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE);
+
+ SCDec(ActualAccount->InternetQueries);
+ UsingInternet = TRUE;
+
+ try {
+ SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED);
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<--------Communication-------->\n");
+ #endif
+ if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) {
+ SetAccountStatus(ActualAccount, TranslateT("Connecting to server"));
+
+ DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS);
+
+ char *timestamp = nullptr;
+ if (DataRX != nullptr) {
+ if (ActualAccount->Flags & YAMN_ACC_APOP) {
+ char *lpos = strchr(DataRX, '<');
+ char *rpos = strchr(DataRX, '>');
+ if (lpos && rpos && rpos > lpos) {
+ int sz = (int)(rpos - lpos + 2);
+ timestamp = new char[sz];
+ memcpy(timestamp, lpos, sz - 1);
+ timestamp[sz - 1] = '\0';
+ }
+ }
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualAccount->Flags & YAMN_ACC_APOP) {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<--------Deleting requested mails-------->\n");
+ #endif
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not need to get mails on server as we have already it from check function
+ {
+ SetAccountStatus(ActualAccount, TranslateT("Deleting requested mails"));
+
+ DataRX = MyClient->Stat();
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting stat>\n");
+ #endif
+ ExtractStat(DataRX, &mboxsize, &msgs);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<MailBoxSize>%d</MailBoxSize>\n", mboxsize);
+ DebugLog(DecodeFile, "<Msgs>%d</Msgs>\n", msgs);
+ DebugLog(DecodeFile, "</Extracting stat>\n");
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ for (i = 0; i < msgs; i++) {
+ if (!i)
+ MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ else {
+ MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ if (MsgQueuePtr == nullptr) {
+ ActualAccount->SystemError = EPOP3_QUEUEALLOC;
+ throw (uint32_t)ActualAccount->SystemError;
+ }
+ }
+
+ if (msgs) {
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting UIDL>\n");
+ #endif
+ DataRX = MyClient->Uidl();
+ ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting UIDL>\n");
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ // we get "new mails" on server (NewMails will contain all mails on server not found in DeleteMails)
+ // but also in DeleteMails we get only those, which are still on server with their responsable numbers
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&DeleteMails, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ }
+ }
+ else SetAccountStatus(ActualAccount, TranslateT("Deleting spam"));
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)EACC_STOPPED;
+
+ if (msgs || POP3_DELETEFROMCHECK == POP3PluginParam) {
+ try {
+ HYAMNMAIL Temp;
+
+ for (i = 0, MsgQueuePtr = DeleteMails; MsgQueuePtr != nullptr; i++) {
+ if (!(MsgQueuePtr->Flags & YAMN_MSG_VIRTUAL)) //of course we can only delete real mails, not virtual
+ {
+ DataRX = MyClient->Dele(MsgQueuePtr->Number);
+ Temp = MsgQueuePtr->Next;
+ if (POP3_FOK == MyClient->AckFlag) //if server answers that mail was deleted
+ {
+ DeleteMIMEMessage((HYAMNMAIL *)&DeleteMails, MsgQueuePtr);
+ HYAMNMAIL DeletedMail = FindMIMEMessageByID((HYAMNMAIL)ActualAccount->Mails, MsgQueuePtr->ID);
+ if ((MsgQueuePtr->Flags & YAMN_MSG_MEMDELETE)) //if mail should be deleted from memory (or disk)
+ {
+ DeleteMIMEMessage((HYAMNMAIL *)&ActualAccount->Mails, DeletedMail); //remove from queue
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)POP3Plugin, (LPARAM)DeletedMail);
+ }
+ else //else mark it only as "deleted mail"
+ {
+ DeletedMail->Flags |= (YAMN_MSG_VIRTUAL | YAMN_MSG_DELETED);
+ DeletedMail->Flags &= ~(YAMN_MSG_NEW | YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE); //clear "new mail"
+ }
+ delete MsgQueuePtr->MailData;
+ delete[] MsgQueuePtr->ID;
+ delete MsgQueuePtr;
+ }
+ MsgQueuePtr = Temp;
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ else
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ }
+ catch (...) //if any exception in the code where we have write-access to account occured, don't forget to leave write-access
+ {
+ MsgsWriteDone(ActualAccount);
+ throw; //and go to the main exception handling
+ }
+
+ if (NewMails != nullptr)
+ // in ActualAccount->Mails we have all mails stored before calling this function
+ // in NewMails we have all mails not found in DeleteMails (in other words: we performed new ID checking and we
+ // stored all mails found on server, then we deleted the ones we wanted to delete in this function
+ // and NewMails queue now contains actual state of mails on server). But we will not use NewMails as actual state, because NewMails does not contain header data (subject, from...)
+ // We perform deleting from ActualAccount->Mails: we remove from original queue (ActualAccount->Mails) all deleted mails
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ // Now ActualAccount->Mails contains all mails when calling this function except the ones, we wanted to delete (these are in DeleteMails)
+ // And in NewMails we have new mails (if any)
+ else if (POP3_DELETEFROMCHECK != POP3PluginParam) {
+ DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails);
+ ActualAccount->Mails = nullptr;
+ }
+ }
+ else {
+ DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails);
+ ActualAccount->Mails = nullptr;
+ }
+
+ MsgsWriteDone(ActualAccount);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</--------Deleting requested mails-------->\n");
+ #endif
+
+ // TODO: now, we have in NewMails new mails. If NewMails is not NULL, we found some new mails, so Checking for new mail should be performed
+ // now, we do not call CheckPOP3
+
+ // if there is no waiting thread for internet connection close it
+ // else leave connection open
+ // if this functin was called from SynchroPOP3, then do not try to disconnect
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, YAMN_ACC_MSGP, YAMNParam};
+
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+
+ if (0 == SCGetNumber(ActualAccount->InternetQueries)) {
+ DataRX = MyClient->Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ MyClient->NetClient->Disconnect();
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+ }
+
+ UsingInternet = FALSE;
+ SetEvent(ActualAccount->UseInternetFree);
+ }
+ SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ }
+ #ifdef DEBUG_COMM
+ catch (uint32_t ErrorCode)
+ #else
+ catch (uint32_t)
+ #endif
+ {
+ if (ActualAccount->Client.POP3Error == EPOP3_STOPPED)
+ ActualAccount->SystemError = EACC_STOPPED;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "ERROR %x\n", ErrorCode);
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ switch (ActualAccount->SystemError) {
+ case EACC_QUEUEALLOC:
+ case EACC_STOPPED:
+ ActualAccount->Client.NetClient->Disconnect();
+ break;
+ default:
+ PostErrorProc(ActualAccount, YAMNParam, POP3PluginParam, MyClient->SSL); //it closes internet connection too
+ }
+
+ if (UsingInternet && (POP3_DELETEFROMCHECK != POP3PluginParam)) //if our thread still uses internet and it is needed to release internet
+ SetEvent(ActualAccount->UseInternetFree);
+ }
+
+ free(ActualCopied.ServerName);
+ free(ActualCopied.ServerLogin);
+ free(ActualCopied.ServerPasswd);
+
+ DeleteMIMEQueue(ActualAccount, NewMails);
+ DeleteMIMEQueue(ActualAccount, DeleteMails);
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</--------Communication-------->\n");
+ #endif
+
+ // WriteAccounts();
+ SCDec(ActualAccount->UsingThreads);
+ return;
+}
+
+void ExtractStat(char *stream, int *mboxsize, int *mails)
+{
+ char *finder = stream;
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ if (ACKLINE(finder)) {
+ while (!WS(finder)) finder++;
+ while (WS(finder)) finder++;
+ }
+ if (1 != sscanf(finder, "%d", mails))
+ throw (uint32_t)EPOP3_STAT;
+ while (!WS(finder)) finder++;
+ while (WS(finder)) finder++;
+ if (1 != sscanf(finder, "%d", mboxsize))
+ throw (uint32_t)EPOP3_STAT;
+}
+void ExtractMail(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr = queue;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n");
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr))
+ throw (uint32_t)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+ // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++);
+ // if (i != msgnr)
+ // throw (uint32_t)EPOP3_UIDL;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ while (!WS(finderend) && !ENDLINE(finderend)) finderend++;
+ queueptr->ID = new char[finderend - finder + 1];
+ for (i = 0; finder != finderend; finder++, i++)
+ queueptr->MailData->Body[i] = *finder;
+ queueptr->MailData->Body[i] = 0; //ends string
+ queueptr->Number = msgnr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->MailData->Body);
+ DebugLog(DecodeFile, "</Message>\n");
+ #endif
+ queueptr = queueptr->Next;
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+void ExtractUIDL(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr = queue;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n");
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr))
+ throw (uint32_t)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+ // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++);
+ // if (i != msgnr)
+ // throw (uint32_t)EPOP3_UIDL;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ while (!WS(finderend) && !ENDLINE(finderend)) finderend++;
+ queueptr->ID = new char[finderend - finder + 1];
+ for (i = 0; finder != finderend; finder++, i++)
+ queueptr->ID[i] = *finder;
+ queueptr->ID[i] = 0; //ends string
+ queueptr->Number = msgnr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->ID);
+ DebugLog(DecodeFile, "</Message>\n");
+ #endif
+ queueptr = queueptr->Next;
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+void ExtractList(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n", NULL, 0);
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr)) //message nr.
+ throw (uint32_t)EPOP3_LIST;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+
+ for (i = 1, queueptr = queue; (queueptr->Next != nullptr) && (i < msgnr); queueptr = queueptr->Next, i++);
+ if (i != msgnr)
+ throw (uint32_t)EPOP3_LIST;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ if (1 != sscanf(finder, "%u", &queueptr->MailData->Size))
+ throw (uint32_t)EPOP3_LIST;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", queueptr->MailData->Size);
+ #endif
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+wchar_t *WINAPI GetErrorString(DWORD Code)
+{
+ static wchar_t *POP3Errors[] =
+ {
+ LPGENW("Memory allocation error."), //memory allocation
+ LPGENW("Account is about to be stopped."), //stop account
+ LPGENW("Cannot connect to POP3 server."),
+ LPGENW("Cannot allocate memory for received data."),
+ LPGENW("Cannot login to POP3 server."),
+ LPGENW("Bad user or password."),
+ LPGENW("Server does not support APOP authorization."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ };
+
+ static wchar_t *NetlibErrors[] =
+ {
+ LPGENW("Cannot connect to server with NetLib."),
+ LPGENW("Cannot send data."),
+ LPGENW("Cannot receive data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ static wchar_t *SSLErrors[] =
+ {
+ LPGENW("OpenSSL not loaded."),
+ LPGENW("Windows socket 2.0 init failed."),
+ LPGENW("DNS lookup error."),
+ LPGENW("Error while creating base socket."),
+ LPGENW("Error connecting to server with socket."),
+ LPGENW("Error while creating SSL structure."),
+ LPGENW("Error connecting socket with SSL."),
+ LPGENW("Server rejected connection with SSL."),
+ LPGENW("Cannot write SSL data."),
+ LPGENW("Cannot read SSL data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ wchar_t *ErrorString = new wchar_t[ERRORSTR_MAXLEN];
+ POP3_ERRORCODE *ErrorCode = (POP3_ERRORCODE *)(UINT_PTR)Code;
+
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"), ErrorCode->AppError, ErrorCode->POP3Error, ErrorCode->NetError, ErrorCode->SystemError);
+ if (ErrorCode->POP3Error)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(POP3Errors[ErrorCode->POP3Error - 1]));
+ if (ErrorCode->NetError) {
+ if (ErrorCode->SSL)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(SSLErrors[ErrorCode->NetError - 1]));
+ else
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(NetlibErrors[ErrorCode->NetError - 4]));
+ }
+
+ return ErrorString;
+}
+
+void WINAPI DeleteErrorString(LPVOID String)
+{
+ delete (char *)String;
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3opt.cpp b/protocols/YAMN/src/proto/pop3/pop3opt.cpp index 80764d85bb..a1dfa14199 100644 --- a/protocols/YAMN/src/proto/pop3/pop3opt.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3opt.cpp @@ -1,1137 +1,1137 @@ -/* - * This code implements POP3 options window handling - * - * (c) majvan 2002-2003 -*/ - -#include "../../stdafx.h" - -//-------------------------------------------------------------------------------------------------- - -static char DlgInput[MAX_PATH]; - -static BOOL DlgSetItemText(HWND hDlg, WPARAM wParam, const char *str) -{ - if (str == nullptr) - SetDlgItemTextA(hDlg, wParam, ""); - else - SetDlgItemTextA(hDlg, wParam, str); - return TRUE; -} - -static BOOL DlgSetItemTextW(HWND hDlg, WPARAM wParam, const wchar_t *str) -{ - if (str == nullptr) - SetDlgItemTextW(hDlg, wParam, L""); - else - SetDlgItemTextW(hDlg, wParam, str); - return TRUE; -} - -struct CBaseOptionsDlg : public CDlgBase -{ - CBaseOptionsDlg(int iDlgId) : - CDlgBase(g_plugin, iDlgId) - {} - - void DlgShowAccount(HPOP3ACCOUNT pAccount) - { - int i; - - if (pAccount) { - // we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - WaitToRead(pAccount); - - DlgSetItemText(m_hwnd, IDC_EDITSERVER, pAccount->Server->Name); - DlgSetItemText(m_hwnd, IDC_EDITNAME, pAccount->Name); - DlgSetItemText(m_hwnd, IDC_EDITLOGIN, pAccount->Server->Login); - DlgSetItemText(m_hwnd, IDC_EDITPASS, pAccount->Server->Passwd); - DlgSetItemTextW(m_hwnd, IDC_EDITAPP, pAccount->NewMailN.App); - DlgSetItemTextW(m_hwnd, IDC_EDITAPPPARAM, pAccount->NewMailN.AppParam); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, pAccount->Server->Port, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, pAccount->Interval / 60, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, pAccount->NewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, pAccount->NoNewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, pAccount->BadConnectN.PopupTime, FALSE); - for (i = 0; i <= CPLENSUPP; i++) - if ((i < CPLENSUPP) && (CodePageNamesSupp[i].CP == pAccount->CP)) { - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)i, 0); - break; - } - - if (i == CPLENSUPP) - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0); - - CheckDlgButton(m_hwnd, IDC_CHECK, pAccount->Flags & YAMN_ACC_ENA ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSND, pAccount->NewMailN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKMSG, pAccount->NewMailN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKICO, pAccount->NewMailN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKPOP, pAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCOL, pAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPP, pAccount->NewMailN.Flags & YAMN_ACC_APP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKKBN, pAccount->NewMailN.Flags & YAMN_ACC_KBN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNPOP, pAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNCOL, pAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNMSGP, pAccount->NoNewMailN.Flags & YAMN_ACC_MSGP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFSND, pAccount->BadConnectN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFMSG, pAccount->BadConnectN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFICO, pAccount->BadConnectN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFPOP, pAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFCOL, pAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, pAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, pAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSSL, pAccount->Flags & YAMN_ACC_SSL23 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, pAccount->Flags & YAMN_ACC_NOTLS ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPOP, pAccount->Flags & YAMN_ACC_APOP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_AUTOBODY, pAccount->Flags & YAMN_ACC_BODY ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSTART, pAccount->StatusFlags & YAMN_ACC_STARTS ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFORCE, pAccount->StatusFlags & YAMN_ACC_FORCE ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, pAccount->NewMailN.Flags & YAMN_ACC_CONT ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNICK, pAccount->NewMailN.Flags & YAMN_ACC_CONTNICK ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNOEVENT, pAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT ? BST_CHECKED : BST_UNCHECKED); - - wchar_t accstatus[256]; - GetAccountStatus(pAccount, accstatus); - SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus); - ReadDone(pAccount); - } - else { - DlgSetItemText(m_hwnd, IDC_EDITSERVER, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITNAME, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITLOGIN, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITPASS, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITAPP, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITAPPPARAM, nullptr); - DlgSetItemText(m_hwnd, IDC_STTIMELEFT, nullptr); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, 110, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, 30, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE); - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0); - CheckDlgButton(m_hwnd, IDC_CHECK, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSND, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKMSG, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKICO, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKPOP, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCOL, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPP, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFSND, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFMSG, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFICO, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFPOP, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFCOL, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSTART, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFORCE, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSSL, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPOP, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_AUTOBODY, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, BST_CHECKED); - - SetDlgItemText(m_hwnd, IDC_STSTATUS, TranslateT("No account selected")); - } - } -}; - -//======================================================================================= -// General options dialog - -struct CGeneralOptDlg : public CBaseOptionsDlg -{ - CGeneralOptDlg() : - CBaseOptionsDlg(IDD_YAMNOPT) - {} - - bool OnInitDialog() override - { - CheckDlgButton(m_hwnd, IDC_CHECKTTB, g_plugin.getByte(YAMN_TTBFCHECK, 1) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_LONGDATE, (optDateTime & SHOWDATELONG) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_SMARTDATE, (optDateTime & SHOWDATENOTODAY) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_NOSECONDS, (optDateTime & SHOWDATENOSECONDS) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CLOSEONDELETE, g_plugin.getByte(YAMN_CLOSEDELETE, 0) ? BST_CHECKED : BST_UNCHECKED); - return true; - } - - bool OnApply() override - { - g_plugin.setByte(YAMN_CLOSEDELETE, IsDlgButtonChecked(m_hwnd, IDC_CLOSEONDELETE)); - g_plugin.setByte(YAMN_TTBFCHECK, IsDlgButtonChecked(m_hwnd, IDC_CHECKTTB)); - - AddTopToolbarIcon(0, 0); - - optDateTime = 0; - if (IsDlgButtonChecked(m_hwnd, IDC_LONGDATE)) optDateTime |= SHOWDATELONG; - if (IsDlgButtonChecked(m_hwnd, IDC_SMARTDATE)) optDateTime |= SHOWDATENOTODAY; - if (IsDlgButtonChecked(m_hwnd, IDC_NOSECONDS)) optDateTime |= SHOWDATENOSECONDS; - g_plugin.setByte(YAMN_DBTIMEOPTIONS, optDateTime); - return true; - } -}; - -//-------------------------------------------------------------------------------------------------- - -static int g_iStatusControls[] = {IDC_CHECKST0, IDC_CHECKST1, IDC_CHECKST2, IDC_CHECKST3, IDC_CHECKST4, IDC_CHECKST5, IDC_CHECKST6, IDC_CHECKST7}; - -static BOOL DlgShowAccountStatus(HWND hDlg, HPOP3ACCOUNT ActualAccount) -{ - if (ActualAccount) { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - - CheckDlgButton(hDlg, IDC_CHECKST0, ActualAccount->StatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST1, ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST2, ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST3, ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST4, ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST5, ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST6, ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST7, ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED); - - ReadDone(ActualAccount); - } - else { - CheckDlgButton(hDlg, IDC_CHECKST0, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST1, BST_CHECKED); - CheckDlgButton(hDlg, IDC_CHECKST2, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST3, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST4, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST5, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST6, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST7, BST_CHECKED); - } - return TRUE; -} - -static INT_PTR CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM) -{ - static HPOP3ACCOUNT ActualAccount; - switch (msg) { - case WM_INITDIALOG: - ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput); - if (ActualAccount != nullptr) { - DlgShowAccountStatus(hDlg, ActualAccount); - for (auto &it : g_iStatusControls) - EnableWindow(GetDlgItem(hDlg, it), true); - } - else { - for (auto &it : g_iStatusControls) - CheckDlgButton(hDlg, it, BST_CHECKED); - } - TranslateDialogDefault(hDlg); - SendMessage(GetParent(hDlg), PSM_UNCHANGED, (WPARAM)hDlg, 0); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hDlg, 0); - DestroyWindow(hDlg); - break; - - case IDOK: - int iShift = 1; - ActualAccount->StatusFlags = 0; - for (auto &it : g_iStatusControls) { - if (IsDlgButtonChecked(hDlg, it)) - ActualAccount->StatusFlags |= iShift; - iShift <<= 1; - } - - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUSOPTION, 0, 0); - EndDialog(hDlg, 0); - DestroyWindow(hDlg); - break; - } - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Account options - -class CAccOptDlg : public CBaseOptionsDlg -{ - INT_PTR Result; - UCHAR ActualStatus; - HPOP3ACCOUNT ActualAccount = nullptr; - - CCtrlCheck chkContact, chkSsl, chkApp; - CCtrlCombo cmbAccount, cmbCP; - CCtrlButton btnStatus, btnAdd, btnDel, btnApp, btnDefault, btnReset; - - void DlgEnableAccount(bool bEnable) - { - cmbAccount.Enable(POP3Plugin->FirstAccount != nullptr); - - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECK), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITSERVER), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNAME), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPORT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITLOGIN), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPASS), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITINTERVAL), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSND), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKMSG), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKICO), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKKBN), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNMSGP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFSND), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFMSG), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFICO), bEnable); - - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSTART), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFORCE), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_COMBOCP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_STTIMELEFT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNRESET), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEFAULT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNSTATUS), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSSL), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), chkSsl.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_AUTOBODY), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), chkContact.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), chkContact.IsChecked() && bEnable); - } - -public: - CAccOptDlg() : - CBaseOptionsDlg(IDD_POP3ACCOUNTOPT), - cmbCP(this, IDC_COMBOCP), - btnAdd(this, IDC_BTNADD), - btnApp(this, IDC_BTNAPP), - btnDel(this, IDC_BTNDEL), - chkApp(this, IDC_CHECKAPP), - chkSsl(this, IDC_CHECKSSL), - btnReset(this, IDC_BTNRESET), - btnStatus(this, IDC_BTNSTATUS), - btnDefault(this, IDC_BTNDEFAULT), - cmbAccount(this, IDC_COMBOACCOUNT), - chkContact(this, IDC_CHECKCONTACT) - { - cmbCP.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_CP); - - cmbAccount.OnChange = Callback(this, &CAccOptDlg::onChange_Account); - cmbAccount.OnKillFocus = Callback(this, &CAccOptDlg::onKillFocus_Account); - cmbAccount.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_Account); - - chkApp.OnChange = Callback(this, &CAccOptDlg::onChangeApp); - chkSsl.OnChange = Callback(this, &CAccOptDlg::onChangeSsl); - chkContact.OnChange = Callback(this, &CAccOptDlg::onChangeContact); - - btnAdd.OnClick = Callback(this, &CAccOptDlg::onClick_Add); - btnDel.OnClick = Callback(this, &CAccOptDlg::onClick_Del); - btnApp.OnClick = Callback(this, &CAccOptDlg::onClick_App); - btnReset.OnClick = Callback(this, &CAccOptDlg::onClick_Reset); - btnStatus.OnClick = Callback(this, &CAccOptDlg::onClick_Status); - btnDefault.OnClick = Callback(this, &CAccOptDlg::onClick_Default); - } - - bool OnInitDialog() override - { - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - - DlgEnableAccount(false); - DlgShowAccount(0); - - // Fill accounts - WaitToReadSO(POP3Plugin->AccountBrowserSO); - - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - cmbAccount.AddStringA(ActualAccount->Name); - cmbAccount.SetCurSel(0); - - ReadDoneSO(POP3Plugin->AccountBrowserSO); - - // Fill code pages - cmbCP.AddString(TranslateT("Default")); - for (int i = 1; i < CPLENSUPP; i++) { - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[i].CP, 0, &info); - size_t len = mir_wstrlen(info.CodePageName + 7); - info.CodePageName[len + 6] = 0; - cmbCP.AddString(info.CodePageName + 7); - } - cmbCP.SetCurSel(0); - - ActualAccount = nullptr; - SendMessage(GetParent(m_hwnd), PSM_UNCHANGED, (WPARAM)m_hwnd, 0); - - WindowList_Add(pYAMNVar->MessageWnds, m_hwnd); - return true; - } - - void OnDestroy() override - { - WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override - { - switch (msg) { - case WM_YAMN_CHANGESTATUS: - if ((HPOP3ACCOUNT)wParam == ActualAccount) { - wchar_t accstatus[256]; - GetAccountStatus(ActualAccount, accstatus); - SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus); - return TRUE; - } - break; - - case WM_YAMN_CHANGESTATUSOPTION: - NotifyChange(); - return TRUE; - - case WM_YAMN_CHANGETIME: - if ((HPOP3ACCOUNT)wParam == ActualAccount) { - wchar_t Text[256]; - mir_snwprintf(Text, TranslateT("Time left to next check [s]: %d"), (uint32_t)lParam); - SetDlgItemText(m_hwnd, IDC_STTIMELEFT, Text); - } - return TRUE; - } - return CDlgBase::DlgProc(msg, wParam, lParam); - } - - void onChange_Account(CCtrlCombo *) - { - ActualAccount = nullptr; - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - DlgEnableAccount(0 != GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput))); - } - - void onKillFocus_Account(CCtrlCombo *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - DlgEnableAccount(mir_strlen(DlgInput) > 0); - } - else { - DlgShowAccount(ActualAccount); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - } - } - - void onSelChange_Account(CCtrlCombo *) - { - if (CB_ERR != (Result = cmbAccount.GetCurSel())) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput); - - if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - } - else { - DlgShowAccount(ActualAccount); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - } - } - - void onSelChange_CP(CCtrlCombo *) - { - int sel = cmbCP.GetCurSel(); - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info); - DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName); - } - - void onChangeContact(CCtrlCheck *) - { - bool bEnabled = chkContact.IsChecked(); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), bEnabled); - } - - void onChangeSsl(CCtrlCheck *) - { - bool bEnabled = chkSsl.IsChecked(); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, bEnabled ? 995 : 110, FALSE); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), !bEnabled); - } - - void onChangeApp(CCtrlCheck *) - { - bool bEnabled = chkApp.IsChecked(); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), bEnabled); - } - - void onClick_Status(CCtrlButton *) - { - DialogBoxParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES), m_hwnd, DlgProcPOP3AccStatusOpt, NULL); - } - - void onClick_Add(CCtrlButton *) - { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - DlgShowAccount(0); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - DlgSetItemTextW(m_hwnd, IDC_EDITNAME, TranslateT("New Account")); - - int index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)TranslateT("New Account")); - if (index != CB_ERR && index != CB_ERRSPACE) - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, index, (LPARAM)TranslateT("New Account")); - } - - void onClick_App(CCtrlButton *) - { - wchar_t filter[MAX_PATH]; - mir_snwprintf(filter, L"%s (*.exe;*.bat;*.cmd;*.com)%c*.exe;*.bat;*.cmd;*.com%c%s (*.*)%c*.*%c", - TranslateT("Executables"), 0, 0, TranslateT("All Files"), 0, 0); - - OPENFILENAME OFNStruct = {0}; - OFNStruct.lStructSize = sizeof(OPENFILENAME); - OFNStruct.hwndOwner = m_hwnd; - OFNStruct.lpstrFilter = filter; - OFNStruct.nFilterIndex = 1; - OFNStruct.nMaxFile = MAX_PATH; - OFNStruct.lpstrFile = new wchar_t[MAX_PATH]; - OFNStruct.lpstrFile[0] = (wchar_t)0; - OFNStruct.lpstrTitle = TranslateT("Select executable used for notification"); - OFNStruct.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; - if (!GetOpenFileName(&OFNStruct)) { - if (CommDlgExtendedError()) - MessageBox(m_hwnd, TranslateT("Dialog box error"), TranslateT("Failed"), MB_OK); - } - else DlgSetItemTextW(m_hwnd, IDC_EDITAPP, OFNStruct.lpstrFile); - delete[] OFNStruct.lpstrFile; - } - - void onClick_Default(CCtrlButton *) - { - DlgShowAccount(0); - } - - void onClick_Del(CCtrlButton *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - if ((CB_ERR == (Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0))) - || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) - return; - - if (IDOK != MessageBox(m_hwnd, TranslateT("Do you really want to delete this account?"), TranslateT("Delete account confirmation"), MB_OKCANCEL | MB_ICONWARNING)) - return; - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - if (ActualAccount->hContact != NULL) - db_delete_contact(ActualAccount->hContact); - - CallService(MS_YAMN_DELETEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)ActualAccount); - - // We can consider our account as deleted. - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_DELETESTRING, Result, 0); - DlgSetItemText(m_hwnd, IDC_COMBOACCOUNT, nullptr); - DlgEnableAccount(false); - DlgShowAccount(0); - } - - void onClick_Reset(CCtrlButton *) - { - if (ActualAccount != nullptr) - ActualAccount->TimeLeft = ActualAccount->Interval; - } - - bool OnApply() override - { - char Text[MAX_PATH]; - wchar_t TextW[MAX_PATH]; - BOOL Translated, NewAcc = FALSE; - size_t Length, index; - - if (!GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text))) - return false; - - BOOL Check = (IsDlgButtonChecked(m_hwnd, IDC_CHECK) == BST_CHECKED); - BOOL CheckSSL = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSSL) == BST_CHECKED); - BOOL CheckNoTLS = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNOTLS) == BST_CHECKED); - BOOL CheckAPOP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPOP) == BST_CHECKED); - - BOOL CheckABody = (IsDlgButtonChecked(m_hwnd, IDC_AUTOBODY) == BST_CHECKED); - BOOL CheckMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKMSG) == BST_CHECKED); - BOOL CheckSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSND) == BST_CHECKED); - BOOL CheckIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKICO) == BST_CHECKED); - - BOOL CheckApp = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPP) == BST_CHECKED); - BOOL CheckKBN = (IsDlgButtonChecked(m_hwnd, IDC_CHECKKBN) == BST_CHECKED); - BOOL CheckContact = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACT) == BST_CHECKED); - BOOL CheckContactNick = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNICK) == BST_CHECKED); - BOOL CheckContactNoEvent = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNOEVENT) == BST_CHECKED); - - BOOL CheckFSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFSND) == BST_CHECKED); - BOOL CheckFMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFMSG) == BST_CHECKED); - BOOL CheckFIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFICO) == BST_CHECKED); - - BOOL CheckNMsgP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNMSGP) == BST_CHECKED); - - UINT Port = GetDlgItemInt(m_hwnd, IDC_EDITPORT, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITPORT)); - return false; - } - - UINT Interval = GetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITINTERVAL)); - return false; - } - - GetDlgItemTextA(m_hwnd, IDC_EDITAPP, Text, _countof(Text)); - if (CheckApp && !(Length = mir_strlen(Text))) { - MessageBox(m_hwnd, TranslateT("Please select application to run"), TranslateT("Input error"), MB_OK); - return false; - } - - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) { - GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) - return false; - } - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)Text))) { - NewAcc = TRUE; - WaitToWriteSO(POP3Plugin->AccountBrowserSO); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) { - WriteDoneSO(POP3Plugin->AccountBrowserSO); - MessageBox(m_hwnd, TranslateT("Cannot allocate memory space for new account"), TranslateT("Memory error"), MB_OK); - return false; - } - DlgEnableAccount(true); - } - else { // We have to get full access to AccountBrowser, so other iterating thrads cannot get new account until new account is right set - WaitToWriteSO(POP3Plugin->AccountBrowserSO); - } - - if (WAIT_OBJECT_0 != WaitToWrite(ActualAccount)) - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) - return false; - if (nullptr != ActualAccount->Name) - delete[] ActualAccount->Name; - ActualAccount->Name = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Name, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITSERVER, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Name) - delete[] ActualAccount->Server->Name; - ActualAccount->Server->Name = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Name, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITLOGIN, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Login) - delete[] ActualAccount->Server->Login; - ActualAccount->Server->Login = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Login, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITPASS, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Passwd) - delete[] ActualAccount->Server->Passwd; - ActualAccount->Server->Passwd = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Passwd, Text); - - GetDlgItemTextW(m_hwnd, IDC_EDITAPP, TextW, _countof(TextW)); - if (nullptr != ActualAccount->NewMailN.App) - delete[] ActualAccount->NewMailN.App; - ActualAccount->NewMailN.App = new wchar_t[mir_wstrlen(TextW) + 1]; - mir_wstrcpy(ActualAccount->NewMailN.App, TextW); - - GetDlgItemTextW(m_hwnd, IDC_EDITAPPPARAM, TextW, _countof(TextW)); - if (nullptr != ActualAccount->NewMailN.AppParam) - delete[] ActualAccount->NewMailN.AppParam; - ActualAccount->NewMailN.AppParam = new wchar_t[mir_wstrlen(TextW) + 1]; - mir_wstrcpy(ActualAccount->NewMailN.AppParam, TextW); - - ActualAccount->Server->Port = Port; - ActualAccount->Interval = Interval * 60; - - if (CB_ERR == (index = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0))) - index = CPDEFINDEX; - ActualAccount->CP = CodePageNamesSupp[index].CP; - - if (NewAcc) - ActualAccount->TimeLeft = Interval * 60; - - BOOL CheckStart = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSTART) == BST_CHECKED); - BOOL CheckForce = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFORCE) == BST_CHECKED); - - ActualAccount->Flags = - (Check ? YAMN_ACC_ENA : 0) | - (CheckSSL ? YAMN_ACC_SSL23 : 0) | - (CheckNoTLS ? YAMN_ACC_NOTLS : 0) | - (CheckAPOP ? YAMN_ACC_APOP : 0) | - (CheckABody ? YAMN_ACC_BODY : 0) | - (ActualAccount->Flags & YAMN_ACC_POPN); - - ActualAccount->StatusFlags &= 0xFFFF; - ActualAccount->StatusFlags |= - (CheckStart ? YAMN_ACC_STARTS : 0) | - (CheckForce ? YAMN_ACC_FORCE : 0); - - ActualAccount->NewMailN.Flags = - (CheckSnd ? YAMN_ACC_SND : 0) | - (CheckMsg ? YAMN_ACC_MSG : 0) | - (CheckIco ? YAMN_ACC_ICO : 0) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_POP) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) | - (CheckApp ? YAMN_ACC_APP : 0) | - (CheckKBN ? YAMN_ACC_KBN : 0) | - (CheckContact ? YAMN_ACC_CONT : 0) | - (CheckContactNick ? YAMN_ACC_CONTNICK : 0) | - (CheckContactNoEvent ? YAMN_ACC_CONTNOEVENT : 0) | - YAMN_ACC_MSGP; //this is default: when new mail arrives and window was displayed, leave it displayed. - - ActualAccount->NoNewMailN.Flags = - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP) | - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) | - (CheckNMsgP ? YAMN_ACC_MSGP : 0); - - ActualAccount->BadConnectN.Flags = - (CheckFSnd ? YAMN_ACC_SND : 0) | - (CheckFMsg ? YAMN_ACC_MSG : 0) | - (CheckFIco ? YAMN_ACC_ICO : 0) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC); - - WriteDone(ActualAccount); - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - - index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0); - - HPOP3ACCOUNT temp = ActualAccount; - - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0); - if (POP3Plugin->FirstAccount != nullptr) - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)ActualAccount->Name); - - ActualAccount = temp; - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, (WPARAM)index, (LPARAM)ActualAccount->Name); - - WritePOP3Accounts(); - RefreshContact(); - return TRUE; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Popup options - -class CPopupOptsDlg : public CBaseOptionsDlg -{ - HPOP3ACCOUNT ActualAccount = nullptr; - UCHAR ActualStatus; - - CCtrlCombo cmbAccount, cmbCP; - CCtrlCheck chkCol, chkFcol, chkNcol, chkPop, chkFpop, chkNpop; - CCtrlButton btnPreview; - - void DlgShowAccountPopup() - { - if (ActualAccount) { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, ActualAccount->NewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, ActualAccount->NoNewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, ActualAccount->BadConnectN.PopupTime, FALSE); - - chkPop.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POP); - chkCol.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POPC); - chkNpop.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP); - chkNcol.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC); - chkFpop.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - chkFcol.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); - ReadDone(ActualAccount); - } - else { // default - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE); - chkPop.SetState(true); - chkCol.SetState(true); - chkNpop.SetState(true); - chkNcol.SetState(true); - chkFpop.SetState(true); - chkFcol.SetState(true); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED); - } - } - - void DlgEnableAccountPopup(bool bEnable) - { - chkPop.Enable(bEnable); - chkCol.Enable(chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), chkPop.IsChecked() && bEnable); - - chkNpop.Enable(bEnable); - chkNcol.Enable(chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable); - - chkFpop.Enable(bEnable); - chkFcol.Enable(chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable); - } - - void DlgShowAccountColors() - { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - - if (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - if (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - - ReadDone(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - } - -public: - CPopupOptsDlg() : - CBaseOptionsDlg(IDD_POP3ACCOUNTPOPUP), - cmbCP(this, IDC_COMBOCP), - chkCol(this, IDC_CHECKCOL), - chkPop(this, IDC_CHECKPOP), - chkFcol(this, IDC_CHECKFCOL), - chkFpop(this, IDC_CHECKFPOP), - chkNcol(this, IDC_CHECKNCOL), - chkNpop(this, IDC_CHECKNPOP), - btnPreview(this, IDC_PREVIEW), - cmbAccount(this, IDC_COMBOACCOUNT) - { - chkPop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Pop); - chkFpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Fpop); - chkNpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Npop); - chkCol.OnChange = chkFcol.OnChange = chkNcol.OnChange = Callback(this, &CPopupOptsDlg::onChange_Col); - - cmbCP.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_CP); - - btnPreview.OnClick = Callback(this, &CPopupOptsDlg::onClick_Preview); - - cmbAccount.OnKillFocus = Callback(this, &CPopupOptsDlg::onKillFocus_Account); - cmbAccount.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_Account); - } - - bool OnInitDialog() override - { - WindowList_Add(pYAMNVar->MessageWnds, m_hwnd); - - DlgEnableAccountPopup(false); - DlgShowAccountPopup(); - - WaitToReadSO(POP3Plugin->AccountBrowserSO); - - if (POP3Plugin->FirstAccount != nullptr) - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - cmbAccount.AddStringA(ActualAccount->Name); - - ReadDoneSO(POP3Plugin->AccountBrowserSO); - ActualAccount = nullptr; - cmbAccount.SetCurSel(0); - return true; - } - - void OnDestroy() override - { - WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd); - } - - void onKillFocus_Account(CCtrlCombo *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - if (mir_strlen(DlgInput)) - DlgEnableAccountPopup(true); - else - DlgEnableAccountPopup(false); - } - else { - DlgShowAccount(ActualAccount); - DlgShowAccountColors(); - DlgEnableAccountPopup(true); - } - } - - void onSelChange_Account(CCtrlCombo *) - { - int Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0); - if (CB_ERR != Result) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput); - if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - } - else { - DlgShowAccount(ActualAccount); - DlgShowAccountColors(); - DlgEnableAccountPopup(true); - } - } - - void onSelChange_CP(CCtrlCombo *) - { - int sel = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0); - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info); - DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName); - } - - void onChange_Col(CCtrlCheck *) - { - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked()); - } - - void onClick_Preview(CCtrlButton *) - { - if (chkPop.IsChecked()) { - POPUPDATAW Tester = {}; - Tester.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - mir_wstrncpy(Tester.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME); - mir_wstrncpy(Tester.lpwzText, TranslateT("You have N new mail messages"), MAX_SECONDLINE); - if (chkCol.IsChecked()) { - Tester.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0); - Tester.colorText = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0); - } - else { - Tester.colorBack = GetSysColor(COLOR_BTNFACE); - Tester.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&Tester); - } - - if (chkFpop.IsChecked()) { - POPUPDATAW TesterF = {}; - TesterF.lchIcon = g_plugin.getIcon(IDI_BADCONNECT); - mir_wstrncpy(TesterF.lpwzContactName, TranslateT("Account Test (failed)"), MAX_CONTACTNAME); - mir_wstrncpy(TesterF.lpwzText, TranslateT("Connection failed message"), MAX_SECONDLINE); - if (chkFcol.IsChecked()) { - TesterF.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0); - TesterF.colorText = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0); - } - else { - TesterF.colorBack = GetSysColor(COLOR_BTNFACE); - TesterF.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&TesterF); - } - - if (chkNpop.IsChecked()) { - POPUPDATAW TesterN = {}; - TesterN.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP); - mir_wstrncpy(TesterN.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME); - mir_wstrncpy(TesterN.lpwzText, TranslateT("No new mail message"), MAX_SECONDLINE); - if (chkNcol.IsChecked()) { - TesterN.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0); - TesterN.colorText = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0); - } - else { - TesterN.colorBack = GetSysColor(COLOR_BTNFACE); - TesterN.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&TesterN); - } - } - - void onChange_Pop(CCtrlCheck *) - { - bool bEnabled = chkPop.IsChecked(); - chkCol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), bEnabled); - } - - void onChange_Fpop(CCtrlCheck *) - { - bool bEnabled = chkFpop.IsChecked(); - chkFcol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), bEnabled); - } - - void onChange_Npop(CCtrlCheck *) - { - bool bEnabled = chkNpop.IsChecked(); - chkNcol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), bEnabled); - } - - bool OnApply() override - { - wchar_t Text[MAX_PATH]; - if (!GetDlgItemText(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text))) - return false; - - BOOL CheckPopup = chkPop.IsChecked(); - BOOL CheckPopupW = chkCol.IsChecked(); - - BOOL CheckFPopup = chkFpop.IsChecked(); - BOOL CheckFPopupW = chkFcol.IsChecked(); - - BOOL CheckNPopup = chkNpop.IsChecked(); - BOOL CheckNPopupW = chkNcol.IsChecked(); - - BOOL CheckPopN = (IsDlgButtonChecked(m_hwnd, IDC_RADIOPOPN) == BST_CHECKED); - - BOOL Translated; - UINT Time = GetDlgItemInt(m_hwnd, IDC_EDITPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITPOPS)); - return false; - } - UINT TimeN = GetDlgItemInt(m_hwnd, IDC_EDITNPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITNPOPS)); - return false; - } - UINT TimeF = GetDlgItemInt(m_hwnd, IDC_EDITFPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITFPOPS)); - return false; - } - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - ActualAccount->Flags = - (ActualAccount->Flags & YAMN_ACC_ENA) | - (ActualAccount->Flags & YAMN_ACC_SSL23) | - (ActualAccount->Flags & YAMN_ACC_NOTLS) | - (ActualAccount->Flags & YAMN_ACC_APOP) | - (ActualAccount->Flags & YAMN_ACC_BODY) | - (CheckPopN ? YAMN_ACC_POPN : 0); - - ActualAccount->NewMailN.Flags = - (ActualAccount->NewMailN.Flags & YAMN_ACC_SND) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_MSG) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_ICO) | - (CheckPopup ? YAMN_ACC_POP : 0) | - (CheckPopupW ? YAMN_ACC_POPC : 0) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_APP) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONT) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT) | - YAMN_ACC_MSGP; - - ActualAccount->NoNewMailN.Flags = - (CheckNPopup ? YAMN_ACC_POP : 0) | - (CheckNPopupW ? YAMN_ACC_POPC : 0) | - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP); - - ActualAccount->BadConnectN.Flags = - (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) | - (CheckFPopup ? YAMN_ACC_POP : 0) | - (CheckFPopupW ? YAMN_ACC_POPC : 0); - - ActualAccount->NewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0); - ActualAccount->NewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0); - ActualAccount->NewMailN.PopupTime = Time; - - ActualAccount->NoNewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0); - ActualAccount->NoNewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0); - ActualAccount->NoNewMailN.PopupTime = TimeN; - - ActualAccount->BadConnectN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0); - ActualAccount->BadConnectN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0); - ActualAccount->BadConnectN.PopupTime = TimeF; - - WriteDone(ActualAccount); - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - WritePOP3Accounts(); - RefreshContact(); - return TRUE; - } -}; - -//-------------------------------------------------------------------------------------------------- - -int YAMNOptInitSvc(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.szGroup.a = LPGEN("Network"); - odp.szTitle.a = LPGEN("YAMN"); - odp.flags = ODPF_BOLDGROUPS; - - odp.szTab.a = LPGEN("Accounts"); - odp.pDialog = new CAccOptDlg(); - g_plugin.addOptions(wParam, &odp); - - odp.szTab.a = LPGEN("General"); - odp.pDialog = new CGeneralOptDlg(); - g_plugin.addOptions(wParam, &odp); - - odp.szGroup.a = LPGEN("Popups"); - odp.szTab.a = LPGEN("YAMN"); - odp.pDialog = new CPopupOptsDlg(); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/*
+ * This code implements POP3 options window handling
+ *
+ * (c) majvan 2002-2003
+*/
+
+#include "../../stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+
+static char DlgInput[MAX_PATH];
+
+static BOOL DlgSetItemText(HWND hDlg, WPARAM wParam, const char *str)
+{
+ if (str == nullptr)
+ SetDlgItemTextA(hDlg, wParam, "");
+ else
+ SetDlgItemTextA(hDlg, wParam, str);
+ return TRUE;
+}
+
+static BOOL DlgSetItemTextW(HWND hDlg, WPARAM wParam, const wchar_t *str)
+{
+ if (str == nullptr)
+ SetDlgItemTextW(hDlg, wParam, L"");
+ else
+ SetDlgItemTextW(hDlg, wParam, str);
+ return TRUE;
+}
+
+struct CBaseOptionsDlg : public CDlgBase
+{
+ CBaseOptionsDlg(int iDlgId) :
+ CDlgBase(g_plugin, iDlgId)
+ {}
+
+ void DlgShowAccount(HPOP3ACCOUNT pAccount)
+ {
+ int i;
+
+ if (pAccount) {
+ // we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ WaitToRead(pAccount);
+
+ DlgSetItemText(m_hwnd, IDC_EDITSERVER, pAccount->Server->Name);
+ DlgSetItemText(m_hwnd, IDC_EDITNAME, pAccount->Name);
+ DlgSetItemText(m_hwnd, IDC_EDITLOGIN, pAccount->Server->Login);
+ DlgSetItemText(m_hwnd, IDC_EDITPASS, pAccount->Server->Passwd);
+ DlgSetItemTextW(m_hwnd, IDC_EDITAPP, pAccount->NewMailN.App);
+ DlgSetItemTextW(m_hwnd, IDC_EDITAPPPARAM, pAccount->NewMailN.AppParam);
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, pAccount->Server->Port, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, pAccount->Interval / 60, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, pAccount->NewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, pAccount->NoNewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, pAccount->BadConnectN.PopupTime, FALSE);
+ for (i = 0; i <= CPLENSUPP; i++)
+ if ((i < CPLENSUPP) && (CodePageNamesSupp[i].CP == pAccount->CP)) {
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)i, 0);
+ break;
+ }
+
+ if (i == CPLENSUPP)
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0);
+
+ CheckDlgButton(m_hwnd, IDC_CHECK, pAccount->Flags & YAMN_ACC_ENA ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSND, pAccount->NewMailN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKMSG, pAccount->NewMailN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKICO, pAccount->NewMailN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKPOP, pAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCOL, pAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPP, pAccount->NewMailN.Flags & YAMN_ACC_APP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKKBN, pAccount->NewMailN.Flags & YAMN_ACC_KBN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNPOP, pAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNCOL, pAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNMSGP, pAccount->NoNewMailN.Flags & YAMN_ACC_MSGP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFSND, pAccount->BadConnectN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFMSG, pAccount->BadConnectN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFICO, pAccount->BadConnectN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFPOP, pAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFCOL, pAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, pAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, pAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSSL, pAccount->Flags & YAMN_ACC_SSL23 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, pAccount->Flags & YAMN_ACC_NOTLS ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPOP, pAccount->Flags & YAMN_ACC_APOP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_AUTOBODY, pAccount->Flags & YAMN_ACC_BODY ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSTART, pAccount->StatusFlags & YAMN_ACC_STARTS ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFORCE, pAccount->StatusFlags & YAMN_ACC_FORCE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, pAccount->NewMailN.Flags & YAMN_ACC_CONT ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNICK, pAccount->NewMailN.Flags & YAMN_ACC_CONTNICK ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNOEVENT, pAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT ? BST_CHECKED : BST_UNCHECKED);
+
+ wchar_t accstatus[256];
+ GetAccountStatus(pAccount, accstatus);
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus);
+ ReadDone(pAccount);
+ }
+ else {
+ DlgSetItemText(m_hwnd, IDC_EDITSERVER, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITNAME, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITLOGIN, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITPASS, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITAPP, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITAPPPARAM, nullptr);
+ DlgSetItemText(m_hwnd, IDC_STTIMELEFT, nullptr);
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, 110, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, 30, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE);
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0);
+ CheckDlgButton(m_hwnd, IDC_CHECK, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSND, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKMSG, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKICO, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKPOP, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCOL, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPP, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFSND, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFMSG, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFICO, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFPOP, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFCOL, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSTART, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFORCE, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSSL, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPOP, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_AUTOBODY, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, BST_CHECKED);
+
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, TranslateT("No account selected"));
+ }
+ }
+};
+
+//=======================================================================================
+// General options dialog
+
+struct CGeneralOptDlg : public CBaseOptionsDlg
+{
+ CGeneralOptDlg() :
+ CBaseOptionsDlg(IDD_YAMNOPT)
+ {}
+
+ bool OnInitDialog() override
+ {
+ CheckDlgButton(m_hwnd, IDC_CHECKTTB, g_plugin.getByte(YAMN_TTBFCHECK, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_LONGDATE, (optDateTime & SHOWDATELONG) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_SMARTDATE, (optDateTime & SHOWDATENOTODAY) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_NOSECONDS, (optDateTime & SHOWDATENOSECONDS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CLOSEONDELETE, g_plugin.getByte(YAMN_CLOSEDELETE, 0) ? BST_CHECKED : BST_UNCHECKED);
+ return true;
+ }
+
+ bool OnApply() override
+ {
+ g_plugin.setByte(YAMN_CLOSEDELETE, IsDlgButtonChecked(m_hwnd, IDC_CLOSEONDELETE));
+ g_plugin.setByte(YAMN_TTBFCHECK, IsDlgButtonChecked(m_hwnd, IDC_CHECKTTB));
+
+ AddTopToolbarIcon(0, 0);
+
+ optDateTime = 0;
+ if (IsDlgButtonChecked(m_hwnd, IDC_LONGDATE)) optDateTime |= SHOWDATELONG;
+ if (IsDlgButtonChecked(m_hwnd, IDC_SMARTDATE)) optDateTime |= SHOWDATENOTODAY;
+ if (IsDlgButtonChecked(m_hwnd, IDC_NOSECONDS)) optDateTime |= SHOWDATENOSECONDS;
+ g_plugin.setByte(YAMN_DBTIMEOPTIONS, optDateTime);
+ return true;
+ }
+};
+
+//--------------------------------------------------------------------------------------------------
+
+static int g_iStatusControls[] = {IDC_CHECKST0, IDC_CHECKST1, IDC_CHECKST2, IDC_CHECKST3, IDC_CHECKST4, IDC_CHECKST5, IDC_CHECKST6, IDC_CHECKST7};
+
+static BOOL DlgShowAccountStatus(HWND hDlg, HPOP3ACCOUNT ActualAccount)
+{
+ if (ActualAccount) {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+
+ CheckDlgButton(hDlg, IDC_CHECKST0, ActualAccount->StatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST1, ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST2, ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST3, ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST4, ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST5, ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST6, ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST7, ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED);
+
+ ReadDone(ActualAccount);
+ }
+ else {
+ CheckDlgButton(hDlg, IDC_CHECKST0, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST1, BST_CHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST2, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST3, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST4, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST5, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST6, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST7, BST_CHECKED);
+ }
+ return TRUE;
+}
+
+static INT_PTR CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ static HPOP3ACCOUNT ActualAccount;
+ switch (msg) {
+ case WM_INITDIALOG:
+ ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput);
+ if (ActualAccount != nullptr) {
+ DlgShowAccountStatus(hDlg, ActualAccount);
+ for (auto &it : g_iStatusControls)
+ EnableWindow(GetDlgItem(hDlg, it), true);
+ }
+ else {
+ for (auto &it : g_iStatusControls)
+ CheckDlgButton(hDlg, it, BST_CHECKED);
+ }
+ TranslateDialogDefault(hDlg);
+ SendMessage(GetParent(hDlg), PSM_UNCHANGED, (WPARAM)hDlg, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ break;
+
+ case IDOK:
+ int iShift = 1;
+ ActualAccount->StatusFlags = 0;
+ for (auto &it : g_iStatusControls) {
+ if (IsDlgButtonChecked(hDlg, it))
+ ActualAccount->StatusFlags |= iShift;
+ iShift <<= 1;
+ }
+
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUSOPTION, 0, 0);
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Account options
+
+class CAccOptDlg : public CBaseOptionsDlg
+{
+ INT_PTR Result;
+ UCHAR ActualStatus;
+ HPOP3ACCOUNT ActualAccount = nullptr;
+
+ CCtrlCheck chkContact, chkSsl, chkApp;
+ CCtrlCombo cmbAccount, cmbCP;
+ CCtrlButton btnStatus, btnAdd, btnDel, btnApp, btnDefault, btnReset;
+
+ void DlgEnableAccount(bool bEnable)
+ {
+ cmbAccount.Enable(POP3Plugin->FirstAccount != nullptr);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECK), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITSERVER), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNAME), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPORT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITLOGIN), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPASS), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITINTERVAL), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSND), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKMSG), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKICO), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKKBN), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNMSGP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFSND), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFMSG), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFICO), bEnable);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSTART), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFORCE), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_COMBOCP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_STTIMELEFT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNRESET), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEFAULT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNSTATUS), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSSL), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), chkSsl.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_AUTOBODY), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), chkContact.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), chkContact.IsChecked() && bEnable);
+ }
+
+public:
+ CAccOptDlg() :
+ CBaseOptionsDlg(IDD_POP3ACCOUNTOPT),
+ cmbCP(this, IDC_COMBOCP),
+ btnAdd(this, IDC_BTNADD),
+ btnApp(this, IDC_BTNAPP),
+ btnDel(this, IDC_BTNDEL),
+ chkApp(this, IDC_CHECKAPP),
+ chkSsl(this, IDC_CHECKSSL),
+ btnReset(this, IDC_BTNRESET),
+ btnStatus(this, IDC_BTNSTATUS),
+ btnDefault(this, IDC_BTNDEFAULT),
+ cmbAccount(this, IDC_COMBOACCOUNT),
+ chkContact(this, IDC_CHECKCONTACT)
+ {
+ cmbCP.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_CP);
+
+ cmbAccount.OnChange = Callback(this, &CAccOptDlg::onChange_Account);
+ cmbAccount.OnKillFocus = Callback(this, &CAccOptDlg::onKillFocus_Account);
+ cmbAccount.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_Account);
+
+ chkApp.OnChange = Callback(this, &CAccOptDlg::onChangeApp);
+ chkSsl.OnChange = Callback(this, &CAccOptDlg::onChangeSsl);
+ chkContact.OnChange = Callback(this, &CAccOptDlg::onChangeContact);
+
+ btnAdd.OnClick = Callback(this, &CAccOptDlg::onClick_Add);
+ btnDel.OnClick = Callback(this, &CAccOptDlg::onClick_Del);
+ btnApp.OnClick = Callback(this, &CAccOptDlg::onClick_App);
+ btnReset.OnClick = Callback(this, &CAccOptDlg::onClick_Reset);
+ btnStatus.OnClick = Callback(this, &CAccOptDlg::onClick_Status);
+ btnDefault.OnClick = Callback(this, &CAccOptDlg::onClick_Default);
+ }
+
+ bool OnInitDialog() override
+ {
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+
+ DlgEnableAccount(false);
+ DlgShowAccount(0);
+
+ // Fill accounts
+ WaitToReadSO(POP3Plugin->AccountBrowserSO);
+
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ cmbAccount.AddStringA(ActualAccount->Name);
+ cmbAccount.SetCurSel(0);
+
+ ReadDoneSO(POP3Plugin->AccountBrowserSO);
+
+ // Fill code pages
+ cmbCP.AddString(TranslateT("Default"));
+ for (int i = 1; i < CPLENSUPP; i++) {
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[i].CP, 0, &info);
+ size_t len = mir_wstrlen(info.CodePageName + 7);
+ info.CodePageName[len + 6] = 0;
+ cmbCP.AddString(info.CodePageName + 7);
+ }
+ cmbCP.SetCurSel(0);
+
+ ActualAccount = nullptr;
+ SendMessage(GetParent(m_hwnd), PSM_UNCHANGED, (WPARAM)m_hwnd, 0);
+
+ WindowList_Add(pYAMNVar->MessageWnds, m_hwnd);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd);
+ }
+
+ INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override
+ {
+ switch (msg) {
+ case WM_YAMN_CHANGESTATUS:
+ if ((HPOP3ACCOUNT)wParam == ActualAccount) {
+ wchar_t accstatus[256];
+ GetAccountStatus(ActualAccount, accstatus);
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus);
+ return TRUE;
+ }
+ break;
+
+ case WM_YAMN_CHANGESTATUSOPTION:
+ NotifyChange();
+ return TRUE;
+
+ case WM_YAMN_CHANGETIME:
+ if ((HPOP3ACCOUNT)wParam == ActualAccount) {
+ wchar_t Text[256];
+ mir_snwprintf(Text, TranslateT("Time left to next check [s]: %d"), (uint32_t)lParam);
+ SetDlgItemText(m_hwnd, IDC_STTIMELEFT, Text);
+ }
+ return TRUE;
+ }
+ return CDlgBase::DlgProc(msg, wParam, lParam);
+ }
+
+ void onChange_Account(CCtrlCombo *)
+ {
+ ActualAccount = nullptr;
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ DlgEnableAccount(0 != GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)));
+ }
+
+ void onKillFocus_Account(CCtrlCombo *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ DlgEnableAccount(mir_strlen(DlgInput) > 0);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+ }
+ }
+
+ void onSelChange_Account(CCtrlCombo *)
+ {
+ if (CB_ERR != (Result = cmbAccount.GetCurSel()))
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput);
+
+ if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+ }
+ }
+
+ void onSelChange_CP(CCtrlCombo *)
+ {
+ int sel = cmbCP.GetCurSel();
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info);
+ DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName);
+ }
+
+ void onChangeContact(CCtrlCheck *)
+ {
+ bool bEnabled = chkContact.IsChecked();
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), bEnabled);
+ }
+
+ void onChangeSsl(CCtrlCheck *)
+ {
+ bool bEnabled = chkSsl.IsChecked();
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, bEnabled ? 995 : 110, FALSE);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), !bEnabled);
+ }
+
+ void onChangeApp(CCtrlCheck *)
+ {
+ bool bEnabled = chkApp.IsChecked();
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), bEnabled);
+ }
+
+ void onClick_Status(CCtrlButton *)
+ {
+ DialogBoxParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES), m_hwnd, DlgProcPOP3AccStatusOpt, NULL);
+ }
+
+ void onClick_Add(CCtrlButton *)
+ {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ DlgShowAccount(0);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ DlgSetItemTextW(m_hwnd, IDC_EDITNAME, TranslateT("New Account"));
+
+ int index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)TranslateT("New Account"));
+ if (index != CB_ERR && index != CB_ERRSPACE)
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, index, (LPARAM)TranslateT("New Account"));
+ }
+
+ void onClick_App(CCtrlButton *)
+ {
+ wchar_t filter[MAX_PATH];
+ mir_snwprintf(filter, L"%s (*.exe;*.bat;*.cmd;*.com)%c*.exe;*.bat;*.cmd;*.com%c%s (*.*)%c*.*%c",
+ TranslateT("Executables"), 0, 0, TranslateT("All Files"), 0, 0);
+
+ OPENFILENAME OFNStruct = {0};
+ OFNStruct.lStructSize = sizeof(OPENFILENAME);
+ OFNStruct.hwndOwner = m_hwnd;
+ OFNStruct.lpstrFilter = filter;
+ OFNStruct.nFilterIndex = 1;
+ OFNStruct.nMaxFile = MAX_PATH;
+ OFNStruct.lpstrFile = new wchar_t[MAX_PATH];
+ OFNStruct.lpstrFile[0] = (wchar_t)0;
+ OFNStruct.lpstrTitle = TranslateT("Select executable used for notification");
+ OFNStruct.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
+ if (!GetOpenFileName(&OFNStruct)) {
+ if (CommDlgExtendedError())
+ MessageBox(m_hwnd, TranslateT("Dialog box error"), TranslateT("Failed"), MB_OK);
+ }
+ else DlgSetItemTextW(m_hwnd, IDC_EDITAPP, OFNStruct.lpstrFile);
+ delete[] OFNStruct.lpstrFile;
+ }
+
+ void onClick_Default(CCtrlButton *)
+ {
+ DlgShowAccount(0);
+ }
+
+ void onClick_Del(CCtrlButton *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ if ((CB_ERR == (Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0)))
+ || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))))
+ return;
+
+ if (IDOK != MessageBox(m_hwnd, TranslateT("Do you really want to delete this account?"), TranslateT("Delete account confirmation"), MB_OKCANCEL | MB_ICONWARNING))
+ return;
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ if (ActualAccount->hContact != NULL)
+ db_delete_contact(ActualAccount->hContact);
+
+ CallService(MS_YAMN_DELETEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)ActualAccount);
+
+ // We can consider our account as deleted.
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_DELETESTRING, Result, 0);
+ DlgSetItemText(m_hwnd, IDC_COMBOACCOUNT, nullptr);
+ DlgEnableAccount(false);
+ DlgShowAccount(0);
+ }
+
+ void onClick_Reset(CCtrlButton *)
+ {
+ if (ActualAccount != nullptr)
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ }
+
+ bool OnApply() override
+ {
+ char Text[MAX_PATH];
+ wchar_t TextW[MAX_PATH];
+ BOOL Translated, NewAcc = FALSE;
+ size_t Length, index;
+
+ if (!GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)))
+ return false;
+
+ BOOL Check = (IsDlgButtonChecked(m_hwnd, IDC_CHECK) == BST_CHECKED);
+ BOOL CheckSSL = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSSL) == BST_CHECKED);
+ BOOL CheckNoTLS = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNOTLS) == BST_CHECKED);
+ BOOL CheckAPOP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPOP) == BST_CHECKED);
+
+ BOOL CheckABody = (IsDlgButtonChecked(m_hwnd, IDC_AUTOBODY) == BST_CHECKED);
+ BOOL CheckMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKMSG) == BST_CHECKED);
+ BOOL CheckSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSND) == BST_CHECKED);
+ BOOL CheckIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKICO) == BST_CHECKED);
+
+ BOOL CheckApp = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPP) == BST_CHECKED);
+ BOOL CheckKBN = (IsDlgButtonChecked(m_hwnd, IDC_CHECKKBN) == BST_CHECKED);
+ BOOL CheckContact = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACT) == BST_CHECKED);
+ BOOL CheckContactNick = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNICK) == BST_CHECKED);
+ BOOL CheckContactNoEvent = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNOEVENT) == BST_CHECKED);
+
+ BOOL CheckFSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFSND) == BST_CHECKED);
+ BOOL CheckFMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFMSG) == BST_CHECKED);
+ BOOL CheckFIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFICO) == BST_CHECKED);
+
+ BOOL CheckNMsgP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNMSGP) == BST_CHECKED);
+
+ UINT Port = GetDlgItemInt(m_hwnd, IDC_EDITPORT, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITPORT));
+ return false;
+ }
+
+ UINT Interval = GetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITINTERVAL));
+ return false;
+ }
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITAPP, Text, _countof(Text));
+ if (CheckApp && !(Length = mir_strlen(Text))) {
+ MessageBox(m_hwnd, TranslateT("Please select application to run"), TranslateT("Input error"), MB_OK);
+ return false;
+ }
+
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text))) {
+ GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ return false;
+ }
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)Text))) {
+ NewAcc = TRUE;
+ WaitToWriteSO(POP3Plugin->AccountBrowserSO);
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) {
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+ MessageBox(m_hwnd, TranslateT("Cannot allocate memory space for new account"), TranslateT("Memory error"), MB_OK);
+ return false;
+ }
+ DlgEnableAccount(true);
+ }
+ else { // We have to get full access to AccountBrowser, so other iterating thrads cannot get new account until new account is right set
+ WaitToWriteSO(POP3Plugin->AccountBrowserSO);
+ }
+
+ if (WAIT_OBJECT_0 != WaitToWrite(ActualAccount))
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ return false;
+ if (nullptr != ActualAccount->Name)
+ delete[] ActualAccount->Name;
+ ActualAccount->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Name, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITSERVER, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Name)
+ delete[] ActualAccount->Server->Name;
+ ActualAccount->Server->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Name, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITLOGIN, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Login)
+ delete[] ActualAccount->Server->Login;
+ ActualAccount->Server->Login = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Login, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITPASS, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Passwd)
+ delete[] ActualAccount->Server->Passwd;
+ ActualAccount->Server->Passwd = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Passwd, Text);
+
+ GetDlgItemTextW(m_hwnd, IDC_EDITAPP, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.App)
+ delete[] ActualAccount->NewMailN.App;
+ ActualAccount->NewMailN.App = new wchar_t[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(ActualAccount->NewMailN.App, TextW);
+
+ GetDlgItemTextW(m_hwnd, IDC_EDITAPPPARAM, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.AppParam)
+ delete[] ActualAccount->NewMailN.AppParam;
+ ActualAccount->NewMailN.AppParam = new wchar_t[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(ActualAccount->NewMailN.AppParam, TextW);
+
+ ActualAccount->Server->Port = Port;
+ ActualAccount->Interval = Interval * 60;
+
+ if (CB_ERR == (index = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0)))
+ index = CPDEFINDEX;
+ ActualAccount->CP = CodePageNamesSupp[index].CP;
+
+ if (NewAcc)
+ ActualAccount->TimeLeft = Interval * 60;
+
+ BOOL CheckStart = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSTART) == BST_CHECKED);
+ BOOL CheckForce = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFORCE) == BST_CHECKED);
+
+ ActualAccount->Flags =
+ (Check ? YAMN_ACC_ENA : 0) |
+ (CheckSSL ? YAMN_ACC_SSL23 : 0) |
+ (CheckNoTLS ? YAMN_ACC_NOTLS : 0) |
+ (CheckAPOP ? YAMN_ACC_APOP : 0) |
+ (CheckABody ? YAMN_ACC_BODY : 0) |
+ (ActualAccount->Flags & YAMN_ACC_POPN);
+
+ ActualAccount->StatusFlags &= 0xFFFF;
+ ActualAccount->StatusFlags |=
+ (CheckStart ? YAMN_ACC_STARTS : 0) |
+ (CheckForce ? YAMN_ACC_FORCE : 0);
+
+ ActualAccount->NewMailN.Flags =
+ (CheckSnd ? YAMN_ACC_SND : 0) |
+ (CheckMsg ? YAMN_ACC_MSG : 0) |
+ (CheckIco ? YAMN_ACC_ICO : 0) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) |
+ (CheckApp ? YAMN_ACC_APP : 0) |
+ (CheckKBN ? YAMN_ACC_KBN : 0) |
+ (CheckContact ? YAMN_ACC_CONT : 0) |
+ (CheckContactNick ? YAMN_ACC_CONTNICK : 0) |
+ (CheckContactNoEvent ? YAMN_ACC_CONTNOEVENT : 0) |
+ YAMN_ACC_MSGP; //this is default: when new mail arrives and window was displayed, leave it displayed.
+
+ ActualAccount->NoNewMailN.Flags =
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) |
+ (CheckNMsgP ? YAMN_ACC_MSGP : 0);
+
+ ActualAccount->BadConnectN.Flags =
+ (CheckFSnd ? YAMN_ACC_SND : 0) |
+ (CheckFMsg ? YAMN_ACC_MSG : 0) |
+ (CheckFIco ? YAMN_ACC_ICO : 0) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC);
+
+ WriteDone(ActualAccount);
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+
+ index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+
+ HPOP3ACCOUNT temp = ActualAccount;
+
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0);
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)ActualAccount->Name);
+
+ ActualAccount = temp;
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, (WPARAM)index, (LPARAM)ActualAccount->Name);
+
+ WritePOP3Accounts();
+ RefreshContact();
+ return TRUE;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popup options
+
+class CPopupOptsDlg : public CBaseOptionsDlg
+{
+ HPOP3ACCOUNT ActualAccount = nullptr;
+ UCHAR ActualStatus;
+
+ CCtrlCombo cmbAccount, cmbCP;
+ CCtrlCheck chkCol, chkFcol, chkNcol, chkPop, chkFpop, chkNpop;
+ CCtrlButton btnPreview;
+
+ void DlgShowAccountPopup()
+ {
+ if (ActualAccount) {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, ActualAccount->NewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, ActualAccount->NoNewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, ActualAccount->BadConnectN.PopupTime, FALSE);
+
+ chkPop.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POP);
+ chkCol.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POPC);
+ chkNpop.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP);
+ chkNcol.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC);
+ chkFpop.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ chkFcol.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED);
+ ReadDone(ActualAccount);
+ }
+ else { // default
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE);
+ chkPop.SetState(true);
+ chkCol.SetState(true);
+ chkNpop.SetState(true);
+ chkNcol.SetState(true);
+ chkFpop.SetState(true);
+ chkFcol.SetState(true);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED);
+ }
+ }
+
+ void DlgEnableAccountPopup(bool bEnable)
+ {
+ chkPop.Enable(bEnable);
+ chkCol.Enable(chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), chkPop.IsChecked() && bEnable);
+
+ chkNpop.Enable(bEnable);
+ chkNcol.Enable(chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable);
+
+ chkFpop.Enable(bEnable);
+ chkFcol.Enable(chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable);
+ }
+
+ void DlgShowAccountColors()
+ {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+
+ if (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+ if (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ ReadDone(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ }
+
+public:
+ CPopupOptsDlg() :
+ CBaseOptionsDlg(IDD_POP3ACCOUNTPOPUP),
+ cmbCP(this, IDC_COMBOCP),
+ chkCol(this, IDC_CHECKCOL),
+ chkPop(this, IDC_CHECKPOP),
+ chkFcol(this, IDC_CHECKFCOL),
+ chkFpop(this, IDC_CHECKFPOP),
+ chkNcol(this, IDC_CHECKNCOL),
+ chkNpop(this, IDC_CHECKNPOP),
+ btnPreview(this, IDC_PREVIEW),
+ cmbAccount(this, IDC_COMBOACCOUNT)
+ {
+ chkPop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Pop);
+ chkFpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Fpop);
+ chkNpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Npop);
+ chkCol.OnChange = chkFcol.OnChange = chkNcol.OnChange = Callback(this, &CPopupOptsDlg::onChange_Col);
+
+ cmbCP.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_CP);
+
+ btnPreview.OnClick = Callback(this, &CPopupOptsDlg::onClick_Preview);
+
+ cmbAccount.OnKillFocus = Callback(this, &CPopupOptsDlg::onKillFocus_Account);
+ cmbAccount.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_Account);
+ }
+
+ bool OnInitDialog() override
+ {
+ WindowList_Add(pYAMNVar->MessageWnds, m_hwnd);
+
+ DlgEnableAccountPopup(false);
+ DlgShowAccountPopup();
+
+ WaitToReadSO(POP3Plugin->AccountBrowserSO);
+
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ cmbAccount.AddStringA(ActualAccount->Name);
+
+ ReadDoneSO(POP3Plugin->AccountBrowserSO);
+ ActualAccount = nullptr;
+ cmbAccount.SetCurSel(0);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd);
+ }
+
+ void onKillFocus_Account(CCtrlCombo *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ if (mir_strlen(DlgInput))
+ DlgEnableAccountPopup(true);
+ else
+ DlgEnableAccountPopup(false);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgShowAccountColors();
+ DlgEnableAccountPopup(true);
+ }
+ }
+
+ void onSelChange_Account(CCtrlCombo *)
+ {
+ int Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+ if (CB_ERR != Result)
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput);
+ if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgShowAccountColors();
+ DlgEnableAccountPopup(true);
+ }
+ }
+
+ void onSelChange_CP(CCtrlCombo *)
+ {
+ int sel = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0);
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info);
+ DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName);
+ }
+
+ void onChange_Col(CCtrlCheck *)
+ {
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked());
+ }
+
+ void onClick_Preview(CCtrlButton *)
+ {
+ if (chkPop.IsChecked()) {
+ POPUPDATAW Tester = {};
+ Tester.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ mir_wstrncpy(Tester.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(Tester.lpwzText, TranslateT("You have N new mail messages"), MAX_SECONDLINE);
+ if (chkCol.IsChecked()) {
+ Tester.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0);
+ Tester.colorText = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ Tester.colorBack = GetSysColor(COLOR_BTNFACE);
+ Tester.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&Tester);
+ }
+
+ if (chkFpop.IsChecked()) {
+ POPUPDATAW TesterF = {};
+ TesterF.lchIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ mir_wstrncpy(TesterF.lpwzContactName, TranslateT("Account Test (failed)"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterF.lpwzText, TranslateT("Connection failed message"), MAX_SECONDLINE);
+ if (chkFcol.IsChecked()) {
+ TesterF.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0);
+ TesterF.colorText = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ TesterF.colorBack = GetSysColor(COLOR_BTNFACE);
+ TesterF.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&TesterF);
+ }
+
+ if (chkNpop.IsChecked()) {
+ POPUPDATAW TesterN = {};
+ TesterN.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP);
+ mir_wstrncpy(TesterN.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterN.lpwzText, TranslateT("No new mail message"), MAX_SECONDLINE);
+ if (chkNcol.IsChecked()) {
+ TesterN.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0);
+ TesterN.colorText = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ TesterN.colorBack = GetSysColor(COLOR_BTNFACE);
+ TesterN.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&TesterN);
+ }
+ }
+
+ void onChange_Pop(CCtrlCheck *)
+ {
+ bool bEnabled = chkPop.IsChecked();
+ chkCol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), bEnabled);
+ }
+
+ void onChange_Fpop(CCtrlCheck *)
+ {
+ bool bEnabled = chkFpop.IsChecked();
+ chkFcol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), bEnabled);
+ }
+
+ void onChange_Npop(CCtrlCheck *)
+ {
+ bool bEnabled = chkNpop.IsChecked();
+ chkNcol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), bEnabled);
+ }
+
+ bool OnApply() override
+ {
+ wchar_t Text[MAX_PATH];
+ if (!GetDlgItemText(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)))
+ return false;
+
+ BOOL CheckPopup = chkPop.IsChecked();
+ BOOL CheckPopupW = chkCol.IsChecked();
+
+ BOOL CheckFPopup = chkFpop.IsChecked();
+ BOOL CheckFPopupW = chkFcol.IsChecked();
+
+ BOOL CheckNPopup = chkNpop.IsChecked();
+ BOOL CheckNPopupW = chkNcol.IsChecked();
+
+ BOOL CheckPopN = (IsDlgButtonChecked(m_hwnd, IDC_RADIOPOPN) == BST_CHECKED);
+
+ BOOL Translated;
+ UINT Time = GetDlgItemInt(m_hwnd, IDC_EDITPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITPOPS));
+ return false;
+ }
+ UINT TimeN = GetDlgItemInt(m_hwnd, IDC_EDITNPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITNPOPS));
+ return false;
+ }
+ UINT TimeF = GetDlgItemInt(m_hwnd, IDC_EDITFPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITFPOPS));
+ return false;
+ }
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ ActualAccount->Flags =
+ (ActualAccount->Flags & YAMN_ACC_ENA) |
+ (ActualAccount->Flags & YAMN_ACC_SSL23) |
+ (ActualAccount->Flags & YAMN_ACC_NOTLS) |
+ (ActualAccount->Flags & YAMN_ACC_APOP) |
+ (ActualAccount->Flags & YAMN_ACC_BODY) |
+ (CheckPopN ? YAMN_ACC_POPN : 0);
+
+ ActualAccount->NewMailN.Flags =
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_SND) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_MSG) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_ICO) |
+ (CheckPopup ? YAMN_ACC_POP : 0) |
+ (CheckPopupW ? YAMN_ACC_POPC : 0) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_APP) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONT) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT) |
+ YAMN_ACC_MSGP;
+
+ ActualAccount->NoNewMailN.Flags =
+ (CheckNPopup ? YAMN_ACC_POP : 0) |
+ (CheckNPopupW ? YAMN_ACC_POPC : 0) |
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP);
+
+ ActualAccount->BadConnectN.Flags =
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) |
+ (CheckFPopup ? YAMN_ACC_POP : 0) |
+ (CheckFPopupW ? YAMN_ACC_POPC : 0);
+
+ ActualAccount->NewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NewMailN.PopupTime = Time;
+
+ ActualAccount->NoNewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NoNewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NoNewMailN.PopupTime = TimeN;
+
+ ActualAccount->BadConnectN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->BadConnectN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->BadConnectN.PopupTime = TimeF;
+
+ WriteDone(ActualAccount);
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ WritePOP3Accounts();
+ RefreshContact();
+ return TRUE;
+ }
+};
+
+//--------------------------------------------------------------------------------------------------
+
+int YAMNOptInitSvc(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szGroup.a = LPGEN("Network");
+ odp.szTitle.a = LPGEN("YAMN");
+ odp.flags = ODPF_BOLDGROUPS;
+
+ odp.szTab.a = LPGEN("Accounts");
+ odp.pDialog = new CAccOptDlg();
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.a = LPGEN("General");
+ odp.pDialog = new CGeneralOptDlg();
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szGroup.a = LPGEN("Popups");
+ odp.szTab.a = LPGEN("YAMN");
+ odp.pDialog = new CPopupOptsDlg();
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/YAMN/src/protoplugin.cpp b/protocols/YAMN/src/protoplugin.cpp index c6e6a6aecc..b192ac1f5f 100644 --- a/protocols/YAMN/src/protoplugin.cpp +++ b/protocols/YAMN/src/protoplugin.cpp @@ -1,172 +1,172 @@ -/* - * YAMN plugin export functions for protocols - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin = nullptr; - -INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM); - -//Removes plugin from queue and deletes registration structures -INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin); - -INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM); - -//Removes plugins from queue and deletes registration structures -INT_PTR UnregisterProtoPlugins(); - -//Sets imported functions for an plugin and therefore it starts plugin to be registered and running -// Plugin- plugin, which wants to set its functions -// YAMNFcn- pointer to imported functions with accounts -// YAMNFcnVer- version of YAMN_PROTOIMPORTFCN, use YAMN_PROTOIMPORTFCNVERSION -// YAMNMailFcn- pointer to imported functions with mails -// YAMNMailFcnVer- version of YAMN_MAILIMPORTFCN, use YAMN_MAILIMPORTFCNVERSION -// returns nonzero if success -int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer); - -struct CExportedFunctions ProtoPluginExportedFcn[] = -{ - {YAMN_SETPROTOCOLPLUGINFCNIMPORTID, (void *)SetProtocolPluginFcnImportFcn}, -}; - -struct CExportedServices ProtoPluginExportedSvc[] = -{ - {MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc}, - {MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc}, - {MS_YAMN_GETFILENAME, GetFileNameSvc}, - {MS_YAMN_DELETEFILENAME, DeleteFileNameSvc}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR RegisterProtocolPluginSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_PROTOREGISTRATION Registration = (PYAMN_PROTOREGISTRATION)wParam; - HYAMNPROTOPLUGIN Plugin; - - if (lParam != YAMN_PROTOREGISTRATIONVERSION) - return 0; - if ((Registration->Name == nullptr) || (Registration->Ver == nullptr)) - return (INT_PTR)NULL; - if (nullptr == (Plugin = new YAMN_PROTOPLUGIN)) - return (INT_PTR)NULL; - - Plugin->PluginInfo = Registration; - - Plugin->FirstAccount = nullptr; - - Plugin->AccountBrowserSO = new SWMRG; - SWMRGInitialize(Plugin->AccountBrowserSO, nullptr); - - Plugin->Fcn = nullptr; - Plugin->MailFcn = nullptr; - - return (INT_PTR)Plugin; -} - -int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer) -{ - PYAMN_PROTOPLUGINQUEUE Parser; - - if (YAMNFcnVer != YAMN_PROTOIMPORTFCNVERSION) - return 0; - if (YAMNMailFcnVer != YAMN_MAILIMPORTFCNVERSION) - return 0; - if (YAMNFcn == nullptr) - return 0; - if (YAMNMailFcn == nullptr) - return 0; - - Plugin->Fcn = YAMNFcn; - Plugin->MailFcn = YAMNMailFcn; - - mir_cslock lck(PluginRegCS); - // We add protocol to the protocol list - for (Parser = FirstProtoPlugin; Parser != nullptr && Parser->Next != nullptr; Parser = Parser->Next); - if (Parser == nullptr) { - FirstProtoPlugin = new YAMN_PROTOPLUGINQUEUE; - Parser = FirstProtoPlugin; - } - else { - Parser->Next = new YAMN_PROTOPLUGINQUEUE; - Parser = Parser->Next; - } - - Parser->Plugin = Plugin; - Parser->Next = nullptr; - return 1; -} - -INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin) -{ - PYAMN_PROTOPLUGINQUEUE Parser, Found; - - if (FirstProtoPlugin->Plugin == Plugin) { - Found = FirstProtoPlugin; - FirstProtoPlugin = FirstProtoPlugin->Next; - } - else { - for (Parser = FirstProtoPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next); - if (Parser->Next != nullptr) { - Found = Parser->Next; - Parser->Next = Parser->Next->Next; - } - else - Found = nullptr; - } - if (Found != nullptr) { - StopAccounts(Plugin); - DeleteAccounts(Plugin); - if (Plugin->Fcn->UnLoadFcn != nullptr) - Plugin->Fcn->UnLoadFcn((void *)nullptr); - - delete Found->Plugin->AccountBrowserSO; - delete Found->Plugin; - delete Found; - } - else - return 0; - return 1; -} - -INT_PTR UnregisterProtocolPluginSvc(WPARAM wParam, LPARAM) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - - mir_cslock lck(PluginRegCS); - UnregisterProtocolPlugin(Plugin); - return 1; -} - -INT_PTR UnregisterProtoPlugins() -{ - mir_cslock lck(PluginRegCS); - // We remove protocols from the protocol list - while (FirstProtoPlugin != nullptr) - UnregisterProtocolPlugin(FirstProtoPlugin->Plugin); - return 1; -} - -INT_PTR GetFileNameSvc(WPARAM wParam, LPARAM) -{ - wchar_t *FileName = new wchar_t[MAX_PATH]; - if (FileName == nullptr) - return NULL; - - mir_snwprintf(FileName, MAX_PATH, L"%s\\yamn-accounts.%s.%s.book", UserDirectory, (wchar_t *)wParam, ProfileName); - return (INT_PTR)FileName; -} - -INT_PTR DeleteFileNameSvc(WPARAM wParam, LPARAM) -{ - if ((wchar_t *)wParam != nullptr) - delete[](wchar_t *) wParam; - - return 0; -} +/*
+ * YAMN plugin export functions for protocols
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin = nullptr;
+
+INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM);
+
+//Removes plugin from queue and deletes registration structures
+INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin);
+
+INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM);
+
+//Removes plugins from queue and deletes registration structures
+INT_PTR UnregisterProtoPlugins();
+
+//Sets imported functions for an plugin and therefore it starts plugin to be registered and running
+// Plugin- plugin, which wants to set its functions
+// YAMNFcn- pointer to imported functions with accounts
+// YAMNFcnVer- version of YAMN_PROTOIMPORTFCN, use YAMN_PROTOIMPORTFCNVERSION
+// YAMNMailFcn- pointer to imported functions with mails
+// YAMNMailFcnVer- version of YAMN_MAILIMPORTFCN, use YAMN_MAILIMPORTFCNVERSION
+// returns nonzero if success
+int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer);
+
+struct CExportedFunctions ProtoPluginExportedFcn[] =
+{
+ {YAMN_SETPROTOCOLPLUGINFCNIMPORTID, (void *)SetProtocolPluginFcnImportFcn},
+};
+
+struct CExportedServices ProtoPluginExportedSvc[] =
+{
+ {MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc},
+ {MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc},
+ {MS_YAMN_GETFILENAME, GetFileNameSvc},
+ {MS_YAMN_DELETEFILENAME, DeleteFileNameSvc},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR RegisterProtocolPluginSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_PROTOREGISTRATION Registration = (PYAMN_PROTOREGISTRATION)wParam;
+ HYAMNPROTOPLUGIN Plugin;
+
+ if (lParam != YAMN_PROTOREGISTRATIONVERSION)
+ return 0;
+ if ((Registration->Name == nullptr) || (Registration->Ver == nullptr))
+ return (INT_PTR)NULL;
+ if (nullptr == (Plugin = new YAMN_PROTOPLUGIN))
+ return (INT_PTR)NULL;
+
+ Plugin->PluginInfo = Registration;
+
+ Plugin->FirstAccount = nullptr;
+
+ Plugin->AccountBrowserSO = new SWMRG;
+ SWMRGInitialize(Plugin->AccountBrowserSO, nullptr);
+
+ Plugin->Fcn = nullptr;
+ Plugin->MailFcn = nullptr;
+
+ return (INT_PTR)Plugin;
+}
+
+int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer)
+{
+ PYAMN_PROTOPLUGINQUEUE Parser;
+
+ if (YAMNFcnVer != YAMN_PROTOIMPORTFCNVERSION)
+ return 0;
+ if (YAMNMailFcnVer != YAMN_MAILIMPORTFCNVERSION)
+ return 0;
+ if (YAMNFcn == nullptr)
+ return 0;
+ if (YAMNMailFcn == nullptr)
+ return 0;
+
+ Plugin->Fcn = YAMNFcn;
+ Plugin->MailFcn = YAMNMailFcn;
+
+ mir_cslock lck(PluginRegCS);
+ // We add protocol to the protocol list
+ for (Parser = FirstProtoPlugin; Parser != nullptr && Parser->Next != nullptr; Parser = Parser->Next);
+ if (Parser == nullptr) {
+ FirstProtoPlugin = new YAMN_PROTOPLUGINQUEUE;
+ Parser = FirstProtoPlugin;
+ }
+ else {
+ Parser->Next = new YAMN_PROTOPLUGINQUEUE;
+ Parser = Parser->Next;
+ }
+
+ Parser->Plugin = Plugin;
+ Parser->Next = nullptr;
+ return 1;
+}
+
+INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin)
+{
+ PYAMN_PROTOPLUGINQUEUE Parser, Found;
+
+ if (FirstProtoPlugin->Plugin == Plugin) {
+ Found = FirstProtoPlugin;
+ FirstProtoPlugin = FirstProtoPlugin->Next;
+ }
+ else {
+ for (Parser = FirstProtoPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next);
+ if (Parser->Next != nullptr) {
+ Found = Parser->Next;
+ Parser->Next = Parser->Next->Next;
+ }
+ else
+ Found = nullptr;
+ }
+ if (Found != nullptr) {
+ StopAccounts(Plugin);
+ DeleteAccounts(Plugin);
+ if (Plugin->Fcn->UnLoadFcn != nullptr)
+ Plugin->Fcn->UnLoadFcn((void *)nullptr);
+
+ delete Found->Plugin->AccountBrowserSO;
+ delete Found->Plugin;
+ delete Found;
+ }
+ else
+ return 0;
+ return 1;
+}
+
+INT_PTR UnregisterProtocolPluginSvc(WPARAM wParam, LPARAM)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterProtocolPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterProtoPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+ // We remove protocols from the protocol list
+ while (FirstProtoPlugin != nullptr)
+ UnregisterProtocolPlugin(FirstProtoPlugin->Plugin);
+ return 1;
+}
+
+INT_PTR GetFileNameSvc(WPARAM wParam, LPARAM)
+{
+ wchar_t *FileName = new wchar_t[MAX_PATH];
+ if (FileName == nullptr)
+ return NULL;
+
+ mir_snwprintf(FileName, MAX_PATH, L"%s\\yamn-accounts.%s.%s.book", UserDirectory, (wchar_t *)wParam, ProfileName);
+ return (INT_PTR)FileName;
+}
+
+INT_PTR DeleteFileNameSvc(WPARAM wParam, LPARAM)
+{
+ if ((wchar_t *)wParam != nullptr)
+ delete[](wchar_t *) wParam;
+
+ return 0;
+}
diff --git a/protocols/YAMN/src/resource.h b/protocols/YAMN/src/resource.h index 3f6a52fa55..70cb2647c8 100644 --- a/protocols/YAMN/src/resource.h +++ b/protocols/YAMN/src/resource.h @@ -1,111 +1,111 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by W:\miranda-ng\protocols\YAMN\res\YAMN.rc -// -#define IDI_CHECKMAIL 104 -#define IDI_LAUNCHAPP 105 -#define IDD_DLGVIEWMESSAGES 107 -#define IDD_DLGSHOWMESSAGE 108 -#define IDI_ICOYAMN2 112 -#define IDI_ICOYAMN1 113 -#define IDD_DLGBADCONNECT 115 -#define IDD_POP3ACCOUNTOPT 121 -#define IDD_YAMNOPT 126 -#define IDI_BADCONNECT 131 -#define IDI_ICOTTBUP 138 -#define IDI_NEWMAIL 159 -#define IDD_CHOOSESTATUSMODES 310 -#define IDD_OPTIONS 311 -#define IDD_POP3ACCOUNTPOPUP 312 -#define IDC_EDITSERVER 1000 -#define IDC_EDITPORT 1001 -#define IDC_EDITLOGIN 1002 -#define IDC_EDITPASS 1003 -#define IDC_COMBOACCOUNT 1005 -#define IDC_BTNDEFAULT 1006 -#define IDC_EDITINTERVAL 1007 -#define IDC_CHECKSND 1008 -#define IDC_CHECKMSG 1009 -#define IDC_CHECKAPP 1010 -#define IDC_BTNAPP 1011 -#define IDC_CHECKICO 1012 -#define IDC_CHECK 1013 -#define IDC_BTNDEL 1014 -#define IDC_CHECKFSND 1016 -#define IDC_CHECKFMSG 1017 -#define IDC_CHECKFICO 1018 -#define IDC_CHECKST0 1019 -#define IDC_CHECKST1 1020 -#define IDC_CHECKST2 1021 -#define IDC_CHECKST3 1022 -#define IDC_CHECKST4 1023 -#define IDC_CHECKST5 1024 -#define IDC_CHECKST6 1025 -#define IDC_CHECKST7 1026 -#define IDC_EDITAPP 1027 -#define IDC_CHECKCONTACT 1030 -#define IDC_CHECKCONTACTNICK 1031 -#define IDC_CHECKCONTACTNOEVENT 1032 -#define IDC_STTIMELEFT 1033 -#define IDC_LISTMAILS 1038 -#define IDC_LISTHEADERS 1039 -#define IDC_EDITAPPPARAM 1044 -#define IDC_BTNOK 1047 -#define IDC_COMBOCP 1050 -#define IDC_STATICMSG 1055 -#define IDC_AUTOBODY 1062 -#define IDC_BTNRESET 1063 -#define IDC_CHECKSTART 1064 -#define IDC_STWCHECK 1065 -#define IDC_CHECKFORCE 1066 -#define IDC_RADIOPOP1 1068 -#define IDC_RADIOPOPN 1069 -#define IDC_CPB 1070 -#define IDC_CPNB 1071 -#define IDC_CHECKCOL 1073 -#define IDC_CPT 1074 -#define IDC_CPFB 1075 -#define IDC_CPFT 1076 -#define IDC_CHECKFCOL 1077 -#define IDC_CHECKNCOL 1078 -#define IDC_CPNT 1079 -#define IDC_CHECKPOP 1087 -#define IDC_CHECKNPOP 1088 -#define IDC_CHECKFPOP 1089 -#define IDC_EDITPOPS 1090 -#define IDC_EDITNPOPS 1091 -#define IDC_EDITFPOPS 1092 -#define IDC_GBNEWMAIL 1094 -#define IDC_GBNONEWMAIL 1095 -#define IDC_GBBADCONNECT 1096 -#define IDC_STSTATUS 1102 -#define IDC_CHECKTTB 1117 -#define IDC_CHECKSSL 1117 -#define IDC_CHECKNMSGP 1118 -#define IDC_CHECKNOTLS 1120 -#define IDC_CHECKKBN 1121 -#define IDC_BTNSTATUS 1123 -#define IDC_OPTIONSTAB 1124 -#define IDC_BTNCHECKALL 1125 -#define IDC_CLOSEONDELETE 1127 -#define IDC_LONGDATE 1128 -#define IDC_SMARTDATE 1129 -#define IDC_NOSECONDS 1130 -#define IDC_CHECKAPOP 1200 -#define IDC_STATUSGROUP 1338 -#define IDC_SPLITTER 1400 -#define IDC_EDITBODY 1401 -#define IDC_PREVIEW 1402 -#define IDC_BTNADD 1403 -#define IDC_EDITNAME 1404 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 144 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1407 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by W:\miranda-ng\protocols\YAMN\res\YAMN.rc
+//
+#define IDI_CHECKMAIL 104
+#define IDI_LAUNCHAPP 105
+#define IDD_DLGVIEWMESSAGES 107
+#define IDD_DLGSHOWMESSAGE 108
+#define IDI_ICOYAMN2 112
+#define IDI_ICOYAMN1 113
+#define IDD_DLGBADCONNECT 115
+#define IDD_POP3ACCOUNTOPT 121
+#define IDD_YAMNOPT 126
+#define IDI_BADCONNECT 131
+#define IDI_ICOTTBUP 138
+#define IDI_NEWMAIL 159
+#define IDD_CHOOSESTATUSMODES 310
+#define IDD_OPTIONS 311
+#define IDD_POP3ACCOUNTPOPUP 312
+#define IDC_EDITSERVER 1000
+#define IDC_EDITPORT 1001
+#define IDC_EDITLOGIN 1002
+#define IDC_EDITPASS 1003
+#define IDC_COMBOACCOUNT 1005
+#define IDC_BTNDEFAULT 1006
+#define IDC_EDITINTERVAL 1007
+#define IDC_CHECKSND 1008
+#define IDC_CHECKMSG 1009
+#define IDC_CHECKAPP 1010
+#define IDC_BTNAPP 1011
+#define IDC_CHECKICO 1012
+#define IDC_CHECK 1013
+#define IDC_BTNDEL 1014
+#define IDC_CHECKFSND 1016
+#define IDC_CHECKFMSG 1017
+#define IDC_CHECKFICO 1018
+#define IDC_CHECKST0 1019
+#define IDC_CHECKST1 1020
+#define IDC_CHECKST2 1021
+#define IDC_CHECKST3 1022
+#define IDC_CHECKST4 1023
+#define IDC_CHECKST5 1024
+#define IDC_CHECKST6 1025
+#define IDC_CHECKST7 1026
+#define IDC_EDITAPP 1027
+#define IDC_CHECKCONTACT 1030
+#define IDC_CHECKCONTACTNICK 1031
+#define IDC_CHECKCONTACTNOEVENT 1032
+#define IDC_STTIMELEFT 1033
+#define IDC_LISTMAILS 1038
+#define IDC_LISTHEADERS 1039
+#define IDC_EDITAPPPARAM 1044
+#define IDC_BTNOK 1047
+#define IDC_COMBOCP 1050
+#define IDC_STATICMSG 1055
+#define IDC_AUTOBODY 1062
+#define IDC_BTNRESET 1063
+#define IDC_CHECKSTART 1064
+#define IDC_STWCHECK 1065
+#define IDC_CHECKFORCE 1066
+#define IDC_RADIOPOP1 1068
+#define IDC_RADIOPOPN 1069
+#define IDC_CPB 1070
+#define IDC_CPNB 1071
+#define IDC_CHECKCOL 1073
+#define IDC_CPT 1074
+#define IDC_CPFB 1075
+#define IDC_CPFT 1076
+#define IDC_CHECKFCOL 1077
+#define IDC_CHECKNCOL 1078
+#define IDC_CPNT 1079
+#define IDC_CHECKPOP 1087
+#define IDC_CHECKNPOP 1088
+#define IDC_CHECKFPOP 1089
+#define IDC_EDITPOPS 1090
+#define IDC_EDITNPOPS 1091
+#define IDC_EDITFPOPS 1092
+#define IDC_GBNEWMAIL 1094
+#define IDC_GBNONEWMAIL 1095
+#define IDC_GBBADCONNECT 1096
+#define IDC_STSTATUS 1102
+#define IDC_CHECKTTB 1117
+#define IDC_CHECKSSL 1117
+#define IDC_CHECKNMSGP 1118
+#define IDC_CHECKNOTLS 1120
+#define IDC_CHECKKBN 1121
+#define IDC_BTNSTATUS 1123
+#define IDC_OPTIONSTAB 1124
+#define IDC_BTNCHECKALL 1125
+#define IDC_CLOSEONDELETE 1127
+#define IDC_LONGDATE 1128
+#define IDC_SMARTDATE 1129
+#define IDC_NOSECONDS 1130
+#define IDC_CHECKAPOP 1200
+#define IDC_STATUSGROUP 1338
+#define IDC_SPLITTER 1400
+#define IDC_EDITBODY 1401
+#define IDC_PREVIEW 1402
+#define IDC_BTNADD 1403
+#define IDC_EDITNAME 1404
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 144
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1407
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/YAMN/src/services.cpp b/protocols/YAMN/src/services.cpp index 822f5d9f31..361fb01636 100644 --- a/protocols/YAMN/src/services.cpp +++ b/protocols/YAMN/src/services.cpp @@ -1,378 +1,378 @@ -#include "stdafx.h" - -static INT_PTR Service_GetCaps(WPARAM wParam, LPARAM) -{ - switch (wParam) { - case PFLAGNUM_4: - return PF4_NOCUSTOMAUTH; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)TranslateT("Nick"); - case PFLAG_MAXLENOFMESSAGE: - return 400; - case PFLAGNUM_2: - case PFLAGNUM_5: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND; - } - - return 0; -} - -static INT_PTR Service_GetName(WPARAM wParam, LPARAM lParam) -{ - mir_strncpy((char *)lParam, YAMN_DBMODULE, wParam); - return 0; -} - -static INT_PTR Service_LoadIcon(WPARAM wParam, LPARAM) -{ - if (LOWORD(wParam) == PLI_PROTOCOL) - return (INT_PTR)CopyIcon(g_plugin.getIcon(IDI_CHECKMAIL)); // noone cares about other than PLI_PROTOCOL - - return (INT_PTR)(HICON)NULL; -} - -INT_PTR ClistContactDoubleclicked(WPARAM, LPARAM lParam) -{ - ContactDoubleclicked(((CLISTEVENT *)lParam)->lParam, lParam); - return 0; -} - -static int Service_ContactDoubleclicked(WPARAM wParam, LPARAM lParam) -{ - ContactDoubleclicked(wParam, lParam); - return 0; -} - -static INT_PTR ContactApplication(WPARAM wParam, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(wParam); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return 0; - - DBVARIANT dbv; - if (g_plugin.getString(wParam, "Id", &dbv)) - return 0; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - STARTUPINFOW si = {0}; - si.cb = sizeof(si); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - - PROCESS_INFORMATION pi; - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - db_free(&dbv); - return 0; -} - -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); -static INT_PTR AccountMailCheck(WPARAM wParam, LPARAM lParam) -{ - //This service will check/sincronize the account pointed by wParam - CAccount *ActualAccount = (CAccount *)wParam; - // copy/paste make mistakes - if (ActualAccount != nullptr) { - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - return 0; - //if we want to close miranda, we get event and do not run pop3 checking anymore - if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) - return 0; - - mir_cslock lck(PluginRegCS); - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) { - } - else { - if ((ActualAccount->Flags & YAMN_ACC_ENA) && ActualAccount->Plugin->Fcn->SynchroFcnPtr) { - CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam != 0 ? YAMN_FORCECHECK : YAMN_NORMALCHECK, nullptr, nullptr}; - - ActualAccount->TimeLeft = ActualAccount->Interval; - DWORD tid; - HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid); - if (NewThread) { - WaitForSingleObject(ThreadRunningEV, INFINITE); - CloseHandle(NewThread); - } - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - CloseHandle(ThreadRunningEV); - } - return 0; -} - -static INT_PTR ContactMailCheck(WPARAM hContact, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(hContact); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return 0; - - DBVARIANT dbv; - if (g_plugin.getString(hContact, "Id", &dbv)) - return 0; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV; - if (nullptr == (ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr))) - return 0; - //if we want to close miranda, we get event and do not run pop3 checking anymore - if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) - return 0; - mir_cslock lck(PluginRegCS); - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - } - else { - if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check - { - if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) - ReadDoneFcn(ActualAccount->AccountAccessSO); - - DWORD tid; - struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr}; - if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) - ReadDoneFcn(ActualAccount->AccountAccessSO); - else - WaitForSingleObject(ThreadRunningEV, INFINITE); - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - CloseHandle(ThreadRunningEV); - } - db_free(&dbv); - return 0; -} - -/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(wParam); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return; - - DBVARIANT dbv; - if (g_plugin.getString(wParam, "Id", &dbv)) - return; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - YAMN_MAILBROWSERPARAM Param = {nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr}; - - Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nnflags = Param.nnflags & ~YAMN_ACC_POP; - - Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nflags = Param.nflags & ~YAMN_ACC_POP; - - RunMailBrowserSvc((WPARAM)&Param, YAMN_MAILBROWSERVERSION); - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - db_free(&dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HBITMAP LoadBmpFromIcon(HICON hIcon) -{ - int IconSizeX = 16; - int IconSizeY = 16; - - HBRUSH hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE)); - - BITMAPINFOHEADER bih = {0}; - bih.biSize = sizeof(bih); - bih.biBitCount = 24; - bih.biPlanes = 1; - bih.biCompression = BI_RGB; - bih.biHeight = IconSizeY; - bih.biWidth = IconSizeX; - - RECT rc; - rc.top = rc.left = 0; - rc.right = bih.biWidth; - rc.bottom = bih.biHeight; - - HDC hdc = GetDC(nullptr); - HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); - HDC hdcMem = CreateCompatibleDC(hdc); - HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); - FillRect(hdcMem, &rc, hBkgBrush); - DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL); - SelectObject(hdcMem, hoBmp); - return hBmp; -} - -int AddTopToolbarIcon(WPARAM, LPARAM) -{ - if (g_plugin.getByte(YAMN_TTBFCHECK, 1)) { - if (ServiceExists(MS_TTB_REMOVEBUTTON) && hTTButton == nullptr) { - TTBButton btn = {}; - btn.pszService = MS_YAMN_FORCECHECK; - btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP; - btn.hIconHandleUp = btn.hIconHandleDn = g_plugin.getIconHandle(IDI_CHECKMAIL); - btn.name = btn.pszTooltipUp = LPGEN("Check mail"); - hTTButton = g_plugin.addTTB(&btn); - } - } - else { - if (hTTButton != nullptr) { - CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); - hTTButton = nullptr; - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int Shutdown(WPARAM, LPARAM) -{ - CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); - - g_plugin.setDword(YAMN_DBMSGPOSX, HeadPosX); - g_plugin.setDword(YAMN_DBMSGPOSY, HeadPosY); - g_plugin.setDword(YAMN_DBMSGSIZEX, HeadSizeX); - g_plugin.setDword(YAMN_DBMSGSIZEY, HeadSizeY); - g_plugin.setWord(YAMN_DBMSGPOSSPLIT, HeadSplitPos); - YAMNVar.Shutdown = TRUE; - KillTimer(nullptr, SecTimer); - - UnregisterProtoPlugins(); - UnregisterFilterPlugins(); - return 0; -} - -int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp - -void HookEvents(void) -{ - HookEvent(ME_SYSTEM_MODULESLOADED, SystemModulesLoaded); - HookEvent(ME_TTB_MODULELOADED, AddTopToolbarIcon); - HookEvent(ME_OPT_INITIALISE, YAMNOptInitSvc); - HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown); - HookEvent(ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked); -} - -void CreateServiceFunctions(void) -{ - // Standard 'protocol' services - CreateServiceFunction(YAMN_DBMODULE PS_GETCAPS, Service_GetCaps); - CreateServiceFunction(YAMN_DBMODULE PS_GETNAME, Service_GetName); - CreateServiceFunction(YAMN_DBMODULE PS_LOADICON, Service_LoadIcon); - - // Function with which protocol plugin can register - CreateServiceFunction(MS_YAMN_GETFCNPTR, GetFcnPtrSvc); - - // Function returns pointer to YAMN variables - CreateServiceFunction(MS_YAMN_GETVARIABLES, GetVariablesSvc); - - // Function with which protocol plugin can register - CreateServiceFunction(MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc); - - // Function with which protocol plugin can unregister - CreateServiceFunction(MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc); - - // Function creates an account for plugin - CreateServiceFunction(MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc); - - // Function deletes plugin account - CreateServiceFunction(MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc); - - // Finds account for plugin by name - CreateServiceFunction(MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc); - - // Creates next account for plugin - CreateServiceFunction(MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc); - - // Function removes account from YAMN queue. Does not delete it from memory - CreateServiceFunction(MS_YAMN_DELETEACCOUNT, DeleteAccountSvc); - - // Function finds accounts for specified plugin - CreateServiceFunction(MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc); - - // Function that stores all plugin mails to one file - CreateServiceFunction(MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc); - - // Function that returns user's filename - CreateServiceFunction(MS_YAMN_GETFILENAME, GetFileNameSvc); - - // Releases unicode string from memory - CreateServiceFunction(MS_YAMN_DELETEFILENAME, DeleteFileNameSvc); - - // Checks mail - CreateServiceFunction(MS_YAMN_FORCECHECK, ForceCheckSvc); - - // Runs YAMN's mail browser - CreateServiceFunction(MS_YAMN_MAILBROWSER, RunMailBrowserSvc); - - // Function creates new mail for plugin - CreateServiceFunction(MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc); - - // Function deletes plugin account - CreateServiceFunction(MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc); - - // Function with which filter plugin can register - CreateServiceFunction(MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc); - - // Function with which filter plugin can unregister - CreateServiceFunction(MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc); - - // Function filters mail - CreateServiceFunction(MS_YAMN_FILTERMAIL, FilterMailSvc); - - // Function contact list double click - CreateServiceFunction(MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked); - - // Function to check individual account - CreateServiceFunction(MS_YAMN_ACCOUNTCHECK, AccountMailCheck); - - // Function contact list context menu click - CreateServiceFunction(MS_YAMN_CLISTCONTEXT, ContactMailCheck); - - // Function contact list context menu click - CreateServiceFunction(MS_YAMN_CLISTCONTEXTAPP, ContactApplication); -} - -// Function to put all enabled contact to the Online status -void RefreshContact(void) -{ - CAccount *Finder; - for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - if (Finder->hContact != NULL) { - Contact::Hide(Finder->hContact, !(Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)); - } - else if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { - Finder->hContact = db_add_contact(); - Proto_AddToContact(Finder->hContact, YAMN_DBMODULE); - g_plugin.setString(Finder->hContact, "Id", Finder->Name); - g_plugin.setString(Finder->hContact, "Nick", Finder->Name); - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE); - db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); - } - } -} +#include "stdafx.h"
+
+static INT_PTR Service_GetCaps(WPARAM wParam, LPARAM)
+{
+ switch (wParam) {
+ case PFLAGNUM_4:
+ return PF4_NOCUSTOMAUTH;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)TranslateT("Nick");
+ case PFLAG_MAXLENOFMESSAGE:
+ return 400;
+ case PFLAGNUM_2:
+ case PFLAGNUM_5:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND;
+ }
+
+ return 0;
+}
+
+static INT_PTR Service_GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char *)lParam, YAMN_DBMODULE, wParam);
+ return 0;
+}
+
+static INT_PTR Service_LoadIcon(WPARAM wParam, LPARAM)
+{
+ if (LOWORD(wParam) == PLI_PROTOCOL)
+ return (INT_PTR)CopyIcon(g_plugin.getIcon(IDI_CHECKMAIL)); // noone cares about other than PLI_PROTOCOL
+
+ return (INT_PTR)(HICON)NULL;
+}
+
+INT_PTR ClistContactDoubleclicked(WPARAM, LPARAM lParam)
+{
+ ContactDoubleclicked(((CLISTEVENT *)lParam)->lParam, lParam);
+ return 0;
+}
+
+static int Service_ContactDoubleclicked(WPARAM wParam, LPARAM lParam)
+{
+ ContactDoubleclicked(wParam, lParam);
+ return 0;
+}
+
+static INT_PTR ContactApplication(WPARAM wParam, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return 0;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ STARTUPINFOW si = {0};
+ si.cb = sizeof(si);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+
+ PROCESS_INFORMATION pi;
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+static INT_PTR AccountMailCheck(WPARAM wParam, LPARAM lParam)
+{
+ //This service will check/sincronize the account pointed by wParam
+ CAccount *ActualAccount = (CAccount *)wParam;
+ // copy/paste make mistakes
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ return 0;
+ //if we want to close miranda, we get event and do not run pop3 checking anymore
+ if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0))
+ return 0;
+
+ mir_cslock lck(PluginRegCS);
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) {
+ }
+ else {
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && ActualAccount->Plugin->Fcn->SynchroFcnPtr) {
+ CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam != 0 ? YAMN_FORCECHECK : YAMN_NORMALCHECK, nullptr, nullptr};
+
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ DWORD tid;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread) {
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(NewThread);
+ }
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ return 0;
+}
+
+static INT_PTR ContactMailCheck(WPARAM hContact, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(hContact, "Id", &dbv))
+ return 0;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV;
+ if (nullptr == (ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ return 0;
+ //if we want to close miranda, we get event and do not run pop3 checking anymore
+ if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0))
+ return 0;
+ mir_cslock lck(PluginRegCS);
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ }
+ else {
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check
+ {
+ if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr)
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ DWORD tid;
+ struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr};
+ if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid))
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ else
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ YAMN_MAILBROWSERPARAM Param = {nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr};
+
+ Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nnflags = Param.nnflags & ~YAMN_ACC_POP;
+
+ Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nflags = Param.nflags & ~YAMN_ACC_POP;
+
+ RunMailBrowserSvc((WPARAM)&Param, YAMN_MAILBROWSERVERSION);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ db_free(&dbv);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+HBITMAP LoadBmpFromIcon(HICON hIcon)
+{
+ int IconSizeX = 16;
+ int IconSizeY = 16;
+
+ HBRUSH hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+
+ BITMAPINFOHEADER bih = {0};
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biPlanes = 1;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = IconSizeY;
+ bih.biWidth = IconSizeX;
+
+ RECT rc;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+
+ HDC hdc = GetDC(nullptr);
+ HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
+ FillRect(hdcMem, &rc, hBkgBrush);
+ DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL);
+ SelectObject(hdcMem, hoBmp);
+ return hBmp;
+}
+
+int AddTopToolbarIcon(WPARAM, LPARAM)
+{
+ if (g_plugin.getByte(YAMN_TTBFCHECK, 1)) {
+ if (ServiceExists(MS_TTB_REMOVEBUTTON) && hTTButton == nullptr) {
+ TTBButton btn = {};
+ btn.pszService = MS_YAMN_FORCECHECK;
+ btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP;
+ btn.hIconHandleUp = btn.hIconHandleDn = g_plugin.getIconHandle(IDI_CHECKMAIL);
+ btn.name = btn.pszTooltipUp = LPGEN("Check mail");
+ hTTButton = g_plugin.addTTB(&btn);
+ }
+ }
+ else {
+ if (hTTButton != nullptr) {
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+ hTTButton = nullptr;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int Shutdown(WPARAM, LPARAM)
+{
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+
+ g_plugin.setDword(YAMN_DBMSGPOSX, HeadPosX);
+ g_plugin.setDword(YAMN_DBMSGPOSY, HeadPosY);
+ g_plugin.setDword(YAMN_DBMSGSIZEX, HeadSizeX);
+ g_plugin.setDword(YAMN_DBMSGSIZEY, HeadSizeY);
+ g_plugin.setWord(YAMN_DBMSGPOSSPLIT, HeadSplitPos);
+ YAMNVar.Shutdown = TRUE;
+ KillTimer(nullptr, SecTimer);
+
+ UnregisterProtoPlugins();
+ UnregisterFilterPlugins();
+ return 0;
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp
+
+void HookEvents(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, SystemModulesLoaded);
+ HookEvent(ME_TTB_MODULELOADED, AddTopToolbarIcon);
+ HookEvent(ME_OPT_INITIALISE, YAMNOptInitSvc);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown);
+ HookEvent(ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked);
+}
+
+void CreateServiceFunctions(void)
+{
+ // Standard 'protocol' services
+ CreateServiceFunction(YAMN_DBMODULE PS_GETCAPS, Service_GetCaps);
+ CreateServiceFunction(YAMN_DBMODULE PS_GETNAME, Service_GetName);
+ CreateServiceFunction(YAMN_DBMODULE PS_LOADICON, Service_LoadIcon);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_GETFCNPTR, GetFcnPtrSvc);
+
+ // Function returns pointer to YAMN variables
+ CreateServiceFunction(MS_YAMN_GETVARIABLES, GetVariablesSvc);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc);
+
+ // Function with which protocol plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc);
+
+ // Function creates an account for plugin
+ CreateServiceFunction(MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc);
+
+ // Finds account for plugin by name
+ CreateServiceFunction(MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc);
+
+ // Creates next account for plugin
+ CreateServiceFunction(MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc);
+
+ // Function removes account from YAMN queue. Does not delete it from memory
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNT, DeleteAccountSvc);
+
+ // Function finds accounts for specified plugin
+ CreateServiceFunction(MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc);
+
+ // Function that stores all plugin mails to one file
+ CreateServiceFunction(MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc);
+
+ // Function that returns user's filename
+ CreateServiceFunction(MS_YAMN_GETFILENAME, GetFileNameSvc);
+
+ // Releases unicode string from memory
+ CreateServiceFunction(MS_YAMN_DELETEFILENAME, DeleteFileNameSvc);
+
+ // Checks mail
+ CreateServiceFunction(MS_YAMN_FORCECHECK, ForceCheckSvc);
+
+ // Runs YAMN's mail browser
+ CreateServiceFunction(MS_YAMN_MAILBROWSER, RunMailBrowserSvc);
+
+ // Function creates new mail for plugin
+ CreateServiceFunction(MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc);
+
+ // Function with which filter plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc);
+
+ // Function with which filter plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc);
+
+ // Function filters mail
+ CreateServiceFunction(MS_YAMN_FILTERMAIL, FilterMailSvc);
+
+ // Function contact list double click
+ CreateServiceFunction(MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked);
+
+ // Function to check individual account
+ CreateServiceFunction(MS_YAMN_ACCOUNTCHECK, AccountMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXT, ContactMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXTAPP, ContactApplication);
+}
+
+// Function to put all enabled contact to the Online status
+void RefreshContact(void)
+{
+ CAccount *Finder;
+ for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ if (Finder->hContact != NULL) {
+ Contact::Hide(Finder->hContact, !(Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT));
+ }
+ else if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ }
+ }
+}
diff --git a/protocols/YAMN/src/stdafx.h b/protocols/YAMN/src/stdafx.h index 05681d467b..38f1c1b5fe 100644 --- a/protocols/YAMN/src/stdafx.h +++ b/protocols/YAMN/src/stdafx.h @@ -1,253 +1,253 @@ - -#ifndef __YAMN_H -#define __YAMN_H - -#define VC_EXTRALEAN - -#include <windows.h> -#include <windowsx.h> -#include <commctrl.h> - -#include <newpluginapi.h> -#include <m_clistint.h> -#include <m_contacts.h> -#include <m_database.h> -#include <m_hotkeys.h> -#include <m_icolib.h> -#include <m_langpack.h> -#include <m_messages.h> -#include <m_netlib.h> -#include <m_options.h> -#include <m_popup.h> -#include <m_protosvc.h> -#include <m_skin.h> -#include <m_timezones.h> - -#include <m_toptoolbar.h> -#include <m_kbdnotify.h> -#include <m_filterplugin.h> -#include <m_yamn.h> -#include <m_protoplugin.h> -#include <m_folders.h> - -#include "main.h" -#include "mails/decode.h" -#include "browser/browser.h" -#include "resource.h" -#include "debug.h" -#include "version.h" -#include "proto/netclient.h" -#include "proto/netlib.h" -#include "proto/pop3/pop3.h" -#include "proto/pop3/pop3comm.h" - -struct CMPlugin : public PLUGIN<CMPlugin> -{ - CMPlugin(); - - int Load() override; - int Unload() override; -}; - -// From services.cpp -void CreateServiceFunctions(void); -void HookEvents(void); -void RefreshContact(void); -void ContactDoubleclicked(WPARAM wParam, LPARAM lParam); -INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam); - -extern mir_cs PluginRegCS; -extern SCOUNTER *AccountWriterSO; -extern HANDLE ExitEV; -extern HANDLE WriteToFileEV; - -// From debug.cpp -#ifdef _DEBUG -void InitDebug(); -void UnInitDebug(); -#endif - -// From yamn.cpp -INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam); -INT_PTR GetVariablesSvc(WPARAM, LPARAM); -void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD); -INT_PTR ForceCheckSvc(WPARAM, LPARAM); - -extern struct YAMNExportedFcns *pYAMNFcn; - -// From account.cpp -INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam); -INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM); -int InitAccount(CAccount *Which); -void DeInitAccount(CAccount *Which); -void StopSignalFcn(CAccount *Which); -void CodeDecodeString(char *Dest, BOOL Encrypt); -uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End); - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); -#endif -uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo); -uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End); -uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, wchar_t *End); -INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam); - -uint32_t WriteStringToFile(HANDLE File, char *Source); -uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source); - - -DWORD WriteMessagesToFile(HANDLE File, CAccount *Which); -DWORD WINAPI WritePOP3Accounts(); -INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam); -INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam); -INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam); - -INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM); -void __cdecl DeleteAccountInBackground(void *Which); -int StopAccounts(HYAMNPROTOPLUGIN Plugin); -int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess = FALSE); -int DeleteAccounts(HYAMNPROTOPLUGIN Plugin); - -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value); -void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value); - -INT_PTR UnregisterProtoPlugins(); -INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM); -INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM); -INT_PTR GetFileNameSvc(WPARAM, LPARAM); -INT_PTR DeleteFileNameSvc(WPARAM, LPARAM); - -//From filterplugin.cpp -//struct CExportedFunctions FilterPluginExported[]; -INT_PTR UnregisterFilterPlugins(); -INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM); -INT_PTR UnregisterFilterPluginSvc(WPARAM, LPARAM); -INT_PTR FilterMailSvc(WPARAM, LPARAM); - -//From mails.cpp (MIME) -//struct CExportedFunctions MailExported[]; -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); -INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); -INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); - -//From mime.cpp -//void WINAPI ExtractHeaderFcn(char *,int,uint16_t,HYAMNMAIL); //already in MailExported -struct _tcptable -{ - char *NameBase, *NameSub; - BOOLEAN isValid; - unsigned short int CP; -}; -extern struct _tcptable CodePageNamesAll[]; // in mime/decode.cpp -extern int CPLENALL; -extern struct _tcptable *CodePageNamesSupp; // in mime/decode.cpp -extern int CPLENSUPP; - -extern int PosX, PosY, SizeX, SizeY; -extern int HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, HeadSplitPos; - -//#define CPDEFINDEX 63 //ISO-8859-1 -#define CPDEFINDEX 0 //ACP - -//From pop3comm.cpp -int RegisterPOP3Plugin(WPARAM, LPARAM); - -//From mailbrowser.cpp -INT_PTR RunMailBrowserSvc(WPARAM, LPARAM); - -//From badconnect.cpp -int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo); - -//From YAMNopts.cpp -int YAMNOptInitSvc(WPARAM, LPARAM); - -//From main.cpp -int PostLoad(WPARAM, LPARAM); //Executed after all plugins loaded YAMN reads mails from file and notify every protocol it should set its functions -int Shutdown(WPARAM, LPARAM); //Executed before Miranda is going to shutdown -int AddTopToolbarIcon(WPARAM, LPARAM); //Executed when TopToolBar plugin loaded Adds bitmap to toolbar - -extern wchar_t UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ" -extern wchar_t ProfileName[]; //e.g. "majvan" -extern SWMRG *AccountBrowserSO; -extern YAMN_VARIABLES YAMNVar; -extern HANDLE hNewMailHook; -extern HANDLE hTTButton; -extern HCURSOR hCurSplitNS, hCurSplitWE; -extern UINT SecTimer; - -//From synchro.cpp -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); -uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr); -void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr); -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject); -void WINAPI ReadDoneFcn(PSWMRG SObject); -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter); -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter); -BOOL WINAPI SWMRGInitialize(PSWMRG, wchar_t *); -void WINAPI SWMRGDelete(PSWMRG); -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout); -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); - -//From mails.cpp -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSet, int mode); - -//From mime.cpp -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); -void DeleteHeaderContent(struct CHeader *head); -void DeleteShortHeaderContent(struct CShortHeader *head); -char *ExtractFromContentType(char *ContentType, char *value); -wchar_t *ParseMultipartBody(char *src, char *bond); - -//From account.cpp -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value); - -extern HYAMNPROTOPLUGIN POP3Plugin; - -//from decode.cpp -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); -int DecodeBase64(char *Src, char *Dst, int DstLen); - -//From filterplugin.cpp -extern PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin; - -//From protoplugin.cpp -extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin; - -extern struct CExportedFunctions ProtoPluginExportedFcn[1]; -extern struct CExportedServices ProtoPluginExportedSvc[5]; -//From filterplugin.cpp -extern struct CExportedFunctions FilterPluginExportedFcn[1]; -extern struct CExportedServices FilterPluginExportedSvc[2]; -//From synchro.cpp -extern struct CExportedFunctions SynchroExportedFcn[7]; -//From account.cpp -extern struct CExportedFunctions AccountExportedFcn[2]; -extern struct CExportedServices AccountExportedSvc[9]; -//From mails.cpp (MIME) -extern struct CExportedFunctions MailExportedFcn[8]; -extern struct CExportedServices MailExportedSvc[5]; - -extern char *iconDescs[]; -extern char *iconNames[]; -extern HIMAGELIST CSImages; - -extern void __stdcall SSL_DebugLog(const char *fmt, ...); - -extern struct WndHandles *MessageWnd; - -extern int GetCharsetFromString(char *input, size_t size); -extern void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); -extern void __cdecl MailBrowser(void *Param); -extern void __cdecl BadConnection(void *Param); -extern PVOID TLSCtx; -extern PVOID SSLCtx; - -extern PYAMN_VARIABLES pYAMNVar; - -#endif +
+#ifndef __YAMN_H
+#define __YAMN_H
+
+#define VC_EXTRALEAN
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include <newpluginapi.h>
+#include <m_clistint.h>
+#include <m_contacts.h>
+#include <m_database.h>
+#include <m_hotkeys.h>
+#include <m_icolib.h>
+#include <m_langpack.h>
+#include <m_messages.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <m_timezones.h>
+
+#include <m_toptoolbar.h>
+#include <m_kbdnotify.h>
+#include <m_filterplugin.h>
+#include <m_yamn.h>
+#include <m_protoplugin.h>
+#include <m_folders.h>
+
+#include "main.h"
+#include "mails/decode.h"
+#include "browser/browser.h"
+#include "resource.h"
+#include "debug.h"
+#include "version.h"
+#include "proto/netclient.h"
+#include "proto/netlib.h"
+#include "proto/pop3/pop3.h"
+#include "proto/pop3/pop3comm.h"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+// From services.cpp
+void CreateServiceFunctions(void);
+void HookEvents(void);
+void RefreshContact(void);
+void ContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+
+extern mir_cs PluginRegCS;
+extern SCOUNTER *AccountWriterSO;
+extern HANDLE ExitEV;
+extern HANDLE WriteToFileEV;
+
+// From debug.cpp
+#ifdef _DEBUG
+void InitDebug();
+void UnInitDebug();
+#endif
+
+// From yamn.cpp
+INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR GetVariablesSvc(WPARAM, LPARAM);
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
+INT_PTR ForceCheckSvc(WPARAM, LPARAM);
+
+extern struct YAMNExportedFcns *pYAMNFcn;
+
+// From account.cpp
+INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM);
+int InitAccount(CAccount *Which);
+void DeInitAccount(CAccount *Which);
+void StopSignalFcn(CAccount *Which);
+void CodeDecodeString(char *Dest, BOOL Encrypt);
+uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End);
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString);
+#endif
+uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo);
+uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End);
+uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, wchar_t *End);
+INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam);
+
+uint32_t WriteStringToFile(HANDLE File, char *Source);
+uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source);
+
+
+DWORD WriteMessagesToFile(HANDLE File, CAccount *Which);
+DWORD WINAPI WritePOP3Accounts();
+INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam);
+
+INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM);
+void __cdecl DeleteAccountInBackground(void *Which);
+int StopAccounts(HYAMNPROTOPLUGIN Plugin);
+int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess = FALSE);
+int DeleteAccounts(HYAMNPROTOPLUGIN Plugin);
+
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value);
+void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value);
+
+INT_PTR UnregisterProtoPlugins();
+INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM);
+INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM);
+INT_PTR GetFileNameSvc(WPARAM, LPARAM);
+INT_PTR DeleteFileNameSvc(WPARAM, LPARAM);
+
+//From filterplugin.cpp
+//struct CExportedFunctions FilterPluginExported[];
+INT_PTR UnregisterFilterPlugins();
+INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM);
+INT_PTR UnregisterFilterPluginSvc(WPARAM, LPARAM);
+INT_PTR FilterMailSvc(WPARAM, LPARAM);
+
+//From mails.cpp (MIME)
+//struct CExportedFunctions MailExported[];
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM);
+INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//From mime.cpp
+//void WINAPI ExtractHeaderFcn(char *,int,uint16_t,HYAMNMAIL); //already in MailExported
+struct _tcptable
+{
+ char *NameBase, *NameSub;
+ BOOLEAN isValid;
+ unsigned short int CP;
+};
+extern struct _tcptable CodePageNamesAll[]; // in mime/decode.cpp
+extern int CPLENALL;
+extern struct _tcptable *CodePageNamesSupp; // in mime/decode.cpp
+extern int CPLENSUPP;
+
+extern int PosX, PosY, SizeX, SizeY;
+extern int HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, HeadSplitPos;
+
+//#define CPDEFINDEX 63 //ISO-8859-1
+#define CPDEFINDEX 0 //ACP
+
+//From pop3comm.cpp
+int RegisterPOP3Plugin(WPARAM, LPARAM);
+
+//From mailbrowser.cpp
+INT_PTR RunMailBrowserSvc(WPARAM, LPARAM);
+
+//From badconnect.cpp
+int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo);
+
+//From YAMNopts.cpp
+int YAMNOptInitSvc(WPARAM, LPARAM);
+
+//From main.cpp
+int PostLoad(WPARAM, LPARAM); //Executed after all plugins loaded YAMN reads mails from file and notify every protocol it should set its functions
+int Shutdown(WPARAM, LPARAM); //Executed before Miranda is going to shutdown
+int AddTopToolbarIcon(WPARAM, LPARAM); //Executed when TopToolBar plugin loaded Adds bitmap to toolbar
+
+extern wchar_t UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ"
+extern wchar_t ProfileName[]; //e.g. "majvan"
+extern SWMRG *AccountBrowserSO;
+extern YAMN_VARIABLES YAMNVar;
+extern HANDLE hNewMailHook;
+extern HANDLE hTTButton;
+extern HCURSOR hCurSplitNS, hCurSplitWE;
+extern UINT SecTimer;
+
+//From synchro.cpp
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From);
+uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject);
+void WINAPI ReadDoneFcn(PSWMRG SObject);
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter);
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter);
+BOOL WINAPI SWMRGInitialize(PSWMRG, wchar_t *);
+void WINAPI SWMRGDelete(PSWMRG);
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout);
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG);
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG);
+
+//From mails.cpp
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode);
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSet, int mode);
+
+//From mime.cpp
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head);
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head);
+void DeleteHeaderContent(struct CHeader *head);
+void DeleteShortHeaderContent(struct CShortHeader *head);
+char *ExtractFromContentType(char *ContentType, char *value);
+wchar_t *ParseMultipartBody(char *src, char *bond);
+
+//From account.cpp
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value);
+
+extern HYAMNPROTOPLUGIN POP3Plugin;
+
+//from decode.cpp
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+
+//From filterplugin.cpp
+extern PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin;
+
+//From protoplugin.cpp
+extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin;
+
+extern struct CExportedFunctions ProtoPluginExportedFcn[1];
+extern struct CExportedServices ProtoPluginExportedSvc[5];
+//From filterplugin.cpp
+extern struct CExportedFunctions FilterPluginExportedFcn[1];
+extern struct CExportedServices FilterPluginExportedSvc[2];
+//From synchro.cpp
+extern struct CExportedFunctions SynchroExportedFcn[7];
+//From account.cpp
+extern struct CExportedFunctions AccountExportedFcn[2];
+extern struct CExportedServices AccountExportedSvc[9];
+//From mails.cpp (MIME)
+extern struct CExportedFunctions MailExportedFcn[8];
+extern struct CExportedServices MailExportedSvc[5];
+
+extern char *iconDescs[];
+extern char *iconNames[];
+extern HIMAGELIST CSImages;
+
+extern void __stdcall SSL_DebugLog(const char *fmt, ...);
+
+extern struct WndHandles *MessageWnd;
+
+extern int GetCharsetFromString(char *input, size_t size);
+extern void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+extern void __cdecl MailBrowser(void *Param);
+extern void __cdecl BadConnection(void *Param);
+extern PVOID TLSCtx;
+extern PVOID SSLCtx;
+
+extern PYAMN_VARIABLES pYAMNVar;
+
+#endif
diff --git a/protocols/YAMN/src/synchro.cpp b/protocols/YAMN/src/synchro.cpp index c4bb58e6de..184156787d 100644 --- a/protocols/YAMN/src/synchro.cpp +++ b/protocols/YAMN/src/synchro.cpp @@ -1,315 +1,315 @@ -/* - * This code implements synchronization objects code between threads. If you want, you can include it to your - * code. This file is not dependent on any other external code (functions) - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - // Initializes a SWMRG structure. This structure must be - // initialized before any writer or reader threads attempt - // to wait on it. - // The structure must be allocated by the application and - // the structure's address is passed as the first parameter. - // The lpszName parameter is the name of the object. Pass - // NULL if you do not want to share the object. -BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name); - -// Deletes the system resources associated with a SWMRG -// structure. The structure must be deleted only when -// no writer or reader threads in the calling process -// will wait on it. -void WINAPI SWMRGDelete(PSWMRG pSWMRG); - -// A writer thread calls this function to know when -// it can successfully write to the shared data. -// returns WAIT_FINISH when we are in write-access or WAIT_FAILED -// when event about quick finishing is set (or when system returns fail when waiting for synchro object) -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout); - -// A writer thread calls this function to let other threads -// know that it no longer needs to write to the shared data. -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); - -// A reader thread calls this function to know when -// it can successfully read the shared data. -// returns WAIT_FINISH when we are in read-access or WAIT_FAILED -// when event about quick finishing is set (or when system returns fail when waiting for synchro object) -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); - -// A reader thread calls this function to let other threads -// know when it no longer needs to read the shared data. -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); - -// WaitToReadFcn -// is used to wait for read access with SWMRG SO, but it also increments counter if successfull -// returns WAIT_FAILED or WAIT_FINISH -// when WAIT_FAILED, we should not begin to access datas, we are not in read-access mode -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject); - -// WriteDoneFcn -// is used to release read access with SWMRG SO, but it also decrements counter if successfull -void WINAPI ReadDoneFcn(PSWMRG SObject); - -// This functions is for export purposes -// Plugin can call this function to manage SCOUNTER synchronization object - -// Gets number value stored in SCOUNTER SO -// Note you must not read the number from memory directly, because -// CPU can stop reading thread when it has read HI-Word, then another thread -// can change the value and then OS starts the previous thread, that reads the -// LO-uint16_t of uint32_t. And the return value HI+LO-uint16_t is corrupted -uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter); - -// Increments SCOUNTER and unsets event -// Returns Number after incrementing -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter); - -// Decrements SCOUNTER and sets event if zero -// Returns Number after decrementing -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter); - -struct CExportedFunctions SynchroExportedFcn[] = -{ - {YAMN_WAITTOWRITEID, (void *)WaitToWriteFcn}, - {YAMN_WRITEDONEID, (void *)WriteDoneFcn}, - {YAMN_WAITTOREADID, (void *)WaitToReadFcn}, - {YAMN_READDONEID, (void *)ReadDoneFcn}, - {YAMN_SCGETNUMBERID, (void *)SCGetNumberFcn}, - {YAMN_SCINCID, (void *)SCIncFcn}, - {YAMN_SCDECID, (void *)SCDecFcn}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void WINAPI SWMRGDelete(PSWMRG pSWMRG) -{ - // Destroys any synchronization objects that were - // successfully created. - if (nullptr != pSWMRG->hEventNoWriter) - CloseHandle(pSWMRG->hEventNoWriter); - if (nullptr != pSWMRG->hEventNoReaders) - CloseHandle(pSWMRG->hEventNoReaders); - if (nullptr != pSWMRG->hSemNumReaders) - CloseHandle(pSWMRG->hSemNumReaders); - if (nullptr != pSWMRG->hFinishEV) - CloseHandle(pSWMRG->hFinishEV); -} - -BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name) -{ - pSWMRG->hEventNoWriter = nullptr; - pSWMRG->hEventNoReaders = nullptr; - pSWMRG->hSemNumReaders = nullptr; - pSWMRG->hFinishEV = nullptr; - - // Creates the automatic-reset event that is signalled when - // no writer threads are writing. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'W'; - pSWMRG->hEventNoWriter = CreateEvent(nullptr, FALSE, TRUE, Name); - - // Creates the manual-reset event that is signalled when - // no reader threads are reading. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'R'; - pSWMRG->hEventNoReaders = CreateEvent(nullptr, TRUE, TRUE, Name); - - // Initializes the variable that indicates the number of - // reader threads that are reading. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'C'; - pSWMRG->hSemNumReaders = CreateSemaphore(nullptr, 0, 0x7FFFFFFF, Name); - - if (Name != nullptr) - Name[0] = (wchar_t)'F'; - pSWMRG->hFinishEV = CreateEvent(nullptr, TRUE, FALSE, Name); - - // If a synchronization object could not be created, - // destroys any created objects and return failure. - if ((nullptr == pSWMRG->hEventNoWriter) || (nullptr == pSWMRG->hEventNoReaders) || (nullptr == pSWMRG->hSemNumReaders) || (nullptr == pSWMRG->hFinishEV)) { - SWMRGDelete(pSWMRG); - return FALSE; - } - return TRUE; -} - -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout) -{ - uint32_t dw; - HANDLE aHandles[2]; - - // We can write if the following are true: - // 1. No other threads are writing. - // 2. No threads are reading. - // But first we have to know if SWMRG structure is not about to delete - aHandles[0] = pSWMRG->hEventNoWriter; - aHandles[1] = pSWMRG->hEventNoReaders; - if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0))) - return WAIT_FINISH; - if (WAIT_FAILED == dw) - return dw; - dw = WaitForMultipleObjects(2, aHandles, TRUE, dwTimeout); - // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete - if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) { - SetEvent(pSWMRG->hEventNoWriter); - return WAIT_FINISH; - } - - // This thread can write to the shared data. - // Automatic event for NoWriter sets hEventNoWriter to nonsignaled after WaitForMultipleObject - - // Because a writer thread is writing, the Event - // should not be reset. This stops other - // writers and readers. - return dw; -} - -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG) -// Presumably, a writer thread calling this function has -// successfully called WaitToWrite. This means that we -// do not have to wait on any synchronization objects -// here because the writer already owns the Event. -{ - // Allow other writer/reader threads to use - // the SWMRG synchronization object. - SetEvent(pSWMRG->hEventNoWriter); -} - -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout) -{ - uint32_t dw; - LONG lPreviousCount; - - // We can read if no threads are writing. - // And there's not request to delete structure - if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0))) - return WAIT_FINISH; - if (WAIT_FAILED == dw) - return dw; - dw = WaitForSingleObject(pSWMRG->hEventNoWriter, dwTimeout); - // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete - if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) { - SetEvent(pSWMRG->hEventNoWriter); - return WAIT_FINISH; - } - - if (dw == WAIT_OBJECT_0) { - // This thread can read from the shared data. - // Increment the number of reader threads. - // But there can't be more than one thread incrementing readers, - // so this is why we use semaphore. - ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount); - if (lPreviousCount == 0) - // If this is the first reader thread, - // set event to reflect this. Other reader threads can read, no writer thread can write. - ResetEvent(pSWMRG->hEventNoReaders); - - // Allow other writer/reader threads to use - // the SWMRG synchronization object. hEventNoWrite is still non-signaled - // (it looks like writer is processing thread, but it is not true) - SetEvent(pSWMRG->hEventNoWriter); - } - - return(dw); -} - -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG) -{ - HANDLE aHandles[2]; - LONG lNumReaders; - - // We can stop reading if the events are available, - // but when we stop reading we must also decrement the - // number of reader threads. - aHandles[0] = pSWMRG->hEventNoWriter; - aHandles[1] = pSWMRG->hSemNumReaders; - WaitForMultipleObjects(2, aHandles, TRUE, INFINITE); - - // Get the remaining number of readers by releasing the - // semaphore and then restoring the count by immediately - // performing a wait. - ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lNumReaders); - WaitForSingleObject(pSWMRG->hSemNumReaders, INFINITE); - - // If there are no remaining readers, - // set the event to relect this. - if (lNumReaders == 0) - // If there are no reader threads, - // set our event to reflect this. - SetEvent(pSWMRG->hEventNoReaders); - - // Allow other writer/reader threads to use - // the SWMRG synchronization object. - // (it looks like writer is processing thread, but it is not true) - SetEvent(pSWMRG->hEventNoWriter); -} - -uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter) -{ - uint32_t EnterCode; - - if (WAIT_OBJECT_0 == (EnterCode = SWMRGWaitToWrite(SObject, INFINITE))) - if (SCounter != nullptr) - SCIncFcn(SCounter); - - return EnterCode; -} - -void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter) -{ - SWMRGDoneWriting(SObject); - if (SCounter != nullptr) - SCDecFcn(SCounter); -} - -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject) -{ - uint32_t EnterCode = SWMRGWaitToRead(SObject, INFINITE); - return EnterCode; -} - -void WINAPI ReadDoneFcn(PSWMRG SObject) -{ - SWMRGDoneReading(SObject); -} - -uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter) -{ - - EnterCriticalSection(&SCounter->CounterCS); - - uint32_t Temp = SCounter->Number; - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} - -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter) -{ - EnterCriticalSection(&SCounter->CounterCS); - - uint32_t Temp = ++SCounter->Number; - ResetEvent(SCounter->Event); - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} - -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter) -{ - uint32_t Temp; - EnterCriticalSection(&SCounter->CounterCS); - - if (!(Temp = --SCounter->Number)) { - SetEvent(SCounter->Event); - } - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} +/*
+ * This code implements synchronization objects code between threads. If you want, you can include it to your
+ * code. This file is not dependent on any other external code (functions)
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ // Initializes a SWMRG structure. This structure must be
+ // initialized before any writer or reader threads attempt
+ // to wait on it.
+ // The structure must be allocated by the application and
+ // the structure's address is passed as the first parameter.
+ // The lpszName parameter is the name of the object. Pass
+ // NULL if you do not want to share the object.
+BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name);
+
+// Deletes the system resources associated with a SWMRG
+// structure. The structure must be deleted only when
+// no writer or reader threads in the calling process
+// will wait on it.
+void WINAPI SWMRGDelete(PSWMRG pSWMRG);
+
+// A writer thread calls this function to know when
+// it can successfully write to the shared data.
+// returns WAIT_FINISH when we are in write-access or WAIT_FAILED
+// when event about quick finishing is set (or when system returns fail when waiting for synchro object)
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout);
+
+// A writer thread calls this function to let other threads
+// know that it no longer needs to write to the shared data.
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG);
+
+// A reader thread calls this function to know when
+// it can successfully read the shared data.
+// returns WAIT_FINISH when we are in read-access or WAIT_FAILED
+// when event about quick finishing is set (or when system returns fail when waiting for synchro object)
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+
+// A reader thread calls this function to let other threads
+// know when it no longer needs to read the shared data.
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG);
+
+// WaitToReadFcn
+// is used to wait for read access with SWMRG SO, but it also increments counter if successfull
+// returns WAIT_FAILED or WAIT_FINISH
+// when WAIT_FAILED, we should not begin to access datas, we are not in read-access mode
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject);
+
+// WriteDoneFcn
+// is used to release read access with SWMRG SO, but it also decrements counter if successfull
+void WINAPI ReadDoneFcn(PSWMRG SObject);
+
+// This functions is for export purposes
+// Plugin can call this function to manage SCOUNTER synchronization object
+
+// Gets number value stored in SCOUNTER SO
+// Note you must not read the number from memory directly, because
+// CPU can stop reading thread when it has read HI-Word, then another thread
+// can change the value and then OS starts the previous thread, that reads the
+// LO-uint16_t of uint32_t. And the return value HI+LO-uint16_t is corrupted
+uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter);
+
+// Increments SCOUNTER and unsets event
+// Returns Number after incrementing
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter);
+
+// Decrements SCOUNTER and sets event if zero
+// Returns Number after decrementing
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter);
+
+struct CExportedFunctions SynchroExportedFcn[] =
+{
+ {YAMN_WAITTOWRITEID, (void *)WaitToWriteFcn},
+ {YAMN_WRITEDONEID, (void *)WriteDoneFcn},
+ {YAMN_WAITTOREADID, (void *)WaitToReadFcn},
+ {YAMN_READDONEID, (void *)ReadDoneFcn},
+ {YAMN_SCGETNUMBERID, (void *)SCGetNumberFcn},
+ {YAMN_SCINCID, (void *)SCIncFcn},
+ {YAMN_SCDECID, (void *)SCDecFcn},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void WINAPI SWMRGDelete(PSWMRG pSWMRG)
+{
+ // Destroys any synchronization objects that were
+ // successfully created.
+ if (nullptr != pSWMRG->hEventNoWriter)
+ CloseHandle(pSWMRG->hEventNoWriter);
+ if (nullptr != pSWMRG->hEventNoReaders)
+ CloseHandle(pSWMRG->hEventNoReaders);
+ if (nullptr != pSWMRG->hSemNumReaders)
+ CloseHandle(pSWMRG->hSemNumReaders);
+ if (nullptr != pSWMRG->hFinishEV)
+ CloseHandle(pSWMRG->hFinishEV);
+}
+
+BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name)
+{
+ pSWMRG->hEventNoWriter = nullptr;
+ pSWMRG->hEventNoReaders = nullptr;
+ pSWMRG->hSemNumReaders = nullptr;
+ pSWMRG->hFinishEV = nullptr;
+
+ // Creates the automatic-reset event that is signalled when
+ // no writer threads are writing.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'W';
+ pSWMRG->hEventNoWriter = CreateEvent(nullptr, FALSE, TRUE, Name);
+
+ // Creates the manual-reset event that is signalled when
+ // no reader threads are reading.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'R';
+ pSWMRG->hEventNoReaders = CreateEvent(nullptr, TRUE, TRUE, Name);
+
+ // Initializes the variable that indicates the number of
+ // reader threads that are reading.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'C';
+ pSWMRG->hSemNumReaders = CreateSemaphore(nullptr, 0, 0x7FFFFFFF, Name);
+
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'F';
+ pSWMRG->hFinishEV = CreateEvent(nullptr, TRUE, FALSE, Name);
+
+ // If a synchronization object could not be created,
+ // destroys any created objects and return failure.
+ if ((nullptr == pSWMRG->hEventNoWriter) || (nullptr == pSWMRG->hEventNoReaders) || (nullptr == pSWMRG->hSemNumReaders) || (nullptr == pSWMRG->hFinishEV)) {
+ SWMRGDelete(pSWMRG);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout)
+{
+ uint32_t dw;
+ HANDLE aHandles[2];
+
+ // We can write if the following are true:
+ // 1. No other threads are writing.
+ // 2. No threads are reading.
+ // But first we have to know if SWMRG structure is not about to delete
+ aHandles[0] = pSWMRG->hEventNoWriter;
+ aHandles[1] = pSWMRG->hEventNoReaders;
+ if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0)))
+ return WAIT_FINISH;
+ if (WAIT_FAILED == dw)
+ return dw;
+ dw = WaitForMultipleObjects(2, aHandles, TRUE, dwTimeout);
+ // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete
+ if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) {
+ SetEvent(pSWMRG->hEventNoWriter);
+ return WAIT_FINISH;
+ }
+
+ // This thread can write to the shared data.
+ // Automatic event for NoWriter sets hEventNoWriter to nonsignaled after WaitForMultipleObject
+
+ // Because a writer thread is writing, the Event
+ // should not be reset. This stops other
+ // writers and readers.
+ return dw;
+}
+
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG)
+// Presumably, a writer thread calling this function has
+// successfully called WaitToWrite. This means that we
+// do not have to wait on any synchronization objects
+// here because the writer already owns the Event.
+{
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object.
+ SetEvent(pSWMRG->hEventNoWriter);
+}
+
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout)
+{
+ uint32_t dw;
+ LONG lPreviousCount;
+
+ // We can read if no threads are writing.
+ // And there's not request to delete structure
+ if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0)))
+ return WAIT_FINISH;
+ if (WAIT_FAILED == dw)
+ return dw;
+ dw = WaitForSingleObject(pSWMRG->hEventNoWriter, dwTimeout);
+ // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete
+ if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) {
+ SetEvent(pSWMRG->hEventNoWriter);
+ return WAIT_FINISH;
+ }
+
+ if (dw == WAIT_OBJECT_0) {
+ // This thread can read from the shared data.
+ // Increment the number of reader threads.
+ // But there can't be more than one thread incrementing readers,
+ // so this is why we use semaphore.
+ ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount);
+ if (lPreviousCount == 0)
+ // If this is the first reader thread,
+ // set event to reflect this. Other reader threads can read, no writer thread can write.
+ ResetEvent(pSWMRG->hEventNoReaders);
+
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object. hEventNoWrite is still non-signaled
+ // (it looks like writer is processing thread, but it is not true)
+ SetEvent(pSWMRG->hEventNoWriter);
+ }
+
+ return(dw);
+}
+
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG)
+{
+ HANDLE aHandles[2];
+ LONG lNumReaders;
+
+ // We can stop reading if the events are available,
+ // but when we stop reading we must also decrement the
+ // number of reader threads.
+ aHandles[0] = pSWMRG->hEventNoWriter;
+ aHandles[1] = pSWMRG->hSemNumReaders;
+ WaitForMultipleObjects(2, aHandles, TRUE, INFINITE);
+
+ // Get the remaining number of readers by releasing the
+ // semaphore and then restoring the count by immediately
+ // performing a wait.
+ ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lNumReaders);
+ WaitForSingleObject(pSWMRG->hSemNumReaders, INFINITE);
+
+ // If there are no remaining readers,
+ // set the event to relect this.
+ if (lNumReaders == 0)
+ // If there are no reader threads,
+ // set our event to reflect this.
+ SetEvent(pSWMRG->hEventNoReaders);
+
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object.
+ // (it looks like writer is processing thread, but it is not true)
+ SetEvent(pSWMRG->hEventNoWriter);
+}
+
+uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter)
+{
+ uint32_t EnterCode;
+
+ if (WAIT_OBJECT_0 == (EnterCode = SWMRGWaitToWrite(SObject, INFINITE)))
+ if (SCounter != nullptr)
+ SCIncFcn(SCounter);
+
+ return EnterCode;
+}
+
+void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter)
+{
+ SWMRGDoneWriting(SObject);
+ if (SCounter != nullptr)
+ SCDecFcn(SCounter);
+}
+
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject)
+{
+ uint32_t EnterCode = SWMRGWaitToRead(SObject, INFINITE);
+ return EnterCode;
+}
+
+void WINAPI ReadDoneFcn(PSWMRG SObject)
+{
+ SWMRGDoneReading(SObject);
+}
+
+uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter)
+{
+
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ uint32_t Temp = SCounter->Number;
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
+
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter)
+{
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ uint32_t Temp = ++SCounter->Number;
+ ResetEvent(SCounter->Event);
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
+
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter)
+{
+ uint32_t Temp;
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ if (!(Temp = --SCounter->Number)) {
+ SetEvent(SCounter->Event);
+ }
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
diff --git a/protocols/YAMN/src/yamn.cpp b/protocols/YAMN/src/yamn.cpp index d0d80021f8..2af7efd74f 100644 --- a/protocols/YAMN/src/yamn.cpp +++ b/protocols/YAMN/src/yamn.cpp @@ -1,230 +1,230 @@ -/* - * This code implements miscellaneous usefull functions - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -//Plugin registration CS -//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins -mir_cs PluginRegCS; - -//AccountWriterCS -//We want to store number of writers of Accounts (number of Accounts used for writing) -//If we want to read all accounts (for saving to file) immidiatelly, we have to wait until no account is changing (no thread writing to account) -SCOUNTER *AccountWriterSO; - -//NoExitEV -//Event that is signaled when there's a request to exit, so no new pop3 check should be performed -HANDLE ExitEV; - -//WriteToFileEV -//If this is signaled, write accounts to file is performed. Set this event if you want to actualize your accounts and messages -HANDLE WriteToFileEV; - -//Returns pointer to YAMN exported function -INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam); - -//Returns pointer to YAMN variables -INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM); - -// Function every seconds decrements account counter of seconds and checks if they are 0 -// If yes, creates a POP3 thread to check account -void CALLBACK TimerProc(HWND, UINT, UINT, uint32_t); - -// Function called to check all accounts immidialtelly -// no params -INT_PTR ForceCheckSvc(WPARAM, LPARAM); - -//thread is running all the time -//waits for WriteToFileEV and then writes all accounts to file -//uint32_t WINAPI FileWritingThread(PVOID); - -// Function is called when Miranda notifies plugin that it is about to exit -// Ensures succesfull end of POP3 checking, sets event that no next checking should be performed -// If there's no writer to account (POP3 thread), saves the results to the file -//not used now, perhaps in the future - - -//int ExitProc(WPARAM wParam, LPARAM lParam); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM) -{ - int i; - - for (i=0;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, ProtoPluginExportedFcn[i].ID)) - return (INT_PTR)ProtoPluginExportedFcn[i].Ptr; - for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, ProtoPluginExportedSvc[i].ID)) - return (INT_PTR)ProtoPluginExportedSvc[i].Ptr; - for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, SynchroExportedFcn[i].ID)) - return (INT_PTR)SynchroExportedFcn[i].Ptr; - for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, AccountExportedFcn[i].ID)) - return (INT_PTR)AccountExportedFcn[i].Ptr; - for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, AccountExportedSvc[i].ID)) - return (INT_PTR)AccountExportedSvc[i].Ptr; - for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, MailExportedFcn[i].ID)) - return (INT_PTR)MailExportedFcn[i].Ptr; - for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, MailExportedSvc[i].ID)) - return (INT_PTR)MailExportedSvc[i].Ptr; - for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, FilterPluginExportedFcn[i].ID)) - return (INT_PTR)FilterPluginExportedFcn[i].Ptr; - for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, FilterPluginExportedSvc[i].ID)) - return (INT_PTR)FilterPluginExportedSvc[i].Ptr; - return (INT_PTR)NULL; -} - -INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM) -{ - return wParam==YAMN_VARIABLESVERSION ? (INT_PTR)&YAMNVar : (INT_PTR)NULL; -} - -void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) -{ - CAccount *ActualAccount; - DWORD Status, tid; - - // we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - return; - - // if we want to close miranda, we get event and do not run checking anymore - if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) - return; - - // Get actual status of current user in Miranda - Status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); - - mir_cslock lck(PluginRegCS); - for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) { - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) // we want to access accounts immiadtelly - return; - - for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - if (ActualAccount->Plugin == nullptr || ActualAccount->Plugin->Fcn == nullptr) //account not inited - continue; - - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) - continue; - - BOOL isAccountCounting = 0; - if ((ActualAccount->Flags & YAMN_ACC_ENA) && - (((ActualAccount->StatusFlags & YAMN_ACC_ST0) && (Status <= ID_STATUS_OFFLINE)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST1) && (Status == ID_STATUS_ONLINE)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST2) && (Status == ID_STATUS_AWAY)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST3) && (Status == ID_STATUS_DND)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST4) && (Status == ID_STATUS_NA)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST5) && (Status == ID_STATUS_OCCUPIED)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST6) && (Status == ID_STATUS_FREECHAT)) || - ((ActualAccount->StatusFlags & YAMN_ACC_ST7) && (Status == ID_STATUS_INVISIBLE)))) - { - if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr == nullptr) - goto ChangeIsCountingStatusLabel; - - if (ActualAccount->TimeLeft) { - ActualAccount->TimeLeft--; - isAccountCounting = TRUE; - } - - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGETIME, (WPARAM)ActualAccount, (LPARAM)ActualAccount->TimeLeft); - if (!ActualAccount->TimeLeft) { - struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_NORMALCHECK, (void *)nullptr, nullptr}; - - ActualAccount->TimeLeft = ActualAccount->Interval; - HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid); - if (NewThread == nullptr) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - else { - WaitForSingleObject(ThreadRunningEV, INFINITE); - CloseHandle(NewThread); - } - } - } - -ChangeIsCountingStatusLabel: - if (((ActualAccount->isCounting) != 0) != isAccountCounting) { - ActualAccount->isCounting = isAccountCounting; - uint16_t cStatus = g_plugin.getWord(ActualAccount->hContact, "Status"); - switch (cStatus) { - case ID_STATUS_ONLINE: - case ID_STATUS_OFFLINE: - g_plugin.setWord(ActualAccount->hContact, "Status", isAccountCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - default: - break; - } - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); - } - CloseHandle(ThreadRunningEV); -} - -INT_PTR ForceCheckSvc(WPARAM, LPARAM) -{ - CAccount *ActualAccount; - DWORD tid; - - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - return 0; - //if we want to close miranda, we get event and do not run pop3 checking anymore - if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) - return 0; - - { - mir_cslock lck(PluginRegCS); - for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) { - SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, INFINITE); - for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - if (ActualAccount->Plugin->Fcn == nullptr) //account not inited - continue; - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - continue; - - if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) { //account cannot be forced to check - if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr }; - - if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - else - WaitForSingleObject(ThreadRunningEV, INFINITE); - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); - } - } - - CloseHandle(ThreadRunningEV); - - if (hTTButton) - CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, 0); - return 1; -} +/*
+ * This code implements miscellaneous usefull functions
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+//Plugin registration CS
+//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins
+mir_cs PluginRegCS;
+
+//AccountWriterCS
+//We want to store number of writers of Accounts (number of Accounts used for writing)
+//If we want to read all accounts (for saving to file) immidiatelly, we have to wait until no account is changing (no thread writing to account)
+SCOUNTER *AccountWriterSO;
+
+//NoExitEV
+//Event that is signaled when there's a request to exit, so no new pop3 check should be performed
+HANDLE ExitEV;
+
+//WriteToFileEV
+//If this is signaled, write accounts to file is performed. Set this event if you want to actualize your accounts and messages
+HANDLE WriteToFileEV;
+
+//Returns pointer to YAMN exported function
+INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam);
+
+//Returns pointer to YAMN variables
+INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM);
+
+// Function every seconds decrements account counter of seconds and checks if they are 0
+// If yes, creates a POP3 thread to check account
+void CALLBACK TimerProc(HWND, UINT, UINT, uint32_t);
+
+// Function called to check all accounts immidialtelly
+// no params
+INT_PTR ForceCheckSvc(WPARAM, LPARAM);
+
+//thread is running all the time
+//waits for WriteToFileEV and then writes all accounts to file
+//uint32_t WINAPI FileWritingThread(PVOID);
+
+// Function is called when Miranda notifies plugin that it is about to exit
+// Ensures succesfull end of POP3 checking, sets event that no next checking should be performed
+// If there's no writer to account (POP3 thread), saves the results to the file
+//not used now, perhaps in the future
+
+
+//int ExitProc(WPARAM wParam, LPARAM lParam);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM)
+{
+ int i;
+
+ for (i=0;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedFcn[i].ID))
+ return (INT_PTR)ProtoPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedSvc[i].ID))
+ return (INT_PTR)ProtoPluginExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, SynchroExportedFcn[i].ID))
+ return (INT_PTR)SynchroExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedFcn[i].ID))
+ return (INT_PTR)AccountExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedSvc[i].ID))
+ return (INT_PTR)AccountExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedFcn[i].ID))
+ return (INT_PTR)MailExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedSvc[i].ID))
+ return (INT_PTR)MailExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, FilterPluginExportedFcn[i].ID))
+ return (INT_PTR)FilterPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, FilterPluginExportedSvc[i].ID))
+ return (INT_PTR)FilterPluginExportedSvc[i].Ptr;
+ return (INT_PTR)NULL;
+}
+
+INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM)
+{
+ return wParam==YAMN_VARIABLESVERSION ? (INT_PTR)&YAMNVar : (INT_PTR)NULL;
+}
+
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ CAccount *ActualAccount;
+ DWORD Status, tid;
+
+ // we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ return;
+
+ // if we want to close miranda, we get event and do not run checking anymore
+ if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0))
+ return;
+
+ // Get actual status of current user in Miranda
+ Status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0);
+
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) {
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) // we want to access accounts immiadtelly
+ return;
+
+ for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ if (ActualAccount->Plugin == nullptr || ActualAccount->Plugin->Fcn == nullptr) //account not inited
+ continue;
+
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0))
+ continue;
+
+ BOOL isAccountCounting = 0;
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) &&
+ (((ActualAccount->StatusFlags & YAMN_ACC_ST0) && (Status <= ID_STATUS_OFFLINE)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST1) && (Status == ID_STATUS_ONLINE)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST2) && (Status == ID_STATUS_AWAY)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST3) && (Status == ID_STATUS_DND)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST4) && (Status == ID_STATUS_NA)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST5) && (Status == ID_STATUS_OCCUPIED)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST6) && (Status == ID_STATUS_FREECHAT)) ||
+ ((ActualAccount->StatusFlags & YAMN_ACC_ST7) && (Status == ID_STATUS_INVISIBLE))))
+ {
+ if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr == nullptr)
+ goto ChangeIsCountingStatusLabel;
+
+ if (ActualAccount->TimeLeft) {
+ ActualAccount->TimeLeft--;
+ isAccountCounting = TRUE;
+ }
+
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGETIME, (WPARAM)ActualAccount, (LPARAM)ActualAccount->TimeLeft);
+ if (!ActualAccount->TimeLeft) {
+ struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_NORMALCHECK, (void *)nullptr, nullptr};
+
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread == nullptr) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ else {
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(NewThread);
+ }
+ }
+ }
+
+ChangeIsCountingStatusLabel:
+ if (((ActualAccount->isCounting) != 0) != isAccountCounting) {
+ ActualAccount->isCounting = isAccountCounting;
+ uint16_t cStatus = g_plugin.getWord(ActualAccount->hContact, "Status");
+ switch (cStatus) {
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_OFFLINE:
+ g_plugin.setWord(ActualAccount->hContact, "Status", isAccountCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ default:
+ break;
+ }
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO);
+ }
+ CloseHandle(ThreadRunningEV);
+}
+
+INT_PTR ForceCheckSvc(WPARAM, LPARAM)
+{
+ CAccount *ActualAccount;
+ DWORD tid;
+
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ return 0;
+ //if we want to close miranda, we get event and do not run pop3 checking anymore
+ if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0))
+ return 0;
+
+ {
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) {
+ SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, INFINITE);
+ for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ if (ActualAccount->Plugin->Fcn == nullptr) //account not inited
+ continue;
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ continue;
+
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) { //account cannot be forced to check
+ if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr };
+
+ if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ else
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO);
+ }
+ }
+
+ CloseHandle(ThreadRunningEV);
+
+ if (hTTButton)
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, 0);
+ return 1;
+}
|